Amateur radio and embedded systems

  • Best practices in firmware

    Across the years spent writing firmware I have come across techniques that have helped me with reliability, meeting delivery deadlines, and overall "debug quality of life". In this article I want to focus on developments practices and lifehacks that apply uniquely to firmware and avoid the ones that apply to "big" desktop or server software.

    This article will be updated as more ideas become crystallized so please add my blog to your RSS reader. 🙂


  • Connecting a high speed parallel ADC to SAM E70

    ADCs come in all shapes and sizes. Converters built into MCUs made great progress across the years but sometimes you need a dedicated discrete ADC. At the extremes of the "speed spectrum" there are "slow but precise" ADCs (that tend to use SPI or I2C), and absolute monsters with SerDes outputs that can only be consumed by an FPGA.

    My application needed an ADC from the middle ground but with multiple channels and simultaneous sampling. Interfacing a medium-speed multichannel ADC to an SAM E70 MCU turned out more interesting than I wished for. 😊


  • Triggering DMA from timers (or GPIO) on the SAM E70

    The SAM E70 is still a powerful MCU despite being released around 2015. It has a 300 MHz Cortex-M7, 150 MHz bus system and high-speed USB. High-speed USB (not the same thing as USB 2.0) is pretty rare in Cortex-M devices. It is usually the domain of much more powerful Cortex-A chips. When developing a data acquisition system on the SAM E70 I was surprised that there is no obvious way to trigger a DMA transfer from a timer!


  • Interrupt remapping on Cortex-M0 (and other small chips)

    Interrupt remapping is the ability to change the interrupt handlers at runtime. Why would you need to change handlers on the fly? During "normal" operation this is indeed unlikely. A simple branch like if (something){ handle1(); } else { handle2(); } in the handler is enough. Remapping is useful when there are totally different applications running. For example a manufacturing test application and a regular application, or a bootloader and the application.


  • Lifehack: detecting debugger connection for Cortex-M0 & Ozone

    I find it useful to be able to detect from firmware if a debugger is attached. For example when an assertion fails I can use a simple __BKPT(123); to stop the code and immediately inspect everything manually in the debugger. In the field I would rather prepare debugging breadcrumbs and reset. Of course having two different firmware behaviours comes with its own risks. For example enabling debug output can affect timings and make some bugs (dis)appear. However, when hunting bugs this is also an important information on its own.


  • Reducing Home Assistant RAM usage

    I tried running Home Assistant with zigbee2mqtt on an A20 OLinuXino board that has only 1 GB of RAM. Startup and initial operation was okay but after a random while (days) the system locked up and become unreachable over the network. Without Home Assistant the board was running okay for weeks so I guessed that it must have been RAM usage.


  • Very simple stack overflow detection for Cortex-M and RISC-V

    There are many ways of detecting and dealing with stack overflow in embedded systems. Here is a very, very easy stack canary with minimal overhead that can be used on Cortex-M and RISC-V with GNU and LLVM toolchains.


  • Yet another autossh tutorial

    SSH remote port forwarding is very useful to access machines behind firewalls and NATs. The ssh client connects to the server (the server must be publicly reachable). The server then starts listening on ports requested by the client and passes the traffic to the client. To the outside world this looks like the public machine has extra services running.

    I find this scheme especially handy to access devices connected using 5G. Mobile networks almost never provide public IP addresses and use CGNAT unless you are a big business customer.


  • Abusing reserved interrupt vectors on Cortex-M for metadata

    Bootloaders in embedded systems need a way to tell if there is a valid application available in memory. Executables on devices with an operating system use elaborate file formats like elf and exe but small bare-metal bootloaders need something simpler to keep both the bootloader size and the application size small. In this post I present the simplest possible scheme - a single CRC32 checksum appended to a raw binary file and how to do it.


  • Wiznet W7500 flash programming

    W7500 is a nice little MCU from Wiznet with a built-in hardware TCP/IP stack and Ethernet MAC. You can get quite far with your IoT application on a Cortex-M0 running at 48 MHz when the networking is offloaded in hardware. The device begins to show its age in 2023 (it was released around 2016). There is no crypto acceleration whatsoever, no AES. Only an RNG is available. I think that modern TLS is practically impossible but some lighter cryptography should be possible. Nevertheless, if you can put the device on an isolated VLAN the chip can still be useful today.