Off and on there have been discussions on this and other forums about how real-time capable the .NET Micro Framework is. As a prime example: could and should a quadrocopter be programmed purely in C#? I have seen mostly two positions:
NETMF is not designed to be real-time. If you want real-time guarantees, create a special firmware version with C code for the control loop, or load the C code at runtime using non-standard extensions to NETMF, or don’t use NETMF at all. One glaring problem regarding real-time is the garbage collector. It blocks for an indeterminate time, and this destroys all real-time quarantees.
With a fast enough processor, NETMF should be able to handle such real-time tasks.
We asked ourselves the same question. It was clear to us that in general we would not [em]recommend [/em]doing real-time programming in NETMF, but would it really be that much beyond its capabilities? After all, it is a small and highly controlled environment, and real-time tasks are often few and simple in a real-world system. In NETMF, there are no operating system services that are scheduled at unknown times. We have written all the device drivers of [em]NETMF for STM32 [/em]ourselves, so we know where interrupts may occur and might introduce non-deterministic timings. (Speed is irrelevant in the definition of real-time, it only matters whether the timing is fully predictable.)
But how about the garbage collector? We knew for certain that a GC is not necessarily a problem. Fifteen years ago we have designed and implemented a bootable hard real-time Java runtime - with a garbage collector - that did not interfere with real-time tasks (not even with periodic tasks executing at well above 1 kHz, on rather slow microcontrollers). The key insight was that no one in his right mind dynamically allocates objects in a real-time task (at least not after its initialization phase). However, the often more numerous [em]non [/em]real-time threads (e.g., for communication purposes) should be allowed to allocate memory, and memory should be garbage-collected when necessary. The challenge was to implement the GC in such a way that it is interruptible anytime, i.e., it must never hold a global lock or something like that for more than a few processor cycles. While this was difficult to implement, it was still feasible. As a result, the real-time tasks (our own API, separate from the normal Java threads) always had absolute priority over all other code - including the GC. Their execution thus was fully deterministic.
NETMF doesn’t have such an intricate GC, nor does it have an API for real-time tasks and a suitable scheduler. But if a simple program avoids all allocations, there is no reason for it to become non-deterministic, as the GC will simply never run.
Beat thought that the proof of the pudding is in the eating, so rather than throwing around opinions, he built a proof. He designed a custom board for a quadrocopter, with an STM32F1 at 72 MHz plus a Bluetooth module. No separate microcontroller for the real-time stuff! The firmware was our standard F1 edition of [em]NETMF for STM32[/em]. No special C code linked in, no runtime loadable modules, no cheats. The control loop runs at 200 Hz, which is sufficient for stabilizing the flight of the quadrocopter.
The hardware has been ready for quite a while, see e.g.
NETMF ARM STM32 Quadcopter w/ Bluetooth, Beat Heeb, Oberon… | Flickr
Tuning the control loop parameters had to wait until recently, but by now the quadrocopter is flying quite well:
So what’s the moral of the story? NETMF is rather deterministic if you are careful with your code. In some cases, it can thus be feasible, and possibly even reasonable, to implement simple real-time chores in C#. It should not, however, be mistaken for a full-fledged real-time operating system. But it is good to know that it can be stretched quite a bit beyond its original design goals.
Cuno (but the work was all done by Beat!)
In another thread, Justin challenged me to show and tell about this project - thanks for the trigger