I am developing some firmware for the Cortex-M4 CPU within the NXP i.MX8.
Part of the process resolves around a periodic event so I have set up one of the general purpose timers. The hardware interrupt handler calls
vTaskNotifyGiveFromISR() to wake up the thread that does the actual work - at the moment it just toggles a GPIO output.
I seem to be hitting an issue where I can’t get the interrupt to run faster than about 25KHz.
I can’t figure out at the moment what the fastest rate ought to be and whether this is down to the hardware timer not getting programmed correctly, the latency within FreeRTOS switching to the thread from the hardware interrupt handler, or my oscilloscope not being capable of tracking a faster switching signal.
First you would need to check the hardware timer is capable of generating interrupts faster than 25K.
Second I suggest, as a test, just toggle the LED directly in the interrupt handler without unblocking a task. That could potentially eliminate some of the causes.
However, I don’t recommend unblocking a task at that frequency as you will generate thousands of context switches for every tick period - creating a large kernel overhead. Instead, consider performing whatever action the task is going to perform directly within the interrupt service routine. The FreeRTOS Cortex-M port only disables interrupts up to the setting of configMAX_SYSCALL_INTERRUPT_PRIORITY, so by setting the timer’s priority above that it won’t get delayed by anything the kernel is doing.
If I disable the thread and toggle the LED directly within the timer IRQ handler then I can program the timer to toggle it at 250KHz.
Looks like the issue is somewhere within FreeRTOS (or the way I have it configured).
The hardware interrupt is enabled using:
#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY ((1U << (configPRIO_BITS)) - 1).
The call to
xTaskCreate() has the
uxPriority parameter set to
tskIDLE_PRIORITY + 3
One big thing to remember is that at 250kHz, you are doing something every 4 us, and in this time you are doing an ISR entry and exit, as well as TWO context switches (into and out of the task). This could well be saturating the processor depending on the speed you are running it at.
The Cortex-M4 in the i.MX8 variant we are using is clocked at 400MHz. Long term it will migrate to another one of the family that is a Cortex-M7 at 750MHz.
Based on the feedback from @rtel then most of the work would be done within the interrupt handler so I may drop FreeRTOS and go back to bare metal.
400 MHz may sound fast, but 1600 cycles isn’t a lot, especially if stacks aren’t in internal Tightly Coupled memory and incur wait states. I would think it could handle that sort of operation, but it depends a lot on what else you are doing in the task, and how efficient the code is. The scheduler can easily run for 100s of cycles.