2

I am starting a project which uses LittleVGL as its GUI library.

I'm using an STM32H743, running at 480MHz. (It's rather over-powered, but only $1/15% more expensive than something half as fast with less RAM and flash, which would itself need external flash at additional cost.)

The worst case screen draw is 10ms. This will get considerably better when I implement LittleVGL's blitting and filling hooks with ChromART/DMA2D.

None of the board's non-GUI operations would suffer if delayed by up to 20ms.

If the screen drawing was slower, and needed to be interrupted by a more urgent operation, the need for an RTOS would be obvious.

Are there reasons to use an RTOS, rather than a single infinite loop, when all operations are quicker than the deadline of the most urgent?

(I am not familiar with FreeRTOS, and, most importantly, have no experience of debugging a FreeRTOS project.)

fadedbee
  • 42,671
  • 44
  • 178
  • 308
  • 1
    If I don't need more features from the RTOS than to simplify interrupt handling and/or preemptive and/or cooperative multitasking, I would not use one, to save the time to learn its usage. However, there are always reasons to decide this way or the other. – the busybee Mar 12 '20 at 11:01
  • 1
    Thanks, how does an RTOS simplify interrupt handling? – fadedbee Mar 12 '20 at 11:08
  • 3
    It's mostly a matter of how many tasks you need to execute simultaneously. Eventually it comes to a point where you are basically implementing scheduler-like functionality etc yourself, re-inventing the wheel instead of using a RTOS. But if you don't need that, it just adds needless complexity. – Lundin Mar 12 '20 at 11:45
  • 4
    Clear functional partitioning, responsiveness to real-time events and reusability in future projects that may require an RTOS are clear benefits, but the question is a matter of opinion. It is not possible to be specific about the benefits without details of your application - you say nothing about input methods for example or the real-time requirements of the application for which this is a GUI. Projects have a habit of becoming complex, and an RTOS can in many cases reduce that complexity. If you have a GUI worthy of the name, it is already complex. – Clifford Mar 12 '20 at 12:09
  • 1
    I don't use an RTOS in my projects, but that does not mean that I don't have a run-time executive. You need to consider how data management and execution sequencing are to happen. In my case, the execution model is based on event dispatch to interacting state machines. It is not an RTOS by the traditional definition in that it is single threaded and provides no concept of a processor context or preemptive tasks. However, it is much more than an ad hoc infinite loop calling who knows what. The choices and trade-offs are more complex than that and always involve some learning curve. – andy mango Mar 12 '20 at 20:01
  • @andymango - This strikes a chord. I expect the infinite loop to have several operations - the most urgent will be at the top of the loop body. They will execute if needed, then `continue` to the top of the loop. Screen rendering will be near the end of the loop and only happen when there is nothing more urgent to do (which will be 99.999% of the time). An RTOS makes this sort of prioritisation explicit, but more complex to debug. It sound like you have found a useful halfway house, using interacting state machines. Have you written more on this? – fadedbee Mar 13 '20 at 09:34
  • 1
    @fadedbee - This may be a case of be careful what you ask for. All my work is open and you can look [here](https://repos.modelrealization.com/cgi-bin/fossil/mrtools/doc/trunk/micca/doc/micca.pdf). Part V -- Runtime Support explains whats going on and includes the code. – andy mango Mar 13 '20 at 23:53
  • 1
    @fadedbee if you have to ask this question - do not use any RTOS. You are not ready. – 0___________ Apr 07 '20 at 12:04
  • 1
    @P__J__ Following that logic, how would anyone (except the arrogant) ever start using an RTOS? (In 20+ years of software development, I've always been required to teach myself everything I need - formal training is not an answer here.) – fadedbee Apr 07 '20 at 15:30
  • 1
    The answer is simple: At some point you start to understand why main loop way is not good, what threads are for and how convenient is to have IPC mechanisms provided by RTOS-es. It comes with more complicated projects. – 0___________ Apr 07 '20 at 15:36
  • 1
    @P__J__ Ah, yes. For embedded systems (and most server projects) I have always written event-driven code with no long running processes. This is my first embedded project with a GUI, and I've measured LittleVGL as blocking for up to 10ms to paint the framebuffer. There are probably good reasons why LittleVGL has not been written in an event-driven style, but not having written a GUI framework myself, I do not know what these are. – fadedbee Apr 07 '20 at 15:44
  • 1
    try to write simple uart to usb converter both ways and you will see the difference. – 0___________ Apr 07 '20 at 15:49
  • @P__J__ Thanks, I will give that a try as a first RTOS project. – fadedbee Apr 07 '20 at 15:58
  • @fadedbee - You mentioned that you are experienced in writing event-driven code. Then your step to using an RTOS is not far (you could/should have already started using RTOSes then!). Please feel encouraged to try it out! The problem about a non-event driven stack like your GUI framework at hand is a typical challenge, but not a show-stopper if you have noticed this issue already. You can focus part of your efforts on creating an event-driven wrapper to the GUI (a task loop with a few message connections etc.). The UART interface (in place of GUI) is a good intermediate to get RTOS running. – HelpingHand Apr 11 '20 at 17:03
  • @andymango - You are right that there are non-preemptive runtime systems that are designed to support event-driven software architectures. But, as a matter of fact, no other scheduling model fits event-driven tasks as well as a premptive (i.e. RTOS) scheduling. – HelpingHand May 01 '20 at 12:51
  • 1
    @thebusybee - I just saw your initial comment when to use RTOS. I disagree: *If I only need "features from the RTOS" other "than to simplify interrupt handling and/or preemptive and/or cooperative multitasking" then I will not use the RTOS any more.* The main big question to answer is whether you want to follow the preemptive model that is placed by both ISRs and RTOS scheduling - then you use an RTOS (kernel). I know that some RTOSes come with a hawker's tray of middleware features. => It is not that "the middleware also comes with an RTOS", but v.v. – HelpingHand May 01 '20 at 12:58
  • 1
    @HelpingHand - I'm not sure I would agree that it is a matter of fact that preemptive scheduling is the best fit for event-driven tasks. Preemptive scheduling in the RTOS sense puts you squarely in the realm of a multi-threaded, shared state situation. Those programs are difficult to get right. It is quite easy to end up with something that runs 99% of the time and fails oddly. I've written and debugged many of them. Preemption is another engineering tradeoff that needs careful consideration. Sadly, most folks, and my self included, just toss in a RTOS without much consideration. – andy mango May 02 '20 at 15:10
  • 1
    @andymango - You mentioned the important point: When changing to an RTOS, one *must* do it deliberately, not just toss it in (even if getting started the thorough way costs more efforts at the beginning, and it requires to gather some competences on how to program in "*the realm of a multithreaded [...] situation*": The point is that states shall not be shared, but managed. I have seen bad RTOS projects, too, which only worked 99% of the time - *because people only obeyed 99% of thread-safety rules*. The result was that *people* were spending like 99% of the time chasing sync bugs. – HelpingHand May 02 '20 at 15:40

1 Answers1

1

I start with picking the main question out of the question block:

Are there reasons to use an RTOS, rather than a single infinite loop, when all operations are quicker than the deadline of the most urgent?

Yes, there are. Most important of all: An RTOS is a means to partition a complex software into pieces that are easy (or even trivial!) to maintain. This partitioning considers the time a CPU spends on the present piece of software. You can apply it trivially whenever your software does several unrelated things on the same CPU/controller. I'd like to compare this to splitting up a big monolithic source code into small modules and functions that take care of a small fraction of the memory and program code. In contrast, each RTOS task takes care of one thing to be done by the controller firmware.

This was the trivial part of the reason, and I took the freedom to answer a bit imprecise to highlight the main point. Now for the less-trivial reasons:

Using an RTOS, you can also split parts of the software that do not run independently but represent different stages of processing from input data (measurements) to output data (set values). On a realistic embedded system, you often have to take care of so many requirements that implementing all in a single main loop would end up (or crash along the way) in some program code that you can write down once, but which you can hardly maintain (by fixing smaller and bigger bugs, by extending the software to some new ideas and requirments) if you return to the code more than a week later.

For me, the main motivation to use some RTOS (it doesn't have to be freertos, but that one isn't a bad start at all) in order to decompose a monolithic software into parts my head is able to handle.

Your question originally points to a different aspect:

I am starting a project which uses [...] GUI [...]

I'm using an STM32H743, running at 480MHz. (It's rather over-powered, but only $1/15% more expensive than something half as fast with less RAM and flash, which would itself need external flash at additional cost.)

The worst case screen draw is 10ms. [...] None of the [...] operations would suffer if delayed by up to 20ms.

If the screen drawing was slower, and needed to be interrupted by a more urgent operation, the need for an RTOS would be obvious.

You are right, another reason to use an RTOS is to interleave different processes on the system in a more or less dynamic way so that every task is finished before its deadline. I didn't investigate all the circumstances of your concrete case (see my elipses in the citation), but I feel convinced that this argument does not apply in your present situation. Just a few caveats to this perspective:

  • You compare the end prices for single pieces of µC hardware, probably soldered to some ready-to-use eval board. This is a good idea, I'm doing the same for private projects. But as soon as you make professional embedded software for commercial products, you have to consider the price for multiple controllers (depending on your industry branch, some tens to some billions), and the price for the µC itself because it is soldered to a PCB that just fits the product you are programming. Then it might happen that nobody will grant you an STM32H7-something unless you really prove that this is the controller class you need to implement all the software requirements.

  • You only described to us the screen/GUI driven by the STM32, but not the purpose of the screen. Usually, the device purpose implies some real-time requirements on the peripherals tied to the controller's I/O. Then, you may be forced to process some parts of your program with less latency than 10-20 ms. This leads you first to using interrupts, then (unless you want to handle every data transfer between contexts with lots of manual interrupt suppressions) to using an RTOS.

Maybe I am wrong, and you don't have any constraints to perform any reaction faster than 20 ms, or to replace the STM32H7 some day against a cheaper STM32. Then, the only argument that remains is handling complexity. Of course you can try to go on with a main loop. You will be successful as long as the requirements are simple enough that you can handle all with a kind of "all-in-my-head" architecture.

Credits to those who contributed parts of this answer in earlier comments: @Lundin, @Clifford

Community
  • 1
  • 1
HelpingHand
  • 1,294
  • 11
  • 27
  • 1
    Thanks, that's a comprehensive answer. As the complexity of device is nearly all in the GUI, we have decided to start with a single infinite loop. – fadedbee Apr 07 '20 at 07:44
  • 1
    You're welcome. The way you started is quite natural. When you start adding features (or structure, or IRQ handling) to the firmware, you should introduce an RTOS. Note that an RTOS with a single task behaves quite like a lonely main loop, so you can add the RTOS as refactoring step, and then add further tasks. /// Some suggestions for migration: (1) The GUI system shouldn't remain a monolith forever, but you'll find some preprocessing you may want to deploy to a different task. (2) The GUI contents are coming from/going somewhere, so you may have to integrate a bus interface, I/O or similar. – HelpingHand Apr 07 '20 at 09:31