May 20, 2016

IDR: the secret sauce in SWD initialization on ARM Cortex M

There are a lot of Cortex M0 cores out there because it's so cheap and sucks up so little current.  But the flip side is that they have limited capabilities.  So one way to compose a fairly complex system is to control multiple M0-equipped peripherals (like the Nordic BLE chips) from a more powerful master uC (say an M4/7, which should just sleep most of the time).  But this approach engenders additional complexity: the FW update and operational control of the M0 from M4/7.  You could of course run the master uC as a serial interface master and the M0 as a slave.  But this eats into the precious serial interface ports on the master, and especially on the slave, which is already constrained in the number of serial interfaces (remember the cost is an important concern for the M0 uC).

Noting that ALL Cortex uC have SWD pins (they have to be programmed at some point after all), the master uC could control the slave by acting like a simple debugger HW (like the SEGGER JLink or the ST-link) over the SWD lines.  If you have never looked at the SWD at work, you are in for quite a learning experience.  But with patience and the 2 key references from ARM LTD (the ARM Debug Interface Spec v5 and the ARMv6-M Architecture Reference Manual), and example codes like the Open-OCD, you can pull this off.

Recently, I spent a long time figuring out why the SWD interface goes comatose after a hard reset or power cycle of the M0.  The go-to references and the example codes didn't show me that I was doing anything wrong.  It appeared that the M0 was returning status (in the CSW register) with DeviceEn bit = 0, but since I was already following the ARM recommended steps to initialize the SWD interface, I didn't know what else I had to do to make the M0 come alive.

Finally, I sniffed what JLink was doing, and waded through the hundreds of (undocumented) transactions it was doing with M0.  I noticed it was READING from the IDR (identification register).  When I inserted it into my code--at the end of the SWD debug domain power-up, M0 SWD DeviceEn bit was finally set to 1.  In all my searches for the CSW.DeviceEn bit or even the IDR register, I did not find 1 mention of this side effect of reading the IDR.  Perhaps someone can explain this undocumented (as far as I can tell) behavior of the Cortex-M0 debug core.

No comments:

Post a Comment