Using GnuK with DFU bootloader

Peter Lebbing peter at
Fri Dec 28 20:08:13 CET 2018

Hello Niibe!

On 26/12/2018 06:53, NIIBE Yutaka wrote:
> Thanks for your fixes.  I merged and released Gnuk 1.2.13.

Thank you, it's much appreciated!

> As I added a comment in the commit log, we should know that this reset
> event in the first run uses old RESET vector.  This does not go through
> newly written SYS.  Thus, the VCR register keeps its old value.  When
> there is no power cycle, after reGNUal's reset, it might go wrong place.

I've been investigating this when I had free time during the congress.

I think that it's not the case that the NVIC system reset actually uses
a relocated vector table to find the reset vector! It is my
interpretation that on NVIC system reset, the VCR register is cleared to
default and the vector at 0x0000 0004 and MSP at 0x0000 0000 are taken.
I've found statements on reset and reset vector in the following

Programming Manual (PM0056):
- Page 15 -> Stack pointer and Program counter
- Page 32 -> Reset
- Page 15 -> Directly below figure
- Page 133 -> Vector table offset register reset value
Reference manual (RM0008):
- Page 90 -> System reset ("resets all registers to their reset values
  except...") and they explicitly group 'Software reset' under this type
  of reset.

And this is also what seems to happen when nvic_system_reset() is
invoked from device_initialize_once(), as the following gdb trace seems
to indicate. Now, debugging over reset is a bit funky, openocd drops the
connection for a moment (fraction of a second), but the program counter
when it picks up again is where it would be for the vector at
0x0000 0004.

The break at 0x80031d8 is at main.c:154, the call to nvic_system_reset
from device_initialize_once(). I show all the various vector tables, and
then single-step over the reset instruction. What we see is that openocd
regains control at 0x8000272, which is only referenced from the table at
0x8000000. So it appears that is the table that is used, i.e., VCR is
cleared before the reset vector is looked up.

While reading, keep a close eye on the hexadecimal address of a
function. Since there are sys-stmf103.o's at both 0x8000000 and
0x8002000, the labels are ambiguous and you need the address to know
which of those it refers to.

--8<---------------cut here---------------start------------->8---
$ arm-none-eabi-gdb --eval-command="target remote :3333" build/gnuk.elf
GNU gdb (7.12-6+9+b2)
Reading symbols from build/gnuk.elf...done.
Remote debugging using :3333
0x080000f0 in ?? ()
(gdb) add-symbol-file build/stdaln-sys.elf 0x8000000
add symbol table from file "build/stdaln-sys.elf" at
        .text_addr = 0x8000000
(y or n) y
Reading symbols from build/stdaln-sys.elf...warning: section .text not found in /home/peter/src/arm/gnuk/src/build/stdaln-sys.elf
(gdb) break *0x80031d8
Breakpoint 1 at 0x80031d8: file ../chopstx/mcu/sys-stm32f103.h, line 119.
(gdb) continue
Note: automatically using hardware breakpoints for read-only addresses.

Breakpoint 1, 0x080031d8 in nvic_system_reset ()
    at ../chopstx/mcu/sys-stm32f103.h:119
119       (func) ();
(gdb) display/i $pc
1: x/i $pc
=> 0x80031d8 <main+232>:        blx     r3
(gdb) display/a $msp
2: /a $msp = 0x20000060 <main_base+96>
(gdb) x/a 0xe000ed00 + 8
0xe000ed08:     0x8003000 <vector_table>
(gdb) x/2a 0x8000000
0x8000000 <vector>:     0x20005000      0x8000271 <reset>
(gdb) x/2a 0x8001000
0x8001000:      0x20000060 <main_base+96>       0x8002271 <reset>
(gdb) x/2a 0x8002000
0x8002000 <vector>:     0x20005000      0x8002271 <reset>
(gdb) x/2a 0x8003000
0x8003000 <vector_table>:       0x20000060 <main_base+96>       0x8003491 <entry>
(gdb) si 6
0x08002260      309       SCB->AIRCR = (0x05FA0000 | (SCB->AIRCR & 0x70) | SCB_AIRCR_SYSRESETREQ);
1: x/i $pc
=> 0x8002260 <nvic_system_reset+12>:    str     r3, [r1, #12]
2: /a $msp = 0x20000060 <main_base+96>
(gdb) si
0x08000272 in reset () at ../chopstx/mcu/sys-stm32f103.c:323
323       asm volatile ("cpsid  i\n\t"          /* Mask all interrupts. */
1: x/i $pc
=> 0x8000272 <reset+2>: ldr     r0, [pc, #32]   ; (0x8000294 <reset+36>)
2: /a $msp = 0x20005000
--8<---------------cut here---------------end--------------->8---

OpenOCD complains on that (last) "si" above:

--8<---------------cut here---------------start------------->8---
Info : SWD IDCODE 0x1ba01477
Error: Failed to read memory at 0xfffff000
--8<---------------cut here---------------end--------------->8---

I don't know why that error is there. It has something to do with a
reset during a debugging session.

So... I think the VCR register contents don't matter on invoking

Also, I think that if a "reset" call from a bare-programmed GnuK works,
then a "reset" call from a DFU-programmed GnuK should work as well. On a
bare-programmed GnuK, it would take these vectors if VCR were unchanged:

--8<---------------cut here---------------start------------->8---
(gdb) x/a 0xe000ed00 + 8
0xe000ed08:     0x8001000 <vector_table>
(gdb) x/2a 0x8001000
0x8001000 <vector_table>:       0x20000060 <main_base+96>       0x80013f1 <entry>
--8<---------------cut here---------------end--------------->8---

That's no different than a DFU-programmed GnuK taking the vectors at
0x8003000: they would both skip setting up the VCR and take the correct
MSP directly from the vector table, and continue running in the main

However, current GnuK doesn't ever invoke nvic_system_reset() AFAIK.
reGNUal does, and actually has VCR pointing into the SRAM when it calls
nvic_system_reset(). Again, this is a moot point since VCR is not used.
I investigated the reGNUal reset and it goes fine as well.

> It seems that it's common in China.  I hope they change MPN
> (manufacturer part number), when having such changes (hardware-wise or
> firmware-wise), so that a user can distinguish changes.

I think they handled it pretty well. The silkscreen of the board clearly
indicates a new board revision. The AliExpress product ID is the same.
The old "item specifics" didn't mention a model number, but the new one
has the new board revision as the model number now. The product pictures
clearly show a new board with a new board revision code clearly visible
in the silkscreen. And the new bootloader is compatible with the old
bootloader in usage, so it's a very welcome improvement that they now
flash the more advanced bootloader STM32duino-bootloader. They had one
omission: the product text still says you need a mini-B cable. I alerted
them to this and they said they would change the text.

I agree it could be even better, but at the price point they sell them
at, you really can't realistically expect everything to be best of
industry :-).

I hope this clears up some more details!



I use the GNU Privacy Guard (GnuPG) in combination with Enigmail.
You can send me encrypted mail if you want some privacy.
My key is available at <>

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 488 bytes
Desc: OpenPGP digital signature
URL: <>

More information about the Gnuk-users mailing list