Advanced debugging of MKS Robin Nano (STM32) board

If you need to debug your printer's firmware, you've probably read my previous post already. If not, I advice you to read it.

This post is about solving the remaining issues and/or shortcomings with the debugging so that a debugging session is 100% stable and reproductible.

Requirement

I'm focusing on MKS Robin Nano v1.2 board because it's what I have. The instructions below are generic enough to work on any board, but the provided bootloader file is specific to this board so you must not use it on any other board.

You need a ST-Link V2 USB dongle (or, if you have an older ST-Link dongle, it'll also work).

You need OpenOCD installed (see previous post for instructions)

What you'll obtain

After all the painful steps below, you'll get:

  1. An unlocked bootloader
  2. GDB will be able to reset the board without loosing the connection
  3. GDB will be able to upload a firmware (so no more SD card hacking & swapping after each build)
  4. 100% reliable debugging (access to protected registers from GDB is working, so you'll be able to dump flash content while backtracing code for example)
  5. Silent OpenOCD (all ST-Link V2 errors will be gone since most of them are due to the flash protection)
  6. Symbols! (since you can now run run in GDB, it'll reload symbols from the current ELF file so all symbols will now be found by GDB)

Situation

As you might have experienced already, debugging with ST-Link V2 is painful when there is a locked bootloader installed on the flash (default when you receive the board). It prevents you from manipulating the flash content (so you must copy the .BIN file to the SD card after each build, and set some specific "synchronization" point so that you can Ctrl+C in GDB later on and change state to continue). You have many limitation to the GDB commands you can use (like 'run' is not working correctly).

This all happens because of the lock state of the flash memory. This is a protection for STM32 microcontroller to prevent reading the flash content, and, as such, prevent loosing trade secret. Unfortunately, if you unlock the flash memory, the flash content is erased, so you're going to loose the bootloader. Without a bootloader, your board will no longer boot (or you'll need to modify a lot of stuff in internal Marlin core).

The stupid thing about this system is that the bootloader implement a feature to erase / read and write the flash, since it's able to update the firmware. So, nothing prevents a developer to write a software that's dumping the bootloader and saving it on the SD card, rendering the protection useless.

Don't worry, it was already done and I'm linking here the dump file so you don't have to go into a huge mess. The "official bootloader" from this source code repository does not work, it's just too big.

Beware that the bootloader binary above only work for MKS Robin Nano v1.2 board, if you have a different board, it'll fail and brick your printer.

If you have another board, you must locate a valid bootloader binary for it, feel free to add in the comment your bootloader.bin for your board.

Ok, now we have all we need, let's start hacking!

Step 1 : Unlocking CPU

STM32 has a protection system that, once activated, prevent external access to flash content. By external, I mean via JTAG/SWD. This protection has 3 levels:

  1. Level 0: No protection
  2. Level 1: Reads are not allowed, but the protection can be reset to level 0
  3. Level 2: Debug interface is disabled. There is no way to disable the protection.

If you are in the Level 2 case, bad luck. This is very unlikely, since it would mean that the bootloader would be a lot more complex. We are going to unlock the CPU so it resets to level 0. Doing so means erasing the flash, so make sure you have a valid bootloader .BIN file before attempting anything else, else you'll brick your board

Ok, so you'll need to trigger OpenOCD and start GDB (see previous post). Once in GDB, you'll need to connect to the board like this:

(gdb) tar ext:3333
blah blah : success
(gdb)

Then we need to send a command to OpenOCD directly, via the GDB monitor command:

(gdb) monitor reset halt
(gdb) monitor stm32f1x unlock 0
(gdb) monitor reset halt

The second line erases all the flash. This means that after calling this line, your board will no longer boot (unless you proceed to next step)

Step 2: Programming the bootloader again

Once the flash is completely erased, you'll need to flash the bootloader again. I'm doing this via the command:

(gdb) monitor program bootloader.bin 0x8000000
(gdb) monitor reset run

After the second command, the display on the printer should display its usual Booting with its ugly chime. If this does not work, you can use st-flash from st-util, basically you want to flash the bootloader.bin file at address 0x8000000 (that's the beginning of the flash address).

Step 3: Enjoy!

Ok, you've made the hardest work, let's explore what this gives you:

  1. You can run gdb on the ELF file so you'll have symbol and GDB will not be lost mapping them back
     (gdb) file .pio/build/mks_robin_nano35/firmware.elf
  2. You can restart a program and all previous breakpoint will be re-installed transparently, any change to the source firmware will be reloaded transparently
     (gdb) run
     Reloading source file because it has changed...
  3. You can flash a new binary directly from your debugger (beware: you must select a bin file and set the flash offset yourself or you'll erase the bootloader)
    (gdb) monitor program .pio/build/mks_robin_nano35/firmware.bin 0x8007000

Hope it helps!

Previous Post Next Post

Related Posts