I have been programming firmware for microcontrollers with C or modern C++ bare-metal or using FreeRTOS. For example, a few colleagues and I used FreeRTOS on an omni-wheeled robot to control three motors from a speed vector, keeping track of its position and speed, displaying orientation on an LED strip and simultaneously interfacing a virtual COM port over USB. The RTOS allowed for easy synchronization and communication between the tasks. On the other hand, some obscure issues emerged, some from casting a void pointer into the wrong type, sharing the address of a variable that later went out of scope and stack overflows. Here I thought that there should be an RTOS that checks the types of messages and tasks parameters at compile time. And in particular, a stack overflow should not crash the system.
In contrast to C, C++ made development more convenient with classes, lists, iterators and generic code through templates. On the other hand, I have to carefully listen to the static analyzer and think of the implication on embedded devices from some features (e.g., virtual methods, polymorphism, RTTI, exceptions). This is why Rust intrigues me: the language offers modern paradigms, but I do not have to worry about overhead in the assembly output. The drawback of Rust is that the language is still under development, so some features might just be missing altogether.