Hello,
I have an application running on a teensy 4.1 with a SPI based ADC running at a very high sample rate. There is one interrupt per sample and each interrupt must do a SPI read. I also have a 10 second interrupt based timer that sets a flag on each timer interrupt. Loop checks that flag and dumps some statistics every ten seconds. I'm omitting code here because this all works.
Now we get to the problem I'm trying to solve. I would like to run my sample clock rate "at the limit" which means sometimes the hardware sample clock (falling edge of a digital pin) happens before the ISR has returned. I would like to skip the work portion of my if that occurs but increment a counter each time I do it.
My "vanilla" ISR is as more or less as follows:
void myISR()
{
int32_t data = SPI.transfer32();
myWorkFunction(data); // some filtering and transfer of data to a queue to be read by "loop"
}
In this case, as one would expect, if I cross the "at the limit" threshold for the interrupt rate, eventually the "loop()" function never gets called as I am perpetually servicing the interrupt.
What I would like to do is the following:
volatile bool isAdcBusy = false;
volatile uint32_t busyCount = 0;
void myISR()
{
if (isAdcBusy)
{
busyCount++;
return;
}
isAdcBusy = true;
sei(); // See explanation below
int32_t data = SPI.transfer32();
myWorkFunction(data);
isAdcBusy = false;
}
The documentation for sei() seemed to indicate that calling it in the ISR would reenable interrupts allowing the next sample clock interrupt to call "myISR()" even if "myWorkFunction()" had not yet returned from the previous ISR. In that case busyCount would be incremented but the work portion would be skipped.
If this worked, my expectation would be that when I up the clock just past the "at the limit" threshold, "loop()" would still be called and "busyCount" would be incremented roughly every other sample. Instead, I find that the two forms of the ISR exhibit identical behavior: as I up the clock rate I go from loop being called with a busyCount of 0 to loop never being called at all.
This tells me that I misunderstood the documentation for "sei()" and maybe it will not allow the nesting I am seeking to accomplish. If sei() doesn't do what I want, I would like to know if there is any function available to reenable the sample clock interrupt that is calling myISR() at the point where the above code fragment has a call to sei().
Please note that the discussion of upping the clock rate till it is past the "at the limit" threshold is simply how I intended to test the second form of the ISR. In real life my code will be operating where "myWorkFunction" usually finishes on time but occasionally it will take long enough to "miss" an interrupt. I need to keep stats on how often that happens.
Thanking you in advance
I have an application running on a teensy 4.1 with a SPI based ADC running at a very high sample rate. There is one interrupt per sample and each interrupt must do a SPI read. I also have a 10 second interrupt based timer that sets a flag on each timer interrupt. Loop checks that flag and dumps some statistics every ten seconds. I'm omitting code here because this all works.
Now we get to the problem I'm trying to solve. I would like to run my sample clock rate "at the limit" which means sometimes the hardware sample clock (falling edge of a digital pin) happens before the ISR has returned. I would like to skip the work portion of my if that occurs but increment a counter each time I do it.
My "vanilla" ISR is as more or less as follows:
void myISR()
{
int32_t data = SPI.transfer32();
myWorkFunction(data); // some filtering and transfer of data to a queue to be read by "loop"
}
In this case, as one would expect, if I cross the "at the limit" threshold for the interrupt rate, eventually the "loop()" function never gets called as I am perpetually servicing the interrupt.
What I would like to do is the following:
volatile bool isAdcBusy = false;
volatile uint32_t busyCount = 0;
void myISR()
{
if (isAdcBusy)
{
busyCount++;
return;
}
isAdcBusy = true;
sei(); // See explanation below
int32_t data = SPI.transfer32();
myWorkFunction(data);
isAdcBusy = false;
}
The documentation for sei() seemed to indicate that calling it in the ISR would reenable interrupts allowing the next sample clock interrupt to call "myISR()" even if "myWorkFunction()" had not yet returned from the previous ISR. In that case busyCount would be incremented but the work portion would be skipped.
If this worked, my expectation would be that when I up the clock just past the "at the limit" threshold, "loop()" would still be called and "busyCount" would be incremented roughly every other sample. Instead, I find that the two forms of the ISR exhibit identical behavior: as I up the clock rate I go from loop being called with a busyCount of 0 to loop never being called at all.
This tells me that I misunderstood the documentation for "sei()" and maybe it will not allow the nesting I am seeking to accomplish. If sei() doesn't do what I want, I would like to know if there is any function available to reenable the sample clock interrupt that is calling myISR() at the point where the above code fragment has a call to sei().
Please note that the discussion of upping the clock rate till it is past the "at the limit" threshold is simply how I intended to test the second form of the ISR. In real life my code will be operating where "myWorkFunction" usually finishes on time but occasionally it will take long enough to "miss" an interrupt. I need to keep stats on how often that happens.
Thanking you in advance
Last edited: