Debug and Log¶
Overview¶
Debugging an embedded system can be done in multiple ways. For Moto Mod basic logging can be done along with using a Joint Test Action Group (JTAG) or Serial Wire Debug (SWD) debugger. For convenience and to keep development costs low the MDK comes with an integrated FTDI4232which can be used for both JTAG and SWD as well as UART logging. This document will cover how to use this for JTAG to the Motorola High Speed Bridge (HSB) ARM Cortex M3 as well as SWD for the Mods Microcontroller (MuC) ARM Cortex M4.
Using GNU DeBugger (GDB) with the FTDI via OpenOCD is covered in this document. GDB will use a socket to communicate with OpenOCD, which will communicate with the target through the integrated FTDI4232. The FTDI4232 will emulate JTAG for the Moto Bridge and emulate SWD for the MuC.
Connecting to the FTDI for JTAG or SWD requires the following:
- PC Running Linux
- USB Type C cable
- GDB ARM (See Setup Your Development Environment for installation)
- OpenOCD (See Setup Your Development Environment for installation)
In order for the debug Type C connector to power the phone the DIP Switch B4 must be in the on position. See the MDK User Guide for more information on the hardware including the DIP switches. The DIP Switch locations are called out in the figure below:

Document Conventions¶
Commands are presented in text boxes within the document. The prompt within the box indicates which tool the command is to be used with.
- The following box and command prompt is used for commands executed on the command line (in a terminal emulator):
- The following box is used for command issued within the OpenOCD telnet session:
- The following box is used for commands issued within GDB:
- A hash mark (‘#’) within any of the command windows indicates a comment and does not need to be issued on the command line.
- Filenames which need to be filled in when the command is executed are indicated as
. - Commands and paths listed within the text will are in a
fixed widthfont.
Debugger Usage¶
Connecting to the Target¶
The procedure for connecting to the target is as follows:
- Connect your host to debug port USB #1 with a USB Type-C cable
- Start OpenOCD to communicate with the target
- Start GDB and connect to the OpenOCD target interface of either the MuC or MHB
- Configure hardware specifics for breakpoints and watchpoints
- Load symbols into GDB
- Optionally, load the code onto the target flash or RAM
NOTE: Sleep mode on the MuC complicates the connection procedure because the internal debug hardware may be powered down. The simplest fix is to disable power management mode by disabling CONFIG_PM in the MuC defconfigfile. If it cannot be disabled, the MuC will exit sleep mode when receiving characters over the MuC nuttx shell. The MuC nuttx shell is attached to Port C of the FTDI4232. Simply attach to the USB UART for Port C via a terminal emulator and send characters (“enter” works well) during the connection procedures. See the section “Accessing the MuC nuttx Shell” below for more details.
Starting OpenOCD¶
The following commands are used to start OpenOCD:
Starting OpenOCD Server for the MuC without Resetting¶
This procedure will attach to an already running MuC. You will need to be sure the MuC is not in low power sleep mode when attaching.
Starting OpenOCD Server for the MuC with Reset¶
The reset configuration will reset the MuC during the connection phase of OpenOCD. The reset will guarantee the MuC is not in low power mode. The side effect of this is that the current MuC state will be lost.
For the MuC the default OpenOCD port is 3333 for GDB and 4444 for Telnet.
Starting OpenOCD Server for the Motorola High-Speed Bridge¶
For the MHB the default OpenOCD port is 3334 for GDB and 4445 for Telnet.
The following scripts are involved in the startup process for OpenOCD:
| Script | Location | Description |
moto_mdk_hsb.cfg |
openocd/tcl/board |
Main configuration for the Motorola High-Speed Bridge. Includes the dependant files. Changing port numbers can be done in this configuration file. |
moto_mdk_muc.cfg |
openocd/tcl/board |
Main configuration for the MuC. Includes the dependant files. Changing port numbers can be done in this configuration file. |
moto_mdk_muc_reset.cfg |
openocd/tcl/board |
Same as moto_mdk_muc.cfg except this script performs a reset of the MDK before SWD attach. |
moto_mdk_muc_common.cfg |
openocd/tcl/board |
Contains the common code and defines for the normal and reset MuC configurations. This includes the routines needed to enable and disable TSB SPI flash. |
hsb.cfg |
openocd/tcl/chip/motorola |
Configuration for the Motorola High-Speed Bridge. |
moto_mdk_jtag.cfg |
openocd/tcl/interface/ftdi |
Configuration of how the onboard FTDI chip communicates over JTAG. |
moto_mdk_swd.cfg |
openocd/tcl/interface/ftdi |
Configuration of how the onboard FTDI chip communicates over SWD. |
moto_mdk_swd_reset.cfg |
openocd/tcl/interface/ftdi |
Same as moto_mdk_swd.cfg except this script performs an FTDI reset of the MDK during configuration. |
stm32l4x.cfg |
openocd/tcl/target |
Configuration file for connection to an STM32L4x series ARM Cortex M4. Includes convenience function definitions. |
Starting GDB¶
Once OpenOCD is up and running, the next step is to start GDB:
After starting GDB you must connect to the remote target and configure hardware specifics for watchpoints and breakpoints. If you are running the debugger interface server (OpenOCD) on the same machine as the target, then you can simply connect to the correct port on the localhost. If you are running it on a different machine then you will have to specify that machine's name or ip address in instead of "localhost" below:
Connecting GDB to the MuC¶
Connecting GDB to the Motorola High-Speed Bridge¶
(gdb) target extended-remote localhost:3334
(gdb) set remote hardware-breakpoint-limit 6
(gdb) set remote hardware-watchpoint-limit 4
Loading the Code and Symbols¶
For systems which have the code in flash memory, the symbol table must be loaded. It is also possible for the debugger to directly load the code into RAM or FLASH.
Loading Symbol Table Only¶
Use the following command to load the symbols into the debugger manually:
Where <elf file> will be either nuttx, or boot_hdk.elf.
If you are developing your own Moto Mod, you may have created your own target. If so, use those files in place of the ones listed above.
Loading Code¶
If you have not placed the code into the phone’s file system to be automatically loaded, it may be desirable to have the debugger load the code into the HSB RAM or the MuC flash. To do this in GDB, first run the file command as stated in “Load Symbol Table Only” section. Once symbols load, run the following command to load the code into RAM on the HSB or FLASH on the MuC:
Additional GDB Setup¶
Once the code and/or symbols are loaded some additional steps may be required to debug the target. Use the following gdb commands as needed for your setup.
The default OpenOCD configuration will connect to a target which is already running. This can be changed by adding a halt command to the end of the moto_mdk_hsb.cfg. However, in most cases leaving the target running until the problem being debugged happens may be the best option. In this case gdb needs to be told that the target is running after gdb is started:
If breakpoints will be used, the watchdog timer on the HSB should be disabled. If it is not the target may reset itself when the watchdog timer expires. This must be done after the all initialization code on the HSB has run. If connecting to an already running target this initialization will most likely be completed once gdb attaches to OpenOCD. It is also recommended that a breakpoint be set at up_assert to allow for debugging of exceptions. To disable the watchdog and set a breakpoint at up_assert use the following sequence:
Please be aware the watchdog on the MuC will automatically stop when the MuC execution is halted, thus no disable code is needed.
Python Enable GDB¶
GDB can be built with support for Python scripting. This is useful to add commands which cannot be handled with simple GDB scripting. A few commands to help with nuttx debugging are included in the file $BUILD_TOP/nuttx/nuttx/tools/gdb_nuttx_data.py. See “Useful GDB Commands” or take a look at the file for the commands supported.
To see if Python is enabled in GDB run:
If the line --with-python=(whereis a path to Python) shows up, Python is enabled. To load the Python script run:
Useful GDB Commands¶
The table below lists useful GDB commands. For the Python based commands to work the gdb_nuttx_data.py script must be loaded. See “Python Enabled GDB for more details.
| Function | Command | Description | Location |
| Dump Memory | dump |
Dumps size bytes from the address or symbol provided in both hex and character format. Where:
|
Python |
x/<n><f><s> |
Dump n memory units of size s with format x. Where:
|
GDB | |
| Dump Nuttx Log | dump syslog |
Prints the nuttx system log. | Python/Nuttx |
| Dump reglog | dump reglog |
Prints the register log if it is configured in the nuttx build. | Python/Nuttx |
| Dump HSB I2S Regs | dump i2s |
Prints the contents of the HSB I2S registers. | Python/HSB |
| Dump Registers | info regs |
Dumps all registers, Can specify which ones after the command. | GDB |
| Disassemble | disassemble /m <address> |
Disassembles the code and mixes in the high level source at address. Where:
|
GDB |
| Heap Info | print g_mmheap |
Prints the raw nuttx heap data. | Nuttx |
| Stack Backtrace | backtrace |
Prints the stack backtrace with local variables included. | GDB |
| Dump Locals | info locals |
Prints the known local variables from the stack/registers. | GDB |
| Symbol | info symbol <address> |
Gets the symbol name for the given address. | GDB |
info address <symbol> |
Gets the address for a symbol. | GDB | |
| Start Execution | cont |
Starts execution at the current program counter. | GDB |
| Set Breakpoint | break <address> |
Sets a breakpoint at the address or symbol provided. | GDB |
| Set Watchpoint | watch <address> |
Sets a watchpoint at the address provided. Please note if can-use-hardware-watchpoint is not set or too many watchpoints are in use this will be very slow. | GDB |
| Print Variable | print/<f> <address> |
Print a high level variable. The / is optional. | GDB |
| Display uC Memory Map | info mem |
Displays the memory map for the remote target. | GDB |
| Turn off press to continue | set pagination off |
Turn off the prompt to press any key to continue. | GDB |
| Array Printing | set print array on |
Print arrays a little nicer. Where:
|
GDB |
NOTE: When specifying addresses in gdb they must be prefixed with an ‘’ for example to set a breakpoint at address 0x10000000 the command ‘break 0x10000000’ must be used.
Standalone OpenOCD¶
As mentioned previously, OpenOCD can be used in a standalone mode. To communicate with it you must open a telnet session:
# Start openocd for the MuC
$ openocd -f board/moto_mdk_muc.cfg &
$ telnet localhost 4444
# Start openocd for the HSB
$ openocd -f board/moto_mdk_hsb.cfg &
$ telnet localhost 4445
Once attached, a full list of commands can be obtained using the help command. Some useful commands are listed below for quick reference. For a complete list with descriptions, please see the OpenOCD online documentation.
| Function | Command | Description |
| Memory Display | md<size> <address> <count> |
Display the memory at <address> for <count> units of <size> where <size> is:
|
| Memory Write | mw<size> <address> <data> |
Write <data> of <size> to the memory at <address> where <size> is:
|
| Memory Modify | mm<size> <address> <set> <clear> |
Set the bits in <set> and clear the bits in <clear> at <address> where <size> is:
|
| Erase MuC Flash | stm32l4x mass_erase 0 |
Erase the entire MuC flash including the bootloader. Please note the last 0 is for bank 0, however all banks on the STM parts are mapped to page 0. |
| Program MuC Bootloader | flash write_image erase unlock mods/bin/boot_hdk-p2_mhb.bin 0x08000000 |
Write the bootloader to the MuC. |
| Halt Execution | halt |
Stops the execution at it’s current location. |
| Resume Execution | resume [address] |
Resume execution at the current program counter or address if specified. |
| Breakpoint | bp <address> |
Set a breakpoint at <address> |
The following commands are defined in moto_mdk_muc_common.cfg and can be used when debugging the MuC only:
| Function | Command | Description |
| Power HSB On | hsb_pwr_on |
Power up the HSB and take it out of reset. |
| Power HSB Off | hsb_pwr_off |
Power off the HSB and assert the reset line. |
| Enable HSB Flash | hsb_flash_enable |
Move the HSB SPI flash from HSB control to MuC control. |
| Disable HSB Flash | hsb_flash_disable |
Move the HSB SPI flash from MuC control to HSB control. |
| Reset the HSB | hsb_reset_assert |
Assert the HSB reset line. |
| Run the HSB | hsb_reset_deassert |
Take the HSB out of reset. |
| Read the HSB flash | hsb_flash_read <filename> |
Enables the HSB flash and reads it into a binary file <filename> |
| Erase the HSB flash | hsb_flash_erase |
Erases the entire HSB flash. |
| Program the HSB flash | hsb_flash_program <filename> |
Enable the HSB flash and program it to the contents of the binary file <filename>. |
Flashing via OpenOCD¶
Programming the MuC Bootloader¶
The Moto version of OpenOCD includes support for programming both the MuC internal flash and the HSB SPI flash. Programming of the bootloader in the MuC flash can be done with the following command run in the OpenOCD telnet session:
Programming the HSB from the MuC¶
Programming the HSB SPI flash is a bit more complicated. The SPI flash is connected to both the MuC and the HSB. This is done so that it can be reprogrammed through the MuC during normal operation. To complicate matters further JTAG support is disabled when the HSB boots and is enabled by the code in the SPI flash. As a result it cannot be flashed through JTAG on the HSB when the flash is blank or not booting correctly. To program the flash on the HSB through the MuC use the following series of commands from the MuC OpenOCD telnet session:
> halt
> hsb_flash_enable
> flash erase_sector 1 0 2047
> flash write_bank 1 $BUILD_TOP/nuttx/nuttx/nuttx.tftf 0
> hsb_flash_disable
A shortcut command to program the flash is also available in the MuC OpenOCD telnet session:
Programming the SPI flash from the MuC can take 2 minutes or longer. Reading can take 11 minutes or longer. If you are working with the HSB flash on the MuC, and you do not run hsb_flash_enable, the command may not flag an error, but the result will not be what is desired. For example you will be able to read the flash with flash read_bank, but all zeros will be returned.
Programming the HSB from the HSB¶
To reprogram the HSB SPI flash via HSB JTAG the following commands can be used over the OpenOCD telnet session. As noted above, JTAG is enabled in the HSB SPI flash code, this cannot be done if the HSB has not fully booted or is blank.
Depending on the firmware loaded into the MuC it may attempt to restart the HSB when debugging or flashing. To avoid this simply start an OpenOCD debugging session on the MuC and halt execution. It can then be resumed when the HSB debugging is completed.
Logging¶
Accessing the MuC nuttx Shell¶
Logging done on both the Motorola High-Speed Bridge (MHB) and the MuC can be accessed through the nuttx shell running on the MuC. The MHB InterProcess Communication (IPC) is used between the MuC and the MHB to move log data from the MHB to the MuC. Since the serial port on the MHB is used for IPC, the serial port is not available for nuttx communication.
The Reference Moto Mod includes an FTDI4232 to handle both JTAG/SWD debugging as well as UART to USB translation. The FTDI is attached to the debug USB Type C connector (USB #1) on the HDK. When it connects to a PC, the following will enumerate:
| Purpose | FTDI Port | |
| MuC Serial Wire Debug | A (if00) | /dev/ttyUSB<n> |
| APBE JTAG | B (if01) | /dev/ttyUSB<n+1> |
| MuC nuttx Shell | C (if02) | /dev/ttyUSB<n+2> |
| APBE-MuC IPC | D (if03) | /dev/ttyUSB<n+3> |
To determine the value of n use ls /dev/ttyUSB* on linux and check for new entries after plugging in the device. The following command can also assist in determining which ttyUSB the FTDI ports are connected. Match the FTDI Port from the above table to the FTDI_Quad_RS232-HS-if??-port0 string produced by the following command:
$ ls /dev/ttyUSB* | xargs -I{} bash -c 'echo -n {}": "; udevadm info --name={} |grep " serial/by-id" |tail --bytes +21'
For the MuC nuttx shell, communications parameters must be set up as:
| Parameter | Value |
| Baudrate | 115200 |
| Data Bits | 8 |
| Parity | None |
| Start Bits | 1 |
| Stop Bits | 1 |
Before using a serial console on a Linux environment, you will need to provide your account access to the serial devices on your computer.
You will need to log out and log back in to apply the permissions. You will also need a terminal emulation program. Picocom is available on most Linux distributions and provides a simple interface. It is not installed by default. To install Picocom:
After attaching the debug USB-C connector to the USB #1 port, you will have four additional tty devices added to your system. Start Picocom as follows replacing [ttyUSBx] with the appropriate interface from the above steps:
Enabling Moto High Speed Bridge Debugging¶
To access the HS Bridge’s debugging capabilities from the MuC Nuttx shell you need to enable the corresponding command-line app in the MuC's defconfig.
To do this, use the menuconfig tool (make menuconfig) and navigate to:
This will add the following config items to your .config file:
Low Level Logging¶
The nuttx baseline comes with simple printf-like logging built in. The following functions can be used to log data with this method:
| Function | Notes |
lldbg(fmt_str, …) |
Logs the string using standard printf formats. |
llvdbg(fmt_str, …) |
Logs the string using standard printf formats only if CONFIG_DEBUG_VERBOSE is defined in your defconfig file. |
Please be aware that it takes time to print the string and convert any numbers provided to ASCII. Please refrain for using these in an interrupt context.
The method to retrieve the log depends on which system is in use. The following table outlines the procedure for retriving the logs through the debug connection:
| System | Log Retrieval Method |
| Moto Bridge | On the MuC in the nuttx shell run:apbe log |
| MuC | On the MuC in the nuttx shell run:cat /dev/ramlog |
| GDB Python Enabled and Loaded (See JTAG/SWD documentation for more details) | On the GDB command line run:dump syslog |
| GDB Python Disabled (Will print the log out of order, but is better than nothing.) | On the GDB command line run:print g_sysdev.rl_buffer |
Advanced reglog Logging¶
Delays introduced through logging to a serial port can disrupt the realtime requirements of your code. To assist in these cases, the Moto Mods nuttx baseline includes a simple logging referred to as reglog. This was originally developed to log the time, address and value of register reads and writes and is very light-weight in processing. Reglog is also useful for general-purpose logging in time-critical code.
To do this, use the menuconfig tool (make menuconfig) and navigate to:
This will add the following config items to your .config file.
Once it is enabled code can be instrumented with:
As mentioned previously address and value were originally intended to be register addresses and values, but they can be any uint32_t values. Only 3 uint32_t values will be added to the log:
- 48 MHz time value at the time of the call
- The address value
- The data value.
Depending on which processor is being used the method for retrieving the log differs. This is because the NuttX shell on the Moto Bridge cannot be directly accessed. For the Moto Bridge, MHB must be used to retrieve the values.
| System | reg log dump method |
| Moto Bridge | In the MuC nuttx shell run:apbe diag reglog |
| MuC | In nuttx shell run:cat /dev/reglog |
| GDB Python Enabled and Loaded (See JTAG/SWD documentation for more details) | On the GDB command line run:dump reglog |
| GDB Python Disabled (This will output the array, which will not be in since it is a circular buffer.) | On the GDB command line run:print/x g_reglog |
The reglog code is capable of running in a Stack mode and a FIFO mode. By default it will startup in FIFO mode. In FIFO mode the code will treat the buffer as a circular buffer, so all calls to reglog_log will result in an entry being written. However, only the latest entries will be retained, due to the limited size of the buffer. If you need data at the start of a run Stack mode should be used. In this mode when the end of the buffer is reached reglog_log will stop adding entries. To switch between modes use the following commands:
| System | Stack Mode | FIFO Mode |
| Moto Bridge | In the MuC nuttx shell run:apbe diagreglog_stack |
In the MuC nuttx shell run:apbe diagreglog_fifo |
| MuC | In the MuC nuttx shell run:echo “stack” > /dev/reglog |
In the MuC nuttx shell run:echo “fifo” > /dev/reglog |
| GDB | set var g_reglog.mode = 1 set var g_relog.head = 0 set var g_reglog.tail = 0 |
set var g_reglog.mode = 0 set var g_relog.head = 0 set var g_reglog.tail = 0 |