In my day job I develop hardware and firmware for sensor networks. Currently, I’m working on underwater acoustic MODEMs. The most recent design I made is a dual Kinetis K20 / ARM Cortex M4 based node which uses one M4 CPU as the system controller and the other as the core DSP/MODEM processor. The processors are daisy-chained via their JTAG interfaces for easy programming and debugging — or so I thought..
When the fully-populated PCBs returned from the board house a few weeks ago, there were some minor production issues but, on the whole, the board looked fine. After a visual inspection, I proceeded to try to load a test program into the CPUs using openOCD 0.7.0 and an Olimex ARM-USB-OCD-H.
OpenOCD correctly detected my two K20 devices on the JTAG bus but after that, it started spewing all kinds of “JTAG-DP STICKY” errors. Many hours of scope probing, source code staring and documentation reading later, it became clear that the K20 CPUs will reset themselves upon executing an invalid instruction and/or a watchdog time-out — nothing out of the ordinary here. However, the K20 CPUs will also drive their own /RESET lines!
In the design, I tied the /RESET lines of the CPUs together to make a single system reset. This is common practice and fits with the fact that JTAG interface pods only features a single /RESET line. In the case of two unprogrammed/blank K20s, things don’t work because when the first CPU comes out of reset for programming, the other will too. The second processor has no valid code and isn’t being controlled by openOCD. This results in invalid instructions being executed and a (global!) reset occurring. Needless to say, this isn’t good.
As a work-around, I developed my own flash programming firmware which works completely from RAM. The firmware disables the watchdog timer, performs a mass erase, set the flash protection bits, and flashes a small program that makes the processor go into a spin lock at start-up. Using openOCD, I can now flash valid code into the two CPUs simultaneously. For this to work, I also had to remove the ‘cortex_m3 reset_config’ line from the K20.cfg openOCD configuration file so openOCD will drive the /RESET pin, instead of producing a core interrupt for resetting.
From the openOCD mailing list, I see that more people are running into this /RESET problem on the Kinetis series and I suspect Freescale isn’t making friends with this /RESET driving business. Hopefully this post will prevent people from spending hours trying to figure out what is wrong with their Kinetis-based design, especially when two or more processors are linked using JTAG and share a common /RESET line.
I still have trouble programming the second Kinetis K20 flash when openOCD knows about the flash in the first CPU. The work-around here is to not define the flash for the first CPU. This “feature” is still present in openOCD 0.8.0 rc1 it seems.