Counting interupt pulses on a teensy 4.1

Hi Everyone.

Does anyone know how to set the NVIC priority level for pin 34.

Im getting confused with how I did it with the Teensy 3.5

Thanks in Advance.
 
Sorry I am guessing what you are asking for:

Are you asking, how to set the priority for doing something like: attachInterrupt(34, func, mode)....
And set the interrupt priority?

On T4.x, which the code starts up, the initial code (startup.c) will switch all of the IO pins to Fast mode (they go from GPIO1-4 to GPIO 6-9)
And in this mode, there is only one interrupt defined for all of the pins: IRQ_GPIO6789
The code in startup.c that changes it is:
Code:
#if defined(__IMXRT1062__)
	// Use fast GPIO6, GPIO7, GPIO8, GPIO9
	IOMUXC_GPR_GPR26 = 0xFFFFFFFF;
	IOMUXC_GPR_GPR27 = 0xFFFFFFFF;
	IOMUXC_GPR_GPR28 = 0xFFFFFFFF;
	IOMUXC_GPR_GPR29 = 0xFFFFFFFF;
#endif
So you can use NVIC_SetPriority(irq, value) to set this to a higher priority (lower value) I believe they all start out at 128. So for example setting to 96 would give it a higher priority.
I don't remember the resolution of this value it is either something like the top 5 bits or the like. i.e. 128 and 129 are probably the same...

Now as has been mentioned in a few other threads. you can at times swith one or more pins back to reqular speed. So for example pin 34 is on Port 2 or 7 pin 29.
So you can update the appropriate bit in IOMUXC_GPR_GPR27 to 0 and have it back on GPIO 2
And with this, you will find there are two IRQs associated with GPIO2
Code:
        IRQ_GPIO2_0_15 =        82,
        IRQ_GPIO2_16_31 =       83,
So you could setup up your own interrupt for IRQ_GPIO2_16_31 and set it's priority. Likely you would only have one pin so it would not have to scan for which ones triggered.

Or there are some libraries out there to do frequency measurements. like FreqMeasure, but these work on specific pins.
Example for T4.x I believe this. is pin 22

FreqMeasureMulti - can handle this on a lot more pins. That is I believe any pin that has a FlexPWM timer associated with it. Unfortunately pin 34 is not one of them.
 
Thank you for the feedback, I'm trying to count the output of a energy meter. When at full steam it would crank out at around 2MHz but I capping out my counting around 5khz which i would of thought the 4.1 could get a lot closer.

I'm not sending or reciveing any serial data while it is counting so not sure if the serial ports are effecting it. I've got four connected togther each trying out count a different output, then when they are all finished i check to see what what the count is.

Code:
const byte interruptPin = 34;
//volatile byte state = LOW;
volatile unsigned long Counter = 0;

 
void setup() {
  // put your setup code here, to run once:
pinMode(interruptPin, INPUT_PULLUP);  
attachInterrupt(digitalPinToInterrupt(interruptPin), Count, RISING);

// Set interrupt priority level to a higher value (lower priority)
NVIC_SET_PRIORITY(IRQ_GPIO2_16_31, 0);


Serial.begin(57600);
Serial1.begin(57600);
Serial2.begin(57600);
Serial3.begin(57600);
Serial4.begin(57600);

Serial.println("Online");
}

void loop() {
  // put your main code here, to run repeatedly:
String readString;
String read2;
String read3;
String read4;
String read5;

String Q;

while (Serial.available()){
  delay(10);
  if(Serial.available()>0){
  char c = Serial.read();
   if (isControl(c)){
  break;
  }
  readString += c;    
  }
 }

while (Serial1.available()){
  delay(20);
  if(Serial1.available()>0){
  char c = Serial1.read();
   if (isControl(c)){
  break;
  }
  read2 += c;     
  }  
 }
if (read2.length() >= 1 )Serial.println(read2);


while (Serial2.available()){
  delay(10);
  if(Serial2.available()>0){
  char c = Serial2.read();
   if (isControl(c)){
  break;
  
  }
  read3 += c;   
  }
}
  
  if (read3.length() >= 1 )Serial.println(read3); 
    
      


while (Serial3.available()){
  delay(10);
  if(Serial3.available()>0){
  char c = Serial3.read();
   if (isControl(c)){
  break;
  }
  read4 += c; 
  }
 // Serial.println(read4);    
 }
 if (read4.length() >= 1 )Serial.println(read4); 


while (Serial4.available()){
  delay(10);
  if(Serial4.available()>0){
  char c = Serial4.read();
   if (isControl(c)){
  break;
  }
  read5 += c; 
  }
 // Serial.println(read4);    
 }
 if (read5.length() >= 1 )Serial.println(read5); 






Q = readString;
if (Q=="read1"){
  Serial1.print("read");
}

if (Q=="read2"){
  Serial2.print("read");
// delay(50);
// Serial.println(read3);
}

if (Q=="read3"){
  Serial3.print("read");
//  delay(50);
//  Serial.println(read4);
}

if (Q=="read4"){
  Serial4.print("read");
//  delay(50);
//  Serial.println(read5);
}

if (Q=="read"){

  Serial.println(Counter);
}

if (Q=="?read"){

  Serial.println(Counter);
  Serial1.println("read");
  delay(1);
  Serial2.println("read");
  delay(1);
  Serial3.println("read");
  delay(1);
  Serial4.println("read");
  delay(1);
  
}




//Reset the counter
if (Q=="reset"){
Serial1.println("reset");
Serial2.println("reset");
Serial3.println("reset");
Serial4.println("reset");
  
Serial.println("resetted");

  Counter = 0;
}
}



//Interupt counter 
void Count() {
  Counter++;
}
 
Think im onto to somthing, external to my counter.. I was like lets put my pulse output on a scope. And sure enough the pulse train its all over this place. Ill check another device from work tomorrow hopefully that will shed some light pulseout.jpg
 
If you have a pulse coming in at 2 MHz then that gives you ~300 cpu clocks per interrupt. Interrupt latencies are around a dozen clock cycles. I'd make the assumption that returning from the interrupt requires a similar amount of time. That's almost 10% of the CPU time jumping to and from interrupts before you run a single line of code.
So my gut call is it should just about be able to cope with that rate as long as you aren't trying to do much else.

Ideally you'd use a timer/counter peripheral to do this so the pulse counting doesn't require any CPU time and you can simply read the current count or get an interrupt every N pulses. But that's more complex to code and has pin restrictions.

I'm not sure what all those delays are for in the code but the interrupt should take priority over them. Also if it's such a high rate then the method of resetting the counter seems a little crude but if it does what you need then that's all that matters.

I take it you want a total count rather than a rate? For rate I will normally have a timer interrupt running at a fixed rate (say 1 Hz or 10 Hz) that copies my counter and resets it. The main loop then reports the most recent value in that copy, that way I get a reasonably current rate measurement that is as accurate as the count period and clock accuracy allows.

Assuming that scope was suitably set up then I think you're right in thinking the issue is hardware. You are counting rising edges, the signal going from 0V to 3.3V. The actual threshold will be around +1 V.
Your scope trace shows a signal that idles at around 0V and pulses down to around -0.45V before returning to 0. So probably not enough out of spec to damage the part but certainly nothing that will get counted reliably.
There is an indication of overshoot when it returns to 0V, assuming that's not a measurement artifact then that spike may at times be high enough to get counted and explain your 5 kHz rate.
 
Any chance those 10ms delays are a factor?

Shows 10, 20 ms delays when there are known bytes .available - then they are read and it is likely to leave with none available given the placement of those too large delays - they'd only need to be as big as a byte or two [maybe 1/2800th a second? 358us?] at the 57K baud rate expected and after .read() empties the buffer - not before.
 
As a quick test, I removed all the serial input stuff and just used a simple 1 second time to always print the count. Here's the result, with my function generator creating a 2 MHz square wave connected to pin 34.

You can see it's successfully counting 2 MHz. Hopefully this helps?

screenshot.png

file.png

Code:
const byte interruptPin = 34;
volatile unsigned long Counter = 0;
elapsedMillis msec;

void setup() {
  // put your setup code here, to run once:
  pinMode(interruptPin, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(interruptPin), Count, RISING);
  Serial.begin(57600);
  Serial.println("Online");
  msec = 0;
}

unsigned long read_and_reset_counter() {
  noInterrupts();
  unsigned long count = Counter;
  Counter = 0;
  interrupts();
  return count;
}

void loop() {
  if (msec >= 1000) {
    msec -= 1000;
    Serial.print("count = ");
    Serial.println(read_and_reset_counter());
  }
}

//Interupt counter
void Count() {
  Counter++;
}
 
Thanks Paul

Thats a massive help, now i know i can easily do it.

I've also just changed out the device i was trying to count. And repeated the test and it works, spot on.
So looks like it was the reference i was counting had the issues.

A bit of background here, the device im trying to count outputs 100000 pulses per watthour, its a
precision watthour reference so I compare those counts against a unit i'm
calibrating.

I still need to test it at 415V at 120Amps but i cant do that at home, so ill keep you posted

Appreciated everyones help.

Thank you and kind regards
Jon.
 
Back
Top