Low Level Debugging

If you are writing your code from scratch, you might need several iteration before having the result you aimed for. There is some tools you can use in order to debug a non working micro-controller

Breakpoint and watch

The first and maybe most instinctive way to check if a code is working as expected is to put a breakpoint at a critical line of code. In that way it is possible to check if the micro-controller is going through a certain instruction and to do a step-by-step execution of the code starting from the breakpoint.

A breakpoint is added by a double click on a line number in the code window. It can be added either during execution (debug session already started) or during editing. When a breakpoint is reached, the view jumps to the breakpoint's line and you will see the following view:

On the previous image you can see several interesting things. Firstly on the left, you can see that the code is currently executing the process() function, you can also see that this process function was called by HAL_I2S_TxHalfCpltCallback() and all the hierarchy of function call that lead to this current execution line.

On the center part of the screen you can see the green line, where the microcontroller actually stopped. The current position of the execution can be slightly different from the breakpoint location, particularly if the breakpoint is set on a line that was optimised during the compilation. It can also happen when the compiled code (assembly code) is too different from the C code, in such case an instruction can take several cycles to be executed.

Then on the right side, all currently available variables are displayed. The content of the variables are accessible, for example look at the input buffer in the following screenshot:

When the micro controller is stopped, you can either resume, or use the advanced stepping methods to continue the execution of the code.

Be careful, breakpoints can also lead to break the synchronization of your internal peripheral or even lead to serious hazard: Imagine, put a breakpoint in the control loop of a coffee machine, this could lead to stop the system with the heater on and you end up melting the whole thing because the control loop is not active.

For this reason, you might want to watch the internal state of your micro controller without stopping it. Modern IDEs usually propose live monitoring. In the case of STM32CubeIDE, there is a Live Expressions tab where you can watch global variables of your program and check their values as we have seen in the benchmaking section.

External tools

When interacting with peripherals that are external to the micro controller, the interaction will either be with digital signals (like in our case I2S protocol) or sometimes with analog signals (imagine if you where reading the analog value of an ambiant light sensor). In both cases you will need to assess if the input and output signals are consistent with what you expect.


To visualise signals, there usually are two possibilities: either a logic analyser or an oscilloscope. Nowadays oscilloscopes tend to also have logic analyser features. An oscilloscope lets you visualise a signal and perform measurements on it. For example you can see below an analog signal on top and a logic analyser with the I2S bus on the bottom of the screenshot.

In the past oscilloscopes had only 2 signals plotted on a cathodic screen with very few parameter available. Now with digital systems and particularly usb oscilloscopes the analysis possibilities are endless. We recommend using the Analog Discovery 2 digital oscilloscope as it gives a lot of IO's at a reasonable cent price compared to more conventional table top oscilloscopes.

Trigger setting

It is much easier to get an impression of how to handle the oscilloscope when signals are moving. For this reason we made two videos, one for the analog mode and one for the digital mode.

Last updated