Real-time software with MicroPython

MicroPython has evolved recently to become a great platform for quick prototyping of microcontroller software. The expressiveness of the Python language and its rich library ecosystem make it extremely useful and allow the testing of embedded software in a matter of minutes.

However, when a real-time solution is needed, care has to be taken as there are inherent limitations imposed by the Python virtual machine. MicroPython tries to work around the lack of memory and the low speed of microcontrollers and is designed with these constrains in mind.

There are ways to maximize the speed at which MicroPython runs. Our tests are simple as they do not involve complex memory allocations, garbage collection or asynchronous programming. We are interested in exhibiting just the limitations of the MicroPython virtual machine and unavoidable architectural issues like cache loading when jumping to code stored in flash. These quick tests provide us with a rough idea of the performance that can be reached when accessing the GPIOs on some of the MicroPython reference boards. These figures are obtained in a system with no additional CPU load, without mounting the mass storage device and trying different code emitters.

GPIO toggling

A line of MicroPython code takes a few μsecs to execute on a PyBoard @168MHz. Toggling a GPIO pin should of course be faster than most instructions. Tests have been performed using the following code:

from pyb import Pin

p_out = Pin('X3', mode=Pin.OUT_PP)
while True:

An oscilloscope can easily show the time it takes to execute the GPIO set/clear functions as well as the time taken by the loop branch. The results are quite stable, with no appreciable jitter:

code emitter loop branch (μs) GPIO set/clear (μs)
bytecode 5.2 2.7
native 3.4 2.3
viper 0.35 2.2

These tests have also been performed on a Nucleo F429ZI board @180MHz where we observe slightly worse values (GPIO set instructions take around 10% longer).

GPIO external interrupts

We measure the time it takes for the PyBoard to set an output GPIO pin in response to an interrupt triggered on an input GPIO. The source of interrupts is a pulse generator that triggers an interrupt every millisecond. The following code has been used to measure the interrupt latency with the help of an oscilloscope:

from pyb import Pin

def gpio_cb(e):

p_out = Pin('X3', mode=Pin.OUT_PP)
ExtInt(Pin('X4'), ExtInt.IRQ_RISING, Pin.PULL_DOWN, gpio_cb)

The interrupt latency results on a PyBoard v1.0 @168MHz are stable and exhibit low jitter, with these results obtained after running for one hour:

code emitter interrupt latency (μs) interrupt jitter (μs)
bytecode 7.3 < 5.0
native 5.7 < 4.0
viper 3.3 < 4.0

The signal was captured with an oscilloscope running in persistent mode. The constant execution time of the GPIO pin toggling instructions gives us confidence that the observed variability is due only to the interrupt jitter.

Tests have also been performed in a Nucleo F429ZI board @180MHz, where we observe a slightly worse performance (GPIO interrupt latency is similar with bytecode but around 20% worse with native and viper emitters). However, the Nucleo board shows a much more stable latency value, with jitter bounded at 2μs.

We have written some code that produces an histogram of the measured latency variability.

Shall we use MicroPython in our real-time projects?

MicroPython is mature, elegant, and offers great productivity advantages over other embedded software environments. MicroPython is quite capable of running real-time code as long as we put some care around its limitations; after all we have to remember that real-time is not about being fast but about being deterministic. Providing the memory/speed resources are sufficient and we can meet our real-time deadlines, it is a great platform which we intend to use more and more in the future.

Industrial Beaglebone Black anyone?

Is it really possible to use the Beaglebone Black in industrial embedded projects? or it is just a maker/hobbyist platform?

I have been searching for an industrial version of the Beaglebone Black in order to leverage the great know-how and resources available on this great open source hardware platform to make it work reliably on industrial environments. A professional version would allow e.g. better platform longevity planning, reliability, customization or industrial temperature ranges. Last year there were some efforts that did not get anywhere.

The Beaglecore project in kickstarter seems like a great attempt at remedying this situation. It is a system on module (SOM) fully compatible with the existing Beaglebone Black, with features aimed at industrial computing and long-term availability. Help them achieve their goals!

Developing a PPS GPIO generator driver on a Beaglebone Black

While working on PTP (Precision Time Protocol, IEEE 1588) with some Beaglebone Black boards, I needed a way of comparing the time on different boards with high resolution (10ns). I saw that there is no currently a PPS generator that uses GPIO pins. There is only an option to use a parallel port.

This was a good excuse to write a kernel driver. I started by modifying the parallel port PPS generator implemented in the kernel to use a GPIO pin instead. You can use this module on other boards providing you modify your device tree file accordingly. This module has been tested with kernel 3.15.3.

The source is at:

Embedded Linux support from board vendors

I have recently completed a project where I used a PC104 SBC (single-board computer) from a hardware vendor that sold our client a Linux development kit in addition to the hardware; the development kit included a busybox-based distribution with quite an old kernel (2.6.21) and a driver supporting some board-specific features. So far, so good. Very often the time required to build a distribution from scratch is more valuable than the price to pay for a commercial Linux distribution, so this approach is often the sensible one.

However, when we started developing the system, we realized that the provided driver included most of its functionality in a binary blob for which the vendor would not provide any source code or much support in the form of updates. We wanted to use a more recent kernel as 2.6.21 was lacking support for a GPS module we had attached to the board. According to the vendor, getting a binary driver compiled for a different kernel version was out of the question, as they did not have the expertise in-house. They even hinted at lacking some of the driver source, as their latest Linux expert (i.e. their only Linux developer) left the company years ago and they did not bother to set up everything in place to be able to build their driver before the Linux guy left. It is amazing that companies that build excellent hardware may exhibit such a slack attitude towards supporting their product with the most popular embedded OS today; it is even more amazing that they charge for such a development kit!

When starting to work on new hardware, we are confronted with the different options available for getting Linux on our boards; these are the main ones:

  • Roll your own distribution. There are a number of open source projects that can be leveraged to build your own distribution, like crosstool-ng, OpenEmbedded or Buildroot. These projects build a distribution based on your hardware requirements. However, this is not an easy task and you may find issues that require a lot of work from your part, depending on how the board and peripheral you use departs from a standard working configuration used by the distribution.
  • Use an open source distribution like Angström. These distributions are aimed at a specific set of boards. They are a good choice if your hardware is similar to some of the hardware supported by the distribution, otherwise they might require significant porting work.
  • Buy a Linux distribution from an independent vendor or consultant. There are different degrees of customization you can expect from vendors; some examples are Montavista, Wind River, or consultancies like DENX or Free Electrons.
  • Get Linux from the SBC vendor. This may be the shortest route to having a properly configured Linux distribution on your system; although you should pay attention at how committed the vendor is at supporting the issues you may find.

Whatever the route you chose, planning ahead and taking into account the different options is essential to the success of your project.

Setting up a NanoBSD router on a Soekris net5501

NanoBSD is a great set of scripts that facilitate the compilation and installation of a custom full FreeBSD system on embedded devices. It is particularly suited for booting from CF cards, as it creates a read-only root file system, with the read-write partitions mounted on RAM (md) so as to reduce wear on the card.

I have had for some time a Soekris net5501 box gathering dust, which I bought to replace the Linksys router I use on my home lan. It is time to roll up my sleeves and get my hands dirty. The Soekris board will be a perfect gateway with around 5W power consumption and no moving parts that allows loads of flexibility to install lan services that are not available (or not so configurable) in a cheap off-the shelf router, like:

  • pf firewall
  • dhcp
  • ntp
  • dns with bind
  • proxy with squid
  • VPN, network monitoring, etc

I have installed a FreeBSD 8.1 system on vmware, to be used for building the NanoBSD images, which together with a null-modem serial cable  for connecting to the net5501 console, and a 4GB Sandisk CF card (yes, I know it is overkill, but it is just 3 euro more than 2GB, the smallest one I can buy) is all I need to give some new life to my Soekris Net5501 box.

Initially I had to update the FlashDevice.sub file with the parameters corresponding to my Sandisk CF card. The quickest way I found of getting the cylinders/heads/sector information for this specific card was to insert it in the Soekris device and boot it up. The BIOS shows the parameters for the inserted card when booting.

These are the different ways to customize a NanoBSD installation:

  • configuration settings that override the default values set within, as well as the kernel compilation settings that will be passed to the buildworld stage.
  • configuration files or scripts copied to the Files directory. The file system hierarchy created on the Files directory gets overlaid into the target root file system during the build, by setting customize_cmd cust_install_files. I got some interesting scripts from here.
  • packages for the software not included in the base system have to be copied to the Pkg directory. These packages will be installed into the target image by setting customize_cmd cust_pkg.

Any configuration changes on the live system need to be written into /cfg, as /etc is mounted on the md (malloc) disk and changes are lost on reboot. It is recommended to keep these changes synchronized with the configuration files in our main computer.

I built the image with

nanobsd –c

There were some issues with booting the CF card, the most annoying being that the boot menu was missing and always the partition 1 was chosen automatically. This issue seems to be caused by boot/boot0sio, so I went to use boot/boot0 instead:


Thus we get the corresponding boot menu after BIOS initialization:

1 Seconds to automatic boot. Press Ctrl-P for entering Monitor.

F1 FreeBSD

F2 FreeBSD


Boot: F1

Furthermore, the TERM environment variable has to match the setting on the terminal program used to connect to the serial console, otherwise there may be issues when displaying programs that use the whole terminal, like vi or sysinstall. I have used vt100 setting on minicom and putty, after updating /etc/ttys accordingly:

ttyu0 “/usr/libexec/getty std.9600” vt100 on secure

Finally, the NanoBSD images can be updated without removing the CF card from the box. In our setup, we have configured two identical partitions to be used alternatively when upgrading the software. When running from partition 1, /root/updatep2 is able to fetch and install remotely a new image on partition 2. Bear in mind there is currently an issue with boot0cfg in these update scripts.

ssh myhost cat _.disk.image.gz | zcat | sh updatep2

And now it is time to bury my head in the pf configuration book and install a bunch of services this box is screaming for.


Embedded World 2010 in Nuremberg was a great exhibition and conference. The trendy topics this year seemed to be Android and energy-efficient computing, with a myriad of vendors selling low-power embedded solutions. There were as well plenty of ARM related tools and chip vendors, with ARM getting bigger all the time. Also, an example of open source and proprietary software coexisting side by side: