I wanted to ask about a couple of points on proper system design using the FreeRTOS primitives, now that I'm trying in earnest to port my old timer-driven code to FreeRTOS.
Of course, I understand that there's a limit to how much 'free' help I can solicit, but this is for an academic project, which makes it a little different situation. In the end, it'll all be open source on GitHub, and could provide as a FreeRTOS example.
The project is a small robot with a number of autonomy-related tasks all running. The uncertainty I have is over how to correctly set up each of these tasks.
For example, there is an IMU reading task @ 1khz that updates values, providing a zeroth-order hold on gyro & accelerometer values. That seems like a good candidate for a medium-priority periodic task.
But there's also a motor control task, that reads back-EMF and updates PID controllers and sets duty cycles, also running at 1Khz. Should this just be set up as a very high priority software task, or should I keep it as a hardware timer interrupt driven task?
Our system also uses SPI peripherals both with busy waiting (for single bytes) or through a hardware interrupt and user callback for DMA for block writes. Should I be using a gatekeeper task for each SPI channel, or just a mutex?
I know that's a lot, but if anyone could provide insight into how to address any of those system design issues, advice would be greatly appreciated. I am searching around for examples that use FreeRTOS for similar applications, but haven't quite found something I can draw from just yet.
For example, there is an IMU reading task @ 1khz
If it is running at that frequency consider running it as an ISR rather than an RTOS task, otherwise the RTOS is going to be constantly switching to that task and back. If taking the reading is fast and does not block then you could place it in the tick hook function if the RTOS tick is running at 1KHz. Likewise the task that reads the back EMF. I have seen this sort of thing done from interrupt triggered from ADC readings. If you are using a CPU that has a full interrupt nesting model then you can run these interrupts at a priority that is guaranteed not to be masked by the activity of the kernel - and so ensure high temporal accuracy (often important in motor control).
Should I be using a gatekeeper task for each SPI channel, or just a mutex?
It depends on how many tasks are using the SPI. If it is just a single task, then you need not use either. If you are using it from multiple tasks then the start with the easiest option, which would be a mutex. If that turns out not to be a good solution you can then try other options. The mutex can be obtained when the SPI is accessed, then given back when the poll is complete (for single bytes) or by the DMA end interrupt (for multiple bytes). You can use the drivers described in this document as an example.