Debugging¶
Starting simple¶
The easiest way to debug and also the way how all the things started was just print out whatever you consider important to know.
Wait the embedded system does not have any screen or printer connected.
Well you are right, but there used to be a serial port. And if it is hopefully free to use and can be connected to real PC then you have your first poor man’s debugger.
Core Module R2¶
Note
If you have older version of Core Module you can visit another chapter to see how to connect it with UART.
Core Module R2 have integrated FTDI chip connected to the UART2. You do not need to use separate serial converter, just connect USB cable to your computer.
Example code¶
You need to add just two function calls into your application:
twr_log_init
intoapplication_init
twr_log_debug
ortwr_log_info
ortwr_log_warning
ortwr_log_error
into handlers
Tip
Have a look into HARDWARIO TOWER SDK twr_log for more detailed info.
Example of modified src/application.c
from default project twr-skeleton
available at GitHub:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | #include <application.h>
// LED instance
twr_led_t led;
// Button instance
twr_button_t button;
void button_event_handler(twr_button_t *self, twr_button_event_t event, void *event_param)
{
(void) self;
(void) event_param;
if (event == TWR_BUTTON_EVENT_PRESS)
{
twr_led_set_mode(&led, TWR_LED_MODE_TOGGLE);
}
// Logging in action
twr_log_info("Button event handler - event: %i", event);
}
void application_init(void)
{
// Initialize logging
twr_log_init(TWR_LOG_LEVEL_DEBUG, TWR_LOG_TIMESTAMP_ABS);
// Initialize LED
twr_led_init(&led, TWR_GPIO_LED, false, false);
twr_led_set_mode(&led, TWR_LED_MODE_ON);
// Initialize button
twr_button_init(&button, TWR_GPIO_BUTTON, TWR_GPIO_PULL_DOWN, false);
twr_button_set_event_handler(&button, button_event_handler, NULL);
}
|
After flashing of Core Module execute terminal emulator, open serial port with USB UART and set communication parameters:
speed: 115 200 baud
8 bits, no parity (8N)
Example of output:
1 2 3 4 5 6 | # 4.54 <I> Button event handler - event: 0
# 4.84 <I> Button event handler - event: 1
# 4.84 <I> Button event handler - event: 2
# 10.24 <I> Button event handler - event: 0
# 12.24 <I> Button event handler - event: 3
# 13.64 <I> Button event handler - event: 1
|
For mapping number to event type have a look into HARDWARIO SDK documentation for twr_button
Read logs with PlatformIO¶
If you want to easily read the logs from the device, you dont have to install any additional program. You should read the PlatformIO installation to know how to install PlatformIO.
After you installed the PlatformIO you can use it for reading the logs from the device.
There are two ways to do it:
PlatformIO IDE
PlatformIO Core CLI
pio device monitor
in your favourite terminal if you have Platformio Core (CLI) installed

Caution
The serial monitor button does not build nor flash the firmware into the device so keep that in mind.
Getting more¶
Sooner or later when you are in troubles you might come to the idea that you want to look inside the CPU check the current values of registers or memory areas. Good news, you are not alone! Bad news, it’s not that easy as on x86 Borland Pascal compiler with embedded debugger and profiler.
Nevertheless there is a standard for that by IEEE, IEEE Standard 1149.1-1990 shortly called JTAG after the group that made the standard.
his standard is intended for those situations when you need to look inside. It is kind of periscope for your desktop PC into the MCU. It builds up on the other standard (fast) bus called SPI it adds some requirements for device (or function block inside device) to comply with. But not to overwhelm you with unnecessary details it gives you exactly that key hole view with capability to stop “time(r)” in order to give you a snapshot of the MCU.
Last but not least point to mention, that even JTAG has undergone evolution and ARM architecture has adopted the JTAG in “less wires* option named Single Wire Debug (aka SWD) which available in ARM based architectures including ARM Cortex M4 ~ STM32L series of MCUs.
From the developer’s point of view you should have working USB adapter that is recognized by your debugger (PC software like OpenOCD/Gdb/DDD or Segger’s Ozone). If I would simplify that even more you can connect any kind of interpret into the debugging abstraction that has capability to map your original C/C++ source code to code and data addresses if the target (MCU) and then on demand read the program counter (PC), stack poiter (SP) and pull the data from target and display them conveniently decoded for your elaboration.
It is worth to note that the debugger is also capable of setting data watch or instruction interrrupt set at particulat address to let you stop your programm and check registers/variables.
Note
Compared to PC where the debugger tends to be invasive i.e. single byte INT 3 instruction injection.
Growing beyond¶
The debugger might not be enough for dynamic or real-time debugging and certification. In such case you might need a tracing capability. The tracing compared to simple break debugging does not actually stop at the trace point. It rather collects data for later (off-line) analysis and continues in execution.
Those traces can also be optional or enabled just for a short period. Well this is because it might add some non-negligible overhead to power, CPU or memory consumption on heavy loaded system. Unfortunately these tools does not come for free and as they are not used that often they come little pricy.
Note
For those who have encoutered instrumentation in a PC form like SystemTap on Linux or DTrace at Solaris, BSD, Linux, these things might sound familiar
Tip
You can check those links for more information: