IntervalTimer interrupt priority

Status
Not open for further replies.

Jp3141

Well-known member
I have a simple demo on Teensy LC that generates an interval timer interrupt nominally each 10 ms and toggles a pin. However the interrupts (or pin toggling) don't come at precise intervals. Here is a screenshot -- note the narrower pulses are not caused by the interrupt coming early, but by the previous edge (which triggers the scope) coming late.
INT.jpg

How can I make the interrupt timing more precise ? I guess it's getting interrupted by some higher priority process -- which ? Can I change the NVIC to improve the toggleLED's interrupts priority ? How ?

Here's my code:
Code:
IntervalTimer myTimer;

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
  Serial.begin(115200);
  myTimer.begin(toggleLED, 1*10); 
}

volatile unsigned long toggleCount = 0;

void toggleLED() {
  noInterrupts();
  toggleCount++;  // increments at 2x blink rate  
  digitalToggleFast(LED_BUILTIN);
}

unsigned long blinkShadow;  
void loop() {
  noInterrupts();
  blinkShadow = toggleCount >> 1;
  interrupts();

//  Serial.printf("blinkCount = %i\n", blinkShadow);
  delay(1000);
}
 
I believe that it defaults to NVIC priority 128 - Default middle of the road.

And I believe this object has a method priority, where you can set a new priority for the underlying interrupt.
Value is 0-255, with the lower the number the higher the priority
 
But how do I do that specifically ? I don't know the interrupt number.

I tried NVIC_SET_PRIORITY(IRQ_PIT, 1);?

and ...,0); -- that helps and reduces the jitter from 10's of us to about 1us. I guess I need use the hardware directly and likely DMA to get 'zero' jitter ?

Presumably there are other INTs also at priority 0 -- if I moved them to '2', would that fix my issue ?
 
Last edited:
Priority values 0-255 - but in groups of 8 having the same actual priority. i.e. 0 and 7 are the same and 8-15 the next lower group etc.
 
But how can I find what other interrupts are using priority 0 and move them to (say) 8 ?
 
But how can I find what other interrupts are using priority 0 and move them to (say) 8 ?

Not sure anything in the default system uses the highest range 0-7. If it does those two would supersede anything, but queue behind each other.

Not sure if FASTRUN void toggleLED() Helps on T_LC?

Also seeing this is T_LC - it has fewer levels with bigger priority groups than 8.

Without USB print needed, observing with scope - build without USB?
 
But how do I do that specifically ? I don't know the interrupt number.

I tried NVIC_SET_PRIORITY(IRQ_PIT, 1);?

and ...,0); -- that helps and reduces the jitter from 10's of us to about 1us. I guess I need use the hardware directly and likely DMA to get 'zero' jitter ?

Presumably there are other INTs also at priority 0 -- if I moved them to '2', would that fix my issue ?
As I mentioned I think this class has a priority method... That is with your code.
Code:
IntervalTimer myTimer;

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
  Serial.begin(115200);
  myTimer.begin(toggleLED, 1*10); 
[COLOR="#FF0000"]  myTimer.priority(1); // set high priority
[/COLOR]}

volatile unsigned long toggleCount = 0;

void toggleLED() {
  noInterrupts();
  toggleCount++;  // increments at 2x blink rate  
  digitalToggleFast(LED_BUILTIN);
}

unsigned long blinkShadow;  
void loop() {
  noInterrupts();
  blinkShadow = toggleCount >> 1;
  interrupts();

//  Serial.printf("blinkCount = %i\n", blinkShadow);
  delay(1000);
}
As for finding others who use the highest priority. I do a search and try to get a look to see...

In my case I use sublime text to do most of my editing. So I do a global search in the cores\teensy3 directory for all places that have: NVIC_SET_PRIORITY...
Code:
Searching 144 files for "NVIC_SET_PRIORITY"

C:\arduino-1.8.13\hardware\teensy\avr\cores\teensy3\AudioStream.cpp:
  303  {
  304  	if (update_scheduled) return false;
  305: 	NVIC_SET_PRIORITY(IRQ_SOFTWARE, 208); // 255 = lowest priority
  306  	NVIC_ENABLE_IRQ(IRQ_SOFTWARE);
  307  	update_scheduled = true;

C:\arduino-1.8.13\hardware\teensy\avr\cores\teensy3\IntervalTimer.cpp:
   67  	channel->TCTRL = 3;
   68  #if defined(KINETISK)
   69: 	NVIC_SET_PRIORITY(IRQ_PIT_CH0 + index, nvic_priority);
   70  	NVIC_ENABLE_IRQ(IRQ_PIT_CH0 + index);
   71  #elif defined(KINETISL)
   72  	nvic_priorites[index] = nvic_priority;
   73  	if (nvic_priorites[0] <= nvic_priorites[1]) {
   74: 		NVIC_SET_PRIORITY(IRQ_PIT, nvic_priorites[0]);
   75  	} else {
   76: 		NVIC_SET_PRIORITY(IRQ_PIT, nvic_priorites[1]);
   77  	}
   78  	NVIC_ENABLE_IRQ(IRQ_PIT);
   ..
   95  		nvic_priorites[index] = 255;
   96  		if (nvic_priorites[0] <= nvic_priorites[1]) {
   97: 			NVIC_SET_PRIORITY(IRQ_PIT, nvic_priorites[0]);
   98  		} else {
   99: 			NVIC_SET_PRIORITY(IRQ_PIT, nvic_priorites[1]);
  100  		}
  101  #endif

C:\arduino-1.8.13\hardware\teensy\avr\cores\teensy3\IntervalTimer.h:
  105  		if (channel) {
  106  			int index = channel - KINETISK_PIT_CHANNELS;
  107: 			NVIC_SET_PRIORITY(IRQ_PIT_CH0 + index, nvic_priority);
  108  		}
  109  		#elif defined(KINETISL)
  ...
  112  			nvic_priorites[index] = nvic_priority;
  113  			if (nvic_priorites[0] <= nvic_priorites[1]) {
  114: 				NVIC_SET_PRIORITY(IRQ_PIT, nvic_priorites[0]);
  115  			} else {
  116: 				NVIC_SET_PRIORITY(IRQ_PIT, nvic_priorites[1]);
  117  			}
  118  		}

C:\arduino-1.8.13\hardware\teensy\avr\cores\teensy3\kinetis.h:
 5664  // Cortex-M0: 0,64,128,192
 5665  #ifdef KINETISK
 5666: #define NVIC_SET_PRIORITY(irqnum, priority)  (*((volatile uint8_t *)0xE000E400 + (irqnum)) = (uint8_t)(priority))
 5667  #define NVIC_GET_PRIORITY(irqnum) (*((uint8_t *)0xE000E400 + (irqnum)))
 5668  #else
 5669: #define NVIC_SET_PRIORITY(irqnum, priority) (*((uint32_t *)0xE000E400 + ((irqnum) >> 2)) = (*((uint32_t *)0xE000E400 + ((irqnum) >> 2)) & (~(0xFF << (8 * ((irqnum) & 3))))) | (((priority) & 0xFF) << (8 * ((irqnum) & 3))))
 5670  #define NVIC_GET_PRIORITY(irqnum) (*((uint32_t *)0xE000E400 + ((irqnum) >> 2)) >> (8 * ((irqnum) & 3)) & 255)
 5671  #endif

C:\arduino-1.8.13\hardware\teensy\avr\cores\teensy3\mk20dx128.c:
  773  	// default all interrupts to medium priority level
  774  	for (i=0; i < NVIC_NUM_INTERRUPTS + 16; i++) _VectorsRam[i] = _VectorsFlash[i];
  775: 	for (i=0; i < NVIC_NUM_INTERRUPTS; i++) NVIC_SET_PRIORITY(i, 128);
  776  	SCB_VTOR = (uint32_t)_VectorsRam;	// use vector table in RAM
  777  

C:\arduino-1.8.13\hardware\teensy\avr\cores\teensy3\serial1.c:
  166  #endif
  167  	UART0_C2 = C2_TX_INACTIVE;
  168: 	NVIC_SET_PRIORITY(IRQ_UART0_STATUS, IRQ_PRIORITY);
  169  	NVIC_ENABLE_IRQ(IRQ_UART0_STATUS);
  170  }

C:\arduino-1.8.13\hardware\teensy\avr\cores\teensy3\serial1_doughboy.txt:
  122  #endif
  123  	UART0_C2 = UART_C2_TE | UART_C2_RE | UART_C2_RIE | UART_C2_ILIE;
  124: 	NVIC_SET_PRIORITY(IRQ_UART0_STATUS, IRQ_PRIORITY);
  125  	NVIC_ENABLE_IRQ(IRQ_UART0_STATUS);
  126  }

C:\arduino-1.8.13\hardware\teensy\avr\cores\teensy3\serial2.c:
  166  #endif
  167  	UART1_C2 = C2_TX_INACTIVE;
  168: 	NVIC_SET_PRIORITY(IRQ_UART1_STATUS, IRQ_PRIORITY);
  169  	NVIC_ENABLE_IRQ(IRQ_UART1_STATUS);
  170  }

C:\arduino-1.8.13\hardware\teensy\avr\cores\teensy3\serial3.c:
  148  #endif
  149  	UART2_C2 = C2_TX_INACTIVE;
  150: 	NVIC_SET_PRIORITY(IRQ_UART2_STATUS, IRQ_PRIORITY);
  151  	NVIC_ENABLE_IRQ(IRQ_UART2_STATUS);
  152  }

C:\arduino-1.8.13\hardware\teensy\avr\cores\teensy3\serial4.c:
  126  	UART3_PFIFO = 0;
  127  	UART3_C2 = C2_TX_INACTIVE;
  128: 	NVIC_SET_PRIORITY(IRQ_UART3_STATUS, IRQ_PRIORITY);
  129  	NVIC_ENABLE_IRQ(IRQ_UART3_STATUS);
  130  }

C:\arduino-1.8.13\hardware\teensy\avr\cores\teensy3\serial5.c:
  119  	UART4_PFIFO = 0;
  120  	UART4_C2 = C2_TX_INACTIVE;
  121: 	NVIC_SET_PRIORITY(IRQ_UART4_STATUS, IRQ_PRIORITY);
  122  	NVIC_ENABLE_IRQ(IRQ_UART4_STATUS);
  123  }

C:\arduino-1.8.13\hardware\teensy\avr\cores\teensy3\serial6.c:
  119  	UART5_PFIFO = 0;
  120  	UART5_C2 = C2_TX_INACTIVE;
  121: 	NVIC_SET_PRIORITY(IRQ_UART5_STATUS, IRQ_PRIORITY);
  122  	NVIC_ENABLE_IRQ(IRQ_UART5_STATUS);
  123  }

C:\arduino-1.8.13\hardware\teensy\avr\cores\teensy3\serial6_lpuart.c:
  193  	// Enable the transmitter, receiver and enable receiver interrupt
  194  	LPUART0_CTRL |= LPUART_CTRL_RIE | LPUART_CTRL_TE | LPUART_CTRL_RE;
  195: 	NVIC_SET_PRIORITY(IRQ_LPUART0, IRQ_PRIORITY);
  196  	NVIC_ENABLE_IRQ(IRQ_LPUART0);
  197  }

C:\arduino-1.8.13\hardware\teensy\avr\cores\teensy3\usb_dev.c:
 1214  
 1215  	// enable interrupt in NVIC...
 1216: 	NVIC_SET_PRIORITY(IRQ_USBOTG, 112);
 1217  	NVIC_ENABLE_IRQ(IRQ_USBOTG);
 1218  

21 matches across 14 files
And then I take a quick look... For example Serial1... And I notice that it depends on some #define IRQ_PRIORITY and so do some of the others. So again do search:
Code:
Searching 144 files for "IRQ_PRIORITY"

C:\arduino-1.8.13\hardware\teensy\avr\cores\teensy3\serial1.c:
   45  #define RTS_HIGH_WATERMARK (SERIAL1_RX_BUFFER_SIZE-24) // RTS requests sender to pause
   46  #define RTS_LOW_WATERMARK  (SERIAL1_RX_BUFFER_SIZE-38) // RTS allows sender to resume
   47: #define IRQ_PRIORITY  64  // 0 = highest priority, 255 = lowest
   48  
   49  
   ..
  166  #endif
  167  	UART0_C2 = C2_TX_INACTIVE;
  168: 	NVIC_SET_PRIORITY(IRQ_UART0_STATUS, IRQ_PRIORITY);
  169  	NVIC_ENABLE_IRQ(IRQ_UART0_STATUS);
  170  }
  ...
  374  	while (tx_buffer_tail == head) {
  375  		int priority = nvic_execution_priority();
  376: 		if (priority <= IRQ_PRIORITY) {
  377  			if ((UART0_S1 & UART_S1_TDRE)) {
  378  				uint32_t tail = tx_buffer_tail;
  ...
  409  			do {
  410  				int priority = nvic_execution_priority();
  411: 				if (priority <= IRQ_PRIORITY) {
  412  					if ((UART0_S1 & UART_S1_TDRE)) {
  413  						uint32_t tail = tx_buffer_tail;

C:\arduino-1.8.13\hardware\teensy\avr\cores\teensy3\serial1_doughboy.txt:
   47  #define SERIAL1_RX_BUFFER_SIZE 64 // number of incoming bytes to buffer
   48  #endif
   49: #define IRQ_PRIORITY  64  // 0 = highest priority, 255 = lowest
   50  
   51  
   ..
  122  #endif
  123  	UART0_C2 = UART_C2_TE | UART_C2_RE | UART_C2_RIE | UART_C2_ILIE;
  124: 	NVIC_SET_PRIORITY(IRQ_UART0_STATUS, IRQ_PRIORITY);
  125  	NVIC_ENABLE_IRQ(IRQ_UART0_STATUS);
  126  }
  ...
  212  	while (tx_buffer_tail == head) {
  213  		int priority = nvic_execution_priority();
  214: 		if (priority <= IRQ_PRIORITY) {
  215  			if ((UART0_S1 & UART_S1_TDRE)) {
  216  				uint32_t tail = tx_buffer_tail;
  ...
  249  			do {
  250  				int priority = nvic_execution_priority();
  251: 				if (priority <= IRQ_PRIORITY) {
  252  					if ((UART0_S1 & UART_S1_TDRE)) {
  253  						uint32_t tail = tx_buffer_tail;

C:\arduino-1.8.13\hardware\teensy\avr\cores\teensy3\serial2.c:
   45  #define RTS_HIGH_WATERMARK (SERIAL2_RX_BUFFER_SIZE-24) // RTS requests sender to pause
   46  #define RTS_LOW_WATERMARK  (SERIAL2_RX_BUFFER_SIZE-38) // RTS allows sender to resume
   47: #define IRQ_PRIORITY  64  // 0 = highest priority, 255 = lowest
   48  
   49  ////////////////////////////////////////////////////////////////
   ..
  166  #endif
  167  	UART1_C2 = C2_TX_INACTIVE;
  168: 	NVIC_SET_PRIORITY(IRQ_UART1_STATUS, IRQ_PRIORITY);
  169  	NVIC_ENABLE_IRQ(IRQ_UART1_STATUS);
  170  }
  ...
  364  	while (tx_buffer_tail == head) {
  365  		int priority = nvic_execution_priority();
  366: 		if (priority <= IRQ_PRIORITY) {
  367  			if ((UART1_S1 & UART_S1_TDRE)) {
  368  				uint32_t tail = tx_buffer_tail;
  ...
  399  			do {
  400  				int priority = nvic_execution_priority();
  401: 				if (priority <= IRQ_PRIORITY) {
  402  					if ((UART1_S1 & UART_S1_TDRE)) {
  403  						uint32_t tail = tx_buffer_tail;

C:\arduino-1.8.13\hardware\teensy\avr\cores\teensy3\serial3.c:
   45  #define RTS_HIGH_WATERMARK (SERIAL3_RX_BUFFER_SIZE-24) // RTS requests sender to pause
   46  #define RTS_LOW_WATERMARK  (SERIAL3_RX_BUFFER_SIZE-38) // RTS allows sender to resume
   47: #define IRQ_PRIORITY  64  // 0 = highest priority, 255 = lowest
   48  
   49  
   ..
  148  #endif
  149  	UART2_C2 = C2_TX_INACTIVE;
  150: 	NVIC_SET_PRIORITY(IRQ_UART2_STATUS, IRQ_PRIORITY);
  151  	NVIC_ENABLE_IRQ(IRQ_UART2_STATUS);
  152  }
  ...
  320  	while (tx_buffer_tail == head) {
  321  		int priority = nvic_execution_priority();
  322: 		if (priority <= IRQ_PRIORITY) {
  323  			if ((UART2_S1 & UART_S1_TDRE)) {
  324  				uint32_t tail = tx_buffer_tail;

C:\arduino-1.8.13\hardware\teensy\avr\cores\teensy3\serial4.c:
   47  #define RTS_HIGH_WATERMARK (SERIAL4_RX_BUFFER_SIZE-24) // RTS requests sender to pause
   48  #define RTS_LOW_WATERMARK  (SERIAL4_RX_BUFFER_SIZE-38) // RTS allows sender to resume
   49: #define IRQ_PRIORITY  64  // 0 = highest priority, 255 = lowest
   50  
   51  
   ..
  126  	UART3_PFIFO = 0;
  127  	UART3_C2 = C2_TX_INACTIVE;
  128: 	NVIC_SET_PRIORITY(IRQ_UART3_STATUS, IRQ_PRIORITY);
  129  	NVIC_ENABLE_IRQ(IRQ_UART3_STATUS);
  130  }
  ...
  260  	while (tx_buffer_tail == head) {
  261  		int priority = nvic_execution_priority();
  262: 		if (priority <= IRQ_PRIORITY) {
  263  			if ((UART3_S1 & UART_S1_TDRE)) {
  264  				uint32_t tail = tx_buffer_tail;

C:\arduino-1.8.13\hardware\teensy\avr\cores\teensy3\serial5.c:
   47  #define RTS_HIGH_WATERMARK (SERIAL5_RX_BUFFER_SIZE-24) // RTS requests sender to pause
   48  #define RTS_LOW_WATERMARK  (SERIAL5_RX_BUFFER_SIZE-38) // RTS allows sender to resume
   49: #define IRQ_PRIORITY  64  // 0 = highest priority, 255 = lowest
   50  
   51  
   ..
  119  	UART4_PFIFO = 0;
  120  	UART4_C2 = C2_TX_INACTIVE;
  121: 	NVIC_SET_PRIORITY(IRQ_UART4_STATUS, IRQ_PRIORITY);
  122  	NVIC_ENABLE_IRQ(IRQ_UART4_STATUS);
  123  }
  ...
  238  	while (tx_buffer_tail == head) {
  239  		int priority = nvic_execution_priority();
  240: 		if (priority <= IRQ_PRIORITY) {
  241  			if ((UART4_S1 & UART_S1_TDRE)) {
  242  				uint32_t tail = tx_buffer_tail;

C:\arduino-1.8.13\hardware\teensy\avr\cores\teensy3\serial6.c:
   47  #define RTS_HIGH_WATERMARK (SERIAL6_RX_BUFFER_SIZE-24) // RTS requests sender to pause
   48  #define RTS_LOW_WATERMARK  (SERIAL6_RX_BUFFER_SIZE-38) // RTS allows sender to resume
   49: #define IRQ_PRIORITY  64  // 0 = highest priority, 255 = lowest
   50  
   51  
   ..
  119  	UART5_PFIFO = 0;
  120  	UART5_C2 = C2_TX_INACTIVE;
  121: 	NVIC_SET_PRIORITY(IRQ_UART5_STATUS, IRQ_PRIORITY);
  122  	NVIC_ENABLE_IRQ(IRQ_UART5_STATUS);
  123  }
  ...
  238  	while (tx_buffer_tail == head) {
  239  		int priority = nvic_execution_priority();
  240: 		if (priority <= IRQ_PRIORITY) {
  241  			if ((UART5_S1 & UART_S1_TDRE)) {
  242  				uint32_t tail = tx_buffer_tail;

C:\arduino-1.8.13\hardware\teensy\avr\cores\teensy3\serial6_lpuart.c:
   55  #define RTS_HIGH_WATERMARK (SERIAL6_RX_BUFFER_SIZE-24) // RTS requests sender to pause
   56  #define RTS_LOW_WATERMARK  (SERIAL6_RX_BUFFER_SIZE-38) // RTS allows sender to resume
   57: #define IRQ_PRIORITY  64  // 0 = highest priority, 255 = lowest
   58  
   59  
   ..
  193  	// Enable the transmitter, receiver and enable receiver interrupt
  194  	LPUART0_CTRL |= LPUART_CTRL_RIE | LPUART_CTRL_TE | LPUART_CTRL_RE;
  195: 	NVIC_SET_PRIORITY(IRQ_LPUART0, IRQ_PRIORITY);
  196  	NVIC_ENABLE_IRQ(IRQ_LPUART0);
  197  }
  ...
  312  	while (tx_buffer_tail == head) {
  313  		int priority = nvic_execution_priority();
  314: 		if (priority <= IRQ_PRIORITY) {
  315  			if ((LPUART0_STAT & LPUART_STAT_TDRE)) {
  316  				uint32_t tail = tx_buffer_tail;

27 matches across 8 files
Looks like most of these are set to 64...
 
Note that you can set a high priority, but some lower priority ISR or a library might briefly disable interrupts - causing jitter. Consider turning off interrupts and doing everything with polling. Or use hardware.
 
As I mentioned I think this class has a priority method... That is with your code.
...
Looks like most of these are set to 64...

@KurtE - I did that same search - only general setting to default mid-range and minor alternates you looked into more since it seemed UART wouldn't get bumped any higher. What I didn't find was anything for USB being adjusted - so suggested shutting it off to assure it isn't a factor with DMA or whatever background stuff might come with that.
 
Thanks all. It seems like
Code:
NVIC_SET_PRIORITY(IRQ_PIT, 1);
and
  myTimer.priority(1); // set high priority
have the same effect of raising the priority.

Furthe looking through my code, it seems that the delay() function in the loop() is the culprit. With delay() in the code and priority(1), I get about 700 ns p-p jitter. Without delay(), I get about half that. I think systick is probably the culprit, but it seems like its priority is 32 -- so it shouldn't.

Compiling to no USB, or using FASTRUN doesn't seem to make any difference.
 
Status
Not open for further replies.
Back
Top