This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Schedular vs RTOS vs Blocking, need scheduler clarification.

EDITTED-

I have a project coming up that uses:

  • BLE Softdevice, a fair amount of GATT data
  • SPIM with a fairly high data rate, slave has a RDYN (data ready now) IO to the rnf52
  • UART
  • some application subfunctions that need to run every 1-5ms
  • a main application that will be immensely easier to code if I can hang out in it's loop for seconds at a time

I'm trying to balance a superloop state machine with a way to easily code the main application. Ideas include SWI, PPI to trigger SPIM with DMA, and Scheduler. I'm having a comprehension issue with the scheduler.

For example:

void SomeSWI_orOtherISR() {
<call scheduler_put for subfunction1>
}

void subfunction1 () {
<toggle LED>
}


<main application code>
do {
  Scheduler_execute();
while(1SecondHasntPassedYet);
<rest of main code>
  1. So this must preempt other main application tasks right? If I'm at that 1 Second Delay in the main context, and the SWI/Timer/OtherISR triggers and puts a scheduler task, does that fire up my subfunction1 right now in the main context, and when done return me to my delay(1Second) where I left off?

  2. Scheduler has arguments for size. What does the size of event mean? Is this in reference to the size on the stack that will need to be pushed/popped in order to shift the context? How do I determine size like that? What if subfunction1 in my example had a 5kB array it uses, is the size of that event over 5k large then?

  3. When using the scheduler like this (if I have the idea right) does my main code need to be an element in scheduler as well? Or is it alright to just "schedule-ize" the tasks that will interrupt?

  4. I kinda get the idea I think - but what is the difference between scheduler and just writing my own ISR flags or polling flags in the main context?

  5. If I were to call scheduler_execute from an ISR... would it immediately start code from its que in the interior context? Or would it finish the current ISR code and then start new code in the main context?

If I'm understanding this correctly, it seems I have enough of an option to write "blocking" code without resorting to an RTOS. I have. Ask ally unlimited power, so I'm not terribly worried about issues there. I'm aware the timing of tasks will be a little off and this isn't for precision timing, but nothing I have requires that. How close am I to how this works?

Thank You!

  • Hi,

    1. Your main function will be running at the least priority look here. This means that the scheduler_execute is popping any functions at the lowest priority. All FreeRTOS tasks run as thread mode, so any ISR will pre-empt them. Any ISR will only put your subfunction1 into the scheduler. You sybfunction1 will only execute when your main function gets a chance to run (when all other ISR have exited) and pops your function from scheduler by scheduler_execute() as per your example.

    2. You subfunction1 might need some data to process and this data can be anything and of any size depending on the application requirement. I suggest you to read my most regarding the scheduler to understand its basic design and why we need to allocate this data and how here. Since we are pushing into scheduler from different ISR context and popping it in other thread like main or any other lower priority interrupt, we need to reserve this space before hand in the stack and Scheduler does this at the time of scheduler init.

    3. I did not quite understand what you mean by "main code need to be an element in scheduler". Scheduler is independent, it is not necessary that you have to use only main to pull the functions out of scheduler. I think the post i mentioned above will also answer this question. If not , let me know.

    4. The difference is in simplicity and the ability to pass arguments between contexts. Using a flag in ISR and waiting in main, you cannot pass a lot of arguments between these two contexts (unless you want to use unnecessary global space). The difference is also in the design in how generic it is designed to fit any application that want to postpone the execution of some function with data exchange between these contexts.

    5. It does not matter if you are calling it in main or any ISR, once the context within which the scheduler_execute is running, it will be synchronous execution and will pop the function (in your example subfuntion1) and execute it before exiting that ISR. (main cannot exit , so its a super loop)

    Yes, I also have suggested that if your application can be kept simple without the use of RTOS, then prefer not to use it and use the scheduler efficiently. May be this thread is interesting for you.

  • 1.) Ok, so if I did want to make things easier on myself and did want to delay(1Second) it would maybe be in my best interest to make sure that my delay function wasn't just a NOP loop for x cycles, but instead was a main context subloop that called SchedulerExecute. Is this even semi-legit or just a really hacky way to avoid re-entering the superloop when I really just want to stay at the current place in code for awhile?

    2/3/4). I think I understand.

    5.) Ok, so because execute will run from whatever context it's called from, it's almost always best to call it from the main context. Which is why in order for my delay example to work, my delay function would have to repetitively be calling sched_execute.

    1. avoid using delays using busy wait by executing NOP, use timers instead.
    2. correct
Related