I've been doing some work recently with a little Silicon Labs EFM8UB3 microcontroller. This is a nice 8051 clone with a bunch of peripherals all in a QFN24 package. I've been using a minimal development board Silicon Labs calls the Thunderboard. It's mostly fine, but it has one failure mode that's pretty annoying. This article is about how to back out of that failure mode if you encounter it.
The Thunderboard has a built-in JLink debugger, and it's unfortunately possible to put the MCU into a state where the debugger can't talk to it. That means that you can't program the board any more, so you might think you're stuck. You're not!
This is an intermediate form of "bricking" a device. It's worse than accidentally deleting a bootloader (just reflash the bootloader: you do have access to the programming interface for your device on your development board, don't you?). It's not as bad as letting the magic smoke out of your MCU (if you do that, your best debugging tool is a credit card...). Your MCU is still alive, it's just unresponsive to the debugger.
The problem, as I understand it so far
I've not quite yet worked out what's going on here, but here's my understanding so far:
- Your MCU really is alive, and when you reset it, it starts executing code as usual.
- Soon after reset, there's something in your code that screws up the debugger connection. It seems usually either to be to do with putting the device into a low power mode, or misconfiguring the clocks.
- The debugger isn't fast enough to get in and halt the processor before it gets into this stuck state.
So you're left with an MCU that is really perfectly fine, but you can't do anything with it using the JLink debugger on the Thunderboard. Annoying, eh?
Never fear! There is a way out. Table 4.3 on page 19 of the EFM8UB3 datasheet has the following information:
So after reset, we have a gap of around 50 μs before the processor starts executing code, and if it's a power-on reset, at least 3 ms, and more likely about 10 ms. Can we get in and halt the processor during that time window?
We're obviously out of luck with the JLink, but we can use the C2 programming interface on the EFM8UB3 directly.
Unbricking with an Arduino
Instead of using the on-board JLink debugger, we can twiddle the C2 clock and data lines ourselves. The easiest way to do this is to hook the Thunderboard up to an Arduino or similar. I used an Arduino MKR WiFi 1010 board, just because that's what I had lying around, but more or less any Arduino-compatible board should work with the unbricking software described below. I plugged both the Arduino and the Thunderboard into a breadboard and made the following connections:
|Digital pin |
|Digital pin |
The Thunderboard is a little bit wide for a standard breadboard, so you may end up doing what I did and routing the ground wire out from underneath the board. My setup looks like this:
We need some software to twiddle the C2 clock and data lines. The C2 algorithm is partially documented in Chapter 23 of the EFM8UB3 reference manual and in more detail in application note AN127: Flash Programming via the C2 Interface, but fortunately, Conor Patrick has already done most of the work for us, by writing a flash programmer for EFM8 devices (conorpp/efm8-arduino-programmer) that uses an Arduino to communicate over the C2 interface.
I took Conor's code and chopped out the parts that I needed and built an "unbricker". You can find the source here. Here's what it does:
You kick it off by giving a command over the Arduino's serial interface. That's just there to give a positive feeling of starting the unbricking process so there's no uncertainty over whether you've actually run the thing...
The C2 connection to the MCU is initialised. This works by resetting the device, then immediately writing the C2 command sequence that halts the device. The idea here is to pull the reset line low for 50 μs, which is long enough to trigger a reset, then to get in quick with the C2 initialisation sequence before the post-reset delay expires and the MCU starts executing code (the code that breaks the debugger!). The only change I've made to the
efm8-arduino-programmercode here is to reduce the time that it waits after letting bringing the reset pin high after reset, just to give more of a chance to get in before the MCU runs bad code.
Once the MCU has been halted by the C2 initialisation sequence, you can do more or less what you want with it. For the unbricker, I keep things simple and just erase the flash on the device. If that's successful, then the MCU is more or less in a "factory fresh" state and the JLink debugger will be able to connect to it with no problem.
So the procedure is:
Connect up your Arduino and Thunderboard as described above.
Make sure the "Power Source" selection switch on your Thunderboard is set to "
unbricker.inosketch to the Arduino.
Start the Arduino's serial monitor and send an "
Disconnect the Thunderboard from the Arduino and connect to the debug USB port as usual. You should now be able to reprogram the Thunderboard using JLink Commander or whatever other programming software you use.
To test an unbricker, you obviously need a reliable way of bricking the thing. The first time I got a Thunderboard into this state, it took me a while to figure out what had happened. Long enough that I'd completely forgotten what I'd done to mess things up in the first place...
I ended up writing a little "
brick-it" program that does some
slapdash clock configuration on the EFM8UB3 that seems to reliably put
the thing in a state where the JLink debugger can't talk to it. (I
still don't understand 100% what's going on here, but I've seen this
problem mostly when trying to enable the 48 MHz HFOSC1 oscillator on
the EFM8UB3. I'm doing something wrong there, for sure, but it's
allowed me to build a reliable means of bricking a Thunderboard, so I
don't feel too bad about it!)
I've included the source for the
brick-it program in the unbricker
repository, but you probably don't want to run it on purpose. It's
useful for testing the unbricker, but that's about it.
Actually, one other thing it might be useful for is to learn what kinds of messages your programming tools display when you connect them to a board that's bricked this way. I use JLink Commander for programming my Thunderboard, and when I try to connect to a bricked board, I get messages that look like this (mostly including these here for the benefit of people who might Google for them):
Connecting to target via C2 DevID, DerivID: 0x36, 0x00 Core: CIP-51 (8051 compatible) Device series: <Unknown> series device CPU supports 4 code breakpoints Flash infos: 512 byte sectors, 80 sectors, all sectors unlocked DevID, DerivID: 0x36, 0x00 Core: CIP-51 (8051 compatible) Device series: <Unknown> series device CPU supports 4 code breakpoints Flash infos: 512 byte sectors, 80 sectors, all sectors unlocked ****** Error: EFM8 (C2): Unsecure failed. DevID, DerivID: 0x36, 0x00 Core: CIP-51 (8051 compatible) Device series: <Unknown> series device CPU supports 4 code breakpoints Flash infos: 512 byte sectors, 80 sectors, all sectors unlocked ****** Error: EFM8 (C2): Connect failed and connected J-Link (S/N 440110519) does not support fallback method (firmware too old). Please get in touch with SEGGER EFM8 (C2): Unsecure failed. Cannot connect to target. Target connection not established yet but required for command. Device "EFM8UB31F40G" selected.
If you ever see something like that, your board might be in this state, and you might be able to recover it using the method described here.
I have so far found the Arduino unbricker sketch to be 100% successful in recovering a Thunderboard that's in this state. I believe that it should also work for other early start-up misconfiguration issues (putting the MCU to sleep in a low power mode right after reset, for example). It may also work for other EFM8 parts, but I have only tested it with the EFM8UB3 Thunderboard, so YMMV.
OK, board unbricked! Back to work! Now I need to figure out how to set these clocks the way I want them without breaking things...