We, as electronics enthusiasts, daily write hundreds of firmware code segments for various microcontrollers. Unlike software, when it comes to debugging microcontroller code, the challenges we face are much more fundamental. I believe that the most common method for debugging firmware is using the good old printf (just like the cout in C++ and println in Java).
When we develop conventional C code for Linux systems, printf works without any hassle. However, to enable the same functionality in microcontrollers, we need to peel away a layer in the C library and find out how exactly printf works.
How printf works?
As you may already know, printf function is implemented within the C library. I will not go through the full printf function definition. If you want you can read http://blog.hostilefork.com/where-printf-rubber-meets-road/. It’s one of the best write-ups I have seen.
However, the important part is, at the end of this function chain, printf calls another function called write. This is a standard system call in Linux, a part of kernel API. However, for microcontrollers, we don’t have such liberties and thus, we have to implement this function ourselves.
The standard implementation is as follows,
int
_write(int file, char *ptr, int len)
{
int DataIdx;
for (DataIdx = 0; DataIdx < len; DataIdx++)
{
__io_putchar(*ptr++);
}
return len;
}
This function basically accepts a character buffer as an argument and invokes another function for each character in that buffer. This new function is, as you can see, __io_putchar.
Let’s say your microcontroller has a UART module which can be used as standard input output module. For the time being, let’s assume that the module is properly configured. A psuedo implementation of __io_putchar looks like,
int __io_putchar(int ch){
uint8_t data = (uint8_t)ch;
UART_Transmit(data);
return 0;
}
For each character you have in printf above function will get invoked and the characters will stream out from the UART module.
This is what you need to do in three steps,
- Configure UART module
- Implement _write function
- Implement __io_putchar function
You are set to use printf as you wish now.
Please note that different toolchains might have different function prototypes for write and ioputchar functions. However, the underlying idea will be the same.
If you have any microcontroller or toolchain specific questions, please post them in the comments section.
Happy coding!
It is a great article with valuable info on microcontroller debugging.
Similar thing can be used in Linux device drivers as in below.
https://www.incrediblediy.com/2013/07/writing-and-testing-linux-kernel.html