Backchannel UART Without The UART

Anyone who has worked with a microcontroller is familiar with using printf as a makeshift debugger. This method is called tracing and it comes with the limitation that it uses up a UART peripheral. Believe it or not, there are 8051 variants out there that come with only one serial block and you are out of luck if your application needs it to communicate with another device.

[Jay Carlson] has a method by which he can piggyback these trace messages over an on-chip debugger. Though the newer ARM Cortex-M software debugger already has this facility but [Jay Carlson]’s hack is designed to work with the SiLabs EFM8 controllers. The idea is to write these debug messages to a predefined location in the RAM which the debugger can access anyway. His application polls a certain area of the memory and when it finds valid information, it reads the data and spits it out into a dedicated window. It’s using the debugger as a makeshift printf!

[Jay Carlson] used slab8051.dll interface and put together a C# program and GUI that works alongside the SiLab’s IDE. The code is available on GitHub for you to check out if you are working the EFM8 and need a helping hand. The idea is quite simple and can be ported to other controllers in a multitude of ways like the MSP430 perhaps. For those of you who like the Teensy, you might want to take a look at adding debugger support to the Teensy 3.5/3.6.

22 thoughts on “Backchannel UART Without The UART

  1. Nice! Make your own memory mapped peripherals… the debugger after-all is a big super complicated full memory mapped device. I’ve done something similar to this (using the hardware debugger) to expand a microcontroller running a racecar.

  2. Did someone just reinvent semi-hosting?

    “Semihosting is a mechanism that enables code running on an ARM target to communicate and use the Input/Output facilities on a host computer that is running a debugger.
    Examples of these facilities include keyboard input, screen output, and disk I/O. For example, you can use this mechanism to enable functions in the C library, such as printf() and scanf(), to use the screen and keyboard of the host instead of having a screen and keyboard on the target system.”

    Standard feature of ARM debugging over JTAG/SWD and similar functionality exists for many other chips too (e.g. Nordic, Renesas, apparently even some AVRs have something similar). Worth checking out the vendor tooling before starting to write it from scratch.

    1. No, it’s different.

      ARM semihosting is like a syscall mechanism, with a software breakpoint instruction replacing the software interrupt and a break triggered handler on the debugger end replacing the syscall ISR. If you want to print using semihosting on Cortex-M, you load a pointer to a string in RAM into R1, load 0x04 (SYS_WRITE0) into R0 to tell the debugger you want to print a null terminated string, then execute BKPT 0xAB to trigger the debugger to service semihosting. Code can be added to the hardfault exception handler to clean up after a failed semihosting call if the debugger isn’t around to service the BKPT.

      OP is using a debugger agnostic method of keeping a FIFO of debug prints in a fixed location, then periodically stopping the target to extract the FIFO contents. It’s a clever solution, with the only real down side being the execution time lost due to unnecessary polls and the RAM taken out for the FIFO.

        1. Semihosting is an ARM standard and is limited to ARM cores. It’s in most JTAG debuggers because ARM is ubiquitous. OP’s scheme should work with any architecture and debugger as long as the debugger is scriptable.

    2. Semihosting sucks as it interrupts the core while waiting for the debugger to catch up.
      Memory mapped trace is much better as you can execute the tracing code freely without being interrupted.
      One good example of it is Segger RTT, albeit it’s only for their supported cores (mainly ARM).

        1. I use ARM MCUs in a lot of designs, but there are certain “sweet spots” where 8/16-bit MCUs work really well (especially in deep-sleep applications, where nothing can touch these guys). And if we’re talking performance & features, the EFM8 is not your grandaddy’s 8051. Three-stage pipelined core running at up to 72 MHz, 5 timers, tons of analog (20 channels of ADC, 4 channels of DAC — all 12-bit), plus Silicon Labs designs it the same way modern ARM MCUs are designed: with an internal, 1.8V core regulator, so power consumption is really good only a few mA when running full speed — and down to 600 nA in sleep mode with the RTC running. Simplicity Studio, their IDE, is fantastic (with good code-gen tools built-in). Oh, and most of their 8-bit MCUs are less than $1. Spec-for-spec, they beat out any tinyAVR or PIC16 (the two big competitors among hobbyists in its price range). The STM8 (and maybe the RL78) are its real competitors, though the SAM D10 and STM32F0 are trying hard to shut down the whole 8-bit game altogether. Look for an upcoming blog post where I’ll do a $1 MCU round-up and explore this stuff!

  3. ” This method is called tracing and it comes with the limitation that it uses up a UART peripheral.”

    There’s more limitations than that, around timing…

    Lots of micros only have 1 uart. They also support debugging on separate dedicated headers, unless you are looking at very low end PIC’s.

  4. i use this same technique for regular “front channel” communication between an STM32 and a PC over USB, because the USB connection is only for STLink (“value line discovery” board). the PC stops the STM32, puts a command code in a designated address, lets it run for a second, stops it and reads the result packet from a different address.

    i was hoping this article was about a more elegant approach, a part of the STLink protocol i was unaware of. *sigh*

  5. Gee. If you’re close to the “metal” then you have access to not only memory, but GPIO, and of-course the single UART. There’s nothing stopping you from modifying the UART code to send you messages when something YOU decide to watch changes (yeah the output is often not-pretty). Of-course “modern” micro-controllers with proprietary bootloader/supervisor binary blob crap prevents you from doing this. If that’s the case then just disable the crap and bit-bang around it yourself. There’s always another way Script Kiddies!

Leave a Reply

Please be kind and respectful to help make the comments section excellent. (Comment Policy)

This site uses Akismet to reduce spam. Learn how your comment data is processed.