grbl config
Inc\my_machine.h中取消注释进行配置 开启如下配置进行学习
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 #define BOARD_BTT_SKR_20 #define TRINAMIC_ENABLE 5160 #define N_AXIS 6 #define TRINAMIC_DYNAMIC_CURRENT #define TRINAMIC_EXTENDED_SETTINGS #define TRINAMIC_POLL_STATUS #define TMC_DRVCONF #define TMC_COOLCONF_SEMIN #define TMC_COOLCONF_SEMAX #define TMC_COOLCONF_SEDN #define TMC_COOLCONF_SEUP #define TMC_COOLCONF_SEIMIN #define TMC_CHOPCONF_HSTRT #define TMC_CHOPCONF_HEND #define TMC_CHOPCONF_TBL #define TMC_CHOPCONF_TOFF #define TMC_CHOPCONF_RDNTF #define TMC_CHOPCONF_CHM #define TMC_CHOPCONF_HDEC #define TMC_CHOPCONF_TFD #define TMC_CHOPCONF_INTPOL
driver_init 驱动初始化 执行各种初始化操作与注册
1 2 3 4 5 6 7 8 9 bool driver_init (void ) { #include "grbl/plugins_init.h" #if TRINAMIC_ENABLE extern bool trinamic_init (void ) ; trinamic_init(); #endif }
grbl_enter 主入口
grbl_enter是main函数的主入口
执行driver_init()进行初始化
进入protocol_main_loop()主循环
执行protocol_execute_realtime()实时执行
执行protocol_exec_rt_system()系统实时执行
执行grbl.on_execute_realtime(state_get());函数,在grbl_enter中进行注册;即task_execute
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 int grbl_enter (void ) { grbl.on_execute_realtime = grbl.on_execute_delay = task_execute; driver.init = driver_init(); while (looping) { if (!(looping = protocol_main_loop())) looping = hal.driver_release == NULL || hal.driver_release(); } } bool protocol_main_loop (void ) { while (true ) { if (!protocol_execute_realtime() && sys.abort ) return !sys.flags.exit ; if (settings.flags.sleep_enable) sleep_check(); } } bool protocol_execute_realtime (void ) { if (protocol_exec_rt_system()) { sys_state_t state = state_get(); if (sys.suspend) protocol_exec_rt_suspend(state); #if NVSDATA_BUFFER_ENABLE if ((state == STATE_IDLE || (state & (STATE_ALARM|STATE_ESTOP))) && settings_dirty.is_dirty && !gc_state.file_run) nvs_buffer_sync_physical(); #endif } return !ABORTED; } bool protocol_exec_rt_system (void ) { grbl.on_execute_realtime(state_get()); } static void task_execute (sys_state_t state) { static uint32_t last_ms = 0 ; core_task_t *task; if (immediate_task && sys.driver_started) { hal.irq_disable(); task = immediate_task; immediate_task = NULL ; hal.irq_enable(); do { void *data = task->data; foreground_task_ptr fn = task->fn; task_free(task); fn(data); } while ((task = task->next)); } uint32_t now = hal.get_elapsed_ticks(); if (now == last_ms || next_task == systick_task) return ; last_ms = now; if ((task = systick_task)) do { task->fn(task->data); } while ((task = task->next)); while (next_task && (int32_t )(next_task->time - now) <= 0 ) { void *data = next_task->data; foreground_task_ptr fn = next_task->fn; task_free(next_task); next_task = next_task->next; fn(data); } }
task API
这些任务是循环执行的,通过task_execute()函数执行
1 2 3 4 5 bool task_add_immediate (foreground_task_ptr fn, void *data) ;bool task_add_delayed (foreground_task_ptr fn, void *data, uint32_t delay_ms) ;void task_delete (foreground_task_ptr fn, void *data) ;bool task_add_systick (foreground_task_ptr fn, void *data) ;void task_delete_systick (foreground_task_ptr fn, void *data) ;
task_add_systick 添加系统任务
进入中断屏蔽
通过task_alloc()分配任务,静态数组中分配
注册执行函数和数据
任务链表为空则直接添加,否则遍历到链表尾部添加
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 ISR_CODE bool ISR_FUNC (task_add_systick) (foreground_task_ptr fn, void *data) { core_task_t *task = NULL ; hal.irq_disable(); if (fn && (task = task_alloc())) { task->fn = fn; task->data = data; task->next = NULL ; if (systick_task == NULL ) systick_task = task; else { core_task_t *t = systick_task; while (t->next) t = t->next; t->next = task; } } hal.irq_enable(); return task != NULL ; }
gcode G代码解析 gc_execute_block 执行G代码块
grbl.user_mcode.execute(state_get(), &gc_block);执行用户自定义M代码
该部分是TMC注册的mcode_execute执行的地方
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 status_code_t gc_execute_block (char *block) { if (gc_block.user_mcode && !check_mode) { if (gc_block.user_mcode_sync) protocol_buffer_synchronize(); gc_block.words.mask = user_words.mask; gc_block.values.f = single_meaning_value.f; gc_block.values.o = single_meaning_value.o; gc_block.values.s = single_meaning_value.s; gc_block.values.t = single_meaning_value.t; grbl.user_mcode.execute(state_get(), &gc_block); gc_block.words.mask = 0 ; } }
stepper 驱动
使用TMC芯片进行驱动,SPI用于通信配置;运动控制使用step/dir信号
st_prep_buffer trinamic 工作模式
StealthChop 2™ 无噪声、高精度斩波算法,用于电机的静止和运动状态下的静音控制。StealthChop2在 StealthChop 的基础上,加快了电机运动加减速特性,降低了所需的电流最小值。
spreadCycle™ 高精度斩波算法,用于高动态电机运动和产生绝对干净的电流波。低噪音、低共振和低振动斩波器。
DcStep™ 与负载相关的速度控制。电机尽可能快地移动,不失步
StallGuard2™ 无传感器的堵转检测和机械负载测量。
CoolStep™ 根据负载自适应电流,可将能耗降低 75 %。
MicroPlyer™ 细分内插器,用于从全步开始,以较低细分输入获得 256 微步的平滑度
StealthChop 2 & SpreadCycle 驱动 StealthChop 是电压斩波器的原理。除了电机机械滚轮轴承产生的噪音,它特别保证了电机在静止和慢速运行时能绝对安静。不同于其他电压模式斩波器, StealthChop 2 不需要任何配置。通电后,它会在第一次运动中自动学习最佳设置,并进一步优化后续运动中的设置。初始的归零过程足以使系统完成StealthChop 最佳配置。也可以配置初始参数加快自学习过程。StealthChop 2 通过对电机速度的变化立即做出反应,允许高的电机动态
数据结构 *
TMC5160的寄存器地址和数据结构
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 typedef union { uint8_t value; struct { uint8_t idx :7 , write :1 ; }; } TMC_addr_t; typedef union { uint32_t value; uint8_t data[4 ]; } TMC_payload_t; typedef struct { TMC_addr_t addr; TMC_payload_t payload; } TMC_spi_datagram_t; tmc_spi_read(driver->config.motor, (TMC_spi_datagram_t *)&driver->drv_status);
TMC SPI TMC_SPI_Read 读取TMC寄存器
常规的SPI读取操作;片选拉低,读取数据,片选拉高
需注意的是,TMC5160的SPI读取是先写入地址读取一次数据;是空数据;第二次读取才是真实数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 TMC_spi_status_t tmc_spi_read (trinamic_motor_t driver, TMC_spi_datagram_t *datagram) { TMC_spi_status_t status; DIGITAL_OUT(cs[driver.id].port, cs[driver.id].pin, 0 ); datagram->payload.value = 0 ; datagram->addr.write = 0 ; spi_put_byte(datagram->addr.value); spi_put_byte(0 ); spi_put_byte(0 ); spi_put_byte(0 ); spi_put_byte(0 ); DIGITAL_OUT(cs[driver.id].port, cs[driver.id].pin, 1 ); delay(); DIGITAL_OUT(cs[driver.id].port, cs[driver.id].pin, 0 ); status = spi_put_byte(datagram->addr.value); datagram->payload.data[3 ] = spi_get_byte(); datagram->payload.data[2 ] = spi_get_byte(); datagram->payload.data[1 ] = spi_get_byte(); datagram->payload.data[0 ] = spi_get_byte(); DIGITAL_OUT(cs[driver.id].port, cs[driver.id].pin, 1 ); return status; }
数据结构
1 2 3 4 5 6 7 typedef struct { uint8_t id; uint8_t axis; uint8_t address; uint8_t seq; void *cs_pin; } trinamic_motor_t ;
TMC5160.c TMC5160 文件结构
TMC5160.c中包含了TMC5160的所有操作函数
TMC5160_hal.c中包含了TMC5160的所有操作函数,对TMC5160.c进行了封装,与tmchal_t结构体进行了绑定
TMC5160_Init 初始化TMC5160
通过SPI读取drv_status
寄存器,检查是否读取到值,判断SPI是否正常
执行状态寄存器读取以清除重置标志
写入配置寄存器
tmc_microsteps_to_mres 微步转分辨率 TMC5160_SetDefaults 设置TMC5160默认值 1 2 static const TMC5160_t tmc5160_defaults ;
TMC5160_AddMotor 添加TMC5160电机 1 const tmchal_t *TMC5160_AddMotor (motor_map_t motor, uint16_t current, uint8_t microsteps, uint8_t r_sense) ;
stealthChop 斩波器配置 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 static void stealthChop (uint8_t motor, bool on) { tmcdriver[motor]->config.mode = on ? TMCMode_StealthChop : TMCMode_CoolStep; if (on) stealthChopEnable(motor); else coolStepEnable(motor); } static void stealthChopEnable (uint8_t motor) { TMC5160_t *driver = tmcdriver[motor]; driver->gconf.reg.diag1_stall = false ; driver->gconf.reg.en_pwm_mode = true ; tmc_spi_write(driver->config.motor, (TMC_spi_datagram_t *)&driver->gconf); driver->pwmconf.reg.pwm_autoscale = true ; tmc_spi_write(driver->config.motor, (TMC_spi_datagram_t *)&driver->pwmconf); setTCoolThrsRaw(motor, 0 ); } static void coolStepEnable (uint8_t motor) { TMC5160_t *driver = tmcdriver[motor]; driver->gconf.reg.en_pwm_mode = false ; tmc_spi_write(driver->config.motor, (TMC_spi_datagram_t *)&driver->gconf); driver->pwmconf.reg.pwm_autoscale = false ; tmc_spi_write(driver->config.motor, (TMC_spi_datagram_t *)&driver->pwmconf); setTCoolThrsRaw(motor, 0 ); }
trinamic.c trinamic_drivers_init 驱动初始化 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 static void trinamic_drivers_init (axes_signals_t axes) { bool ok = axes.value != 0 ; uint_fast8_t motor = n_motors, n_enabled = 0 , seq = 0 ; memset (stepper, 0 , sizeof (stepper)); do { if (bit_istrue(axes.mask, bit(motor_map[--motor].axis))) seq++; } while (motor); motor = n_motors; *min_current = '\0' ; do { if (bit_istrue(axes.mask, bit(motor_map[--motor].axis))) { if ((ok = trinamic_driver_config(motor_map[motor], --seq))) { n_enabled++; if (*min_current == '\0' ) { strcpy (min_current, uitoa(stepper[motor_map[motor].id]->get_current(motor_map[motor].id, TMCCurrent_Min))); strcpy (max_current, uitoa(stepper[motor_map[motor].id]->get_current(motor_map[motor].id, TMCCurrent_Max))); } } } } while (ok && motor); tmc_motors_set(ok ? n_enabled : 0 ); if (!ok) { driver_enabled.mask = 0 ; memset (stepper, 0 , sizeof (stepper)); } #if TRINAMIC_POLL_STATUS || TRINAMIC_DYNAMIC_CURRENT else { #if TRINAMIC_POLL_STATUS task_add_delayed(trinamic_poll_status, NULL , TRINAMIC_POLL_INTERVAL); #endif #if TRINAMIC_DYNAMIC_CURRENT if (stepper_block_start == NULL ) { stepper_block_start = hal.stepper.pulse_start; hal.stepper.pulse_start = dynamic_current_pulse_start; } #endif } #endif }
set_axis_setting 轴设置
可以通过此配置函数设置电机的电流、保持电流、微步数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 static status_code_t set_axis_setting (setting_id_t setting, uint_fast16_t value) { uint_fast8_t axis, motor = n_motors; status_code_t status = Status_OK; switch (settings_get_axis_base(setting, &axis)) { case Setting_AxisStepperCurrent: trinamic.driver[axis].current = (uint16_t )value; do { motor--; if (stepper[motor] && stepper[motor]->get_config(motor)->motor.axis == axis) { stepper[motor]->set_current(motor, trinamic.driver[axis].current, trinamic.driver[axis].hold_current_pct); #if TRINAMIC_DYNAMIC_CURRENT reduced_current[motor] = trinamic.driver[axis].current * trinamic.driver[axis].hold_current_pct / 100 ; #endif } } while (motor); break ; case TMCsetting_HoldCurrentPct: if (value > 100 ) value = 100 ; trinamic.driver[axis].hold_current_pct = (uint16_t )value; do { motor--; if (stepper[motor] && stepper[motor]->get_config(motor)->motor.axis == axis) { stepper[motor]->set_current(motor, trinamic.driver[axis].current, trinamic.driver[axis].hold_current_pct); #if TRINAMIC_DYNAMIC_CURRENT reduced_current[motor] = trinamic.driver[axis].current * trinamic.driver[axis].hold_current_pct / 100 ; #endif } } while (motor); break ; case Setting_AxisMicroSteps: do { motor--; if (stepper[motor] && stepper[motor]->get_config(motor)->motor.axis == axis) { if (stepper[motor]->microsteps_isvalid(motor, (uint16_t )value)) { trinamic.driver[axis].microsteps = value; stepper[motor]->set_microsteps(motor, trinamic.driver[axis].microsteps); if (report.sg_status_motormask.mask & bit(axis)) report.msteps = trinamic.driver[axis].microsteps; } else { status = Status_InvalidStatement; break ; } } } while (motor); break ; default : status = Status_Unhandled; break ; } return status; }
trinamic_settings_get_defaults 获取默认设置 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 static void trinamic_settings_get_defaults (bool cap_only) { const trinamic_cfg_params_t *params; params = TMC5160_GetConfigDefaults(); memcpy (&cfg_cap, ¶ms->cap, sizeof (trinamic_cfg_t )); if (!cap_only) memcpy (cfg_params, ¶ms->dflt, sizeof (trinamic_cfg_t )); #ifdef TMC_DRVCONF cfg_params->drvconf = TMC_DRVCONF; #endif #ifdef TMC_COOLCONF_SEMIN cfg_params->coolconf.semin = TMC_COOLCONF_SEMIN & cfg_cap.coolconf.semin; #endif #ifdef TMC_COOLCONF_SEMAX cfg_params->coolconf.semax = TMC_COOLCONF_SEMAX & cfg_cap.coolconf.semax; #endif #ifdef TMC_COOLCONF_SEDN cfg_params->coolconf.sedn = TMC_COOLCONF_SEDN & cfg_cap.coolconf.sedn; #endif #ifdef TMC_COOLCONF_SEUP cfg_params->coolconf.seup = TMC_COOLCONF_SEUP & cfg_cap.coolconf.seup; #endif #ifdef TMC_COOLCONF_SEIMIN cfg_params->coolconf.seimin = TMC_COOLCONF_SEIMIN & cfg_cap.coolconf.seimin; #endif #ifdef TMC_CHOPCONF_HSTRT cfg_params->chopconf.hstrt = (TMC_CHOPCONF_HSTRT - 1 ) & cfg_cap.chopconf.hstrt; #endif #ifdef TMC_CHOPCONF_HEND cfg_params->chopconf.hend = (TMC_CHOPCONF_HEND + 3 ) & cfg_cap.chopconf.hend; #endif #ifdef TMC_CHOPCONF_TBL cfg_params->chopconf.tbl = TMC_CHOPCONF_TBL & cfg_cap.chopconf.tbl; #endif #ifdef TMC_CHOPCONF_TOFF cfg_params->chopconf.toff = TMC_CHOPCONF_TOFF & cfg_cap.chopconf.toff; #endif #ifdef TMC_CHOPCONF_RDNTF cfg_params->chopconf.rndtf = TMC_CHOPCONF_RDNTF & cfg_cap.chopconf.rndtf; #endif #ifdef TMC_CHOPCONF_CHM cfg_params->chopconf.chm = TMC_CHOPCONF_CHM & cfg_cap.chopconf.chm; #endif #ifdef TMC_CHOPCONF_HDEC cfg_params->chopconf.hdec = TMC_CHOPCONF_HDEC & cfg_cap.chopconf.hdec; #endif #ifdef TMC_CHOPCONF_TFD cfg_params->chopconf.tfd = TMC_CHOPCONF_TFD & cfg_cap.chopconf.tfd; #endif #ifdef TMC_CHOPCONF_INTPOL cfg_params->chopconf.intpol = TMC_CHOPCONF_INTPOL & cfg_cap.chopconf.intpol; #endif vsense[0 ] = params->vsense[0 ] / 1000.0f ; vsense[1 ] = params->vsense[1 ] / 1000.0f ; custom_drvconf = cfg_params->drvconf != params->dflt.drvconf; }
trinamic_driver_config 驱动器配置
cfg.settings = &trinamic.driver[motor.axis];trinamic从set_axis_setting
函数中配置
cfg_params参数通过trinamic_settings_get_defaults
配置为默认值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 static bool trinamic_driver_config (motor_map_t motor, uint8_t seq) { bool ok = false ; trinamic_driver_config_t cfg = { .address = motor.id, .settings = &trinamic.driver[motor.axis] }; if (driver_if.on_driver_preinit) driver_if.on_driver_preinit(motor, &cfg); #if TRINAMIC_ENABLE == 5160 ok = (stepper[motor.id] = TMC5160_AddMotor(motor, cfg.settings->current, cfg.settings->microsteps, cfg.settings->r_sense)) != NULL ; #endif if (!ok) { protocol_enqueue_foreground_task(report_warning, "Could not communicate with stepper driver!" ); return false ; } stepper[motor.id]->get_config(motor.id)->motor.seq = seq; driver_enabled.mask |= bit(motor.axis); #if TRINAMIC_EXTENDED_SETTINGS if (cfg_cap.drvconf && custom_drvconf) stepper[motor.id]->write_register(motor.id, stepper[motor.id]->drvconf_address, cfg_params->drvconf); #endif stepper[motor.id]->sg_filter(motor.id, 1 ); stepper[motor.id]->coolconf(motor.id, cfg_params->coolconf); stepper[motor.id]->chopper_timing(motor.id, cfg_params->chopconf); if (stepper[motor.id]->stealthChop) stepper[motor.id]->stealthChop(motor.id, cfg.settings->mode == TMCMode_StealthChop); else if (cfg.settings->mode == TMCMode_StealthChop) cfg.settings->mode = TMCMode_CoolStep; #if PWM_THRESHOLD_VELOCITY > 0 stepper[motor.id]->set_tpwmthrs(motor.id, (float )PWM_THRESHOLD_VELOCITY / 60.0f , settings.axis[motor.axis].steps_per_mm); #endif stepper[motor.id]->set_current(motor.id, cfg.settings->current, cfg.settings->hold_current_pct); stepper[motor.id]->set_microsteps(motor.id, cfg.settings->microsteps); #if TRINAMIC_DYNAMIC_CURRENT reduced_current[motor.id] = cfg.settings->current * cfg.settings->hold_current_pct / 100 ; #endif if (driver_if.on_driver_postinit) driver_if.on_driver_postinit(motor, stepper[motor.id]); return true ; }
trinamic_poll_status 轮询状态 ??? ??? st_wake_up 和 st_go_idle是什么 ??? CMD_FEED_HOLD
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 static void trinamic_poll_status (void *data) { static bool error_active = false , error_hold = false ; static uint32_t error_count = 0 ; static hold_state_t holding_state = Hold_NotHolding; uint_fast8_t motor = n_motors; uint8_t stall_fault = 0 , otpw_fault = 0 ; sys_state_t current_state = state_get(); task_add_delayed(trinamic_poll_status, NULL , TRINAMIC_POLL_INTERVAL); do { if (stepper[--motor]) { if (current_state == STATE_IDLE) status[motor] = stepper[motor]->get_drv_status(motor); else if (current_state == STATE_HOLD && holding_state == Hold_Pending && sys.holding_state == Hold_Complete) { holding_state == Hold_Complete; st_go_idle(); } if (status[motor].otpw) otpw_fault |= (1 << motor); #if TRINAMIC_DYNAMIC_CURRENT uint_fast8_t axis = motor_map[motor].axis; if ((current_state == STATE_IDLE || (current_state & (STATE_ALARM|STATE_HOLD))) && dynamic_current[motor] == trinamic.driver[axis].current) stepper[motor]->set_current(motor, (dynamic_current[motor] = reduced_current[motor]), trinamic.driver[axis].hold_current_pct); #endif } } while (motor); if (stall_fault || otpw_fault) { if (++error_count > 2 && !error_active) { error_active = true ; if (current_state & (STATE_CYCLE|STATE_HOMING|STATE_JOG)) { grbl.enqueue_realtime_command(CMD_FEED_HOLD); } task_add_immediate(trinamic_status_report, NULL ); } } else if (error_active) { error_active = false ; error_count = 0 ; if (holding_state != Hold_NotHolding) { holding_state = Hold_NotHolding; st_wake_up(); } } }
trinamic_init 初始化 // motor_iterator通过driver_init
中注册
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 bool trinamic_init (void ) { static setting_details_t settings_details = { .settings = trinamic_settings, .n_settings = sizeof (trinamic_settings) / sizeof (setting_detail_t ), #ifndef NO_SETTINGS_DESCRIPTIONS .descriptions = trinamic_settings_descr, .n_descriptions = sizeof (trinamic_settings_descr) / sizeof (setting_descr_t ), #endif .load = trinamic_settings_load, .save = trinamic_settings_save, .restore = trinamic_settings_restore }; if (hal.stepper.motor_iterator) { hal.stepper.motor_iterator(count_motors); if ((motor_map = malloc (n_motors * sizeof (motor_map_t )))) { n_motors = 0 ; hal.stepper.motor_iterator(assign_motors); } } else { motor_map = malloc (N_AXIS * sizeof (motor_map_t )); if (motor_map) { uint_fast8_t idx; for (idx = 0 ; idx < N_AXIS; idx++) { motor_map[idx].id = idx; motor_map[idx].axis = idx; } n_motors = idx; } } if (motor_map && (nvs_address = nvs_alloc(sizeof (trinamic_settings_t )))) { memcpy (&user_mcode, &grbl.user_mcode, sizeof (user_mcode_ptrs_t )); grbl.user_mcode.check = mcode_check; grbl.user_mcode.validate = mcode_validate; grbl.user_mcode.execute = mcode_execute; on_realtime_report = grbl.on_realtime_report; grbl.on_realtime_report = onRealtimeReport; on_report_options = grbl.on_report_options; grbl.on_report_options = onReportOptions; driver_setup = hal.driver_setup; hal.driver_setup = onDriverSetup; settings_changed = hal.settings_changed; hal.settings_changed = onSettingsChanged; limits_enable = hal.limits.enable; hal.limits.enable = limitsEnable; hal.homing.get_feedrate = homingGetFeedrate; settings_register(&settings_details); #if TRINAMIC_I2C stepper_enable = hal.stepper.enable; hal.stepper.enable = stepperEnable; #endif } }
mcode_execute M代码执行