I am having a little trouble getting the FreeRTOS scheduler to work as expected with v8.2 using the ARM Cortex-A9 port. In this simple example, I have two tasks: one is a 96 KHz audio processing task and one is a 10 Hz video processing task.
In the scheduler setup routine, I have the audio task at priority (idle + 4) and the video task at (idle + 3); the audio is of higher priority than the video, as it will need to preempt the video task often. There is another task, the scheduler sender task, which runs with priority (idle + 1) and at a 96 KHz rate. It sends updates to the audio and video queues at their respective frame intervals to wake them up using vTaskDelayUntil (where the slave tasks use xQueueReceive).
These all start and queue correctly; I see that the audio task nominally runs at 96 KHz with a good amount of processing slack and the video task is woken up every 10 Hz. However, the video task takes about 712us to complete and is never preempted by the audio task, despite the video task having relatively well placed taskYIELD() calls throughout this processing interval. This is leading to audio dropouts at a 10 Hz rate. Any thought on what may be happening?
Thanks in advance, I will gladly share code and oscilloscope traces as needed.
I think I see my problem now; the queuing task is at a priority lower than all the other tasks, so it never preempts the video task to wake everyone else up. Sorry about the forum clutter!
Do I take it from your post that you are switching a task in and out at
96KHz? If so I think that might be a bit ambitious, and perhaps
consider performing the 96KHz processing in an interrupt. Sorry I don't
know enough about audio processing to know if that is feasible or practical.
From what I understand about your application, the task that is scheduling the audio (and video) task is runnining at a lower priority than the video task so is likely to be pre-empted from triggering the audio task. Why not use a call to
vTaskDelayUntil(...) in your audio (and video) task to control the timing, which should give you the expected behaviour vis-a-vis your assigned priorities? Alternatively, raise the priority of your scheduling task so that it pre-empts the video task and wakes up the audio task.
Ah, a quick refresh caused by previewing before posting reveals that you have already realised this, but I'll post anyway to re-inforce the message.
What do you mean with "a 96 KHz audio processing task"? Is that a task that needs 96,000 task switches per second?
It sounds like you're sampling audio at 96 KHz, but why does a task have to be woken-up for every sample? Is it doing calculations, filtering?
You are using a "ARM Cortex-A9", that CPU can easily handle 4 x 192 Khz audio without even getting hot :-)
- video task at priority (idle + 3)
- audio task at priority (idle + 4)
The video task has work for 712us continuously and you expect it to get interrupted by the audio task.
I don't think that the video task has to call taskYIELD(): as soon as a higher-priority task is runnable it will run. If that doesn't happen, it looks like the audio task doesn't become runnable (like for instance a successful xQueueReceive() )
Later you write that the task calling xQueueSend had a priority which was too low.
Although the problem is solved I still have some questions:
Isn't it possible to use DMA to receive the audio samples? When using DMA you would get a much lower interrupt load.
And if a DMA method is not available, isn't it possible, like Richard suggested, to get an interrupt for every audio sample? The interrupt can continuously store samples and call 'xSemaphoreGiveFromISR' when a buffer is full.
Are you using FreeRTOS queues to pass individual samples? Queues are great but not for "raw data transport". Like I wrote, you could use a Queue to notify that an audio buffer is filled (when using 2 alternating buffers).
Here is another interrupt-safe method of passing raw data from one task to another:
FreeRTOS_Stream_Buffer.[ch], which is part of +TCP ( http://freertos.org/tcp )
To summarise: 96,000 task switches to handle as many samples give a lot of overhead. Sending 96 K samples through a Queue also gives a lot of overhead.
And if their is no DMA available, I would simulate it by filling buffers from an interrupt.