This article describes the µVision Debugger, the user interface for testing applications. Whether simulating or controlling the target device using a debug adapter, the debugging interface can be used in the same way. While debugging, developers have full access to the source code and can control as well as analyze program execution on C/C++ or assembly level.
Before we get started debugging we should connect our modules to ST-LINK/V2 programmer available in STM32 Nucleo boards as shown below:
The Serial Wire Debug (SWD) interface enables real-time debugging. You will need an STM32-compatible programmer/debugger (e.g., ST-LINK V2 or ST-LINK V3 or the Nucleo board) and a programming software tool (KEIL uVision IDE). Three module pads are needed for connection (plus GND): C (SWD Clock), D (SWD Data) and R (MCU Reset).
You will need to make the following connections between the programmer and the module (example provided for Nucleo programming header CN4):
- Pin 2 (starting up) >> C.
- Pin 4 >> D.
- Pin 5 >> R.
You need to connect GND between ST-LINK and the module. If your module is powered from a USB-UART cable connected to the same laptop that you connect the ST-LINK to, then, they both have a common ground and you might not need a separate GND connection.
Software vs Hardware Debug:
There are two methods to debug your program: software debug and hardware debug.
By using the software debug, you do not have to have the hardware board to debug a software program. However, the hardware debug requires you to connect the board to the computer.
Note:if you have more than one module and you want to debug both of them simultaneously (using two uVision instances) you need to check which is which by going to settings as shown below and selecting the right debug adapter.
Once you enter Debug mode, you should see the following interface.
1) Run, Stop and Reset your program.
- Run: Continues the execution from the current position until you click Stop or the program is paused by a breakpoint.
- Reset: will Reset your CPU.
2) Code Stepping:
- Step In: Execute one step and enter the function if the current step calls a function.
- Step Over: Execute one step and run the function all at once if the current step calls a function.
- Step Out: Execute until the current function returns.
3) Starting debug.
- Click the debug button to start debugging and click it again to exit debugging.
4) Watch windows: we will talk about it later.
- You can program the Hexabitz Modules flash by clicking the LOAD button .
- Click the debug button to start the debug and click it again to exit the debug.
- You can use the breakpoint button to set a breakpoint in either disassembly or source windows.
- Keil IDE allows up to six breakpoints during hardware debugging. However, ST-LINK debuggers allow only three hardware breakpoints. Other more-expensive debuggers give you access to more hardware breakpoints. When a program stops at a breakpoint, the corresponding instruction has not been executed yet.
The following table summarizes commonly used debug control buttons.
The memory window is used to view the memory content in real time. By default, the address of data memory (RAM) starts at 0x2000_0000. This is specified in the scatter-loading file (*.sct).
The following assembly program defines and allocates an array of four words. Each word consists of four bytes. When we type the memory address 0x20000000, we can see the content of this array.
The memory content is displayed in bytes by default.
By right click, we can select different display format. For example, we can show the content as unsigned integers.
Program counter (PC) r15 holds the memory address (location in memory) of the next instruction to be fetched from the instruction memory.
Stack point (SP) r13 holds a memory address that points to the top of the stack. SP is a shadow of either MSP or PSP.
xPSR (Special-purpose program status registers) is a combination of the following three processor status registers:
- Application PSR
- Interrupt PSR
- Execution PSR
- Base priority mask register (BASEPRI) defines the minimum priority for exception processing.
- Priority mask register (PRIMASK) is used to disable all interrupts excluding hard faults and non-maskable interrupts (NMI). If an interrupt is masked, this interrupt is ignored (i.e. disabled) by the processor.
- Control register (CONTROL) sets the choice of main stack or process stack, and the choice of privileged or unprivileged mode.
- Fault mask register (FAULTMASK) is used to disable all interrupts excluding non-maskable interrupts (NMI).
From the menu: Peripherals ⟶ System Viewer, we can view and update the control and data registers of all available peripherals. The following figures show all registers for GPIO Port A, such as mode register (MODER), output type register (OTYPER), Output Speed Register (OSPEEDER), Input Data Register (IDR) and Output Data Register (ODR). This provides great conveniences for debugging.
You may constantly view the contents of variables, structures, and arrays. Open the Watch Window from the View menu or with the toolbar. The Locals page shows all local symbols of the current function. The Watch #1 and Watch #2 pages allow you to enter any program variables as described in the following:
- Select the text <enter here> with a mouse click and wait a second. Another mouse click enters edit mode that allows you to add variables. In the same way you can modify variable values.
- Select a variable name in an Editor Window and open the local menu with a right mouse click and use the command Add to Watch Window.
- You can enter WatchSet in the Output Window – Command page.
To remove a variable, click on the line and press the Delete key.
Structures and arrays open on demand when you click on the [+] symbol. Display lines are indented to reflect the nesting level.
The Watch Window updates at the end of each execution command. You enable may enable Periodic Window Update in the View menu to update the watch window during program execution.