I am using a 2 core esp32. The second core, which is suppose to run its own scheduler, has only 1 task, which is running a sensor/processing loop at high priority. It is the only thing being done on the second core. The sensor/processing loop must execute in 20us. Fortunately, the loop can be completed in 15us so from that respect all is fine. Unfortunately, every 10ms the tick timer goes off and starts the scheduler. The scheduler takes 6.9us to execute which violates the 20us specification.
Is there a way to shorten or eliminate that 6.9us processing time?
There will only be one task, so the scheduler will never need to determine if a context change needs to occur. Is there a way to set up the scheduler so it doesnāt waste time checking if there needs to be a context change (speaking from state of ignorance here)?
If you only every have one task running (not even switching to the idle task) you donāt need an RTOS, and can just run a bare-metal application.
If you still want FreeRTOS running because you want to block to wait for work (so you DO have the idle task running, and switch between the two tasks), but never need a timeout, just manualy disable the interrupt for the tick interrupt.
The tick timer is on core 0 and is used for the schedulers running on core 0 and core 1. I will need the RTOS on core 0 so I canāt really disable the timer because it is shared by the RTOS of both cores.
It was not entirely correct to say that I only have one task because it ignores the IDLE task. I may be looking for a way to tell the scheduler that there is no reason to go to the IDLE. I am assuming that when the tick timer expires that there will be a complete context switch to go to the IDLE task and back.
No, the (lowest prio) idle task runs (i.e. is selected to run by the scheduler) only if all other, higher prioritized tasks are blocked/waiting for something. Hence IDLE task.
Is it correct to assume then that the 6.9us is caused entirely by the scheduler checking to see if there is another task that should be run, finding that there is no other task to run, then returning processing to the task, with no context switch ever being done?
to minimize the tick handler processing time if this still matches your requirements.
What about doing the sensor processing in a (HW timer triggered) ISR with a prio above FreeRTOS covered range ? Given the sensor processing doesnāt need any FreeRTOS API calls, of course.
I have not done esp32, so I donāt know what happens when the tick timer interrupt goes off or whatās typical for a context switch. In most, if not all, of my FreeRTOS projects, thereās always a timer task that deals with dispatching the timer expiration events at thread rather than interrupt context. The scheduler should not be taking a significant amount of time when itās called. If I remember correctly, the runnable tasks are kept in a priority ordered queue, and if the priority of the current task is higher than the head of the runnable queue, it shouldnāt do anything more; it does not have to look at anything else. If thereās a timer task, however, and the timer interrupt handler first makes the timer task runnable, the timer task is likely to be the highest priority, and when the scheduler is called at the end of the timer interrupt handler, the task context switch will occur, the timer task will deal with timeouts and software timers, then block until the next tick which causes the scheduler to perform a context switch back to the highest runnable priority task, which is your task.
I donāt have time to go back and look to be sure Iām correct in my above conjecture, but that may be whatās taking so long.
Is it correct to assume then that the 6.9us is caused entirely by the scheduler checking to see if there is another task that should be run, finding that there is no other task to run, then returning processing to the task, with no context switch ever being done?
The time 6.9 us may consist of the followings:
The time to handle tick interrupt
The time for xTaskIncremenTick() call in the tick ISR. As you described above, if you have preemption and time slicing enabled, the scheduler will check if there are any tasks with equal priority that are ready to run in the xTaskIncrementTick() function.
As hs2 mentioned, disabling configUSE_PREEMPTION and configUSE_TIME_SLICING can minimize the time spent in the xTaskIncrementTick() call. Itās worth experimenting with these two configs disabled to find out the CPU time saved.
The other question I would like to know is whether you are using an AMP or SMP configuration since your ESP32 platform has 2 cores.
Thanks for your explanation. I havenāt created a timer task but I do have a bare metal timer running. If I turn off the bare metal timer the 6.9us still occurs. There is an inter processor communication task that the ESP32 environment creates so maybe that is being called and doing something.
Thanks for your feedback
.
The documentation says it is SMP, but it also says that each core has its own scheduler. Iām not sure both can be true. Maybe one instance of FreeRTOS with 2 schedulers, one for each core (insert my dumbfounded facial expression here)??? When I do a vTaskListTasks it lists an IDLE, and InterProcessorComunication task for each core.
There is only one configUSE_PREEMPTION and configUSE_TIME_SLICING so Iām thinking this means there is only one FreeRTOS.
A Dual core processor can run either SMP with one copy of FreeRTOS that controls and schedules both core or AMP with a separate copy of FreeRTOS, one for each core, which sounds like what you want.
The AMP structure should end up generating two independent program files that each get loaded in its own location of memory, one for each processor. Normally you have two build scripts, one for each processor, and that should allow having separate FreeRTOSConfig files for the two processors, but they might not actually implement that capability in the default build structure (in my mind they should, but they might not).
If one call to vTaskListTasks lists two Idle processes, one for each core, the the system is running SMP, but then I donāt understand the need for an āInterProcessorComunicationā task, as the processors are just sharing. (Unless they have a not-very-symmetric SMP where FreeRTOS sits in the shared memory, but a lot of the tasks run in private memory for one of the cores.)
It still wouldnāt make a difference. The sensor processing must run once every 20us and is initiated by a timer. The sensor processing will take 15us regardless of whether some of it is running in an ISR or not. That leaves 5us of free time. The FreeRTOS process takes 9.6us which is longer than the free time. Running some, or all, in an ISR would restrict the 9.6us from starting during the ISR, but it would not prevent the 9.6us from running after returning from the interrupt, so the sensor process and 9.6us would still not complete in 20us.
When I had a task similar to that, I put the timer interrupt higher in priority then could use FreeRTOS, so it did not get masked by critical sections, and did everything in the ISR. If it needs to interface with FreeRTOS at times, it needs to trigger a lower priority interrupt and that can do that part of the actions.
If the ESP32 canāt do that, it may just be the wrong processor for the task.
That wouldnāt make much sense I guess. But e.g. on Cortex-M MCUs FreeRTOS covers only a certain range of interrupt priorities. Interrupts with a logically higher prio outside this range are not disabled by critical sections etc. but on the other hand the corresponding ISRs canāt call FreeRTOS API functions.
This might be used for harder (much less jitter) realtime interrupt processing as seemingly required in your case. So the plan was or could be to have a periodic 20 us HW timer interrupt with a higher prio than covered by FreeRTOS, do the needed sensor processing in the ISR and return. If you have to use FreeRTOS API in addition you wouldāve to use the mechanism described by @richard-damon and set a lower, FreeRTOS covered prio interrupt in the RT ISR (by SW) and do the FreeRTOS API calls in the corresponding ātrampolineā ISR.