"hardened" code related to ioports claiming and PWM2 spindle configuration.

Added API call and expanded one.
This commit is contained in:
Terje Io
2025-07-16 10:58:31 +02:00
parent 7467c07567
commit 5dae16ad83
9 changed files with 108 additions and 53 deletions

View File

@@ -1,6 +1,6 @@
## grblHAL ## ## grblHAL ##
Latest build date is 20250706, see the [changelog](changelog.md) for details. Latest build date is 20250716, see the [changelog](changelog.md) for details.
> [!NOTE] > [!NOTE]
> A settings reset will be performed on an update of builds prior to 20241208. Backup and restore of settings is recommended. > A settings reset will be performed on an update of builds prior to 20241208. Backup and restore of settings is recommended.

View File

@@ -1,5 +1,25 @@
## grblHAL changelog ## grblHAL changelog
<a name="20250716">Build 20250716
Core:
* "hardened" code related to ioports claiming and PWM2 spindle configuration. Added API call and expanded one.
Drivers:
* iMXRT1062: removed stray code guard preventing initialisation of analog auxiliary outputs. Refs issue [#99](https://github.com/grblHAL/iMXRT1062/issues/99).
* STM32F1xx, STM32F3xx, STM32F4xx, STM32F7xx: ensured stepper enable signals are set to disabled during startup.
> [!NOTE]
> The initial stepper enable signal state will be determined by the stepper driver enable input (pulled up or down) since the related MCU pins are briefly in a high-Z state during startup.
Plugins:
* Spindle, PWM: "hardened" and cleaned up code.
---
<a name="20250706">Build 20250706 <a name="20250706">Build 20250706
Core: Core:

View File

@@ -29,6 +29,22 @@ axes_signals_t xbar_fn_to_axismask (pin_function_t fn)
switch(fn) { switch(fn) {
case Output_StepperEnable:
mask.bits = AXES_BITMASK;
break;
case Output_StepperEnableXY:
mask.x = mask.y = On;
break;
#if N_AXIS > 3
case Output_StepperEnableAB:
mask.a = On;
#if N_AXIS > 4
mask.b = On;
#endif
break;
#endif
case Input_LimitX: case Input_LimitX:
case Input_LimitX_Max: case Input_LimitX_Max:
case Input_LimitX_2: case Input_LimitX_2:
@@ -98,6 +114,8 @@ axes_signals_t xbar_fn_to_axismask (pin_function_t fn)
#endif #endif
default: default:
if(fn >= Output_StepperEnableX && fn <= Output_StepperEnableV)
mask.bits = (1 << (fn - Output_StepperEnableX));
break; break;
} }

View File

@@ -178,9 +178,9 @@ typedef enum {
Output_StepperEnableZ2 = Output_StepperEnableZ, Output_StepperEnableZ2 = Output_StepperEnableZ,
Output_StepperEnableA, Output_StepperEnableA,
Output_StepperEnableB, Output_StepperEnableB,
Output_StepperEnableC,
Output_StepperEnableU, Output_StepperEnableU,
Output_StepperEnableV, Output_StepperEnableV,
Output_StepperEnableC,
Output_StepperEnableXY, Output_StepperEnableXY,
Output_StepperEnableAB, Output_StepperEnableAB,
Output_SpindleOn, Output_SpindleOn,

2
grbl.h
View File

@@ -42,7 +42,7 @@
#else #else
#define GRBL_VERSION "1.1f" #define GRBL_VERSION "1.1f"
#endif #endif
#define GRBL_BUILD 20250705 #define GRBL_BUILD 20250716
#define GRBL_URL "https://github.com/grblHAL" #define GRBL_URL "https://github.com/grblHAL"

View File

@@ -581,6 +581,7 @@ static xbar_t *io_get_pin_info (io_port_type_t type, io_port_direction_t dir, ui
if(is_match(io_port, type, dir, port)) { if(is_match(io_port, type, dir, port)) {
if((pin = io_port->hal.get_pin_info(dir, port - io_port->ports_id->cfg[dir].n_start))) { if((pin = io_port->hal.get_pin_info(dir, port - io_port->ports_id->cfg[dir].n_start))) {
pin->ports_id = io_port->ports_id; pin->ports_id = io_port->ports_id;
pin->cap.claimable = is_aux(cfg, pin->function);
pin->mode.claimed = cfg->claimed.mask & (1UL << (pin->id + io_port->ports_id->cfg[dir].n_start)); pin->mode.claimed = cfg->claimed.mask & (1UL << (pin->id + io_port->ports_id->cfg[dir].n_start));
} }
} }

View File

@@ -978,35 +978,54 @@ static uint32_t get_int (setting_id_t id)
return value; return value;
} }
static status_code_t set_dir_port (setting_id_t id, float value) static float get_port (setting_id_t id)
{ {
sp1_settings.port_dir = value < 0.0f ? 255 : (int8_t)value; uint8_t port;
return Status_OK; switch(id) {
}
static float get_dir_port (setting_id_t id) case Setting_Spindle_OnPort:
{ port = sp1_settings.port_on;
return sp1_settings.port_dir == 255 ? -1.0f : (float)sp1_settings.port_dir; break;
}
static uint32_t get_pwm_port (setting_id_t id) case Setting_Spindle_DirPort:
{ port = sp1_settings.port_dir;
return (uint32_t)sp1_settings.port_pwm; break;
default: // Setting_Spindle_PWMPort:
port = sp1_settings.port_pwm;
break;
}
return port == IOPORT_UNASSIGNED ? -1.0f : (float)port;
} }
bool pwm_port_validate (xbar_t *properties, uint8_t port, void *data) bool pwm_port_validate (xbar_t *properties, uint8_t port, void *data)
{ {
return port == (uint8_t)((uint32_t)data); return port == *(uint8_t *)data;
} }
static status_code_t set_pwm_port (setting_id_t id, uint_fast16_t int_value) static status_code_t set_port (setting_id_t id, float value)
{ {
bool ok; bool ok = true;
uint8_t port = value < 0.0f ? IOPORT_UNASSIGNED : (uint8_t)value;
if((ok = (uint8_t)int_value == sp1_settings.port_pwm || switch(id) {
ioports_enumerate(Port_Analog, Port_Output, (pin_cap_t){ .pwm = On, .claimable = On }, pwm_port_validate, (void *)((uint32_t)int_value))))
sp1_settings.port_pwm = (uint8_t)int_value; case Setting_Spindle_OnPort:
sp1_settings.port_on = port;
break;
case Setting_Spindle_DirPort:
sp1_settings.port_dir = port;
break;
default: // Setting_Spindle_PWMPort:
if((ok = port == sp1_settings.port_pwm ||
ioports_enumerate(Port_Analog, Port_Output, (pin_cap_t){ .claimable = On, .pwm = On }, pwm_port_validate, &port)))
sp1_settings.port_pwm = port;
break;
}
return ok ? Status_OK : Status_SettingValueOutOfRange; return ok ? Status_OK : Status_SettingValueOutOfRange;
} }
@@ -1027,10 +1046,10 @@ static bool has_ports (const setting_detail_t *setting, uint_fast16_t offset)
} }
static const setting_detail_t spindle1_settings[] = { static const setting_detail_t spindle1_settings[] = {
{ Setting_Spindle_OnPort, Group_AuxPorts, "PWM2 spindle on port", NULL, Format_Int8, "##0", "0", max_dport, Setting_NonCore, &sp1_settings.port_on, NULL, has_ports, { .reboot_required = On } }, { Setting_Spindle_OnPort, Group_AuxPorts, "PWM2 spindle on port", NULL, Format_Decimal, "-#0", "0", max_dport, Setting_NonCoreFn, set_port, get_port, has_ports, { .reboot_required = On } },
{ Setting_Spindle_DirPort, Group_AuxPorts, "PWM2 spindle direction port", NULL, Format_Decimal, "-#0", "-1", max_dport, Setting_NonCoreFn, set_dir_port, get_dir_port, has_ports, { .reboot_required = On } }, { Setting_Spindle_DirPort, Group_AuxPorts, "PWM2 spindle direction port", NULL, Format_Decimal, "-#0", "-1", max_dport, Setting_NonCoreFn, set_port, get_port, has_ports, { .reboot_required = On } },
{ Setting_SpindleInvertMask1, Group_Spindle, "PWM2 spindle signals invert", NULL, Format_Bitfield, spindle_signals, NULL, NULL, Setting_IsExtendedFn, set_spindle_invert, get_int, NULL, { .reboot_required = On } }, { Setting_SpindleInvertMask1, Group_Spindle, "PWM2 spindle signals invert", NULL, Format_Bitfield, spindle_signals, NULL, NULL, Setting_IsExtendedFn, set_spindle_invert, get_int, NULL, { .reboot_required = On } },
{ Setting_Spindle_PWMPort, Group_AuxPorts, "PWM2 spindle PWM port", NULL, Format_Int8, "#0", "0", max_aport, Setting_NonCoreFn, set_pwm_port, get_pwm_port, has_ports, { .reboot_required = On } }, { Setting_Spindle_PWMPort, Group_AuxPorts, "PWM2 spindle PWM port", NULL, Format_Decimal, "-#0", "0", max_aport, Setting_NonCoreFn, set_port, get_port, has_ports, { .reboot_required = On } },
{ Setting_SpindlePWMOptions1, Group_Spindle, "PWM2 spindle options", NULL, Format_XBitfield, "Enable,RPM controls spindle enable signal,Disable laser mode capability", NULL, NULL, Setting_IsExtendedFn, set_pwm_options, get_int, has_pwm }, { Setting_SpindlePWMOptions1, Group_Spindle, "PWM2 spindle options", NULL, Format_XBitfield, "Enable,RPM controls spindle enable signal,Disable laser mode capability", NULL, NULL, Setting_IsExtendedFn, set_pwm_options, get_int, has_pwm },
{ Setting_RpmMax1, Group_Spindle, "PWM2 spindle min speed", "RPM", Format_Decimal, "#####0.000", NULL, NULL, Setting_IsLegacy, &sp1_settings.cfg.rpm_max, NULL, has_pwm }, { Setting_RpmMax1, Group_Spindle, "PWM2 spindle min speed", "RPM", Format_Decimal, "#####0.000", NULL, NULL, Setting_IsLegacy, &sp1_settings.cfg.rpm_max, NULL, has_pwm },
{ Setting_RpmMin1, Group_Spindle, "PWM2 spindle max speed", "RPM", Format_Decimal, "#####0.000", NULL, NULL, Setting_IsLegacy, &sp1_settings.cfg.rpm_min, NULL, has_pwm }, { Setting_RpmMin1, Group_Spindle, "PWM2 spindle max speed", "RPM", Format_Decimal, "#####0.000", NULL, NULL, Setting_IsLegacy, &sp1_settings.cfg.rpm_min, NULL, has_pwm },
@@ -1052,7 +1071,6 @@ static const setting_detail_t spindle1_settings[] = {
#endif #endif
}; };
#ifndef NO_SETTINGS_DESCRIPTIONS
static const setting_descr_t spindle1_settings_descr[] = { static const setting_descr_t spindle1_settings_descr[] = {
{ Setting_Spindle_OnPort, "On/off aux port." }, { Setting_Spindle_OnPort, "On/off aux port." },
{ Setting_Spindle_DirPort, "Direction aux port, set to -1 if not required." }, { Setting_Spindle_DirPort, "Direction aux port, set to -1 if not required." },
@@ -1080,7 +1098,6 @@ static const setting_descr_t spindle1_settings_descr[] = {
#endif #endif
#endif #endif
}; };
#endif
static void spindle1_settings_changed (settings_t *settings, settings_changed_flags_t changed) static void spindle1_settings_changed (settings_t *settings, settings_changed_flags_t changed)
{ {
@@ -1144,6 +1161,10 @@ static void spindle1_settings_restore (void)
memcpy(&sp1_settings.cfg, &defaults, sizeof(spindle_pwm_settings_t)); memcpy(&sp1_settings.cfg, &defaults, sizeof(spindle_pwm_settings_t));
sp1_settings.port_pwm = ioport_find_free(Port_Analog, Port_Output, (pin_cap_t){.claimable = On, .pwm = On }, NULL);
sp1_settings.port_on = ioport_find_free(Port_Digital, Port_Output, (pin_cap_t){ .claimable = On }, NULL);
sp1_settings.port_dir = sp1_settings.port_on != IOPORT_UNASSIGNED && sp1_settings.port_on > 0 ? sp1_settings.port_on - 1 : IOPORT_UNASSIGNED;
hal.nvs.memcpy_to_nvs(nvs_address, (uint8_t *)&sp1_settings, sizeof(spindle1_pwm_settings_t), true); hal.nvs.memcpy_to_nvs(nvs_address, (uint8_t *)&sp1_settings, sizeof(spindle1_pwm_settings_t), true);
} }
@@ -1153,35 +1174,16 @@ static void spindle1_settings_load (void)
spindle1_settings_restore(); spindle1_settings_restore();
} }
static bool pwm_count (xbar_t *properties, uint8_t port, void *data)
{
*((uint32_t *)data) += 1;
sp1_settings.port_pwm = max(sp1_settings.port_pwm, port);
return false;
}
static bool check_pwm_ports (void)
{
uint32_t n_pwm_out = 0;
ioports_enumerate(Port_Analog, Port_Output, (pin_cap_t){ .pwm = On, .claimable = On }, pwm_count, &n_pwm_out);
return n_pwm_out != 0;
}
spindle1_pwm_settings_t *spindle1_settings_add (bool claim_ports) spindle1_pwm_settings_t *spindle1_settings_add (bool claim_ports)
{ {
uint8_t n_out; uint8_t a_out = IOPORT_UNASSIGNED;
if((ports_ok = claim_ports && (n_out = ioports_available(Port_Digital, Port_Output)) && check_pwm_ports())) { if((ports_ok = claim_ports &&
ioports_available(Port_Digital, Port_Output) &&
(a_out = ioport_find_free(Port_Analog, Port_Output, (pin_cap_t){ .claimable = On, .pwm = On }, NULL)) != IOPORT_UNASSIGNED)) {
sp1_settings.port_on = n_out - 1; strcpy(max_aport, uitoa(a_out));
sp1_settings.port_dir = n_out > 1 ? n_out - 2 : 255; strcpy(max_dport, uitoa(ioport_find_free(Port_Digital, Port_Output, (pin_cap_t){ .claimable = On }, NULL)));
strcpy(max_aport, uitoa(sp1_settings.port_pwm));
strcpy(max_dport, uitoa(n_out - 1));
} }
return nvs_address == 0 && (!claim_ports || ports_ok) && (nvs_address = nvs_alloc(sizeof(spindle1_pwm_settings_t))) ? &sp1_settings : NULL; return nvs_address == 0 && (!claim_ports || ports_ok) && (nvs_address = nvs_alloc(sizeof(spindle1_pwm_settings_t))) ? &sp1_settings : NULL;
@@ -1193,10 +1195,8 @@ void spindle1_settings_register (spindle_cap_t cap, spindle1_settings_changed_pt
.is_core = true, .is_core = true,
.settings = spindle1_settings, .settings = spindle1_settings,
.n_settings = sizeof(spindle1_settings) / sizeof(setting_detail_t), .n_settings = sizeof(spindle1_settings) / sizeof(setting_detail_t),
#ifndef NO_SETTINGS_DESCRIPTIONS
.descriptions = spindle1_settings_descr, .descriptions = spindle1_settings_descr,
.n_descriptions = sizeof(spindle1_settings_descr) / sizeof(setting_descr_t), .n_descriptions = sizeof(spindle1_settings_descr) / sizeof(setting_descr_t),
#endif
.load = spindle1_settings_load, .load = spindle1_settings_load,
.restore = spindle1_settings_restore, .restore = spindle1_settings_restore,
.save = spindle1_settings_save, .save = spindle1_settings_save,
@@ -1216,4 +1216,4 @@ void spindle1_settings_register (spindle_cap_t cap, spindle1_settings_changed_pt
setting_remove_elements(Setting_SpindleInvertMask1, spindle_state.mask); setting_remove_elements(Setting_SpindleInvertMask1, spindle_state.mask);
} }
#endif #endif // N_SPINDLE > 1

View File

@@ -1297,3 +1297,18 @@ offset_id_t st_get_offset_id (void)
? pl_block->offset_id ? pl_block->offset_id
: -1); : -1);
} }
// Called by driver setup function to get initial enable signals state
// TODO: returns all disabled for now, should return enabled according to configuration if
// not using Trinamic drivers since Trinamic drivers are init'ed after driver setup?
axes_signals_t st_get_enable_out (void)
{
axes_signals_t enable;
//
// enable.mask = (settings.steppers.idle_lock_time == 255 ? AXES_BITMASK : settings.steppers.energize.mask) ^ settings.steppers.enable_invert.mask;
enable.mask = settings.steppers.enable_invert.mask;
return enable;
}

View File

@@ -132,5 +132,6 @@ float st_get_realtime_rate (void);
void stepper_driver_interrupt_handler (void); void stepper_driver_interrupt_handler (void);
offset_id_t st_get_offset_id (void); offset_id_t st_get_offset_id (void);
axes_signals_t st_get_enable_out (void);
#endif #endif