Small motor driver improvements
authorJoseph Coffland <joseph@cauldrondevelopment.com>
Mon, 19 Nov 2018 07:28:54 +0000 (23:28 -0800)
committerJoseph Coffland <joseph@cauldrondevelopment.com>
Mon, 19 Nov 2018 07:50:25 +0000 (23:50 -0800)
src/avr/src/config.h
src/avr/src/motor.c
src/avr/src/stepper.c

index 4c2bd1ffa5f6dcc370bd490ac4922cb6966ffe32..dc6634d4053da5e0a4815a568b8acee192beb3dd 100644 (file)
@@ -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
index 1ba52e826844ba0484714983853d157084be202c..29ee72a51bf5b1d77f0cbc0997b78775d8d4d3aa 100644 (file)
@@ -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
index 167a38e3de41298ab4979ac3e30ca9ca95074f96..dc540c3f681a06a6004938e98dce30735054ed91 100644 (file)
 #include <stdio.h>
 
 
-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
 }