FreeRTOS Gets Class

[Michael Becker] has been using FreeRTOS for about seven years. He decided to start adding some features and has a very interesting C++ class wrapper for the OS available.

Real Time Operating Systems (RTOS) add functionality for single-thread microcontrollers to run multiple programs at the same time without threatening the firmware developer’s sanity. This project adds C++ to the rest of the FreeRTOS benefits. We know that people have strong feelings one way or the other about using C++ in embedded systems. However, as the 24 demo projects illustrate, it is possible.

One nice thing about the library is that it is carefully documented. A large number of examples don’t hurt either. The library is clean with just under 30 classes. It seems to have resisted the trend of having classes for everything. You know the kind of library we mean. To create an Integer object, just build a configuration object to pass to the class factory generator which…. This library doesn’t entertain any of that. It has simple abstractions around threads and timers, queues, and mutexes.

One thing we did find a little surprising was the lack of a “base application.” A common feature of C++ libraries is to have a basic application object that you specialize to create your application. It looks like the wrappers, still require you to use a pretty standard-looking main function and provide some standard callbacks and things. This could easily be put in a class. Of course, the library is young, so perhaps this will be something brought out in a future release.

FreeRTOS is very versatile and runs on a large number of processors and boards. It is also fairly easy to port to new hardware. It can also coexist with a lot of middleware like Mongoose OS, the STM32 HAL library, and much more.

56 thoughts on “FreeRTOS Gets Class

    1. Memory limitations. You don’t want (and shouldn’t need) to use a Cortex-M4 in all your projects because using classes wastes a lot of RAM and program memory and your code can’t fit in a smaller chip.

      Once upon a time, microcontrollers were programmed exclusively in assembly, then C compilers came, then C++, then Arduino (which obviously loads a lot of C++ classes on an 8-bit AVR).

      1. C++ was created on machines that had a lot less memory than today’s 32 bit microcontrollers. Also, C++ doesn’t “waste” memory. You can consume memory to make sophisticated applications, but you wouldn’t be consuming less memory if you wrote the same application in C.

        1. I think what happens in these threads is that you get examples of wildly different experiences. Some who work within consumer electronics might argue that C++ makes their job tremendously easier. Others, like myself, write safety critical software that runs on embedded systems and can barely close their control loop every 1 millisecond with compiler-optimized C. From my experience, there is no silver bullet, and you should always perform the language evaluation on a project-by-project basis.

          I have seen projects fail (or need to be re-done), but usually this is due to an architectural problem that leads to an overly bloated code-base. For this reason, in my industry, C++ is generally not the preferred choice, but that should not remove it as a contender for other embedded applications.

          1. C++ adds zero overhead. I, for one, cannot understand why anyone programs in C anymore.

            If you’re in time-critical code, you can write the same code in C++ that you would write in C and have the same performance.

            Classes produce zero overhead. You can encapsulate your data and methods, protect them against unauthorized access by making them private (that helps when writing safety-critical software) and there is zero run-time overhead. Constructors and destructors will ensure your data is initialized correctly and resources are released when they should be, again with zero run-time overhead.

            If you end up using virtual functions or dynamic memory, well that’s because your application needs it. And it creates no more overhead than function pointers or malloc/free would in C.

          2. @Bob – depending on how you write it. Templates and inheritance have overhead. Rather a lot of it. Also – it is much easier to accidentally increase the code size by just doing things “slightly” wrong. (Can do that in C too, but it is much easier catching it there).

          3. fhunter, inheritance has zero overhead unless you use virtual functions. And if you’re using virtual functions, it must be that you need some sort of indirect function calls. Switching to C wouldn’t eliminate that; it would just make you responsible for handling function pointers.

            Templates also have zero overhead. Reckless use of them can create unnecessarily duplicated code, but that would consume ROM space, not processor time.

          4. “Reckless use of them can create unnecessarily duplicated code, but that would consume ROM space, not processor time.”

            Unless your system has a cache memory.

          5. “C++ exceptions have quite a bit of overhead too.”: Then don’t use ’em, and use whatever haphazard error handling mechanism you’d cobble together in C.

          6. Moore Products had the Quadlog system, which was a TÜV approved, SIL3 safety system written in C++.

            With judicious programming it the resulting​ code is pretty tight, and the compilers are often remarkably good at optimization.

            Ultimately, you need to look.at.the assembly code sometimes, and them refine the high-level code to tweak stuff .. but it’s hard to argue against using expressive tools for writing the code in the first place. In our case, C++ helped with productivity, and it allowed us to use a common code-base for other, non-safety variants of the controller.

          7. @Artenz, you would either avoid any operations that could fail in a constructor or have the constructor set an error flag. Yeah, I know, both of those are kludgy. But they’re no more kludgy than what you’d do if you were writing in C. Remember, I’m addressing the concern that exceptions are bad in embedded systems. I could either 1) argue that they’re not bad or 2) argue that you don’t have to use them and you’ll be no worse off than if you’re coding in C.

            Option 2 is easier to argue.

          8. Having the constructor set an error flag, doesn’t really work well with the RAII paradigm. And if you doing something like calling a function f(a, b) where object b has a copy constructor that can fail, then the function f() needs to know to check error flags that it doesn’t care about.

          9. “doesn’t really work well with the RAII “: I agree completely. It’s not the way I would choose to do this.

            But switching to C doesn’t work well with RAII either, and that’s what I’m arguing against.

          10. Templates are awesome in embedded c++. I write my templated class once for multiple flavours of mcu and leave to the compiler to optimise out all of the conditional code for different mcus. No messy macros. I can even step through the templated code with the debugger.

          11. @ftkalcevic I would love to hear more about your template library. I attempted something that may be similar: a cross-platform template library (e.g. different ARM microcontrollers, Microchip’s PIC32) where the templates abstracted away the different peripheral behaviors and the compiler produced tight, zero-overhead code. It was going pretty well, but I was overwhelmed by the scope of the task and abandoned it.

            I was also worried that while the run-time code would be as efficient as possible, compilation would take forever.

            So as I said, I’d love to hear more about what you’ve done.

          1. Except that everything he decided to do in C, he could’ve done in C++ by simply not using the features he found problematic.

            Assuming his concerns about exceptions are legitimate (and I don’t feel like arguing them here) he’s still throwing the baby out with the bathwater. He should continue to use C++ and just not use certain features in certain areas of code.

    2. Because usually when people write C++ they do lots and lots of dynamic memory allocation without even thinking about it. An embedded system is extremely memory limited, and generally required to *not* randomly fall over because it ran out of memory.

        1. The thing is that C++ makes it easier to overlook what’s happening under the hood, and design patterns that are perfectly fine for a large desktop program, may not be working well on a small embedded target. That doesn’t mean the software is shitty.

    3. Modern C++ compilers are no longer fancy C pre-parsers, and can make low level work difficult.
      Assembly programming is important to learn, but the performance difference is negligible on modern compilers.

      The things that make C++ great (see STL, Boost, GSL and so on) are often difficult to wrangle on low level systems, and compiling the identical code can manifest different timing errors impossible to predict.

      The Arduino pseudo C++ language is good for beginners familiar with PCs, but it only works because gcc makes low quality random optimizations that don’t have pronounced temporal issues. For example, simple scalar promotion can change the number of clock cycles for the identical loop code. Thus, most people become dependent on RTOS guaranteed latency schedulers, and or hardware event timers.

      ANSII C95 code will work on anything from a super computer to your wrist watch.

      1. “ANSII C95 code will work on anything from a super computer to your wrist watch.”

        This to me is really the lynchpin of the argument. If you can master C, you can write good code for almost anything. This is why I would rather spend my time mastering it instead of learning other, more limited languages.

        1. “spend my time mastering it instead of learning other, more limited languages”: First, if you write a lot of code, it doesn’t take that much time to master C. So after a short time mastering C, you have time to learn something else.

          Second, if you know C++, you know C.

          Third, when you’re writing code, it’s most important that it be in a language appropriate to the hardware and the application. C++ is better for complex applications than C is, and the ability to port that complex application to a wrist watch or a supercomputer is usually of no interest to me; most programs I’ve written were targeted at a single platform and would make no sense on a different platform.

          Fourth, C++ will work on smartphones, desktops, supercomputers, and 32 bit embedded systems. All it lacks is some 8 and 16 bit embedded systems. I can program them because my knowledge of C++ includes knowledge of C.

          And finally, don’t dismiss languages like PHP, Python, JavaScript, and others. They are usable in environments where C is not allowed.

    4. There is nothing wrong with using C++ in embedded. On small AVRs I benefit from simplified syntax of C++11 (auto types,range-based loops (for each)) and avoid dynamic memory allocation. But 99% of the time I don’t do dynamic memory allocation in embedded C either..

    5. I’ve done a few little C++ STM32 microcontroller projects with the remarkable https://github.com/andysworkshop/stm32plus . In C it’s 4 lines of boilerplate per to initialize a pin, but the library streamlines it down to a single line, and C++ ensures the peripheral was actually initialized before use. It has saved me many precious hobbyist hours by having the boilerplate in a library instead of getting it wrong.

      I can’t go back to C. Would like to give embedded Rust a try though.

  1. And just when you thought your 1.5ms routine would run, freeRTOS runs off to do garbage collection; and your watchdog timer resets the device causing your engine controller to not switch the polarity of a subcircuit and disaster strikes.. I’ll stick to C95.

    1. I think you are unfamiliar with what FreeRTOS is. It is a real-time operating system, giving you access to periodic preemptive priority-based scheduling.

      It has nothing to do with GC, and I have no idea where you’d get the idea that it does.

    2. Since when C++ features garbage collection? C++ is and have always been about deterministic memory management…

      To the point of C++ – if you don’t use STL and exceptions, it is a pleasure to write firmware for MCUs with it and it provides no extra overhead. For example – do you know the STM32Plus library(https://github.com/andysworkshop/stm32plus). Such a nice interface for peripherals! Nothing to compare with the standard libraries from STM…

      1. C++? Deterministic memory management? With the introduction of shared_ptr, I find it *impossible* to determine whether my objects have actually been freed or whether there’s a single dangling pointer somewhere that keeps it alive because I used a shared_ptr for it. I’m really surprised the people who designed C++11 didn’t put more thought into debugging this.

        1. So you’re saying you’ve lost track of how many references to memory you have. That happens in C too: you free() something when someone still has a pointer to it (invalid pointer) or you forget to free it (memory leak). Nothing new here. shared_ptr, if anything, makes these types of errors less likely.

    3. I’m not aware of any garbage collection that FreeRTOS or C++ do. Yeah, if you allocate and free dynamic memory, free blocks are coalesced, but that’s very different from the type of GC that Java, Python, or LISP do.

      1. This is a common problem. People “know” what the C compiler does and for some reason think it doesn’t do anything extra (it usually does, like adds function preambles and the library–like printf–might call malloc underneath). But there is a perception that C++ just “randomly” add things which is, of course, untrue. If you understand C++, you can understand where it is going to do things like add vtable function call overhead (which is tiny; Rud had a good post about that last year). A lot of normal programs only create objects as pointers using new, but you do not have to do that. You do have to watch for libraries doing that, but that’s true anyway.

        As for FreeRTOS if it is doing garbage collection then you’ve selected the wrong memory allocator.

        If you are blinking a light, it probably doesn’t matter. If you are doing something where you can leverage C++ features, the cost of them is not likely to exceed what you would have to do in C to get the same effect. In other words, if I have a pointer to X which could be a Y or a Z, it is going to take as much code to figure that out as it is to just use a C++ vtable. Now if you don’t need to do that, then why did you write code in C++ that used vtables? You don’t have to.

        Not that everyone doesn’t have a personal preference and I probably write more C than C++, but if you actually understand C++ and why it is used, then there is no reason you can’t use it in embedded. You can argue that you can’t use parts of some common libraries… sure. And you probably don’t use printf in a production build either. Just because you make concessions to your environment doesn’t mean you have to throw the baby out with the bathwater. C adds things too. Parts of C and the C library aren’t suitable for use. The difference is everyone knows those items. C++ has a reputation for being “magic” and that’s just a sign you don’t understand it as deeply as you do some other language (probably C).

        1. Thank you Al, for such a comprehensive response.

          You are absolutely right, I am fully familiar with C, and much less C++; so am much more comfortable with the overheads of C.

          I usually find that I can achieve a timing critical application in C with fewer lines and greater accuracy than my colleagues who choose to use C++ – but as you said; this is probably due to not *fully* understanding how to leverage C++’s features.

          As for the GC comment – just a reference to a bad experience of a previous version of FreeRTOS (which resulted in me shelving it and never looking back).

          I guess I like to write in C and be able to followow the disassembly knowing what code resulted in which instructions.

          I am open to try more C++ however if anyone can give me a hint of a good book to read on it!

        2. Amen .. we were using C++ with an “intersecting” code-base for a system that included:
          – embedded applications (industrial controller and their I/O modules)
          – the GUI that was used to program the whole thing
          – and the HMI that was used for monitoring stuff being controlled by the system.

          The HMI and configuration folks were often completely tone-deaf to the fact that the embedded folks had different constraints, and would occasionally give clueless lectures on “best practices” .. generally repeating stuff from text books full of advice that was irrelevant for embedded programming.

          We generally had to debug embedded code in assembly, and relate that code back to the original C++, so we developed a remarkably solid grasp of which C++ features we could use fruitfully, and which we were better off avoiding.

          At any rate, the better compilers are often shockingly good at optimization. Of course, you do need to watch out for the occasional “cat fail”, but if you have a good team and good processes, you’ll get a good result.

  2. If you’re into C++ and microcontrollers, and want a more standard-compliant environment, check out Miosix (http://miosix.org/). Limited to 32 bit chips, but you get a working (and thread safe) STL out of the box, including exceptions. For threads and synchronization, it has the pthread API. Also the C library is integrated and thread-safe, so you can printf to the serial port straight away.
    PS: yes, I’m the author of that kernel.

    1. Well… C can have problems too. And they DO often run an OS.

      http://www.edn.com/design/automotive/4423428/Toyota-s-killer-firmware–Bad-design-and-its-consequences

      From http://embeddedgurus.com/barr-code/2011/03/unintended-acceleration-and-other-embedded-software-bugs/

      NASA reports that the embedded software in the Main-CPU is written (mostly) in ANSI C and compiled using a GreenHills C compiler (Appendix A, p. 14). Furthermore, an OSEK-compliant real-time operating system with fixed-priority preemptive scheduling is used to manage a redacted (but apparently larger than ten, based on the size of the redaction) number of real-time tasks.

  3. Going through main is essential in any multi-threaded program. The C++ language guarantees that all global static variables and classes have been initialized when main is called. When you throw a global static “app” class in the mix, all bets are off.

    1. That’s typically not true. Every compiler I’ve ever seen has an elaboration code that occurs before the main call and will initialize everything that is global or static.

      So you usually have something like:

      __start:
      ; init stack and heap and any other major items
      ; set up any interrupts required early (if any)
      ; initialize global/statics
      main();
      exit(); ; pick up any atexit handlers or other destructors

      On some systems this code will do even more setup. Just depends. But I can’t think of a case where the compiler depends on main. I know the STM framework have moved a lot of init into main (or calls from main) like setting up clocks and stuff, but that’s a choice and not related to C vs C++.

  4. I think that there’s a place for C++ when used as ‘C with classes’ in the Embedded world. Both the Arduino and mBed APIs are written in C++. Not sure about the C++ standard library though nor some of the more advanced capabilities of the C++ language such as smart pointers, virtual functions, abstract classes e.t.c

    1. Saying that virtual functions are inappropriate in the embedded world is like saying that C function pointers are inappropriate in the embedded world. The appropriateness of virtual functions or function pointers is determined by the application, not the environment. The same is true of smart pointers and the STL.

      These features in C++ provide benefits. If your application needs those benefits and you’re writing in C, you’re going to find yourself implementing them in much the same way C++ does. But you’ll be working harder, debugging more, and it’s very unlikely your code will be more efficient that what C++ would’ve produced.

      1. From my experiences doing embedded stuff in both C and C++, I found that I needed to type more text in C, but that I had to work harder on C++, regularly checking assembly output to see if the C++ compiler performed enough optimizations to make the code acceptable. In the end, programming in C was faster and clearer.

  5. personally, I’m waiting for someone to make a bare metal golang compiler for ARM (and others) MCUs. It would need a automatic garbage collector running in the background…but I’m ok with that

    1. “The background” is a tricky concept in this context. You might run it at idle time. But if it isn’t fully interruptable, you are going to introduce determinism problems. What would be nice would be a CPU with a “mini” MMU that would handle memory allocation and reclamation automatically. It could remap a pool of memory to anywhere you wanted and later reclaim it. You could even have your init code return itself to the free pool. Hmm… now I want to go write that in Verilog.

  6. Alternative approach – use a RTOS that is written in C++ from the ground up (;

    People familiar with C++ know that the result of “wrapping” C-only API with C++ classes is usually far from being perfect (it may be hard to use, has hidden constraints, may be far from being efficient). This is usually because the author of C-only API has no experience in object-oriented design. Another important factor is that in a combination like that, you’ll never be able to use some extremely helpful C++ features like constexpr constructors, making the whole design pretty fragile. However if you write the “core” in C++, it is actually very easy to wrap that in C functions. C++ has all C features, that’s why it’s just the better way (please note that I’m aware of some things which are present in C, but not in C++, but they make absolutely no difference here).

    With all that in mind and after working with several C-only RTOSes (usually writing my own C++ wrappers for them), I finally decided to write my own “modern” C++ RTOS – http://distortos.org/ . Ever wanted to create a thread out of a C++11 lambda? Or with member function? Or with a function which has 17 arguments of different types? No problem – it’s perfectly possible and quite easy <: https://gist.github.com/FreddieChopin/cdb3429236504d4ab788c99ed5ac5fb4

Leave a Reply to GravisCancel reply

Please be kind and respectful to help make the comments section excellent. (Comment Policy)

This site uses Akismet to reduce spam. Learn how your comment data is processed.