Skip to content

Commit 6948b0e

Browse files
committed
Added initial/enhanced support for toolsetter and second probe input.
Moved inbuilt G65 macros to the core and added macro G65P5Q<n> for selecting probe. Added probe id to real time report: |P:<n> will be reported on probe select when more than one probe is available. Fix for WCO and Ov real time status report elements not beeing reported as they should in some circumstances.
1 parent fb3f6b6 commit 6948b0e

25 files changed

+450
-169
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
## grblHAL ##
22

3-
Latest build date is 20250425, see the [changelog](changelog.md) for details.
3+
Latest build date is 20250514, see the [changelog](changelog.md) for details.
44

55
> [!NOTE]
66
> A settings reset will be performed on an update of builds prior to 20241208. Backup and restore of settings is recommended.

changelog.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,35 @@
11
## grblHAL changelog
22

3+
<a name="20250514">Build 20250514
4+
5+
Core:
6+
7+
* Added initial/enhanced support for toolsetter and second probe input.
8+
When more than one probe is available `PROBES:<bits>` is added to the `NEWOPTS` element in the `$I` report. `<bits>` is a bitfield where each bit set represents an available probe.
9+
10+
* Moved inbuilt G65 macros to the core and added macro `G65P5Q<n>` for selecting probe. `<n>` is the probe id: `0` - primary probe, `1` - toolsetter, `2` - secondary probe.
11+
12+
* Added probe id to real time report: `|P:<n>` will be reported on probe select when more than one probe is available.
13+
14+
* Fix for `WCO` and `Ov` real time status report elements not beeing reported as they should in some circumstances.
15+
16+
Drivers:
17+
18+
* All: fix for potential/actual hard fault when a basic on/off spindle is configured. Ref. ESP32 issue [#164](https://github.com/grblHAL/ESP32/issues/164).
19+
20+
* STM32 drivers: fix for incorrect PWM output at max RPM when PWM output is inverted.
21+
22+
Plugins:
23+
24+
* Misc, probe relays: new plugin, can be configured to share the \(single\) probe input between up to three probes.
25+
Probe switching is by the inbuilt `G65P5Q<n>` macro or automatically on "@G59.3" tool changes for a toolsetter. One or two free auxiliary output ports required.
26+
27+
* Misc, BLTouch: improved auto deploy capability.
28+
29+
* SDCard, macros: moved inbuilt G65 macros to the core.
30+
31+
---
32+
333
<a name="20250504">20250504
434

535
Plugins:

crossbar.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ typedef enum {
5353
Input_MotorFaultX_2,
5454
Input_MotorFaultY_2,
5555
Input_MotorFaultZ_2,
56+
Input_Probe2,
57+
Input_Probe2Overtravel,
5658
Input_Toolsetter,
5759
Input_ToolsetterOvertravel,
5860
Input_MPGSelect,
@@ -300,6 +302,8 @@ PROGMEM static const pin_name_t pin_names[] = {
300302
{ .function = Input_MotorFaultX_2, .name = "X motor fault 2" },
301303
{ .function = Input_MotorFaultY_2, .name = "Y motor fault 2" },
302304
{ .function = Input_MotorFaultZ_2, .name = "Z motor fault 2" },
305+
{ .function = Input_Probe2, .name = "Probe 2" },
306+
{ .function = Input_Probe2Overtravel, .name = "Probe 2 overtravel" },
303307
{ .function = Input_Toolsetter, .name = "Toolsetter" },
304308
{ .function = Input_ToolsetterOvertravel, .name = "Toolsetter overtravel" },
305309
{ .function = Input_MPGSelect, .name = "MPG mode select" },

driver_opts.h

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,11 @@
2929

3030
#include "hal.h"
3131
#include "nuts_bolts.h"
32+
33+
#define MODBUS_RTU_ENABLED 0b001
34+
#define MODBUS_RTU_DIR_ENABLED 0b010
35+
#define MODBUS_TCP_ENABLED 0b100
36+
3237
#include "expanders_init.h"
3338

3439
#ifdef OPTS_POSTPROCESSING
@@ -393,10 +398,6 @@
393398
#endif
394399
#endif
395400

396-
#define MODBUS_RTU_ENABLED 0b001
397-
#define MODBUS_RTU_DIR_ENABLED 0b010
398-
#define MODBUS_TCP_ENABLED 0b100
399-
400401
#if MODBUS_ENABLE == 2
401402
#undef MODBUS_ENABLE
402403
#define MODBUS_ENABLE 0b011
@@ -476,6 +477,14 @@
476477
#define LIMITS_OVERRIDE_ENABLE 0
477478
#endif
478479

480+
#ifndef PROBE2_ENABLE
481+
#define PROBE2_ENABLE 0
482+
#endif
483+
484+
#ifndef TOOLSETTER_ENABLE
485+
#define TOOLSETTER_ENABLE 0
486+
#endif
487+
479488
#if SAFETY_DOOR_ENABLE && defined(NO_SAFETY_DOOR_SUPPORT)
480489
#error "Driver does not support safety door functionality!"
481490
#endif

expanders_init.h

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -63,17 +63,24 @@ extern void pca9654e_init(void);
6363

6464
// ModBus expanders
6565

66+
#if PICOHAL_IO_ENABLE || R4SLS08_ENABLE
6667

68+
#if !defined(MODBUS_ENABLE) || !(MODBUS_ENABLE & MODBUS_RTU_ENABLED)
69+
#error "Enabled IO expander(s) require Modbus RTU!"
70+
#endif
6771

68-
#if PICOHAL_IO_ENABLE
69-
70-
#if !MODBUS_ENABLE
71-
#error "Modbus must be enabled to use the Picohal IO expander!"
72+
#if R4SLS08_ENABLE
73+
extern void r4sls08_init (void);
7274
#endif
7375

76+
// Third party Modbus expander plugins goes after this line
77+
78+
#if PICOHAL_IO_ENABLE
7479
extern void picohal_io_init (void);
7580
#endif
7681

82+
#endif // ModBus expanders
83+
7784
// CANBus expanders
7885

7986
//
@@ -94,12 +101,15 @@ static inline void io_expanders_init (void)
94101
mcp4725_init();
95102
#endif
96103

104+
#if R4SLS08_ENABLE
105+
r4sls08_init();
106+
#endif
107+
97108
#if PCA9654E_ENABLE
98109
pca9654e_init();
99110
#endif
100111

101112
#if PICOHAL_IO_ENABLE
102113
picohal_io_init();
103114
#endif
104-
105115
}

gcode.c

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -393,7 +393,7 @@ void gc_init (bool stop)
393393
ngc_flowctrl_init();
394394
#endif
395395
#if NGC_PARAMETERS_ENABLE
396-
ngc_modal_state_invalidate();
396+
ngc_params_init();
397397
#endif
398398
#if ENABLE_ACCELERATION_PROFILES
399399
gc_state.modal.acceleration_factor = gc_get_accel_factor(0); // Initialize machine with default
@@ -762,15 +762,7 @@ status_code_t gc_execute_block (char *block)
762762

763763
DCRAM static parser_block_t gc_block;
764764

765-
#if NGC_EXPRESSIONS_ENABLE
766-
767-
static const parameter_words_t o_label = {
768-
.o = On
769-
};
770-
771-
static ngc_param_t ngc_params[NGC_N_ASSIGN_PARAMETERS_PER_BLOCK];
772-
773-
uint_fast8_t ngc_param_count = 0;
765+
#if NGC_PARAMETERS_ENABLE
774766

775767
// NOTE: this array has to match the parameter_words_t order!
776768
PROGMEM static const gc_value_ptr_t gc_value_ptr[] = {
@@ -823,7 +815,19 @@ status_code_t gc_execute_block (char *block)
823815
{ &gc_block.values.xyz[Z_AXIS], ValueType_Float }
824816
};
825817

826-
#endif
818+
#endif // NGC_PARAMETERS_ENABLE
819+
820+
#if NGC_EXPRESSIONS_ENABLE
821+
822+
static const parameter_words_t o_label = {
823+
.o = On
824+
};
825+
826+
static ngc_param_t ngc_params[NGC_N_ASSIGN_PARAMETERS_PER_BLOCK];
827+
828+
uint_fast8_t ngc_param_count = 0;
829+
830+
#endif // NGC_EXPRESSIONS_ENABLE
827831

828832
char *message = NULL;
829833
status_code_t status = Status_OK;
@@ -2530,8 +2534,7 @@ status_code_t gc_execute_block (char *block)
25302534
#if NGC_PARAMETERS_ENABLE
25312535
if(!ngc_call_push(&gc_state + ngc_call_level()))
25322536
FAIL(Status_FlowControlStackOverflow); // [Call level too deep]
2533-
#endif
2534-
#if NGC_EXPRESSIONS_ENABLE
2537+
25352538
// TODO: add context for local storage?
25362539
{
25372540
uint_fast8_t idx = 1;

grbl.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
#else
4343
#define GRBL_VERSION "1.1f"
4444
#endif
45-
#define GRBL_BUILD 20250425
45+
#define GRBL_BUILD 20250514
4646

4747
#define GRBL_URL "https://github.com/grblHAL"
4848

grbllib.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,16 @@ static void onLinestateChanged (serial_linestate_t state)
190190
on_linestate_changed(state);
191191
}
192192

193+
static bool onProbeToolsetter (tool_data_t *tool, coord_data_t *position, bool at_g59_3, bool on)
194+
{
195+
bool ok = false;
196+
197+
if(at_g59_3 && settings.probe.toolsetter_auto_select)
198+
ok = hal.probe.select(on ? Probe_Toolsetter : Probe_Default);
199+
200+
return ok;
201+
}
202+
193203
static void settings_changed (settings_t *settings, settings_changed_flags_t changed)
194204
{
195205
hal_settings_changed(settings, changed);
@@ -381,6 +391,9 @@ int grbl_enter (void)
381391
hal.stream.on_linestate_changed = onLinestateChanged;
382392
}
383393

394+
if(grbl.on_probe_toolsetter == NULL && hal.driver_cap.toolsetter && hal.probe.select)
395+
grbl.on_probe_toolsetter = onProbeToolsetter;
396+
384397
// Initialization loop upon power-up or a system abort. For the latter, all processes
385398
// will return to this loop to be cleanly re-initialized.
386399
while(looping) {

hal.h

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -68,11 +68,13 @@ typedef union {
6868
no_gcode_message_handling :1,
6969
odometers :1,
7070
pwm_spindle :1,
71-
probe_latch :1,
71+
probe_latch :1, //!< Deprecated.
7272
toolsetter :1, //!< Toolsetter (2nd probe) input is supported.
73+
probe2 :1, //!< 2nd or 3rd probe input is supported.
7374
rtc :1,
7475
rtc_set :1,
75-
unassigned :7;
76+
bltouch_probe :1,
77+
unassigned :6;
7678
};
7779
} driver_cap_t;
7880

@@ -358,9 +360,9 @@ typedef struct {
358360
} delay_t;
359361

360362

361-
/***********
362-
* Probe *
363-
***********/
363+
/************
364+
* Probes *
365+
************/
364366

365367
/*! \brief Pointer to function for getting probe status.
366368
\returns probe state in a \a #probe_state_t union.
@@ -375,8 +377,15 @@ typedef probe_state_t (*probe_get_state_ptr)(void);
375377
*/
376378
typedef void (*probe_configure_ptr)(bool is_probe_away, bool probing);
377379

380+
/*! \brief Pointer to function for selecting probe input.
381+
\param probe_id probe number. 0 - default probe, 1 - toolsetter, ...
382+
\returns true if selectetion succeded, false otherwise.
383+
*/
384+
typedef bool (*probe_select_ptr)(probe_id_t probe_id);
385+
378386
/*! \brief Pointer to function for toggling probe connected status.
379387
388+
380389
If the driver does not support a probe connected input signal this can be used to implement
381390
toggling of probe connected status via a #CMD_PROBE_CONNECTED_TOGGLE real time command.
382391
*/
@@ -386,6 +395,7 @@ typedef void (*probe_connected_toggle_ptr)(void);
386395
typedef struct {
387396
probe_configure_ptr configure; //!< Optional handler for setting probe operation mode.
388397
probe_get_state_ptr get_state; //!< Optional handler for getting probe status. Called from interrupt context.
398+
probe_select_ptr select; //!< Optional handler for selecting probe to use.
389399
probe_connected_toggle_ptr connected_toggle; //!< Optional handler for toggling probe connected status.
390400
} probe_ptrs_t;
391401

ioports.c

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -303,8 +303,10 @@ xbar_t *ioport_claim (io_port_type_t type, io_port_direction_t dir, uint8_t *por
303303

304304
if(get_hcount(type, dir) == hcnt)
305305
dec_hcount(type, dir);
306-
} else
306+
} else {
307307
portinfo = NULL;
308+
*port = IOPORT_UNASSIGNED;
309+
}
308310
}
309311

310312
return portinfo;
@@ -1386,11 +1388,8 @@ static void ioports_configure (settings_t *settings)
13861388
out_config.inverted = (settings->ioport.invert_out.mask & (1 << port)) && is_aux(cfg, xbar->function);
13871389
out_config.open_drain = !!(settings->ioport.od_enable_out.mask & (1 << port));
13881390
xbar->config(xbar, &out_config, false);
1389-
} else { // TODO: same for inputs?
1390-
ioport_bus_t bus;
1391-
bus.mask = cfg->bus.mask & (1 << port);
1392-
setting_remove_elements(Settings_IoPort_InvertOut, bus.mask);
1393-
}
1391+
} else // TODO: same for inputs?
1392+
setting_remove_elements(Settings_IoPort_InvertOut, cfg->bus.mask & ~(1 << port));
13941393
}
13951394
} while(port);
13961395

motion_control.c

Lines changed: 26 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -999,27 +999,13 @@ gc_probe_t mc_probe_cycle (float *target, plan_line_data_t *pl_data, gc_parser_f
999999
if (!protocol_buffer_synchronize())
10001000
return GCProbe_Abort; // Return if system reset has been issued.
10011001

1002-
// Initialize probing control variables
1003-
sys.flags.probe_succeeded = Off; // Re-initialize probe history before beginning cycle.
1004-
hal.probe.configure(parser_flags.probe_is_away, true);
1005-
10061002
#if COMPATIBILITY_LEVEL <= 1
10071003
bool at_g59_3 = false, probe_toolsetter = grbl.on_probe_toolsetter != NULL && state_get() != STATE_TOOL_CHANGE && (sys.homed.mask & (X_AXIS_BIT|Y_AXIS_BIT));
10081004

10091005
if(probe_toolsetter)
1010-
grbl.on_probe_toolsetter(NULL, NULL, at_g59_3 = system_xy_at_fixture(CoordinateSystem_G59_3, TOOLSETTER_RADIUS), true);
1006+
pl_data->condition.probing_toolsetter = grbl.on_probe_toolsetter(NULL, NULL, at_g59_3 = system_xy_at_fixture(CoordinateSystem_G59_3, TOOLSETTER_RADIUS), true);
10111007
#endif
10121008

1013-
// After syncing, check if probe is already triggered or not connected. If so, halt and issue alarm.
1014-
// NOTE: This probe initialization error applies to all probing cycles.
1015-
probe_state_t probe = hal.probe.get_state();
1016-
if (probe.triggered || !probe.connected) { // Check probe state.
1017-
system_set_exec_alarm(Alarm_ProbeFailInitial);
1018-
protocol_execute_realtime();
1019-
hal.probe.configure(false, false); // Re-initialize invert mask before returning.
1020-
return GCProbe_FailInit; // Nothing else to do but bail.
1021-
}
1022-
10231009
if(grbl.on_probe_start) {
10241010

10251011
uint_fast8_t idx = N_AXIS;
@@ -1037,6 +1023,31 @@ gc_probe_t mc_probe_cycle (float *target, plan_line_data_t *pl_data, gc_parser_f
10371023
grbl.on_probe_start(axes, target, pl_data);
10381024
}
10391025

1026+
// Initialize probing control variables
1027+
sys.flags.probe_succeeded = Off; // Re-initialize probe history before beginning cycle.
1028+
hal.probe.configure(parser_flags.probe_is_away, true);
1029+
1030+
// After syncing, check if probe is already triggered or not connected. If so, halt and issue alarm.
1031+
// NOTE: This probe initialization error applies to all probing cycles.
1032+
probe_state_t probe = hal.probe.get_state();
1033+
if (probe.triggered || !probe.connected) { // Check probe state.
1034+
1035+
system_set_exec_alarm(Alarm_ProbeFailInitial);
1036+
protocol_execute_realtime();
1037+
1038+
hal.probe.configure(false, false); // Re-initialize invert mask before returning.
1039+
1040+
#if COMPATIBILITY_LEVEL <= 1
1041+
if(probe_toolsetter)
1042+
grbl.on_probe_toolsetter(NULL, NULL, at_g59_3, false);
1043+
#endif
1044+
1045+
if(grbl.on_probe_completed)
1046+
grbl.on_probe_completed();
1047+
1048+
return GCProbe_FailInit; // Nothing else to do but bail.
1049+
}
1050+
10401051
// Setup and queue probing motion. Auto cycle-start should not start the cycle.
10411052
if(!mc_line(target, pl_data))
10421053
return GCProbe_Abort;

0 commit comments

Comments
 (0)