Author Topic: FreeRTOS - pre-emptive or not?  (Read 4490 times)

0 Members and 1 Guest are viewing this topic.

Offline peter-h

  • Super Contributor
  • ***
  • Posts: 1277
  • Country: gb
  • Doing electronics since the 1960s...
FreeRTOS - pre-emptive or not?
« on: October 08, 2021, 03:38:31 pm »
I've been writing a lot of code for this for last 10 months. All working fine. I use the base priority (zero) for all threads, and always yield to RTOS with osDelay(1) when hanging around. It all works great.

Someone else working on another specific part of the project (replacing the buggy as hell STM-supplied PolarSSL with MbedTLS) has spent a lot of time trying to make that work also (again, buggy as hell and as usual loads of posts all over the place from frustrated coders trying to make it work - this seems to be a pattern with most STM libs and especially SSL stuff) and it appears that this code relies on some threads having a higher priority than others, otherwise the thing just hangs. Is this a weird way to write software? If one thread is generating data and another is consuming it, should they not be same priority but using some appropriate mechanism to communicate? I struggle to think of a scenario where different priorities are the only option, and there is a price to pay because the more levels you define the more RAM it uses.

I am not totally new to this. I wrote my own simple RTOS, in assembler, for Z180 and Z280, yonks ago, and it was absolutely solid and was used in loads of fair volume comms products. It facilitated easy development of complicated protocol converters. But I never implemented priority, because all critical stuff was running off interrupts, and if all the code is written properly and yields when hanging around, everything will still run. And comms products should have buffers on I/O which are interrupt driven. Of course I see that sometimes you want different priorities but often this is not needed, and could be "dangerous" because some tasks may never run at all.

So I bought that book on FreeRTOS recommended here recently and been reading through it. It looks like this RTOS does time-slicing so even a hanging thread gets chopped eventually (not sure where the time delay is configured) but only by a same or higher priority thread.

This is the config

Code: [Select]
#define configUSE_PREEMPTION                     1
#define configSUPPORT_STATIC_ALLOCATION          1
#define configSUPPORT_DYNAMIC_ALLOCATION         1
#define configUSE_IDLE_HOOK                      0
#define configUSE_TICK_HOOK                      0
#define configCPU_CLOCK_HZ                       ( SystemCoreClock )
#define configTICK_RATE_HZ                       ((TickType_t)1000)
#define configMAX_PRIORITIES                     ( 56 )
#define configMINIMAL_STACK_SIZE                 ((uint16_t)512)
#define configTOTAL_HEAP_SIZE                    ((size_t)48*1024)
#define configMAX_TASK_NAME_LEN                  ( 16 )
#define configUSE_TRACE_FACILITY                 1
#define configUSE_16_BIT_TICKS                   0
#define configUSE_MUTEXES                        1
#define configQUEUE_REGISTRY_SIZE                8
#define configUSE_RECURSIVE_MUTEXES              1
#define configUSE_COUNTING_SEMAPHORES            1
#define configUSE_PORT_OPTIMISED_TASK_SELECTION  0
#define configUSE_TRACE_FACILITY 1
#define configUSE_STATS_FORMATTING_FUNCTIONS 1
#define configAPPLICATION_ALLOCATED_HEAP 1 // to use external RTOS buffer


/* Co-routine definitions. */
#define configUSE_CO_ROUTINES                    0
#define configMAX_CO_ROUTINE_PRIORITIES          ( 2 )

/* Software timer definitions. */
#define configUSE_TIMERS                         1
#define configTIMER_TASK_PRIORITY                ( 2 )
#define configTIMER_QUEUE_LENGTH                 10
#define configTIMER_TASK_STACK_DEPTH             256

/* Set the following definitions to 1 to include the API function, or zero
to exclude the API function. */
#define INCLUDE_vTaskPrioritySet            1
#define INCLUDE_uxTaskPriorityGet           1
#define INCLUDE_vTaskDelete                 1
#define INCLUDE_vTaskCleanUpResources       0
#define INCLUDE_vTaskSuspend                1
#define INCLUDE_vTaskDelayUntil             1
#define INCLUDE_vTaskDelay                  1
#define INCLUDE_xTaskGetSchedulerState      1
#define INCLUDE_xTimerPendFunctionCall      1
#define INCLUDE_xQueueGetMutexHolder        1
#define INCLUDE_uxTaskGetStackHighWaterMark 1
#define INCLUDE_eTaskGetState               1
« Last Edit: October 08, 2021, 03:40:53 pm by peter-h »
Z80 Z180 Z280 Z8 S8 8031 8051 H8/300 H8/500 90S1200 32F417
 

Offline capt bullshot

  • Super Contributor
  • ***
  • Posts: 2682
  • Country: de
    • Mostly useless stuff, but nice to have: wunderkis.de
Re: FreeRTOS - pre-emptive or not?
« Reply #1 on: October 08, 2021, 04:07:43 pm »
Looks like we've got some experiences in common, since I've written my own simple (cooperative) embedded OS too, and used it in some commercial products, too.

The way you've done it (yielding to the OS if you've got nothing to do) is the way this just works fine without priorities. With preemptive tasking and priorities, something more flexible and more complicated and more prone to failures (due to the complexity and required knowledge) rose. It also works, if things are done right, but IMO there's more ways to do things wrong with priorities and preemptive tasking.

And yes, tasks don't have to yield to the OS at all if they're idle as they can be preempted by same or higher priority tasks. Anyway, I wouldn't recommend to do so (to not yield)  as it'll always fully load the CPU and have other negative side effects (most important: other tasks could have more time). So yielding and using proper OS supplied inter-task communication (like queues, semaphores, ...) as these will yield implicitely is the correct way to use any RTOS.
Safety devices hinder evolution
 

Offline SiliconWizard

  • Super Contributor
  • ***
  • Posts: 8255
  • Country: fr
Re: FreeRTOS - pre-emptive or not?
« Reply #2 on: October 08, 2021, 05:06:53 pm »
Not sure what your question is here, if there is any. FreeRTOS sure is preemptive.

Now properly using priority with preemptive scheduling isn't trivial, but as far as I've seen, it's not specific to FreeRTOS. The latter implements pretty basic priority-based scheduling.
 

Offline peter-h

  • Super Contributor
  • ***
  • Posts: 1277
  • Country: gb
  • Doing electronics since the 1960s...
Re: FreeRTOS - pre-emptive or not?
« Reply #3 on: October 08, 2021, 07:26:21 pm »
A few questions in my post e.g.

- why is pre-emption by lower-priority threads inhibited (and not configurable afaik)
- what is the time slice interval for threads which don't yield
- is it smart to make use of priorities to get code work at all, and likely scenarios where somebody would do that (it seems to produce impenetrable software)

I know reams have been written on multiuser etc OSs over decades (I remember debates re Windows gradually moving to pre-emptive; it wasn't in 3.1 afaik) but this is more specific.
Z80 Z180 Z280 Z8 S8 8031 8051 H8/300 H8/500 90S1200 32F417
 

Offline capt bullshot

  • Super Contributor
  • ***
  • Posts: 2682
  • Country: de
    • Mostly useless stuff, but nice to have: wunderkis.de
Re: FreeRTOS - pre-emptive or not?
« Reply #4 on: October 08, 2021, 08:31:10 pm »
- why is pre-emption by lower-priority threads inhibited (and not configurable afaik)
This is the whole point of assigning priorities to threads. Higher priority tasks cannot be preempted by lower priority tasks. Or the other way round: A higher priority task gets executed as soon as it is required and while it is running, all lower priority tasks must wait.

Quote
- what is the time slice interval for threads which don't yield
Depends on the configuration, could be e.g. 1ms. Often generated from a ticker interrupt. With each ticker interrupt the scheduler gets invoked and gives control to another task, depending on priorities. Within the same priority, tasks are scheduled round robin. There are tickless variants of RTOSes, too. These usually calculate the next task switch from all pending tasks and priorities and dynamically program a timer for that next scheduling event.
Code: [Select]
configTICK_RATE_HZ                       ((TickType_t)1000)

Quote
- is it smart to make use of priorities to get code work at all, and likely scenarios where somebody would do that (it seems to produce impenetrable software)
No (IMHO). Any task that has to wait for something should yield, either by sleeping or waiting for an event.
You could have a task that does some independent computation all the time, but isn't critical in terms of how long it takes to calculate whatever. This task would never finish or yield at all. You'd assign this task a low priority, so other higher priority tasks that e.g. have to do some data shuffling on I/O events can execute when they're needed. These tasks would wake up on some event and go to sleep or wait for an event when their job is done.
A common example of priorities would be the idle task: It has the lowest priority at all and only gets executed when all other tasks are waiting for something.


« Last Edit: October 08, 2021, 08:35:01 pm by capt bullshot »
Safety devices hinder evolution
 
The following users thanked this post: peter-h

Online westfw

  • Super Contributor
  • ***
  • Posts: 3601
  • Country: us
Re: FreeRTOS - pre-emptive or not?
« Reply #5 on: October 08, 2021, 09:24:12 pm »
Quote
FreeRTOS sure is preemptive.
Only if it's configured that way?
https://www.freertos.org/a00110.html#configUSE_PREEMPTION
Hmm.  Also:
Quote
By default (if configUSE_TIME_SLICING is not defined, or if configUSE_TIME_SLICING is defined as 1) FreeRTOS uses prioritised preemptive scheduling with time slicing. That means the RTOS scheduler will always run the highest priority task that is in the Ready state, and will switch between tasks of equal priority on every RTOS tick interrupt.  If configUSE_TIME_SLICING is set to 0 then the RTOS scheduler will still run the highest priority task that is in the Ready state, but will not switch between tasks of equal priority just because a tick interrupt has occurred.
« Last Edit: October 08, 2021, 09:26:21 pm by westfw »
 
The following users thanked this post: peter-h, newbrain

Offline peter-h

  • Super Contributor
  • ***
  • Posts: 1277
  • Country: gb
  • Doing electronics since the 1960s...
Re: FreeRTOS - pre-emptive or not?
« Reply #6 on: October 09, 2021, 07:55:04 am »
"Depends on the configuration, could be e.g. 1ms."

I think yes, it is this. The tick is 1ms and I see no separate config item for slicing hanging threads after some different time period, say 100ms.
Z80 Z180 Z280 Z8 S8 8031 8051 H8/300 H8/500 90S1200 32F417
 

Offline mikerj

  • Super Contributor
  • ***
  • Posts: 2837
  • Country: gb
Re: FreeRTOS - pre-emptive or not?
« Reply #7 on: October 09, 2021, 09:24:47 am »
"Depends on the configuration, could be e.g. 1ms."

I think yes, it is this. The tick is 1ms and I see no separate config item for slicing hanging threads after some different time period, say 100ms.

If you want the thread to be suspended for some longer period then the task itself must handle this, e.g. though a call to vTaskDelay, vTaskDelayUntil or xTaskDelayUntil which will suspend the task for an integer number of system ticks.  Then you have task notifications, mutexes/semaphores and queues that can be used to suspend a task and have it woken up by another task or some other event such as an interrupt.

Once you get your head around the fundamental concepts of a preemptive RTOS it will make sense.

why is pre-emption by lower-priority threads inhibited (and not configurable afaik)

What would be the point of task priorities if this were allowed to occur?
 
The following users thanked this post: peter-h, newbrain, Jacon, SiliconWizard

Offline newbrain

  • Super Contributor
  • ***
  • Posts: 1265
  • Country: se
Re: FreeRTOS - pre-emptive or not?
« Reply #8 on: October 09, 2021, 12:14:56 pm »
why is pre-emption by lower-priority threads inhibited (and not configurable afaik)

What would be the point of task priorities if this were allowed to occur?
There are cases where this is done, and for good reasons, namely: priority inheritance for mutexes to avoid priority inversion.

This is when a high priority task is waiting on a mutex held by a low priority task - which has no chance to run as there are other higher priority tasks able to run.

The mutex holding low prio task will be raised to the priority of the waiting task, interrupting the formerly-higher-but-now-lower prio tasks that were holding it from running.
(hope it's clear...)

I use the base priority (zero) for all threads, and always yield to RTOS with osDelay(1) when hanging around. It all works great.
This is a bit funny.
Priorities are a very effective way to make sure tasks run when they are supposed to.
Having them all the same might work in some cases, here, though, you have to resort to explicit yielding: IMHO this means a more rational distribution of priorities might help.
What I find even more strange is the use of a delay: if you mean yield, use yield: taskYELD(), why introduce a delay - unless this is the only chance some other tasks have to run, further corroborating my suspicion above.

Till now, I have only used preemption without slicing, and some priorities.
As an example, I have this project where a task takes care of receiving, processing and sending out buffers on a I2S interface, others handle user input (buttons and encoder scanning) and output (update a display) plus stuff that takes long to run and has lower priority (creating and displaying an FFT, showing some statistics).
The priorities are in the order above: I want to make sure that as soon as the DMA finishes filling an input buffer, this is read, processed and sent out. User input and output can be processed in the time left so it has a lower priority. The FFT and stat display runs if we are neither handling user input/output or processing the input signal.
No yields, very few delays used in the various loop code.
Nandemo wa shiranai wa yo, shitteru koto dake.
 

Offline SiliconWizard

  • Super Contributor
  • ***
  • Posts: 8255
  • Country: fr
Re: FreeRTOS - pre-emptive or not?
« Reply #9 on: October 09, 2021, 05:11:14 pm »
Note that there are various ways of doing preemption. A scheduler can be "tickless", for instance. I think there's a way to go tickless with FreeRTOS, IIRC.

As to priorities, of course higher-priority tasks have to "yield" execution at some point to allow execution of lower-priority ones. That's the whole point, as said above.

There are various ways of doing this. Making a task "sleep" is one of them. Or making it wait on some event. Of course through the use of proper functions from the OS - simple busy loops would just allow preemption by same-priority tasks.
 

Offline peter-h

  • Super Contributor
  • ***
  • Posts: 1277
  • Country: gb
  • Doing electronics since the 1960s...
Re: FreeRTOS - pre-emptive or not?
« Reply #10 on: October 09, 2021, 05:54:17 pm »
"What I find even more strange is the use of a delay: if you mean yield, use yield: taskYELD()"

Isn't osDelay(1) equivalent to taskYIELD() if the tick is 1kHz? If you call taskYIELD() will the RTOS ever come back to this task before the next 1ms tick? I can see it could be coded to do that (if say every other task has suspended itself for say 10ms) but...
Z80 Z180 Z280 Z8 S8 8031 8051 H8/300 H8/500 90S1200 32F417
 

Offline newbrain

  • Super Contributor
  • ***
  • Posts: 1265
  • Country: se
Re: FreeRTOS - pre-emptive or not?
« Reply #11 on: October 09, 2021, 06:51:19 pm »
Isn't osDelay(1) equivalent to taskYIELD() if the tick is 1kHz?
Not at all. Read the description for taskYIELD I linked: it can return immediately, if the calling task is the one who should run (due to priority or other task being being blocked on queues/mutexes/semaphores/events).
It would be a strange RTOS if the only way to yield would waste at least one tick!

I think there's a way to go tickless with FreeRTOS, IIRC.
Unless one is using slicing the kernel can be considered tickless: scheduling does not happen at ticks unless, of course, explicitly using timers or, as in peter-h case, delays.
In case of slicing, and for tasks at the same priority, I'm not sure of the scheduling algorithm: round robin? It might be configurable, even.
Nandemo wa shiranai wa yo, shitteru koto dake.
 
The following users thanked this post: peter-h

Offline SiliconWizard

  • Super Contributor
  • ***
  • Posts: 8255
  • Country: fr
Re: FreeRTOS - pre-emptive or not?
« Reply #12 on: October 09, 2021, 07:26:43 pm »
Isn't osDelay(1) equivalent to taskYIELD() if the tick is 1kHz?
Not at all. Read the description for taskYIELD I linked: it can return immediately, if the calling task is the one who should run (due to priority or other task being being blocked on queues/mutexes/semaphores/events).
It would be a strange RTOS if the only way to yield would waste at least one tick!

Besides, delaying doesn't just yield - it's supposed to act as a delay. That means the task calling a delay function will not be rescheduled until the delay has expired, making the task effectively "inactive" during at least that much time.
 
The following users thanked this post: peter-h

Offline peter-h

  • Super Contributor
  • ***
  • Posts: 1277
  • Country: gb
  • Doing electronics since the 1960s...
Re: FreeRTOS - pre-emptive or not?
« Reply #13 on: October 09, 2021, 08:26:00 pm »
Well I learnt something really useful :)

Replacing osDelay(1) with taskYIELD() has not seemingly broken anything but has much improved some strange timing issues I was seeing, which I worked around...

I can also see one could write a "tick-less RTOS" but surely without the RTOS having a concept of time it won't know how much time to give to a task before it chops it, so the only option it would have (if say you have 10 tasks of same priority, each not yielding at all but just running some useful code) would be to execute just one instruction of each task before switching, which would be silly because then the RTOS would be spending say 99.9% of the CPU time running the RTOS. Well, unless the RTOS was somehow counting instructions (executed of each task) or counting CPU clocks (using that 168MHz clock counter we discussed) but then it isn't tick-less; you merely replaced the 1kHz tick with something more crude.
Z80 Z180 Z280 Z8 S8 8031 8051 H8/300 H8/500 90S1200 32F417
 

Online westfw

  • Super Contributor
  • ***
  • Posts: 3601
  • Country: us
Re: FreeRTOS - pre-emptive or not?
« Reply #14 on: October 09, 2021, 10:59:45 pm »
Quote
I have only used preemption without slicing, and some priorities.
I don't think I understand preemption without "slicing"?  Surely if you have several compute-bound tasks at the same priority, you want them ALL to run, don't you?  Probably round-robin?

Quote
it won't know how much time to give to a task before it chops it
Most RTOS stuff is NOT about sharing the CPU between compute-bound tasks.  It's about having "idle" tasks respond quickly ("in real time") to events that cause the task to have something it needs to do.   "tickless" schedulers are used (and important) in very low-power systems, because the permit the CPU to go into low-power sleep modes when there is nothing that needs to be done, instead of continuously running the scheduler loop.


Quote
The tick is 1ms and I see no separate config item for slicing hanging threads after some different time period, say 100ms.
Why would you use a 1ms tick if you wanted some tasks to run for 100ms?

Individual tasks determining their own runtime and then manually yield/suspend/sleeping is pretty much the definition of a cooperative scheduler, rather than preemption.

 

Offline SiliconWizard

  • Super Contributor
  • ***
  • Posts: 8255
  • Country: fr
Re: FreeRTOS - pre-emptive or not?
« Reply #15 on: October 09, 2021, 11:37:10 pm »
Yeah, I don't get the part about "without slicing" either. Strictly speaking, any kind of multitasking program uses "slicing" in one way or another, even if it's not preemptively scheduled. Slicing is just about distributing CPU time, however it's done.

As to tickless scheduling - there isn't a single definition of this. It covers a range of approaches. The common idea is that the scheduler doesn't preempt on a fixed time period (a 'tick'), but that's about it. So, the scheduler can preempt on a variable (dynamic) period depending on the state of tasks. Yes it allows to get lower power (no needless wake-up of CPU when no task needs to be running, while a typical 'ticked' scheduler would wake up the CPU every tick, even when all tasks are inactive, and then would check if one is ready to run...), but it also allows lower latency, as preemption could happen - theoretically - at any time, instead of just on the 'tick'.

Downside is, it's more complex to implement and to get right. I think the 'tickless' approach used by FreeRTOS is relatively basic and mainly used for lowering power consumption.

 

Offline newbrain

  • Super Contributor
  • ***
  • Posts: 1265
  • Country: se
Re: FreeRTOS - pre-emptive or not?
« Reply #16 on: October 10, 2021, 04:40:42 am »
Quote
I have only used preemption without slicing, and some priorities.
I don't think I understand preemption without "slicing"?  Surely if you have several compute-bound tasks at the same priority, you want them ALL to run, don't you?  Probably round-robin?
[snip]
Most RTOS stuff is NOT about sharing the CPU between compute-bound tasks.  It's about having "idle" tasks respond quickly ("in real time") to events that cause the task to have something it needs to do.
Well, I guess you have answered your question yourself!

In my case, the real time, quick responding tasks, are IO bound (processing must still be faster than data coming in and going out, if I need to keep the I2S happy).
User input is polled at a suitable rate and at lower priority. FFT plus display take what's left (aiming for 20 frames/s) and is the only task to be (depending on the load) CPU bound.

Time slicing is not needed, the tasks are run when they can be unblocked, e.g. there's something in an input queue, or they get a notification.
Preemption means that if a higher priority task gets ready to run while a lower priority one is running, the latter is suspended and the former gets the CPU, e.g. if in the middle of an FFT the I2S DMA completion interrupt arrives the FFT is suspended while the input frame is processed and passed to the output DMA.
This works very well, while handling an I2S codec, three I2C peripherals, and an SPI for the display.
Nandemo wa shiranai wa yo, shitteru koto dake.
 

Offline peter-h

  • Super Contributor
  • ***
  • Posts: 1277
  • Country: gb
  • Doing electronics since the 1960s...
Re: FreeRTOS - pre-emptive or not?
« Reply #17 on: October 10, 2021, 07:39:31 am »
The idea of the RTOS running a task when there is some input to process is something I have not tried yet. I just poll the RX queue and if there is nothing there (or not enough bytes to form a usable message) then I yield right away. But I can see this increases power consumption.

How would you config the RTOS to run a task when there is say > 5 bytes in an RX queue? Something must be checking that RX queue, whether it is your task or some code in the RTOS. Presumably the right way is to hook up the RX interrupt and when rx count reaches 5, you make a call to the RTOS to schedule the data processing task to run?

But unless you are putting the CPU into a low power mode most of the time, the power benefit must be minimal.
Z80 Z180 Z280 Z8 S8 8031 8051 H8/300 H8/500 90S1200 32F417
 

Online westfw

  • Super Contributor
  • ***
  • Posts: 3601
  • Country: us
Re: FreeRTOS - pre-emptive or not?
« Reply #18 on: October 10, 2021, 08:12:29 am »
Quote
resumably the right way is to hook up the RX interrupt and when rx count reaches 5, you make a call to the RTOS to schedule the data processing task to run?
Yep.  Note that the "RTOS call" can be as simple as putting the task on a "runnable" queue.

There is an interesting method I've seen, where the task provides a "scheduler test" (a pointer to a function.)  To see if a task is runable, the scheduler calls the scheduler test function - since this is done from the scheduler context, it is much lower overhead than waking the task up all the way to do its own check, allows relatively complex decision making, and it doesn't require that you make all the ISRs scheduler-aware.  OTOH, it has higher overhead than making the ISRs scheduler-aware, might result in security issues, and certainly allows tasks to do stupid things (mainly, to provide "expensive" tests.  They need to be short, rather like ISRs.)
 

Offline peter-h

  • Super Contributor
  • ***
  • Posts: 1277
  • Country: gb
  • Doing electronics since the 1960s...
Re: FreeRTOS - pre-emptive or not?
« Reply #19 on: October 10, 2021, 09:47:50 am »
There seem to be two ways to use an RTOS: the simple way and the elegant way.

The simple way is to write the task like you would write it if nothing else was running on that CPU (except ISRs), and with an RTOS you can have a whole load of such tasks all co-existing happily. Even if they don't yield.

The other way is to get ISRs to trigger RTOS tasks to run, etc.

But unless you are putting the CPU to sleep most of the time, I don't think there will be a difference to power consumption, and operationally it is the same if the I/O is buffered (e.g. typical serial comms).

« Last Edit: October 10, 2021, 01:18:50 pm by peter-h »
Z80 Z180 Z280 Z8 S8 8031 8051 H8/300 H8/500 90S1200 32F417
 

Offline rstofer

  • Super Contributor
  • ***
  • Posts: 8815
  • Country: us
Re: FreeRTOS - pre-emptive or not?
« Reply #20 on: October 10, 2021, 03:41:52 pm »
There seem to be two ways to use an RTOS: the simple way and the elegant way.

The simple way is to write the task like you would write it if nothing else was running on that CPU (except ISRs), and with an RTOS you can have a whole load of such tasks all co-existing happily. Even if they don't yield.

Each task can be coded without interaction with other tasks other than through FreeRTOS structures like semaphores.  This modularization is worthwhile even if the RTOS bit doesn't matter.  The 'super loop' can degenerate to simply

while(1) {
}

rather than the massive loop typical of Arduino code in the loop() function.

We don't test that a button has been pressed, we test whether the 'button-pressed' ISR has set a semaphore.  A very clean interface!
 
The following users thanked this post: newbrain

Online nctnico

  • Super Contributor
  • ***
  • Posts: 22004
  • Country: nl
    • NCT Developments
Re: FreeRTOS - pre-emptive or not?
« Reply #21 on: October 10, 2021, 03:56:03 pm »
We don't test that a button has been pressed, we test whether the 'button-pressed' ISR has set a semaphore.  A very clean interface!
That is a pretty bad example. You really don't want buttons to be connected to a hardware interrupt line if you want to keep your sanity * (unless you do filtering & debouncing in hardware). Lots of things can go wrong resulting in unpredictable CPU loads. So either you have filtering & debouncing in hardware or software. The latter requires having a process that deals with the buttons. Ofcourse that process can fire an event to a higher process to deal with the button presses.

* Over the years I have encountered several software engineers that learned this the hard way. At one of my former employers a particular product showed all kinds of mysterious behaviour and the (external) software engineer wasn't really able to fix it. At some point we hooked some hardware to the inputs which caused the logic levels to flip rapidly and low and behold: the device's responsiveness slowed down to a crawl and looking at the processes it turned out the system was busy serving interrupt requests from the inputs. My reaction was quite close to 'what kind of idiot connects a button input to an interrupt?'. The software engineer then said to me: but isn't that why input pins have interrupts?  :palm: :palm:
« Last Edit: October 10, 2021, 04:03:56 pm by nctnico »
There are small lies, big lies and then there is what is on the screen of your oscilloscope.
 

Offline ogden

  • Super Contributor
  • ***
  • Posts: 3654
  • Country: lv
Re: FreeRTOS - pre-emptive or not?
« Reply #22 on: October 10, 2021, 04:23:22 pm »
We don't test that a button has been pressed, we test whether the 'button-pressed' ISR has set a semaphore.  A very clean interface!
That is a pretty bad example. You really don't want buttons to be connected to a hardware interrupt line if you want to keep your sanity * (unless you do filtering & debouncing in hardware). Lots of things can go wrong resulting in unpredictable CPU loads. So either you have filtering & debouncing in hardware or software. The latter requires having a process that deals with the buttons. Ofcourse that process can fire an event to a higher process to deal with the button presses.

* Over the years I have encountered several software engineers that learned this the hard way. At one of my former employers a particular product showed all kinds of mysterious behaviour and the (external) software engineer wasn't really able to fix it. At some point we hooked some hardware to the inputs which caused the logic levels to flip rapidly and low and behold: the device's responsiveness slowed down to a crawl and looking at the processes it turned out the system was busy serving interrupt requests from the inputs. My reaction was quite close to 'what kind of idiot connects a button input to an interrupt?'. The software engineer then said to me: but isn't that why input pins have interrupts?  :palm: :palm:

Polling is good for most applications except one - low power. If button-cell powered electronics wristwatch would poll it's buttons like you suggest, it's battery won't last long. Problem is not hardware interrupts, but HOW you handle them and why. In said wristwatch example smart thing to do is use hardware ISR to trigger polling sequence for a while.
 

Offline peter-h

  • Super Contributor
  • ***
  • Posts: 1277
  • Country: gb
  • Doing electronics since the 1960s...
Re: FreeRTOS - pre-emptive or not?
« Reply #23 on: October 10, 2021, 04:31:16 pm »
"You really don't want buttons to be connected to a hardware interrupt line if you want to keep your sanity"

I was just going to type the same :)

There is an extra complication setting up an ISR for an input pin and making sure that every possible source of that interrupt gets cleared in the ISR, plus one has to debounce the pin (which complicates the ISR because you now have to do a state machine there to re-examine the pin after say 50ms, so have to involve a timer). It is much easier to test the pin directly in an RTOS task, with an osDelay(50) in the loop, and if the button is a 1 and was 1 50ms ago then it is pressed (etc). That keeps the CPU loading deterministic (under your control) and prevents noise on the pin hanging your system. That task will take only a few us every 50ms.

Another thing is this: the person writing all the code is you. So, while the result is "co-operative" and not "pre-emptive", it should work fine. One day I will have a play with getting ISRs to run tasks but so far I have not seen a need which would make any difference to performance. No doubt there are such cases though; probably where some event has to be serviced regularly (and you can't or don't want to do it in an ISR) while there is another task running which takes a lot of processing (e.g. updating a graphics display) but it doesn't matter if it gets hung up. I guess there is a lot of overlap between a) doing stuff in an ISR and b) doing the same stuff in an RTOS task with a high priority.

"Polling is good for most applications except one - low power. "

I have a product which uses an old AVR (90S1200) running mostly in sleep mode, and it gets woken up by a timer, every few ms, does about 100 instructions, and goes back to sleep.
« Last Edit: October 10, 2021, 04:33:20 pm by peter-h »
Z80 Z180 Z280 Z8 S8 8031 8051 H8/300 H8/500 90S1200 32F417
 

Offline Siwastaja

  • Super Contributor
  • ***
  • Posts: 4810
  • Country: fi
Re: FreeRTOS - pre-emptive or not?
« Reply #24 on: October 10, 2021, 04:43:09 pm »
Polling is good for most applications except one - low power. If button-cell powered electronics wristwatch would poll it's buttons like you suggest, it's battery won't last long.

Not necessarily - polling buttons every 50-100ms is enough for responsiveness, and given the code is not total bloat, checking for button state changes is some microseconds of execution time, resulting in negligible duty cycle and average current comparable to sleep mode leakages.

More problematic are some sensors which need to be dealt with at kHz rate, low enough not to justify CPU being active all the time, but high enough that duty cycle of waking up and related overhead is significant. Some IMUs for example solve this by offering internal FIFOs, allowing burst processing.

Polling buttons has the upside that the very necessary debouncing comes for almost free with little overhead. For example, poll every 50ms in pure timer ISR and require two successive active readings to react. One ISR handles all buttons and button-like signals.
« Last Edit: October 10, 2021, 04:46:52 pm by Siwastaja »
 
The following users thanked this post: nctnico


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf