Search code examples
c++debuggingarduino-unoatmega

How does this ISR routine work?


I at the moment trying to write an the step signal for an stepper motor, and recently found out that atmel had written this application note, and provided some code that purpose. The signal i have to provide my motor, is a pulse modulated signal, where the frequency of the signal determines, the speed, rather than the 4 pin signal which they provide. The code is available on github (link).

But i am currently questioning ISR routine which controls all the stages of the motor (Stop, acceleration, run ,deceleration). More specifically how it keeps track of the step_count which is in charge of changing the state.

#pragma vector=TIMER1_COMPA_vect
__interrupt void speed_cntr_TIMER1_COMPA_interrupt( void )
{
  // Holds next delay period.
  unsigned int new_step_delay;
  // Remember the last step delay used when accelrating.
  static int last_accel_delay;
  // Counting steps when moving.
  static unsigned int step_count = 0;
  // Keep track of remainder from new_step-delay calculation to incrase accurancy
  static unsigned int rest = 0;

  OCR1A = srd.step_delay;

  switch(srd.run_state) {
    case STOP:
      step_count = 0;
      rest = 0;
      // Stop Timer/Counter 1.
      TCCR1B &= ~((1<<CS12)|(1<<CS11)|(1<<CS10));
      status.running = FALSE;
      break;

    case ACCEL:
      sm_driver_StepCounter(srd.dir);
      step_count++;
      srd.accel_count++;
      new_step_delay = srd.step_delay - (((2 * (long)srd.step_delay) + rest)/(4 * srd.accel_count + 1));
      rest = ((2 * (long)srd.step_delay)+rest)%(4 * srd.accel_count + 1);
      // Chech if we should start decelration.
      if(step_count >= srd.decel_start) {
        srd.accel_count = srd.decel_val;
        srd.run_state = DECEL;
      }
      // Chech if we hitted max speed.
      else if(new_step_delay <= srd.min_delay) {
        last_accel_delay = new_step_delay;
        new_step_delay = srd.min_delay;
        rest = 0;
        srd.run_state = RUN;
      }
      break;

    case RUN:
      sm_driver_StepCounter(srd.dir);
      step_count++;
      new_step_delay = srd.min_delay;
      // Chech if we should start decelration.
      if(step_count >= srd.decel_start) {
        srd.accel_count = srd.decel_val;
        // Start decelration with same delay as accel ended with.
        new_step_delay = last_accel_delay;
        srd.run_state = DECEL;
      }
      break;

    case DECEL:
      sm_driver_StepCounter(srd.dir);
      step_count++;
      srd.accel_count++;
      new_step_delay = srd.step_delay - (((2 * (long)srd.step_delay) + rest)/(4 * srd.accel_count + 1));
      rest = ((2 * (long)srd.step_delay)+rest)%(4 * srd.accel_count + 1);
      // Check if we at last step
      if(srd.accel_count >= 0){
        srd.run_state = STOP;
      }
      break;
  }
  srd.step_delay = new_step_delay;
}

As it looks to me, is the step_count being set to zero at the begining of the ISR and the incremented in either state ACCEL,RUN or DECEL.

A quick debug does show that the variable increment to the value i desire it to be, but I really cannot figure out how.

I know missing something very simple.


Solution

  • These three variables are static. That means they will only be initialized once:

    // Remember the last step delay used when accelrating.
    static int last_accel_delay;
    // Counting steps when moving.
    static unsigned int step_count = 0;
    // Keep track of remainder from new_step-delay calculation to incrase accurancy
    static unsigned int rest = 0;
    

    If you follow the code you'll find that they are used to keep state from one interrupt to the next.