Debugging the i.MXRT1021 with SWO

A project log for MiCE47

The MiCE47 is a small Cortex-M7 + iCE40 development board with an i.MXRT1021 ┬ÁC and an iCE40HX8K FPGA.

KnusperkeksKnusperkeks 07/02/2019 at 11:070 Comments

Currently I'm working on the firmware of the µC, especially the USB stuff. I already had a working demo that runs bare metal on the chip and let's you program the FPGA. It worked fine, but the architecture was a bit messy so I decided to rewrite it and incorporate FreeRTOS. While using the MCUXpresso IDE, I realized that it provides some quite interesting runtime analysis features. Equipped with my new debug adapter (I bought a J-Link EDU after having some hickups with my NXP Link2) I was ready to go...deep into the rabbit whole.

On the MiCE47 pcb I put down a single row pin header that is inspired by the STM Nucleo boards. Along with power and ground it provides an SWD interface including SWO and an UART port - so far so good. I found a nice introduction from NXP on how to use SWO with MCUXpresso and some of their µCs. The user guide says I have to configure the pin mux in order to use the optional SWO output pin. This made absolutely sense to me, as I assumed it is shared with JTAG's TDO pin which would be unused in normal SWD operation. The reference manual of the i.MXRT1021 series does say the chip supports SWD (chapter 7.2), but does not list the SWD interface in the pin mux table (chapter 9.1.1) explicitly. If you look at the reference board for the i.MXRT1021, the SWD interface is connected to the OpenSDA (p.13) as one would expect: SWDIO → TMS and SWCLK → TCK. SWO is not supported by the OpenSDA so it is not used. I interpolated this information and concluded that SWO would be multiplexed with TDO (some/many other µCs do). This is unfortunately not the case! On the current i.MXRT series the SWO output is not the TDO pin. Do search the datasheet explicitly or look in the pin configuration tool within MCUXpresso! The newer reference boards (also the i.MXRT1015) support SWO directly and therefore provide a more useful schematic (just the i.MXRT1021 board does not). Luckily I had the necessary pin on my PMOD header so it is easily accessible.

According to the SWO user guide, the next step is configuring and enabling the trace clock which is used inside the core. The configuration can be done using the "ConfigTool" within MCUXpresso (→TRACE_CLK_ROOT) or by code. Enable the clock by calling:


Now connect your debugger correctly, initialize the debug mode, hit on a breakpoint after the clock and pin setup is done and click on the "SWO Trace Config". There you can change the clock speed either by entering or auto detecting (great, what could go wrong?), start your analysis mode of choice and resume your debug session. Congratulation, you have done everything you are expected to do, yet nothing will show up (at least not for me).

While searching for a solution, I found this awesome article which describes how to use SWO on an i.MXRT1064 board. I followed the guide beginning to end and was eager to finally get the damn thing working. Well, it didn't. I suspected some issue with MCUXpresso and the J-Link (the article uses the LPC-Link2) or bad karma because I don't use Windows. It turns out that the solution is quite simple. When you use the auto detect feature for the target clock frequency, it seems to read out the actual core frequency of the µC aka 500 MHz. The linked article shows a screenshot with a 600 MHz clock for the i.MXRT1064 so I assumed this would be right. It is not, at least for my setup with the J-Link! You have to enter the actual frequency for the "CM 7 Trace clock" (TRACE_CLK_ROOT) that you have configured earlier! In my case it is up to 132 MHz for the i.MXRT1021. That's all.

The article also says you should enable a TPIU clock by

*((uint32_t *)(0x400E0600)) = (1 << 11);  /* enable TPIU clock */

 I don't know what this really is about. According the the reference manual (at least on the i.MXRT1021) this memory address is reserved and I could not find any information in the Cortex-M7 header files nor the ARM documentation either. I tried to omit this line and it seems to work fine.