how to get interupt working on teensy 4.0 for idiots

Status
Not open for further replies.

littletim

Member
hello,

i recently got some steppers working with accel stepper and interupts,
i have got the interupt running every 1ms with the help of online forums and it works fine on arduino boards,but i made a pcb shield for the teensy and some steppers not realising that interupts dont work the same and that teensystep doesnt work on teensy 4.0.

so with the code below my question is how can i convert this to teensy,how would i go about changing the interupts to work on teensy 4?

i just need a function to be called every 1ms,

if someone could point me in the right direction that would be cool.

thanks

Code:
#include <Arduino.h>
#include <AccelStepper.h>

#define stepM1  9//  m1
#define  dirM1  8

#define dirM2   7 //  m2 
#define stepM2  6

#define stepM3  4 //  m3
#define  dirM3  5

#define stepM4  2 //  m4
#define  dirM4  3

#define stepM5  15 //  m5
#define  dirM5  16

#define stepM6  13 //  m6
#define  dirM6  14

#define global_enable      10

AccelStepper stepper1(AccelStepper::FULL2WIRE, stepM1, dirM1);
AccelStepper stepper2(AccelStepper::FULL2WIRE, stepM2, dirM2);
AccelStepper stepper3(AccelStepper::FULL2WIRE, stepM3, dirM3);
AccelStepper stepper4(AccelStepper::FULL2WIRE, stepM4, dirM4);
AccelStepper stepper5(AccelStepper::FULL2WIRE, stepM5, dirM5);
AccelStepper stepper6(AccelStepper::FULL2WIRE, stepM6, dirM6);



constexpr uint32_t steps_per_mm = 21; //
long stepstotake = 200 * 4; 
uint8_t stepper_choice = 0;

long previousMillis = 0;
const int interval =  1300;
const uint8_t Amount_of_steppers = 6; 

AccelStepper* stepperArray[Amount_of_steppers] = {
  &stepper1,
  &stepper2,
  &stepper3,
  &stepper4,
  &stepper5,
  &stepper6,
};

void setup()
{

 pinMode(global_enable, OUTPUT);
  digitalWrite(global_enable, LOW);

  for (int x = 0; x < Amount_of_steppers; x++) {  
    stepperArray[x]->setMaxSpeed(50 * steps_per_mm); // 
    stepperArray[x]->setAcceleration(1000 * steps_per_mm); //
  }

  if (!SetUpInterrupts(100)) {  
    while (1)  {
    }
  }

}



void loop()
{
  all_up_down(1);
  wave(1);    

 while (1);
}




int AmountofpassesWave = 0; 

void  wave(uint8_t times ) {

  times = times * 2;

  while (AmountofpassesWave  < 2) {

    unsigned long currentMillis = millis();

    if (currentMillis - previousMillis > interval) {
      previousMillis = currentMillis;
      stepperArray[stepper_choice]->moveTo(stepstotake);
      stepper_choice++;
    }

    if (stepper_choice == Amount_of_steppers) {
      stepper_choice = 0;
      stepstotake -= stepstotake;
      AmountofpassesWave++;

    }

  }
  AmountofpassesWave=0;
}



void  all_up_down(uint8_t times ) {

  times = times * 2;

  while (int Amountofpasses = 0 < 2) {

    for (int x = 0; x < Amount_of_steppers; x++) {
      stepperArray[x]->moveTo(stepstotake/2);
    }
    if (stepper1.distanceToGo() == 0) {
      stepstotake -= stepstotake;
      Amountofpasses++;
    }

  }
    AmountofpassesWave=0;
    

}






ISR(TIMER1_COMPA_vect)    
{
  for (int x = 0; x < Amount_of_steppers; x++) {
    stepperArray[x]->run();
  }
}







/*****************************************************************************
   The standard Arduino has 3 timers,
   timer0 is 8 bit and used for the millis() and micros() functions.
   Timer1 is 16 bit and not used by default,
   timer2 is another 8 bit timer like timer0 but not used by default.
** SetUpInterrupts
** ===============
  Set up interrupt routine to service stepper motor run() function.
*/
// TIMER1_COMPA_vect  TIMSK1,OCIE1A TIFR1,OCF1A Timer 1 Compare A Match
bool SetUpInterrupts(const int usecs) // usec = µs
{
  // initialize Timer1
  cli();          // disable global interrupts
  TCCR1A = 0;     // set entire TCCR1A register to 0
  TCCR1B = 0;     // same for TCCR1B

  // set compare match register to desired timer count (1ms):
  // ATmega328 with a 16MHz clock, clk/8
  // (# timer counts + 1) = (target time) / (timer resolution)
  //                      =     .0001s      /   6.25e-8 s  * 8
  //                      =   200
  const float targetSecs = ((float) usecs) / 1e6;
  const float timerSteps = 6.25e-8;                //    1/16MHz
  int count = 0;
  int prescale = 1;  // valid values: 1, 8, 64, 256, 1024
  do  {
    count = targetSecs / (timerSteps * prescale);
    if (count < 65535) // Timer 1 is 16-bits wide
      break;
    prescale *= 8;
  } while (prescale <= 1024);
  if (prescale > 1024)                // time too long
    return false;
  if (prescale == 1 && count < 100)   // time too short
    return false;

  OCR1A = count;         // Eg, 200 = 0.1ms - I found 1ms gives rough acceleration
  // turn on CTC mode (Clear Timer on Compare Match):
  TCCR1B |= (1 << WGM12);
  // Set CS10 and CS12 bits for 1024 prescaler:
  // CS12   CS11   CS10
  //   0      0      0   no clock source, Timer/counter stopped
  //   0      0      1   clk/1  no prescaling
  //   0      1      0   clk/8
  //   0      1      1   clk/64
  //   1      0      0   clk/256
  //   1      0      1   clk/1024
  //   1      1      0   external clock on T1 pin, falling edge
  //   1      1      1   external clock on T1 pin, rising edge
  switch (prescale)  {
    case 1:
      TCCR1B |= (1 << CS10);                   // 0 0 1
      break;
    case 8:
      TCCR1B |= (1 << CS11);                   // 0 1 0
      break;
    case 64:
      TCCR1B |= (1 << CS11) & (1 << CS10);     // 0 1 1
      break;
    case 256:
      TCCR1B |= (1 << CS12);                   // 1 0 0
      break;
    case 1024:
      TCCR1B |= (1 << CS12) & (1 << CS10);     // 1 0 1
      break;
  }
  // enable timer compare interrupt:
  TIMSK1 |= (1 << OCIE1A);
  // enable global interrupts:
  sei();

  return true;
}
 
thanks kurt compiles fine,
i have set it up with interval timer,works so far but seems to give up after one loop of the steppers so not sure if it gets overloaded with the for loop inside the isr or not.
it should run all_up_down(1); and then wave but it stalls after running all_up_down(1); then never makes it to wave(1) or while(1); so ill have a play around for the day and see if i can fix it.

is there a reason i should use teensy timer more than interval timer?
 
I normally use IntervalTimer, but the Timer Tool has lots of different options depending on your needs. Things like different clocks, speeds, plus he has setups for more C++ stuff.

But again I normally have simple requirements, so again I start of with IntervalTimer.
 
if someone could point me in the right direction that would be cool.

Interrupts may or may not be the right direction. The huge downside of interrupts is the extra effort needed to *reliably* share data between the interrupt code and the rest of your program. It's very easy to make subtle mistakes which only manifest problems under rare conditions, which is incredibly difficult and frustrating to troubleshoot.

If you can make do with elapsedMillis or elapsedMicros, I would highly recommend using those instead. They avoid the difficult problems of interrupts.


is there a reason i should use teensy timer more than interval timer?

If you do go with interrupts, IntervalTimer is definitely the best path if you only need to run a function at regular timing intervals. Internally it does use one of the PIT hardware timers. It is essentially the same as that AVR code you posted, but wrapped up in a nice C++ class so you don't need to directly manipulate the hardware registers. IntervalTimer also automatically manages which of the 4 PIT timers gets used, so your code will automatically work if used together with any libraries or other code which also use IntervalTimer.

Teensy 4.0 has dozens of other hardware timers. They're all documented in great detail in the IMXRT1060 reference manual. But as you will see if you try to read the chapters on those timers, they are loaded with an overwhelming number of very advanced features involving many hundreds of pages of rather terse documentation. If you have a specific need for some of those features, like special phase synchronized PWM pulses across multiple pins, then diving into those timers might be worthwhile.

If you're only trying to run a function at a regular interval, and you really want it by an interrupt, use IntervalTimer. But you should know interrupts come with some pretty rough edges. It's simply the price to be paid for the high precision of a timer interrupt.

If you can avoid using delay() or code that waits, just checking an elapsedMicros variable in your loop() function might be able to work well enough. The timing will only be as precise as the latency imposed by all the other code you run which limits how often you can check the elapsed time. Teensy 4.0 is very fast, so unless you need very precise timing, I'd suggest you at least consider whether elapsedMicros is good enough.
 
"which is incredibly difficult and frustrating to troubleshoot." i have the feeling this is where i spent the day yesterday hah.

anyway i have it working now with interval timer and or elapsedmicros i will continue and test with both.
as im only using the interval timer with one simple step function i think it would be usefull and use less of my brain atm than elapsedmicros.

i have been jumping in and out of arduino and vscode and found while testing i cannot get any accel stepper example to compile inside arduino ide yet works fine in vscode(platformIO)

im getting a whole bunch of errors to do with "PIN_TO_DIGITAL' was not declared in this scope" inside arduino ide 1,8,10 and using teensyduino 1.48
here is a pastbin of the errors https://pastebin.com/pGtJBf4t

is this just me needing to upgrade my ide? i thought accel stepper was teensy compatible out the box!

thanks

p.s if i use elapsedmicros and make a timer to do the access stepper run func that should be called near once every ms like so,,

Code:
elapsedMicros waiting; 

void updateMotors()
{
  if (waiting >= 1000)
  {
    for (int x = 0; x < Amount_of_steppers; x++)
    {
      stepperArray[x]->run();
    }
  }
}

int AmountofpassesWave = 0; 

void  wave(uint8_t times ) {

  times = times * 2;

  while (AmountofpassesWave  < 2) {

    unsigned long currentMillis = millis();

    if (currentMillis - previousMillis > interval) {
      previousMillis = currentMillis;
      stepperArray[stepper_choice]->moveTo(stepstotake);
      stepper_choice++;
    }

    if (stepper_choice == Amount_of_steppers) {
      stepper_choice = 0;
      stepstotake -= stepstotake;
      AmountofpassesWave++;

    }
  }
  AmountofpassesWave=0;
}

the problem is because there is a while loop it exists before finishing the steps the last motors need.
is there a way i can get rid of the while?so i can then have updateMotors() being run all the time without needing to call the fucntion everywhere ?
 
Why are you making AmountofpassesWave a global variable?

Also... what exactly is this doing? What is an "amount of passes wave"? It's not clear to me what the desired outcome is.
 
The current IDE version is 1.8.13 - more importantly current TeensyDuino version is 1.53.

Wouldn't hurt to update at least TeensyDuino to refresh the system as 1.48 was close to release of T_4.0.
 
Why are you making AmountofpassesWave a global variable?

Also... what exactly is this doing? What is an "amount of passes wave"? It's not clear to me what the desired outcome is.

so for me Amountofpasseswave doesnt need to be global no i can change that,it just holds the amount of times i have moved 5 seppers,as they are being used to create a wave visual effect i called it such.

i move the steppers on by one to there pos with a small delay to make them start after each other,creating a wave,the AmountofpassesWave increments when i reach all steppers in the stepper_choice.once its down however many loops of wave it leaves.but if i didnt use a while it would leave the function before running all motors.

hope that helps a bit
 
i updated all to the latest version of both teensy and arduino fine this morning,sadly im still getting the same compile errors as before ,to do with "Applications/Arduino.app/Contents/Java/libraries/Firmata/Firmata.h:125:18: error: 'TOTAL_PINS' was not declared in this scope
int pinState[TOTAL_PINS];"

and the other "'PIN_TO_DIGITAL' was not declared in this scope
if (IS_PIN_DIGITAL(pin + 0) && (bitmask & 0x01) && digitalRead(PIN_TO_DIGITAL(pin + 0))) out |= 0x01;"

these are me trying to compile a basic accelstepper example.

same as the error before update,anyway for the moment im fine in vscode just nice to change back and forth when needed.
 
these are me trying to compile a basic accelstepper example.

I want to help, but I can't without more information.

Please try to think of how your questions are going to appear to everyone reading this forum. Ask yourself these 2 questions:

1: Can anyone simply SEE the problem?
2: Can someone actually REPRODUCT the problem?

In this case, we can see an error message. But it makes little sense, because it's in the Firmata library when you've said you're using "a basic accelstepper example". You've show just a couple lines of code which presumably are from that example. But alone they make little sense.

You may have noticed a "Forum Rule" in red at the top of every page on this forum. We generally ask for you to show the complete code because it makes helping you much easier. Especially for compiler errors, when you put the complete code in your message, or if you're running a specific example without modifications and you clearly say which example you're using, then anyone reading your message can just open the example, or copy the entire code you're shown into Arduino and click Verify to reproduce the problem.

Everyone starts as a beginner. We get that. It's perfectly fine. The most valuable thing you can learn first isn't anything super technical, but rather how to best ask for help. The most important thing you can do is show enough detail, so we can at least see the problem. You'll get the best help when we can reproduce the problem. You can also get much better help when you share enough context about what you're really trying to accomplish, so we can understand what you really need. Sometimes one or more of us might know of a much better or simpler way, but you'll only get that sort of input when you explain a bit more what you're doing.

Please, let us help you. In the toolbar when you post a message is a "#" icon which is meant to enclosing large amount of code. I see you already used it on msg #6. But you didn't copy your entire program. There's no setup() or loop() function! You may intuitive think you're making things easier on us by trimming the code to a smaller size. But in trying to make it easier to read, you're making the problem impossible to reproduce. We also often see cases on this forum where someone trimmed a part of their code which they didn't believe could be the problem, but in fact had some detail (like the specific definition of a variable or function) which turned out to be a central part of the problem. The takeaway is to follow the Forum Rule and paste your complete program. Especially for compile errors which can be reproduced without uploading to real hardware, most of us will copy and paste it into Arduino and click Verify - so do yourself a huge favor and make sure whatever you put into those CODE tags really is the full program. We can and will help you so much more if you give us enough info to do so!
 
thanks paul,no worries i do try, sometimes im not good at explaining things outside of my head.

so the complete code is in msg #1 in my first post,msg #6 is a snippet of that same code ,so the whole code is already posted.

as for the errors i have posted the whole error in a pastbin which i put in msg #6 see: https://pastebin.com/pGtJBf4t

bassicaly i open aduino ide i open a simple accelstepper example i then try and compile the code for teensy 4 and i get the full error that is in the pastbin above,i have since updated to the newest arduino ide adn teensy app and i still recieve the same weird firmata error!!

i have since SOLVED the error as it seems even with updating my arduino ide the firmata boards.h file did not include some definitions for the teensy 4.0,changing my boards.h to this version https://github.com/firmata/arduino/blob/master/Boards.h it all now compiles fine.

for others that come across the same error just add this to your Applications/Arduino.app/Contents/Java/libraries/Firmata/Boards.h

Code:
// Teensy 4.0
#elif defined(__IMXRT1062__)
#define TOTAL_ANALOG_PINS       14
#define TOTAL_PINS              40
#define VERSION_BLINK_PIN       13
#define PIN_SERIAL1_RX          0
#define PIN_SERIAL1_TX          1
#define PIN_SERIAL2_RX          7
#define PIN_SERIAL2_TX          8
#define PIN_SERIAL3_RX          15
#define PIN_SERIAL3_TX          14
#define PIN_SERIAL4_RX          16
#define PIN_SERIAL4_TX          17
#define PIN_SERIAL5_RX          21
#define PIN_SERIAL5_TX          20
#define PIN_SERIAL6_RX          25
#define PIN_SERIAL6_TX          24
#define PIN_SERIAL7_RX          28
#define PIN_SERIAL7_TX          29
#define IS_PIN_DIGITAL(p)       ((p) >= 0 && (p) < TOTAL_PINS)
#define IS_PIN_ANALOG(p)        ((p) >= 14 && (p) <= 27)
#define IS_PIN_PWM(p)           (((p) >= 0 && (p) <= 16) || ((p) >= 18 && (p) <= 19) || ((p) >= 22 && (p) <= 25) || ((p) >= 28 && (p) <= 29)|| ((p) >= 33 && (p) <= 39))
#define IS_PIN_SERVO(p)         ((p) >= 0 && (p) < MAX_SERVOS)
#define IS_PIN_I2C(p)           ((p) == 18 || (p) == 19)
#define IS_PIN_SERIAL(p)        (((p) >= 0 && (p) <= 1) || ((p) >= 7 && (p) <= 8) || ((p) >= 14 && (p) <= 17) || ((p) >= 20 && (p) <= 21) || ((p) >= 24 && (p) <= 25) || ((p) >= 28 && (p) <= 29))
#define PIN_TO_DIGITAL(p)       (p)
#define PIN_TO_ANALOG(p)        ((p) - 14)
#define PIN_TO_PWM(p)           (p)
#define PIN_TO_SERVO(p)         (p)

as for some reason its missing,

as for my problem removing the while loop from inside my wave(); function i have moved it to use a switch case instead so the elapsed micros can be called when needed and there is no blocking code,which means i can use elapesedmicros like suggested,
Code:
#include <Arduino.h>
#include <AccelStepper.h>

#define stepM1 9 //  m1
#define dirM1 8

#define dirM2 7 //  m2
#define stepM2 6

#define stepM3 4 //  m3
#define dirM3 5

#define stepM4 2 //  m4
#define dirM4 3

#define stepM5 15 //  m5
#define dirM5 16

#define stepM6 13 //  m6
#define dirM6 14

#define global_enable 10

//for vscode 
void runStuff(int var);
void updateMotors();

AccelStepper stepper1(AccelStepper::FULL2WIRE, stepM1, dirM1);
AccelStepper stepper2(AccelStepper::FULL2WIRE, stepM2, dirM2);
AccelStepper stepper3(AccelStepper::FULL2WIRE, stepM3, dirM3);
AccelStepper stepper4(AccelStepper::FULL2WIRE, stepM4, dirM4);

constexpr uint32_t steps_per_mm = 21; 
long stepstotake = 200 * 14;     
uint8_t stepper_choice = 0;

long previousMillis = 0;
const int interval = 1300;
const uint8_t Amount_of_steppers = 4;

int WhichRoutineTorun = 0;
int passes = 0;

AccelStepper *stepperArray[Amount_of_steppers] = {
    &stepper1,
    &stepper2,
    &stepper3,
    &stepper4,
};

// void stepMYmotors(void)
// {
//   for (int x = 0; x < Amount_of_steppers; x++)
//   {
//     stepperArray[x]->run();
//   }
// }

void setup()
{
  pinMode(global_enable, OUTPUT);

  for (int x = 0; x < Amount_of_steppers; x++)
  {                                         //changed to interupt version
    stepperArray[x]->setMaxSpeed(2000);     // 100mm/s @ 80 steps/mm
    stepperArray[x]->setAcceleration(1000); // 2000mm/s^2
  }

  // static IntervalTimer mytimer;
  // mytimer.priority(48);
  // mytimer.begin(stepMYmotors, 1000);
}
elapsedMicros waiting; // "waiting" starts at zero

void updateMotors()
{
  if (waiting >= 1000)
  {
    for (int x = 0; x < Amount_of_steppers; x++)
    {
      stepperArray[x]->run();
    }
  }
}

void loop()
{
  runStuff(WhichRoutineTorun);
  updateMotors();

  if (passes >= 2)
  {
    WhichRoutineTorun++;
    passes = 0;
  }

  if (WhichRoutineTorun >= 3)
  {
    WhichRoutineTorun = 0; // start again
    passes = 0;
  }
}

void runStuff(int var)
{

  switch (var)
  {
  case 1:
  {
    unsigned long currentMillis = millis();

    if (currentMillis - previousMillis > interval)
    {
      previousMillis = currentMillis;
      stepperArray[stepper_choice]->moveTo(stepstotake);
      stepper_choice++;
    }

    if (stepper_choice == Amount_of_steppers)
    {
      stepper_choice = 0;
      stepstotake = -stepstotake;
    }
    passes++;
  }
    break;
  case 2:
  {
    for (int x = 0; x < Amount_of_steppers; x++)
    {
      stepperArray[x]->moveTo(stepstotake / 2);
    }
    if (stepper1.distanceToGo() == 0)
    {
      stepstotake = -stepstotake;
    }
    passes++;
  }
    break;
  default:
    // statements
    break;
  }
}
 
Status
Not open for further replies.
Back
Top