From: Joseph Coffland Date: Mon, 19 Nov 2018 07:28:54 +0000 (-0800) Subject: Small motor driver improvements X-Git-Url: https://git.buildbotics.com/?a=commitdiff_plain;h=ed10fdd05c23a7cba8947aaafacb173ff4f7267f;p=bbctrl-firmware Small motor driver improvements --- diff --git a/src/avr/src/config.h b/src/avr/src/config.h index 4c2bd1f..dc6634d 100644 --- a/src/avr/src/config.h +++ b/src/avr/src/config.h @@ -128,21 +128,6 @@ enum { #define TIMER_STEP TCC0 // Step timer (see stepper.h) #define TIMER_PWM TCD1 // PWM timer (see pwm.c) -#define M1_TIMER TCD0 -#define M2_TIMER TCE0 -#define M3_TIMER TCF0 -#define M4_TIMER TCE1 - -#define M1_DMA_CH DMA.CH0 -#define M2_DMA_CH DMA.CH1 -#define M3_DMA_CH DMA.CH2 -#define M4_DMA_CH DMA.CH3 - -#define M1_DMA_TRIGGER DMA_CH_TRIGSRC_TCD0_CCA_gc -#define M2_DMA_TRIGGER DMA_CH_TRIGSRC_TCE0_CCA_gc -#define M3_DMA_TRIGGER DMA_CH_TRIGSRC_TCF0_CCA_gc -#define M4_DMA_TRIGGER DMA_CH_TRIGSRC_TCE1_CCA_gc - // Timer setup for stepper and dwells #define STEP_TIMER_ENABLE TC_CLKSEL_DIV8_gc diff --git a/src/avr/src/motor.c b/src/avr/src/motor.c index 1ba52e8..29ee72a 100644 --- a/src/avr/src/motor.c +++ b/src/avr/src/motor.c @@ -90,31 +90,31 @@ static motor_t motors[MOTORS] = { .axis = AXIS_X, .step_pin = STEP_X_PIN, .dir_pin = DIR_X_PIN, - .timer = &M1_TIMER, - .dma = &M1_DMA_CH, - .dma_trigger = M1_DMA_TRIGGER, + .timer = &TCD0, + .dma = &DMA.CH0, + .dma_trigger = DMA_CH_TRIGSRC_TCD0_CCA_gc, }, { .axis = AXIS_Y, .step_pin = STEP_Y_PIN, .dir_pin = DIR_Y_PIN, - .timer = &M2_TIMER, - .dma = &M2_DMA_CH, - .dma_trigger = M2_DMA_TRIGGER, + .timer = &TCE0, + .dma = &DMA.CH1, + .dma_trigger = DMA_CH_TRIGSRC_TCE0_CCA_gc, }, { .axis = AXIS_Z, .step_pin = STEP_Z_PIN, .dir_pin = DIR_Z_PIN, - .timer = &M3_TIMER, - .dma = &M3_DMA_CH, - .dma_trigger = M3_DMA_TRIGGER, + .timer = &TCF0, + .dma = &DMA.CH2, + .dma_trigger = DMA_CH_TRIGSRC_TCF0_CCA_gc, }, { .axis = AXIS_A, .step_pin = STEP_A_PIN, .dir_pin = DIR_A_PIN, - .timer = (TC0_t *)&M4_TIMER, - .dma = &M4_DMA_CH, - .dma_trigger = M4_DMA_TRIGGER, - } + .timer = (TC0_t *)&TCE1, + .dma = &DMA.CH3, + .dma_trigger = DMA_CH_TRIGSRC_TCE1_CCA_gc, + } }; @@ -267,7 +267,8 @@ void motor_load_move(int motor) { const bool dir = m->negative ^ m->reverse; if (dir != IN_PIN(m->dir_pin)) { SET_PIN(m->dir_pin, dir); - // Need at least 200ns between direction change and next step. + + // We need at least 200ns between direction change and next step. if (m->timer->CCA < m->timer->CNT) m->timer->CNT = m->timer->CCA + 1; } @@ -276,9 +277,9 @@ void motor_load_move(int motor) { m->dma->TRFCNT = 0xffff; m->dma->CTRLA |= DMA_CH_ENABLE_bm; - // Note, it is important to start the clock, if it is stopped, before - // setting PERBUF so that PER is not updated immediately possibly - // interrupting the clock mid step or causing counter wrap around. + // To avoid causing couter wrap around, it is important to start the clock + // before setting PERBUF. If PERBUF is set before the clock is started PER + // updates immediately and possibly mid step. // Set clock and period m->timer->CTRLA = m->clock; // Start clock diff --git a/src/avr/src/stepper.c b/src/avr/src/stepper.c index 167a38e..dc540c3 100644 --- a/src/avr/src/stepper.c +++ b/src/avr/src/stepper.c @@ -40,13 +40,6 @@ #include -typedef enum { - MOVE_TYPE_NULL, // null move - does a no-op - MOVE_TYPE_LINE, // linear move - MOVE_TYPE_DWELL, // delay with no movement -} move_type_t; - - typedef struct { // Runtime bool busy; @@ -56,11 +49,9 @@ typedef struct { power_update_t powers[POWER_MAX_UPDATES]; // Move prep - bool move_ready; // prepped move ready for loader - bool move_queued; // prepped move queued - move_type_t move_type; + bool move_ready; // Prepped move ready for loader + bool move_queued; // Prepped move queued float prep_dwell; - power_update_t prep_powers[POWER_MAX_UPDATES]; uint32_t underflow; @@ -76,10 +67,10 @@ void stepper_init() { DIRSET_PIN(MOTOR_ENABLE_PIN); // Output // Setup step timer - TIMER_STEP.CTRLB = STEP_TIMER_WGMODE; // waveform mode - TIMER_STEP.INTCTRLA = STEP_TIMER_INTLVL; // interrupt mode - TIMER_STEP.PER = STEP_TIMER_POLL; // timer rate - TIMER_STEP.CTRLA = STEP_TIMER_ENABLE; // start step timer + TIMER_STEP.CTRLB = STEP_TIMER_WGMODE; // Waveform mode + TIMER_STEP.INTCTRLA = STEP_TIMER_INTLVL; // Interrupt mode + TIMER_STEP.PER = STEP_TIMER_POLL; // Timer rate + TIMER_STEP.CTRLA = STEP_TIMER_ENABLE; // Start step timer } @@ -89,6 +80,12 @@ static void _end_move() { } +static void _load_move() { + for (int motor = 0; motor < MOTORS; motor++) + motor_load_move(motor); +} + + void st_shutdown() { OUTCLR_PIN(MOTOR_ENABLE_PIN); // Disable motors TIMER_STEP.CTRLA = 0; // Stop stepper clock @@ -156,7 +153,7 @@ static void _update_power() { /// Dwell or dequeue and load next move. -static void _load_move() { +static void _next_move() { static uint8_t tick = 0; // Update spindle power on every tick @@ -166,9 +163,10 @@ static void _load_move() { if (0 < st.dwell) { st.dwell -= 0.001; // 1ms return; - } else st.dwell = 0; + } + st.dwell = 0; - if (tick++ & 3) return; + if (tick++ & 3) return; // Proceed every 4 ticks // If the next move is not ready try to load it if (!st.move_ready) { @@ -179,37 +177,35 @@ static void _load_move() { return; } - // Start move - if (st.move_type == MOVE_TYPE_LINE) - for (int motor = 0; motor < MOTORS; motor++) - motor_load_move(motor); - - else _end_move(); + if (st.prep_dwell) { + // End last move, if any + _end_move(); - ESTOP_ASSERT(st.move_type != MOVE_TYPE_NULL, STAT_STEPPER_NULL_MOVE); - st.busy = true; + // Start dwell + st.dwell = st.prep_dwell; + st.prep_dwell = 0; - // Start dwell - st.dwell = st.prep_dwell; + } else { + // Start move + _load_move(); - // Copy power updates - st.power_index = 0; - memcpy(st.powers, st.prep_powers, sizeof(st.powers)); - _update_power(); + // Handle power updates + st.power_index = 0; + memcpy(st.powers, st.prep_powers, sizeof(st.powers)); + _update_power(); - // We are done with this move - st.move_type = MOVE_TYPE_NULL; - st.prep_dwell = 0; // clear dwell - st.move_ready = false; // flip the flag back + // Request next move when not in a dwell. Requesting the next move may + // power up motors which should not be powered up during a dwell. + _request_exec_move(); + } - // Request next move if not currently in a dwell. Requesting the next move - // may power up motors and the motors should not be powered up during a dwell. - if (!st.dwell) _request_exec_move(); + st.busy = true; // Executing move so mark busy + st.move_ready = false; // We are done with this move, flip the flag back } /// Step timer interrupt routine. -ISR(STEP_TIMER_ISR) {_load_move();} +ISR(STEP_TIMER_ISR) {_next_move();} void st_prep_power(const power_update_t powers[]) { @@ -222,9 +218,6 @@ void st_prep_line(const float target[]) { // Trap conditions that would prevent queuing the line ESTOP_ASSERT(!st.move_ready, STAT_STEPPER_NOT_READY); - // Setup segment parameters - st.move_type = MOVE_TYPE_LINE; - // Prepare motor moves for (int motor = 0; motor < MOTORS; motor++) motor_prep_move(motor, target[motor_get_axis(motor)]); @@ -236,7 +229,6 @@ void st_prep_line(const float target[]) { /// Add a dwell to the move buffer void st_prep_dwell(float seconds) { ESTOP_ASSERT(!st.move_ready, STAT_STEPPER_NOT_READY); - st.move_type = MOVE_TYPE_DWELL; st.prep_dwell = seconds; st.move_queued = true; // signal prep buffer ready }