Build 20240921

Added generic HAL timer API and function for getting which G65 parameter words were supplied.
This commit is contained in:
Terje Io
2024-09-21 18:25:00 +07:00
parent fabec73d0e
commit 3ef6763cec
9 changed files with 194 additions and 19 deletions

View File

@@ -1,5 +1,21 @@
## grblHAL changelog
<a name="20240921">Build 20240921
Core:
* Added generic HAL timer API and function for getting which `G65` parameter words were supplied.
Networking:
* Made parsing of HTTP header keywords case insensitive. Ref. [issue #11](https://github.com/grblHAL/Plugin_networking/issues/11).
SD card (macros):
* Added inbuilt `G65` macro `P3` for getting and setting NGC numerical parameters, typical use case will be for indexed access. Ref. [discussion #309 comment](https://github.com/grblHAL/core/discussions/309#discussioncomment-10710468).
---
<a name="20240907">Build 20240907
Core:

View File

@@ -187,6 +187,7 @@ typedef enum {
Output_MOSI,
Output_SPICLK,
Output_SPICS,
Output_FlashCS,
Output_SdCardCS,
Input_SdCardDetect,
Output_SPIRST,
@@ -385,6 +386,7 @@ PROGMEM static const pin_name_t pin_names[] = {
{ .function = Output_MOSI, .name = "MOSI" },
{ .function = Output_SPICLK, .name = "SPI CLK" },
{ .function = Output_SPICS, .name = "SPI CS" },
{ .function = Output_FlashCS, .name = "Flash CS" },
{ .function = Output_SdCardCS, .name = "SD card CS" },
{ .function = Input_SdCardDetect, .name = "SD card detect" },
{ .function = Output_SPIRST, .name = "SPI reset" },

12
gcode.c
View File

@@ -509,11 +509,17 @@ static status_code_t read_parameter (char *line, uint_fast8_t *char_counter, flo
return status;
}
#endif // NGC_EXPRESSIONS_ENABLE
#if NGC_PARAMETERS_ENABLE
static parameter_words_t g65_words = {0};
parameter_words_t gc_get_g65_arguments (void)
{
return g65_words;
}
bool gc_modal_state_restore (gc_modal_t *copy)
{
bool ok = false;
@@ -950,6 +956,7 @@ status_code_t gc_execute_block (char *block)
if(!is_user_mcode && isnanf(value))
FAIL(Status_BadNumberFormat); // [Expected word value]
g65_words.value = 0;
#else
if((letter < 'A' && letter != '$') || letter > 'Z')
@@ -2435,11 +2442,14 @@ status_code_t gc_execute_block (char *block)
while(gc_block.words.value) {
if(gc_block.words.value & 0x1 && gc_value_ptr[idx].value) switch(gc_value_ptr[idx].type) {
case ValueType_Float:
g65_words.value |= (1 << idx);
ngc_param_set((ngc_param_id_t)idx, *(float *)gc_value_ptr[idx].value);
break;
case ValueType_UInt32:
g65_words.value |= (1 << idx);
ngc_param_set((ngc_param_id_t)idx, (float)*(uint32_t *)gc_value_ptr[idx].value);
break;

View File

@@ -238,8 +238,8 @@ typedef enum {
UserMCode_Generic3 = 103, //!< 103 - For private use only
UserMCode_Generic4 = 104, //!< 104 - For private use only
OpenPNP_GetADCReading = 105, //!< 105 - M105
Fan_On = 106, //!< 106 - M106
Fan_Off = 107, //!< 107 - M107
Fan_On = 106, //!< 106 - M106, Marlin format
Fan_Off = 107, //!< 107 - M107, Marlin format
OpenPNP_GetCurrentPosition = 114, //!< 114 - M114
OpenPNP_FirmwareInfo = 115, //!< 115 - M115
Trinamic_DebugReport = 122, //!< 122 - M122, Marlin format
@@ -685,6 +685,7 @@ void gc_set_tool_offset (tool_offset_mode_t mode, uint_fast8_t idx, int32_t offs
plane_t *gc_get_plane_data (plane_t *plane, plane_select_t select);
#if NGC_PARAMETERS_ENABLE
parameter_words_t gc_get_g65_arguments (void);
bool gc_modal_state_restore (gc_modal_t *copy);
#endif

2
grbl.h
View File

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

84
hal.h
View File

@@ -302,6 +302,13 @@ typedef void (*stepper_output_step_ptr)(axes_signals_t step_outbits, axes_signal
*/
typedef axes_signals_t (*stepper_get_ganged_ptr)(bool auto_squared);
/*! \brief Pointer to function for claiming/releasing motor(s) from/to normal step/dir signalling.
\param axis_id a \a the axis to claim/release motor(s) for.
\param claim \a true to claim a motor(s), \a false to release.
*/
typedef void (*stepper_claim_motor_ptr)(uint_fast8_t axis_id, bool claim);
/*! \brief Pointer to callback function for outputting the next direction and step pulse signals. _Set by the core on startup._
To be called by the driver from the main stepper interrupt handler (when the timer times out).
@@ -318,6 +325,7 @@ typedef struct {
stepper_pulse_start_ptr pulse_start; //!< Handler for starting outputting direction signals and a step pulse. Called from interrupt context.
stepper_interrupt_callback_ptr interrupt_callback; //!< Callback for informing about the next step pulse to output. _Set by the core at startup._
stepper_get_ganged_ptr get_ganged; //!< Optional handler getting which axes are configured for ganging or auto squaring.
stepper_claim_motor_ptr claim_motor; //!< Optional handler for claiming/releasing motor(s) from normal step/dir control.
stepper_output_step_ptr output_step; //!< Optional handler for outputting a single step pulse. _Experimental._ Called from interrupt context.
motor_iterator_ptr motor_iterator; //!< Optional handler iteration over motor vs. axis mappings. Required for the motors plugin (Trinamic drivers).
} stepper_ptrs_t;
@@ -484,6 +492,73 @@ typedef struct {
*/
typedef bool (*irq_claim_ptr)(irq_type_t irq, uint_fast8_t id, irq_callback_ptr callback);
/************
* Timers *
************/
typedef void *hal_timer_t; //!< Timer handle, actual type defined by driver implementation.
typedef enum {
Timer_16bit = 0,
Timer_32bit,
Timer_64bit
} timer_resolution_t;
typedef union {
uint8_t value; //!< All bitmap flags.
struct {
uint8_t periodic :1, //!<
up :1, //!< Timer supports upcounting
comp1 :1, //!< Timer supports compare interrupt 0
comp2 :1; //!< Timer supports compare interrupt 1
};
} timer_cap_t;
typedef void (*timer_irq_handler_ptr)(void *context);
typedef struct {
void *context; //!< Pointer to data to be passed on to the interrupt handlers
bool single_shot; //!< Set to true if timer is single shot
timer_irq_handler_ptr timeout_callback; //!< Pointer to main timeout callback
uint32_t irq0; //!< Compare value for compare interrupt 0
timer_irq_handler_ptr irq0_callback; //!< Pointer to compare interrupt 0 callback
uint32_t irq1; //!< Compare value for compare interrupt 10
timer_irq_handler_ptr irq1_callback; //!< Pointer to compare interrupt 1 callback
} timer_cfg_t;
/*! \brief Pointer to function for claiming a timer.
\param cap pointer to a \a timer_cap_t struct containing the required capabilities.
\param timebase timebase in ns.
\returns a \a hal_timer_t pointer if successful, \a NULL if not.
*/
typedef hal_timer_t (*timer_claim_ptr)(timer_cap_t cap, uint32_t timebase);
/*! \brief Pointer to function for configuring a timer.
\param timer a \a hal_timer_t pointer.
\param cfg pointer to a \a timer_cfg_t struct.
\returns \a true if successful.
*/
typedef bool (*timer_cfg_ptr)(hal_timer_t timer, timer_cfg_t *cfg);
/*! \brief Pointer to function for starting a timer.
\param timer a \a hal_timer_t pointer.
\param period delay in.
\returns \a true if successful.
*/
typedef bool (*timer_start_ptr)(hal_timer_t timer, uint32_t period);
/*! \brief Pointer to function for stopping a running timer.
\param timer a \a hal_timer_t pointer.
\returns \a true if successful.
*/
typedef bool (*timer_stop_ptr)(hal_timer_t timer);
typedef struct {
timer_claim_ptr claim;
timer_cfg_ptr configure;
timer_start_ptr start;
timer_stop_ptr stop;
} timer_ptrs_t;
/**************************
* RTC (Real Time Clock *
@@ -491,13 +566,13 @@ typedef bool (*irq_claim_ptr)(irq_type_t irq, uint_fast8_t id, irq_callback_ptr
/*! \brief Pointer to function for setting the current datetime.
\param datetime pointer to a \a tm struct.
\returns true if successful.
\\returns \a true if successful.
*/
typedef bool (*rtc_get_datetime_ptr)(struct tm *datetime);
/*! \brief Pointer to function for setting the current datetime.
\param datetime pointer to a \a tm struct.
\returns true if successful.
\returns \a true if successful.
*/
typedef bool (*rtc_set_datetime_ptr)(struct tm *datetime);
@@ -541,7 +616,7 @@ typedef struct {
/*! \brief Driver setup handler.
Called once by the core after settings has been loaded. The driver should enable MCU peripherals in the provided function.
\param settings pointer to settings_t structure.
\returns true if completed successfully and the driver supports the _settings->version_ number, false otherwise.
\returns \a true if completed successfully and the driver supports the _settings->version_ number, false otherwise.
*/
driver_setup_ptr driver_setup;
@@ -595,6 +670,7 @@ typedef struct {
settings_changed_ptr settings_changed; //!< Callback handler to be called on settings loaded or settings changed events.
probe_ptrs_t probe; //!< Optional handlers for probe input(s).
tool_ptrs_t tool; //!< Optional handlers for tool changes.
timer_ptrs_t timer; //!< Optional handlers for claiming and controlling timers.
rtc_ptrs_t rtc; //!< Optional handlers for real time clock (RTC).
io_port_t port; //!< Optional handlers for axuillary I/O (adds support for M62-M66).
rgb_ptr_t rgb0; //!< Optional handler for RGB output to LEDs (neopixels) or lamps.
@@ -649,7 +725,7 @@ Then _hal.driver_setup()_ will be called so that the driver can configure the re
__NOTE__: This is the only driver function that is called directly from the core, all others are called via HAL function pointers.
\returns true if completed successfully and the driver matches the _hal.version number_, false otherwise.
\returns \a true if completed successfully and the driver matches the _hal.version number_, \a false otherwise.
*/
extern bool driver_init (void);

View File

@@ -129,6 +129,7 @@ extern char const *const axis_letter[];
typedef union {
uint8_t mask;
uint8_t bits;
uint8_t value;
struct {
uint8_t x :1,

View File

@@ -47,6 +47,7 @@ struct st2_motor {
axes_signals_t axis;
bool is_spindle;
bool is_bound;
bool polling;
bool position_lost;
volatile int64_t position; // absolute step number
position_t ptype; //
@@ -66,6 +67,8 @@ struct st2_motor {
float acceleration; // acceleration steps/s^2
axes_signals_t dir; // current direction
uint64_t next_step;
hal_timer_t step_inject_timer;
foreground_task_ptr on_stopped;
st2_motor_t *next;
};
@@ -76,6 +79,8 @@ static on_set_axis_setting_unit_ptr on_set_axis_setting_unit;
static on_setting_get_description_ptr on_setting_get_description;
static on_reset_ptr on_reset;
static void motor_irq (void *context);
/*! \brief Calculate basic motor configuration.
\param motor pointer to a \a st2_motor structure.
@@ -200,6 +205,11 @@ static const char *st2_setting_get_description (setting_id_t id)
: (on_setting_get_description ? on_setting_get_description(id) : NULL);
}
void st2_motor_register_stopped_callback (st2_motor_t *motor, foreground_task_ptr callback)
{
motor->on_stopped = callback;
}
/*! \brief Bind and initialize a motor.
Binds motor 0 as a spindle.
@@ -240,9 +250,23 @@ If \a is_spindle is set \a true then axis settings will be changed to step/rev e
*/
st2_motor_t *st2_motor_init (uint_fast8_t axis_idx, bool is_spindle)
{
st2_motor_t *motor, *new = motors;
st2_motor_t *motor = NULL, *new = motors;
if((motor = calloc(sizeof(st2_motor_t), 1))) {
if(hal.stepper.output_step && (motor = calloc(sizeof(st2_motor_t), 1))) {
if(hal.timer.claim && (motor->step_inject_timer = hal.timer.claim((timer_cap_t){ .periodic = Off }, 1000))) {
timer_cfg_t step_inject_cfg = {
.single_shot = true,
.timeout_callback = motor_irq
};
step_inject_cfg.context = motor;
hal.timer.configure(motor->step_inject_timer, &step_inject_cfg);
} else if(hal.get_micros)
motor->polling = true;
else {
free(motor);
return NULL;
}
if(!is_spindle) {
@@ -417,6 +441,9 @@ bool st2_motor_move (st2_motor_t *motor, const float move, const float speed, po
motor->step_no = 0; // step counter
motor->next_step = hal.get_micros();
if(motor->step_inject_timer)
hal.timer.start(motor->step_inject_timer, motor->delay);
#ifdef DEBUGOUT
uint32_t nn = motor->n;
float cn = motor->first_delay;
@@ -464,17 +491,12 @@ bool st2_set_position (st2_motor_t *motor, int64_t position)
}
/*! \brief Execute a move commanded by st2_motor_move().
This should be called from the foreground process as often as possible.
\param motor pointer to a \a st2_motor structure.
\returns \a true if motor is moving (steps are output), \a false if not (motion is completed).
*/
bool st2_motor_run (st2_motor_t *motor)
__attribute__((always_inline)) static inline bool _motor_run (st2_motor_t *motor)
{
uint64_t t = hal.get_micros();
if(motor->state == State_Idle || t - motor->next_step < motor->delay)
return motor->state != State_Idle;
st2_state_t prev_state = motor->state;
switch(motor->state) {
@@ -483,7 +505,7 @@ bool st2_motor_run (st2_motor_t *motor)
motor->denom += 4;
motor->c64 -= (motor->c64 << 1) / motor->denom; // ramp algorithm
motor->delay = (motor->c64 + 32768) >> 16; // round 24.16 format -> int16
if (motor->delay < motor->min_delay) { // go to constant speed?
if (motor->delay < motor->min_delay) { // go to constant speed?
// motor->denom -= 6; // causes issues with speed override for infinite moves
motor->state = motor->ptype == Stepper2_InfiniteSteps ? State_RunInfinite : State_Run;
motor->step_down = motor->move - motor->step_no;
@@ -540,7 +562,41 @@ bool st2_motor_run (st2_motor_t *motor)
motor->position++;
motor->step_no++;
motor->next_step = t;
if(motor->state == State_Idle && prev_state != State_Idle && motor->on_stopped)
task_add_delayed(motor->on_stopped, motor, 2);
return motor->state != State_Idle;
}
ISR_CODE static void ISR_FUNC(motor_irq)(void *context)
{
if(_motor_run((st2_motor_t *)context))
hal.timer.start(((st2_motor_t *)context)->step_inject_timer, ((st2_motor_t *)context)->delay);
else
hal.timer.stop(((st2_motor_t *)context)->step_inject_timer);
}
/*! \brief Execute a move commanded by st2_motor_move().
This should be called from the foreground process as often as possible
when step output is not driven by interrupts (polling mode).
\param motor pointer to a \a st2_motor structure.
\returns \a true if motor is moving (steps are output), \a false if not (motion is completed).
*/
bool st2_motor_run (st2_motor_t *motor)
{
if(motor->polling && motor->state != State_Idle) {
uint64_t t = hal.get_micros();
if(t - motor->next_step >= motor->delay) {
_motor_run(motor);
motor->next_step = t;
}
}
return motor->state != State_Idle;
}
@@ -575,6 +631,15 @@ bool st2_motor_stop (st2_motor_t *motor)
return motor->state != State_Idle;
}
/*! \brief Check if motor is run by polling.
\param motor pointer to a \a st2_motor structure.
\returns \a true if motor is run by polling, \a false if not.
*/
bool st2_motor_poll (st2_motor_t *motor)
{
return motor->polling;
}
/*! \brief Check if motor is running.
\param motor pointer to a \a st2_motor structure.
\returns \a true if motor is running, \a false if not.

View File

@@ -22,6 +22,8 @@
#include <stdint.h>
#include <stdbool.h>
#include "task.h"
typedef enum {
Stepper2_Steps = 0, //!< 0
Stepper2_InfiniteSteps, //!< 1
@@ -32,6 +34,7 @@ struct st2_motor; // members defined in stepper2.c
typedef struct st2_motor st2_motor_t;
st2_motor_t *st2_motor_init (uint_fast8_t axis_idx, bool is_spindle);
bool st2_motor_poll (st2_motor_t *motor);
bool st2_motor_bind_spindle (uint_fast8_t axis_idx);
float st2_get_speed (st2_motor_t *motor);
float st2_motor_set_speed (st2_motor_t *motor, float speed);
@@ -42,3 +45,4 @@ bool st2_motor_cruising (st2_motor_t *motor);
bool st2_motor_stop (st2_motor_t *motor);
int64_t st2_get_position (st2_motor_t *motor);
bool st2_set_position (st2_motor_t *motor, int64_t position);
void st2_motor_register_stopped_callback (st2_motor_t *motor, foreground_task_ptr callback);