From ee077d87305a125ed3a6840e995cd995f92e887a Mon Sep 17 00:00:00 2001 From: Terje Io Date: Mon, 9 Mar 2026 00:03:52 +0100 Subject: [PATCH] Changes to allow I/O expander pins for motor fault inputs. Ref. PR #920. --- README.md | 2 +- changelog.md | 18 +++++++++++- crossbar.c | 8 ++--- crossbar.h | 24 ++++++++++----- driver_opts2.h | 56 +++++++++++++++++++++++++++++++++++ grbl.h | 2 +- ioports.c | 19 ++++++++++-- pin_bits_masks.h | 76 ++++++++++++++++++++++++++++++++++++------------ 8 files changed, 170 insertions(+), 35 deletions(-) diff --git a/README.md b/README.md index a17eda3..f4084a8 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ ## grblHAL ## -Latest build date is 20260303, see the [changelog](changelog.md) for details. +Latest build date is 20260308, see the [changelog](changelog.md) for details. > [!NOTE] > A settings reset will be performed on an update of builds prior to 20241208. Backup and restore of settings is recommended. diff --git a/changelog.md b/changelog.md index 154ac5e..ee81c83 100644 --- a/changelog.md +++ b/changelog.md @@ -1,6 +1,22 @@ ## grblHAL changelog -Build 20260303 +Build 20260308 + +Core: + +* Changes to allow I/O expander pins for motor fault inputs. Ref. PR [#920](https://github.com/grblHAL/core/pull/920). + +Drivers: + +* ESP32: fix for compiler error when analog inputs were enabled. + +* RP2040, STM32F4xx and STM32F7xx: updated for core change. + +* STM32F1xx: removed some superfluous code, added reentry lock for MPG mode switch. + +--- + +Build 20260303 Core: diff --git a/crossbar.c b/crossbar.c index c790e39..6731850 100644 --- a/crossbar.c +++ b/crossbar.c @@ -3,7 +3,7 @@ Part of grblHAL - Copyright (c) 2023-2025 Terje Io + Copyright (c) 2023-2026 Terje Io grblHAL is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -53,7 +53,7 @@ axes_signals_t xbar_fn_to_axismask (pin_function_t fn) case Input_LimitX_2: case Input_HomeX: case Input_MotorFaultX: - case Input_MotorFaultX_2: + case Input_MotorFaultX2: case Output_StepperEnableX: mask.x = On; break; @@ -63,7 +63,7 @@ axes_signals_t xbar_fn_to_axismask (pin_function_t fn) case Input_LimitY_2: case Input_HomeY: case Input_MotorFaultY: - case Input_MotorFaultY_2: + case Input_MotorFaultY2: case Output_StepperEnableY: mask.y = On; break; @@ -73,7 +73,7 @@ axes_signals_t xbar_fn_to_axismask (pin_function_t fn) case Input_LimitZ_2: case Input_HomeZ: case Input_MotorFaultZ: - case Input_MotorFaultZ_2: + case Input_MotorFaultZ2: case Output_StepperEnableZ: mask.z = On; break; diff --git a/crossbar.h b/crossbar.h index e7f1d2b..1d607d8 100644 --- a/crossbar.h +++ b/crossbar.h @@ -51,9 +51,9 @@ typedef enum { Input_MotorFaultU, Input_MotorFaultV, Input_MotorFaultW, - Input_MotorFaultX_2, - Input_MotorFaultY_2, - Input_MotorFaultZ_2, + Input_MotorFaultX2, + Input_MotorFaultY2, + Input_MotorFaultZ2, Input_Probe2, Input_Probe2Overtravel, Input_Toolsetter, @@ -306,9 +306,9 @@ PROGMEM static const pin_name_t pin_names[] = { { .function = Input_MotorFaultX, .name = "X motor fault" }, { .function = Input_MotorFaultY, .name = "Y motor fault" }, { .function = Input_MotorFaultZ, .name = "Z motor fault" }, - { .function = Input_MotorFaultX_2, .name = "X motor fault 2" }, - { .function = Input_MotorFaultY_2, .name = "Y motor fault 2" }, - { .function = Input_MotorFaultZ_2, .name = "Z motor fault 2" }, + { .function = Input_MotorFaultX2, .name = "X motor fault 2" }, + { .function = Input_MotorFaultY2, .name = "Y motor fault 2" }, + { .function = Input_MotorFaultZ2, .name = "Z motor fault 2" }, { .function = Input_Probe2, .name = "Probe 2" }, { .function = Input_Probe2Overtravel, .name = "Probe 2 overtravel" }, { .function = Input_Toolsetter, .name = "Toolsetter" }, @@ -804,7 +804,7 @@ typedef union { static inline uint8_t xbar_fault_pin_to_axis (pin_function_t fn) { - return fn >= Input_MotorFaultX && fn <= Input_MotorFaultV ? fn - Input_MotorFaultX : (fn >= Input_MotorFaultX_2 && fn <= Input_MotorFaultZ_2 ? fn - Input_MotorFaultX_2 : 0); + return fn >= Input_MotorFaultX && fn <= Input_MotorFaultV ? fn - Input_MotorFaultX : (fn >= Input_MotorFaultX2 && fn <= Input_MotorFaultZ2 ? fn - Input_MotorFaultX2 : 0); } static inline stepper_state_t xbar_stepper_state_set (stepper_state_t *state, uint8_t axis, bool b) @@ -827,6 +827,16 @@ static inline bool xbar_is_probe_in (pin_function_t fn) return fn == Input_Probe || fn == Input_Probe2 || fn == Input_Toolsetter; } +static inline bool xbar_is_encoder_in (pin_function_t function) +{ + return function == Input_QEI_A || function == Input_QEI_B || function == Input_QEI_Select; +} + +static inline bool xbar_is_motor_fault_in (pin_function_t function) +{ + return function >= Input_MotorFaultX && function <= Input_MotorFaultZ2; +} + #define N_AUX_AIN_MAX (Input_Analog_AuxMax - Input_Analog_Aux0 + 1) #define N_AUX_AOUT_MAX (Output_Analog_AuxMax - Output_Analog_Aux0 + 1) #define N_AUX_DIN_MAX (Input_AuxMax - Input_Aux0 + 1) diff --git a/driver_opts2.h b/driver_opts2.h index 5bc193a..c383c28 100644 --- a/driver_opts2.h +++ b/driver_opts2.h @@ -182,6 +182,62 @@ #endif #endif // DIRECTION_PORT +#ifdef MOTOR_FAULT_PORT + +#if defined(X_MOTOR_FAULT_PIN) && !defined(X_MOTOR_FAULT_PORT) +#define X_MOTOR_FAULT_PORT MOTOR_FAULT_PORT +#endif +#if defined(Y_MOTOR_FAULT_PIN) && !defined(Y_MOTOR_FAULT_PORT) +#define Y_MOTOR_FAULT_PORT MOTOR_FAULT_PORT +#endif +#if defined(Z_MOTOR_FAULT_PIN) && !defined(Z_MOTOR_FAULT_PORT) +#define Z_MOTOR_FAULT_PORT MOTOR_FAULT_PORT +#endif +#if defined(M3_MOTOR_FAULT_PIN) && !defined(M3_MOTOR_FAULT_PORT) +#define M3_MOTOR_FAULT_PORT MOTOR_FAULT_PORT +#endif +#if defined(M4_MOTOR_FAULT_PIN) && !defined(M4_MOTOR_FAULT_PORT) +#define M4_MOTOR_FAULT_PORT MOTOR_FAULT_PORT +#endif +#if defined(M5_MOTOR_FAULT_PIN) && !defined(M5_MOTOR_FAULT_PORT) +#define M5_MOTOR_FAULT_PORT MOTOR_FAULT_PORT +#endif +#if defined(M6_MOTOR_FAULT_PIN) && !defined(M6_MOTOR_FAULT_PORT) +#define M6_MOTOR_FAULT_PORT MOTOR_FAULT_PORT +#endif +#if defined(M7_MOTOR_FAULT_PIN) && !defined(M7_MOTOR_FAULT_PORT) +#define M7_MOTOR_FAULT_PORT MOTOR_FAULT_PORT +#endif + +#elif defined(ESP_PLATFORM) || defined(RP2040) || defined(__IMXRT1062__) + +#if defined(X_MOTOR_FAULT_PIN) && !defined(X_MOTOR_FAULT_PORT) +#define X_MOTOR_FAULT_PORT NULL +#endif +#if defined(Y_MOTOR_FAULT_PIN) && !defined(Y_MOTOR_FAULT_PORT) +#define Y_MOTOR_FAULT_PORT NULL +#endif +#if defined(Z_MOTOR_FAULT_PIN) && !defined(Z_MOTOR_FAULT_PORT) +#define Z_MOTOR_FAULT_PORT NULL +#endif +#if defined(M3_MOTOR_FAULT_PIN) && !defined(M3_MOTOR_FAULT_PORT) +#define M3_MOTOR_FAULT_PORT NULL +#endif +#if defined(M4_MOTOR_FAULT_PIN) && !defined(M4_MOTOR_FAULT_PORT) +#define M4_MOTOR_FAULT_PORT NULL +#endif +#if defined(M5_MOTOR_FAULT_PIN) && !defined(M5_MOTOR_FAULT_PORT) +#define M5_MOTOR_FAULT_PORT NULL +#endif +#if defined(M6_MOTOR_FAULT_PIN) && !defined(M6_MOTOR_FAULT_PORT) +#define M6_MOTOR_FAULT_PORT NULL +#endif +#if defined(M7_MOTOR_FAULT_PIN) && !defined(M7_MOTOR_FAULT_PORT) +#define M7_MOTOR_FAULT_PORT NULL +#endif + +#endif // MOTOR_FAULT_PORTS + #ifdef SPINDLE_PORT #ifndef SPINDLE_ENABLE_PORT #define SPINDLE_ENABLE_PORT SPINDLE_PORT diff --git a/grbl.h b/grbl.h index 07305d9..3116b14 100644 --- a/grbl.h +++ b/grbl.h @@ -42,7 +42,7 @@ #else #define GRBL_VERSION "1.1f" #endif -#define GRBL_BUILD 20260303 +#define GRBL_BUILD 20260308 #define GRBL_URL "https://github.com/grblHAL" diff --git a/ioports.c b/ioports.c index bdadaf3..33f6c73 100644 --- a/ioports.c +++ b/ioports.c @@ -400,7 +400,7 @@ FLASHMEM bool ioport_set_function (xbar_t *pin, pin_function_t function, driver_ case Port_DigitalIn: if(caps.control) hal.signals_cap.mask |= caps.control->mask; - if(function == Input_Probe || function == Input_Probe2 || function == Input_Toolsetter || xbar_fn_to_signals_mask(function).mask) + if(xbar_is_probe_in(function) || xbar_is_motor_fault_in(function) || xbar_fn_to_signals_mask(function).mask) setting_remove_elements(Settings_IoPort_InvertIn, cfg->bus.mask, false); break; @@ -1443,6 +1443,18 @@ FLASHMEM static bool config_probe_pins (pin_function_t function, gpio_in_config_ return ok; } +FLASHMEM static bool config_fault_pins (pin_function_t function, gpio_in_config_t *config) +{ + bool ok; + + if((ok = xbar_is_motor_fault_in(function))) { + config->debounce = Off; + config->inverted = bit_istrue(settings.motor_fault_invert.mask, bit(xbar_fault_pin_to_axis(function))); + } + + return ok; +} + FLASHMEM void ioport_setting_changed (setting_id_t id) { if(on_setting_changed) @@ -1452,6 +1464,7 @@ FLASHMEM void ioport_setting_changed (setting_id_t id) case Setting_InvertProbePin: case Setting_ProbePullUpDisable: + case Setting_MotorFaultsInvert: { xbar_t *xbar; gpio_in_config_t in_config = {0}; @@ -1459,7 +1472,7 @@ FLASHMEM void ioport_setting_changed (setting_id_t id) do { if((xbar = hal.port.get_pin_info(Port_Digital, Port_Input, map_reverse(&ports_cfg[Port_DigitalIn], --port)))) { - if(xbar->config && config_probe_pins(xbar->function, &in_config)) { + if(xbar->config && (config_probe_pins(xbar->function, &in_config) || config_fault_pins(xbar->function, &in_config))) { if(in_config.inverted) settings.ioport.invert_in.mask |= (1 << port); else @@ -1539,7 +1552,7 @@ FLASHMEM static void ioports_configure (settings_t *settings) #endif } else { // For probe and control signals higher level config takes priority in_config.inverted = Off; - if(!config_probe_pins(xbar->function, &in_config) && xbar->function < Input_Probe) { + if(!(config_probe_pins(xbar->function, &in_config) || config_fault_pins(xbar->function, &in_config)) && xbar->function < Input_Probe) { control_signals_t ctrl; if((ctrl = xbar_fn_to_signals_mask(xbar->function)).mask) { in_config.inverted = !!(settings->control_invert.mask & ctrl.mask); diff --git a/pin_bits_masks.h b/pin_bits_masks.h index 6dba8dd..80295a2 100644 --- a/pin_bits_masks.h +++ b/pin_bits_masks.h @@ -124,6 +124,7 @@ #define add_aux_output(fn, aux) { .function = fn, .port = IOPORT_UNASSIGNED, .gpio.port = (void *)aux##_PORT, .gpio.pin = aux##_PIN }, #endif #define add_aux_input_scan(fn, irq, signal_bit) { .function = fn, .irq_mode = irq, .signal.value = signal_bit, .port = IOPORT_UNASSIGNED, .gpio.pin = 0xFF, .scan = On }, +#define add_aux_motor_input(fn, motor, aux, irq) { .function = fn##motor, .irq_mode = irq, .port = IOPORT_UNASSIGNED, .gpio.port = (void *)motor##_##aux##_PORT, .gpio.pin = motor##_##aux##_PIN }, #define add_aux_input_no_signal(fn, irq) { .function = fn, .irq_mode = irq, .port = IOPORT_UNASSIGNED, .gpio.pin = 0xFE }, #define add_aux_output_exp(fn, aux) { .function = fn, .port = IOPORT_UNASSIGNED, .gpio.port = (void *)aux##_PORT, .gpio.pin = aux##_PIN }, @@ -137,7 +138,7 @@ static aux_ctrl_t aux_ctrl[] = { #endif #endif #if (CONTROL_ENABLE & CONTROL_FEED_HOLD) && defined(FEED_HOLD_PIN) - add_aux_input(Input_FeedHold, FEED_HOLD, IRQ_Mode_RisingFalling, SIGNALS_FEEDHOLD_BIT) + add_aux_input(Input_FeedHold, FEED_HOLD, IRQ_Mode_RisingFalling, SIGNALS_FEEDHOLD_BIT) #endif #if (CONTROL_ENABLE & CONTROL_CYCLE_START) && defined(CYCLE_START_PIN) add_aux_input(Input_CycleStart, CYCLE_START, IRQ_Mode_RisingFalling, SIGNALS_CYCLESTART_BIT) @@ -147,7 +148,44 @@ static aux_ctrl_t aux_ctrl[] = { #endif #if MOTOR_FAULT_ENABLE && defined(MOTOR_FAULT_PIN) add_aux_input(Input_MotorFault, MOTOR_FAULT, IRQ_Mode_RisingFalling, SIGNALS_MOTOR_FAULT_BIT) +#else +#if defined(X_MOTOR_FAULT_PIN) + add_aux_motor_input(Input_MotorFault, X, MOTOR_FAULT, IRQ_Mode_None) #endif +#if defined(Y_MOTOR_FAULT_PIN) + add_aux_motor_input(Input_MotorFault, Y, MOTOR_FAULT, IRQ_Mode_None) +#endif +#if defined(Z_MOTOR_FAULT_PIN) + add_aux_motor_input(Input_MotorFault, Z, MOTOR_FAULT, IRQ_Mode_None) +#endif +#if defined(A_MOTOR_FAULT_PIN) + add_aux_motor_input(Input_MotorFault, A, MOTOR_FAULT, IRQ_Mode_None) +#endif +#if defined(B_MOTOR_FAULT_PIN) + add_aux_motor_input(Input_MotorFault, B, MOTOR_FAULT, IRQ_Mode_None) +#endif +#if defined(C_MOTOR_FAULT_PIN) + add_aux_motor_input(Input_MotorFault, C, MOTOR_FAULT, IRQ_Mode_None) +#endif +#if defined(U_MOTOR_FAULT_PIN) + add_aux_motor_input(Input_MotorFault, U, MOTOR_FAULT, IRQ_Mode_None) +#endif +#if defined(V_MOTOR_FAULT_PIN) + add_aux_motor_input(Input_MotorFault, V, MOTOR_FAULT, IRQ_Mode_None) +#endif +#if defined(W_MOTOR_FAULT_PIN) + add_aux_motor_input(Input_MotorFault, W, MOTOR_FAULT, IRQ_Mode_None) +#endif +#if defined(X2_MOTOR_FAULT_PIN) + add_aux_motor_input(Input_MotorFault, X2, MOTOR_FAULT, IRQ_Mode_None) +#endif +#if defined(Y2_MOTOR_FAULT_PIN) + add_aux_motor_input(Input_MotorFault, Y2, MOTOR_FAULT, IRQ_Mode_None) +#endif +#if defined(Z2_MOTOR_FAULT_PIN) + add_aux_motor_input(Input_MotorFault, Z2, MOTOR_FAULT, IRQ_Mode_None) +#endif +#endif // MOTOR_FAULT_ENABLE #if MOTOR_WARNING_ENABLE && defined(MOTOR_WARNING_PIN) add_aux_input(Input_MotorWarning, MOTOR_WARNING, IRQ_Mode_RisingFalling, SIGNALS_MOTOR_WARNING_BIT) #endif @@ -205,16 +243,6 @@ static aux_ctrl_t aux_ctrl[] = { // General inputs -static inline bool aux_ctrl_is_probe (pin_function_t function) -{ - return function == Input_Probe || function == Input_Probe2 || function == Input_Toolsetter; -} - -static inline bool aux_ctrl_is_encoder (pin_function_t function) -{ - return function == Input_QEI_A || function == Input_QEI_B || function == Input_QEI_Select; -} - #ifdef STM32_PLATFORM static inline aux_ctrl_t *aux_ctrl_get_fn (aux_gpio_t gpio) @@ -290,7 +318,7 @@ static inline void aux_ctrl_irq_enable (settings_t *settings, ioport_interrupt_c if(idx) do { if(aux_ctrl[--idx].port != 0xFF && aux_ctrl[idx].irq_mode != IRQ_Mode_None) { - if(!(aux_ctrl_is_probe(aux_ctrl[idx].function) || aux_ctrl_is_encoder(aux_ctrl[idx].function))) { + if(!(xbar_is_probe_in(aux_ctrl[idx].function) || xbar_is_encoder_in(aux_ctrl[idx].function))) { pin_irq_mode_t irq_mode; if((irq_mode = aux_ctrl[idx].irq_mode) & IRQ_Mode_RisingFalling) irq_mode = (settings->control_invert.mask & aux_ctrl[idx].signal.mask) ? IRQ_Mode_Falling : IRQ_Mode_Rising; @@ -316,6 +344,16 @@ static bool __claim_in_port (xbar_t *properties, uint8_t port, void *data) return ((aux_ctrl_t *)data)->port != IOPORT_UNASSIGNED; } +static bool __find_in_ext (xbar_t *properties, uint8_t port, void *data) +{ + bool ok; + + if((ok = properties->pin == ((aux_ctrl_t *)data)->gpio.pin)) + ((aux_ctrl_t *)data)->port = port; + + return ok; +} + static bool __find_in_port (xbar_t *properties, uint8_t port, void *data) { ((aux_ctrl_t *)data)->port = port; @@ -334,9 +372,11 @@ static inline void aux_ctrl_claim_ports (aux_claim_explicit_ptr aux_claim_explic if(sizeof(aux_ctrl)) for(idx = 0; idx < sizeof(aux_ctrl) / sizeof(aux_ctrl_t); idx++) { - if(aux_ctrl[idx].port != IOPORT_UNASSIGNED) + if(aux_ctrl[idx].gpio.port == (void *)EXPANDER_PORT) { + if(ioports_enumerate(Port_Digital, Port_Input, (pin_cap_t){ .irq_mode = aux_ctrl[idx].irq_mode, .external = On, .claimable = On }, __find_in_ext, &aux_ctrl[idx])) + aux_claim_explicit(&aux_ctrl[idx]); + } else if(aux_ctrl[idx].port != IOPORT_UNASSIGNED) aux_claim_explicit(&aux_ctrl[idx]); - else { pin_cap_t cap = { .irq_mode = aux_ctrl[idx].irq_mode, .claimable = On }; @@ -346,7 +386,7 @@ static inline void aux_ctrl_claim_ports (aux_claim_explicit_ptr aux_claim_explic aux_claim_explicit(&aux_ctrl[idx]); #ifdef STM32_PLATFORM - if(aux_ctrl[idx].irq_mode == IRQ_Mode_None && !(aux_ctrl_is_probe(aux_ctrl[idx].function) || aux_ctrl[idx].function == Input_LimitsOverride)) + if(aux_ctrl[idx].irq_mode == IRQ_Mode_None && !(xbar_is_probe_in(aux_ctrl[idx].function) || aux_ctrl[idx].function == Input_LimitsOverride)) continue; #endif if(aux_ctrl[idx].gpio.pin == 0xFF) { @@ -598,7 +638,7 @@ static inline void aux_ctrl_claim_out_ports (aux_claim_explicit_out_ptr aux_clai #if SPINDLE_ENCODER_ENABLE #ifndef SPINDLE_PULSE_PIN -#error "Spindle encoder requires at least SPINDLE_PULSE_PIN defined in the board map!" +//#error "Spindle encoder requires at least SPINDLE_PULSE_PIN defined in the board map!" #endif #if !defined(SPINDLE_PULSE_BIT) && defined(SPINDLE_PULSE_PIN) #define SPINDLE_PULSE_BIT (1<