I have always worked on non real-time systems, i.e. when the reaction of the system to an event should occur in a reasonable time. For example, when the user presses a button, a motor should start rotating. If the motor starts after 100us or 100ms is not so important.
I never used RTOS, so the architecture of my firmware is based on "superloop technique" (background tasks running in the loop and interrupts).
while(1) { task1(); task2(); ... }
All the tasks don't block, ever. As a rule of thumb, I accept a block time of maximum 100us-1ms. When the task needs to block for a greater amount, I try to implement it as a state-machine, avoiding blocking.
The ISRs are very lightweight: they only set/get some flags or push/pop a byte to/from FIFO queues. With 32-bits MCUs (modern Cortex-M MCUs), I can change 32-bits variables (mainly the ticks of the system) in ISRs without caring of race-conditions that could occur on 8-bits MCUS when the background tasks access the same variables.
In the past I used this architecture with success even in medium-complex systems featuring Ethernet, lwip, mbedTLS, USB and touchscreen (emWin).
Sincerely I think this architecture is good enough for all non real-time systems, so I don't understand why to use a RTOS in those cases. However I need to use a RTOS (FreeRTOS) for the next project, because it is one of the requirement. It isn't a real-time system, but the RTOS is required.
I think I can convert my architecture to RTOS by creating a task for each of the function I call in the superloop and starting the OS scheduler. However now the task function can't return, so I can write it in the following way:
void task1_main(void) { while(1) { task1(); } }
task1() can be the *same* function of the superloop architecture.
I can assign each task the same priority: in this case, FreeRTOS will use round-robin scheduling, giving all the tasks the same opportunity to run.
Is it correct?