I am converting an application that has been developed bare metal, and now would benefit from running with FreeRTOS. The code size is about 200K:
I have successfully ported FreeRTOS to the EFM32 environment under IAR. And I can run with some dummy tasks under FreeRTOS.
Next step is to convert the application to run under FreeRTOS: I have mapped each called- execution-thread in the legacy top level executive to a FreeRTOS Task :
ulTaskNotifyTake() … //wait for vTaskNotifyGiveFromISR
FunctionfromLegacyCode() … // Call the execution thread, using LegacyFunction in the
// executive loop
Each execution thread in the executive loop had a “priority” because of the polled sequence of the executive loop. I have given the new corresponding FreeRTOS task the same priority.
The executive loop execution threads (and the new RTOS tasks) pend on flag being set in an ISR. Thus the execution threads (and the RTOS tasks) do not execute, till the appropriate interrupt has set the flag in an ISR (and the RTOS task gets a vTaskNotifyGivefromISR).
Once the application is running reliably under FreeRTOS, I start taking advantage of the FreeRTOS features such as blocking on DMA completion, if the thread fired off a DMA read/write.
I am getting a lot of pushback from the present team (who have never converted a bare-metal to FreeRTOS application). I have used this approach before twice with FreeRTOS.
I am asking the community as well as the technical staff, to advise if I am missing some important step… I am pretty sure doing this conversion will have no problem from the FreeRTOS point of view (maybe I am wrong?)
One thing I didn’t hear you say is to protect access to shared resources, especially memory. Shared memory issues/races can be hard to find. Hopefully, the ‘tasks’ were fairly isolated, so not a big issue.
That would be one of the first things to take advantage of, once the application is running under FreeRTOS. The two things I would implement:
- Use mutexes to protect shared resources between tasks
- Block tasks when accessing slow peripherals (DMA, serial port, etc) and pend on the interrupt that will signal completion of operation and then become ready to run.
Also your approach to pend on (task) notifications signaled by ISR is the best (fastest and lean) way to go.
Thanks @hs2 !
If you and other community and staff members could share, if they have taken this approach successfully, then these written comments would help me in showing the team here that this is not a silly idea, but actually FreeRTOS is designed to successfully take this approach.
(The approach I am referring to is to take the existing running application, convert the call to its polled execution threads into FreeRTOS tasks, and just adding FreeRTOS mechanisms for fast pre-emptive context switching (TaskNotifyTake), shared memory protection (Mutexes), blocking execution threads on peripheral access (semaphores/TaskNotify) and many others; WITHOUT HAVING TO REWRITE THE APPLICATION FROM SCRATCH UNDER FreeRTOS).
I’ve done something similar. I’ve taken a monolithic ‘big loop’ stand-alone program and converted it incrementally to run with FreeRTOS. First, we moved it ‘as is’ to FreeRTOS, with the whole loop running as a priority 0 task, and got that working. This gave a crude baseline that basically worked as before. Then we made small incremental changes pulling out a routine here, and making it its own task, switching device drivers to use interrupt based ones vs polling loops, and slowly migrated it to a reasonably properly done RT program. This was before the direct-to-task system was in place, so ISRs would signal tasks with semaphores, which are slightly less efficient, but not bad. I think we spent a year or so on it, but that was partially it was back burner, as we nearly always had a ‘working’ version and we were just getting improvements to performance.
In the end, large parts got re-written as we worked on taking advantage of new capabilities, but it did come at the cost you would think of as a total rewrite.