As far as I'm aware, the focus of RIOT is to make embedded development as similar as possible to the way you'd write an application on Linux, including most of the relevant POSIX APIs. This is what, as far as I know, sets it apart from other systems such as Contiki or FreeRTOS, which have non-POSIX APIs for interaction with the OS.
Someone on this thread asked why RIOT vs FreeRTOS is not something being compared. FreeRTOS doesn't really come with all the drivers, network stack etc that you need in order to write an embedded IoT application. That is not to say that it's not possible to do so, but it requires more work of picking the right drivers and libraries, whereas RIOT tries to work out of the box for supported devices.
Finally, RIOT was born as a university project, and many of the people working on it are either university students or former students. In that sense, there are many, often conflicting interests and no single governing body. Depending on your point of view, this might either be good or bad.
For example filesystems.
Filesystems are not generally applicable for single-purpose embedded systems. You're never going to need textual filenames, opening and closing file handles, etc. All that is just a waste, typically you just want to store your data to a log. This is much more appropriately stored in a simple circular buffer on FLASH without the overhead and non-determinacy of a filesytem.
Also, processes. These should be static. You typically never ever exit a task/thread on an embedded system.
Resets are a way of life. You have to acknowledge them in your design and error handling takes advantage of this.
I would not take POSIX compliance for a system like this as a plus point.
This is a very broad brush. My Embedded Linux system makes amazingly good use of Linux and its Posix APIs. It’s also way to big to be the target of RIOT, so let’s talk about it’s 3 other embedded MCUs.
> Filesystems are not generally applicatble...You’re never going to need textual filenames
Really? Because I always enjoy talking to my cell radio doing AT+CMOGS=257,FFFFFF^1. That’s open file 257 and write FF.
Maintenance, debugging and robuestness of embedded systems is frequently overlooked. It allows not only a single dev, but a team to work, debug and release a system is a big deal. Embedded systems, esepcially those logging data, holding SSL certs, config data can very much use a filesystem. None of this has to be complex JFFS2 FS.
For example, if it’s an IoT, how do you plan to OTA it without good storage management?
> I would not take POSIX compliance for a system like this as a plus point
As a hirring manager anything that opens my pool of candidates is useful. Teaching someone a whole new environment is a big deal. If there’s similar concept and tools this ia big plus.^2
1) ok, I can’t remember the right AT command or the right file number, but serisouly how did this make it into a public API in 2019?
2) Mostly true. If it’s too close that it’s almost the same, but not due a laundry list of weird exceptions I’ll skip it. Micropython is my example here, it’s like really close to python, may too close but too different. There’s lots of other embeddedable languages that aren’t too close but weird.
- RIOT is obviously targetted at microcontroller-based systems (not Linux level).
- AT commands... you can't use modems in general as a good example of anything. Thes software running on those things tend to be terrible.
- Good storage management != filesystem. you can simply allocate a rotating circular buffer in FLASH with CRCd blocks. This is a simple mechanism that gives you both bad-block-management and wear-levelling in one trivial mechanism. No filenames in sight! ;o)
- Hiring... There is a lot more to embedded systems than "Can they use the API". All RTOSs use similar APIs, thats never been an issue.
MCUs today are pushing the boundary on performance. We'll see GHz Cortex-M7 chips (already 600MHz+ today) running an RTOS in the near future, with external DRAM and flash. Users rightly want to push a LOT of functionality on them and that comes with advanced OS usage, including dynamic memory and threading. The developers using these systems are increasingly coming from an embedded Linux world as the performance line blurs, and POSIX is familiar.
This does not change the fact that a smaller, less capable uC will always be cheaper.
Embedded system designs are typically cost-driven, hence cheaper (and therefore resource-constrained) devices will always be a fact of embedded-life, no matter how "powerful" uC become.
You seem to be conflating embedded systems with safety-critical systems. There are plenty of embedded systems that are neither safety critical nor single-purpose. Also, plenty of non safety-critical embedded systems use microcontrollers that don't have the resources (RAM) to run Linux effectively (even MMU-less Linux) but could benefit from dynamic kernel capabilities like dynamic loading and unloading of drivers for hot-plugging events to support external hardware/accessories.
Accepted general practice for (non-safety-critical) embedded software is to avoid dynamic behaviour wherever you find it.
This increases robustness and makes your code a lot simpler while giving you confidence you've handled your worst-case.
If you're not doing that, you're trying to do desktop-software on an embedded system.
For our current product, (and I would think a lot of IoT apps), power is king. We run on batteries, and getting back to idle/low power states as often as possible is crucial. I've found that a lot of the embedded RTOS often have tickless modes as an "add on." We had problems getting RIOT to a happy point with that for our chip (samd21).
Like some of the other commenters, I've grown a real distaste for embedded RTOS frameworks that try to provide all kinds of layers. In order to be generic/cross platform, they always come up short in capability. The functionality that I'm looking for, is simply getting the basic threading/sync primitives to work well and right. Past that, I'm fine doing the chip IO parts myself. At the time, there was a debate on whether priority inversion was a problem RIOT should worry about or not.
After FreeRTOS, and then RIOT, I found TNEO (https://dmitryfrank.com/articles/how_i_ended_up_writing_my_o...). It's been a dream and rock solid for us. It does not come with a large make/build system. It's just C code. You tweak a couple of things, include one or two bits, and I was off to the races. Coupling it with Unity for testing and then writing ~200 unit tests that stressed all of its functionality was straightforward, helped me understand it even better, and gave me a high degree of confidence in its abilities. It's been super solid for us since. It does the one thing I need it to: MicroKernel for dealing with processes and related synchronization primitives.
- the mentioned RIOT OS (https://riot-os.org/)
- FreeRTOS (https://www.freertos.org/) and Amazon's version of it (https://aws.amazon.com/freertos/)
- Zephyr OS (https://www.zephyrproject.org/)
- MyNewt (https://mynewt.apache.org/)
- Mbed OS (https://os.mbed.com/)
and more... Makes it really hard to choose one!
I really prefer contiki ng
It is however clear, that they started as a research project and had, and still have, some maturing to do before they can be considered for a production environment. In my opinion, they are however on the right track for that. The list of buried corpses tends to get shorter and over the last year, a lot of interesting features were added. They are also currently working on fixing their documentation and getting automated HIL tests running for their supported boards, which should fix alot of problems people getting started with RIOT currently have.
We are likely not going to use RIOT in the next project, however we will continue to use it for teaching.
Contiki's "C Support" is listed as "partial" without any explanation. What does this even mean? It seems to me that this should be between you and your compiler.
Linux is supposedly "partially modular", whereas RIOT is fully modular. That's a bold statement.
I get that they are trying to differentiate their product. But without motivations, statements like these sound a bit hollow to me.
In this level of devices, everything should be statically allocated for the worst-case situations. This is for reliability, simplicity, determinism, etc.
The space taken by the code involved in handling dynamic loading could be better used by giving you a cheaper, simpler, more reliable device.
What seems 'nice' on a desktop system is (in a lot of cases) inappropriate for a resource-constrained embedded system.
1) Dynamic loading and unloading of drivers in a single-purpose embedded system is not a good point.
- Yes, but who said anything about Riot being used only for single-purpose embedded systems?
2) In this level of devices, everything should be statically allocated for the worst-case situations.
You seem to be conflating embedded systems with safety-critical systems. There are plenty of embedded systems that are neither safety critical nor single-purpose. Also, plenty of non safety-critical embedded systems use microcontrollers that don't have the resources (RAM) to run Linux effectively, even MMU-less Linux, but could benefit from dynamic loading and unloading of drivers for hot-plugging events to support external hardware/accessories.
3) The space taken by the code involved in handling dynamic loading could be better used by giving you a cheaper, simpler, more reliable device.
- For certain problems, sure. But I'd challenge your assertion that resource-constrained always equals single-purpose device where dynamic loading for things like hot-plugging events isn't useful
- It's hard to argue this point with the caveat "in a lot of cases", but I'll try. What makes this inappropriate for resource-constrained embedded systems? Again, it seems you're conflating resource-constrained embedded systems with safety-critical embedded systems, where formal methods/functional verification/regulatory certification are necessary and therefore dynamic code loading/unloading isn't feasible
Its an accepted, general premise in embedded systems to always avoid dynamic behaviour, that includes memory allocation, storage behaviour, etc.
Implying that that kind of behaviour is only for safety-critical systems is not correct, its mainly for robustness and simplicity reasons. I would argue that it applies to the vast majority of embedded systems (prototypes excepted).
An embedded system is also (generalising again here) always single-purpose. By definition its a part of another system and you do not interact with the device itself, you interact with the system.
You could argue that not all embedded systems are resource-constrained (again, been there, done that). but typically for this level of system (i.e. microcontroller based), if you're not resource-constrained, you've not optimised your BOM cost and hence you're in prototype stage.
My original point was that claiming that Linux is partially modular while RIOT is fully modular feels like a stretch to show N lines of red crosses and orange circles, followed by one line of only green check marks.
Linux's FLASH/RAM requirements are enough to disqualify it from projects targeted by RIOT, IMHO. No need to make dubious claims of limited modularity.
The only problem with the Linux kernel these days is its sizes. Because with Cortex M3/M4 processors we still have sizes constraints.
Looking at the source code it seemed very Arduino-like in the sense that there's few knobs to turn, which is nice for simple stuff but means you'll have to go straight to registers for anything beyond.
Overall a bit hard to get a feel for what it could do.
There's also the pkg directory (https://github.com/RIOT-OS/RIOT/tree/master/pkg) which incorporates a bunch of third-party libraries and projects without a significant amount of code changes (see the patches/ directory in each pkg). Maybe this gives a good impression of what it takes to port things to RIOT.
Everyone wants a piece of the pie.
RIOT is the only mentioned OS with a copyleft license (well, LGPLv2.1), trying to create a FOSS alternative in the embedded/IoT space.
With permissive licenses for embedded software, open source usually ends at the factory.
NuttX is a kind of Linux-like RTOS. It is very easy to use, as you can see on my video tutorials: www.youtube.com/c/NuttXChannel
Unfortunately using a GPL/LGPL is not an option for embedded system because companies want to keep part of their devices closed.
EDIT Elaborated beyond two words and the slimey
- IPv4 is mentioned in docs: http://doc.riot-os.org/group__net__ipv4.html
- lwip config has ipv4 enabled: https://github.com/RIOT-OS/RIOT/blob/3091cd85bd6df0bce1fcf60...
People, just let it rest.
Oh by the way, I'm sure we all agree that using IPv4 for IoT, especially new deployments, is a particularly bad idea.
Using RIOT you'll get at least multi-threading, power management, a choice of network stacks, a bunch of community-supported libraries and drivers with an extensive test suite, ...
Also, you'd have a clear upgrade path, as applications written for RIOT's API will compile (almost) unchanged for all of RIOT's target hardware. Arduino becomes to slow? Change some pin defines, re-compile for a fast Cortex-M. Intrigued by RISC-V's openness? Recompile for the Hivife1 to find out it's real-world performance with your application.
As someone in the CE field doing this work everyday, I’m getting kind of sick of abstraction layers. Every device mfg takes a crack at it, every RTOS does, ARM itself does, and many IDEs are as well.
I kind of just want my RTOS to do threading, preemption, and resource locking. Middlewares line Amazon’s MQTT are good but I’d really prefer to handle the peripherals myself or use the device mfg’s libs. I am not a believer in write once use everywhere embedded code, it just doesn’t work, because the peripherals are just so different.
Are they though?
You got SPI, I2C, UART Timers and DMA and while their flavor may differ depending on the vendor, they should do about the same no matter what platform you are on.
Sometimes you might have to do some exotic stuff when a chip uses non-standard interfaces, but most of the time the behavior should be fairly generic.
Just at a base level how you work with peripherals is going to be different. Some are better with events, some better as ISRs, some better with polling.
There is no middleware that’s just going to abstract those and get a great implementation of each. They were just designed so differently.
How does this prevent you from hiding all those implementation details behind an API like spi_transfer(spi_t dev, const void* buffer_tx, void* buffer_rx, size_t size)?
RIOT manages to get by with that - granted, most implementations there rely on polling, it's not a conceptual problem.
In your example, if I want a DMA-based transfer it's fine to just hide it and block the thread waiting for the DMA interrupt. But if the hardware designer expects me to poll, now I have to find a way to put the thread to sleep and schedule it. And there are performance and timing implications for either scheme that your abstraction hides from me. At some point I'm going to stumble on those implications and get screwed badly enough by your abstraction that I need to rip it out or work around it to solve a problem. This has happened to me too many times before.
On systems that are small enough to be considered "embedded" I would much rather the OS gets the hell out of my way and lets me pick a sensible abstraction myself.
I don't see much value in having an abstraction layer in these systems unless it's for a hobby project. In an established project you would never recompile your code for a completely different hardware platform "just to see how it performs." You'd stick with the hardware you know, and you'd already have de-risked the performance questions early enough in the project that you wouldn't have written a bunch of application code yet. It's not a problem that needs to be solved in a professional environment.
There is just no way an abstraction is going to pick the best process for my needs.
And yea, while it might be a nice idea to switch chips... I’d have to go through sourcing to figure out if they make a chip in the package i would need at a price I’m willing to pay at a lead time I’m willing to wait, a week or two reading data sheets and reference manuals, updating the board hardware, changing the BOM, getting with purchasing to update the next PO, changing the assembly programming and stencils... plus documentation, plus fragmenting our hardware variations, etc.
The abstraction to switch chips, might be nice for prototyping, but yea, it’s not really useful for production, so I think I would rather my OS developers focus on other things.
It also talks about 8-bit support, but only lists AVR... I mean, AVR is compiler target optimized arch, more like a 16/32 bit system with register width chopped to 8 bits, not limited like other 8-bit MCUs. 8051 support wouldn't hurt.
Plus side there's support for 16-bit MSP430, important due to its low power consumption.
Anyways, it's good to see more OS competition in IoT space.
Signed: embedded & driver developer.
Why does it need to evangelist with statements like this? Isn't RIOT a non-profit endeavour?
- Riot Messenger
- Riot Games
- RIOT OS
It's getting kinda crowded in this namespace :-/
I see projects weekly with RIOT for the name. I suppose it's just too tempting for IoT projects
AWS is certainly tied in the best but you can still use the networking and MQTT library however you want
What exactly does RIOT do for you that isn't on the chip?
There simply look for merged pullrequests of the features you are looking for. That will give a better overview of the degree of support then the documentation.
I've been using it in production for almost a year, and no major complaints so far. There seems to have support for POSIX threads and BSD sockets, but I don't use them, so I can't tell you if they are production-ready or not.
As if IoT manufacturers weren't already ignoring the security of their IoT devices and properly updating them.
I think if IoT devices are to adopt a good open source RTOS it should at least be one written in a memory safe language.
Did I miss another option?
And there are some options. You could achieve barebones VM protections with Pawn(the language enforces very little otherwise, though). You could use something ref-counted like a TCL implementation, which would allow you to design around linear allocation times. The vast majority are using some kind of tracing collector of course, but I wouldn't say this is a total loss for achieving a combination of real time and memory protection.
PAWN for instance is explicitly 32bit and interpreted, so would run dog slow on something like an Arduino.
Something refcounted like TCL implies tons of heap allocations, which implies fragmentation at the very small RAM sizes of a lot of these chips.