Teensy 3.2 vs 4.0 interrupt speed differences causing issues?

I have a project originally written for the 3.2 that I'm trying to port to the 4.0. I have pretty much all functionality working exactly as original but I'm seeing strange behavior related to interrupts.

Here is the attach interrupt in void setup():

attachInterrupt(IN4, isrCP, CHANGE);

And the interrupt method:

void isrCP() { if (digitalRead(IN4) == LOW) { duration = micros() - pilottimer; pilottimer = micros(); } else { accurlim = ((duration - (micros() - pilottimer + 70)) * 60) / duration; //pilottimer + "xx" optocoupler decade ms } }

This is exactly the same code as with the 3.2 but it's producing wildly different results. On the 3.2, accurlim outputs a steady value (eg. 12). On the 4.0, that same value is still the value that occurs most frequently but it also makes huge fluctuations, up to >1,000 and down to 0 for brief periods.

This code is for handling the J1772 EV charge protocol for automatic current limiting, where IN4 sees a 1khz square wave with the duty cycle used to communicate the current limit from the offboard charger.

The way IN4 is handled on the hardware side is the same so it's unlikely it's that. The only thing I can think of that could be causing this is that the 4.0 is so much faster than the 3.2 that isrCP is executing in a way that occasionally creates wildly inaccurate readings.

Any thoughts/ideas/solutions? Thanks!
 
Two quick suggestions, only read micros() once and use digitalReadFast() as shown below. Not sure what your calculation is doing, but are your variables accurlim, duration, plotttimer declared as "volatile"?

Code:
void isrCP() {
  uint32_t us = micros();
  if (digitalReadFast(IN4) == LOW) {
    duration = us - pilottimer;
    pilottimer = us;
  } else {
    accurlim = ((duration - (us - pilottimer + 70)) * 60) / duration;  //pilottimer + "xx" optocoupler decade ms
  }
}
 
Ok, will give this a shot. Yes the variables are all declared as volatile.

Realizing I was also seeing similarly odd behavior for the analog current sensor readings, generally a steady value with sporadic fluctuations that are completely out of range. The pinMode for the pins reading the current was not set, which worked fine with the 3.2 but with the 4.0 was causing all kinds of weirdness. IN4 has always been set as an input for both 3.2 and 4.0 so it's not that in this case. Gonna keep looking!
 
Try adding
Code:
asm volatile("dsb");
to the end of the ISR function. The Teensy 4 CPU is so fast that it can finish the ISR before external hardware register writes have finished, which causes the ISR to immediately re-trigger. The DSB instruction tells it to wait until any pending writes have completed.
 
Thanks for the suggestion, jmarsh. Will give that a shot and report back.

As for the current sensor issue: these are analog voltage from a single or dual channel analog sensor, with CURsens1/2 being the readings directly from the sensor (in the range 0.5-4.5v). CUR1 and CUR2 lead to analog pins on the teensy:

Screenshot 2023-12-04 124158.png


These pins are defined as such:

Code:
const int ACUR2 = A0;
const int ACUR1 = A1;

and then in setup:

Code:
  pinMode(ACUR1, INPUT);
  pinMode(ACUR2, INPUT);

ACUR1/2 are run through an ADC.

On the 3.2 these pinMode definitions were not needed. On the 4.0, behavior was extremely erratic without them, and with them there is still some unexpected behavior (although much closer to what it should be). I am seeing mixed reports on the forums on how this should be declared (not sure what must change before the 3.2 and 4.0):


Wondering what the best way to do this is -- any ideas are appreciated!
 
Thanks for the suggestion, jmarsh. Will give that a shot and report back.

As for the current sensor issue: these are analog voltage from a single or dual channel analog sensor, with CURsens1/2 being the readings directly from the sensor (in the range 0.5-4.5v). CUR1 and CUR2 lead to analog pins on the teensy:

View attachment 32543

These pins are defined as such:

Code:
const int ACUR2 = A0;
const int ACUR1 = A1;

and then in setup:

Code:
  pinMode(ACUR1, INPUT);
  pinMode(ACUR2, INPUT);

ACUR1/2 are run through an ADC.

On the 3.2 these pinMode definitions were not needed. On the 4.0, behavior was extremely erratic without them, and with them there is still some unexpected behavior (although much closer to what it should be). I am seeing mixed reports on the forums on how this should be declared (not sure what must change before the 3.2 and 4.0):


Wondering what the best way to do this is -- any ideas are appreciated!

Instead of this (which would be appropriate when using a pin as a *digital* input. . . leaves the bus keeper that Mark T mentioned enabled):

Code:
  pinMode(ACUR1, INPUT);
  pinMode(ACUR2, INPUT);

Use this (which is appropriate when using a pin for measuring an *analog* voltage . . . disables the bus keeper that Mark T mentioned):

Code:
  pinMode(ACUR1, INPUT_DISABLE);
  pinMode(ACUR2, INPUT_DISABLE);


Hope that helps . . . please report back with any updates.

Mark J Culross
KD5RXT
 
Back
Top