PDA

View Full Version : Possible Priority Inversion with Serial1



duff
01-24-2014, 05:30 PM
Hi all,

in the following code i think that the Serial1 "serial_write" handler function is still not handling "Priority Inversion" correctly. It's my understanding that Teensyduino 1.17 Release Candidate #1 should of fixed this but i'm not sure. The code below sets up the Interval Timer CH0 with a priority that is equal to Serial1 and then prints using Serial1 in the interrupt handler routine for the Interval Timer. It runs for a few cycles then quits printing as far as I can tell. It also makes it so you have to push the upload code button on the teensy to reprogram it.


//example 1
#define NVIC_IABR1 *(volatile uint32_t *)0xE000E300
#define NVIC_IABR2 *(volatile uint32_t *)0xE000E304

IntervalTimer timer;

void PriorityInversionISR(void) {
digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
Serial1.println("Hello, World!!!");
int priority = nvic_execution_priority();
Serial.printf("current priority: %i | NVIC_IABR1: %#X | NVIC_IABR2: %#X\n", priority, NVIC_IABR1, NVIC_IABR2);
}

void setup() {
pinMode(LED_BUILTIN, OUTPUT);
Serial.begin(0);
Serial1.begin(1200);
while(!Serial);
delay(100);
NVIC_SET_PRIORITY(IRQ_PIT_CH0, 64);//<-- same priority as serial1
timer.begin(PriorityInversionISR, 100000);
}

void loop() {}


This might be a issue with the Interval Timer class not handling the inversion also, but if i leave the priority of Interval Timer at 64 and remove the Serial1.print code it works normally. The code below shows this.


example 2
#define NVIC_IABR1 *(volatile uint32_t *)0xE000E300
#define NVIC_IABR2 *(volatile uint32_t *)0xE000E304

IntervalTimer timer;

void PriorityInversionISR(void) {
digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
//Serial1.println("Hello, World!!!");<--- commented out, now works!
int priority = nvic_execution_priority();
Serial.printf("current priority: %i | NVIC_IABR1: %#X | NVIC_IABR2: %#X\n", priority, NVIC_IABR1, NVIC_IABR2);
}

void setup() {
pinMode(LED_BUILTIN, OUTPUT);
Serial.begin(0);
Serial1.begin(1200);
while(!Serial);
delay(100);
NVIC_SET_PRIORITY(IRQ_PIT_CH0, 64); //<-- same priority as serial1
timer.begin(PriorityInversionISR, 100000);
}

void loop() {}


The weird thing is it seems as if the interval timer works still even if the teensy is "sudo" locked up using example 1. The work around i found is to change PIT CH0 priority to 128 before calling Serial1.print and then change it back after shown below.


//example 3
#define NVIC_IABR1 *(volatile uint32_t *)0xE000E300
#define NVIC_IABR2 *(volatile uint32_t *)0xE000E304

IntervalTimer timer;

void PriorityInversionISR(void) {
digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));


NVIC_SET_PRIORITY(IRQ_PIT_CH0, 128);//<--- Lower priority
Serial1.println("Hello, World!!!");
NVIC_SET_PRIORITY(IRQ_PIT_CH0, 64);//<--- increase priority


int priority = nvic_execution_priority();
Serial.printf("current priority: %i | NVIC_IABR1: %#X | NVIC_IABR2: %#X\n", priority, NVIC_IABR1, NVIC_IABR2);
}

void setup() {
pinMode(LED_BUILTIN, OUTPUT);
Serial.begin(0);
Serial1.begin(1200);
while(!Serial);
delay(100);
NVIC_SET_PRIORITY(IRQ_PIT_CH0, 64); //<-- same priority as serial1
timer.begin(PriorityInversionISR, 100000);
}

void loop() {}


The reason i think i have to change the priority to 128 in the above example is that the USB is at priority 112 so that where the inversion i think is happening. Anyway i just wanted to share this case someone in counters the same problem. This probably won't be a issue with 99% of project but it is a problem for those setting priorities in thier code.

duff