Dual Bank STM32L082

I think you need to at least tell the firmware that its base address is now different, since the code is not position-independent (-fPIC). That should be achievable via manipulating certain build flags and upload options in the platformio.ini. Specifcially, for uploading, board_upload.offset_address should be set to the absolute address where the binary shall be flashed. (Then PIO is also perfectly capable of flashing the binary directly).

Further, in the STM32Duino, sadly it only chooses from a handfull of offsets depending on the upload protocol, which won’t be correct for your case. So you would have to manually define -DVECT_TAB_OFFSET=<offset from 0x8000000> and the -Wl,--defsym=LD_FLASH_OFFSET flag.

In general, the Application note AN4767 by STMicroelectronics would also be an interesting read for you.

In any case, if I create an example project like

[env:nucleo_l073rz]
platform = ststm32
board = nucleo_l073rz
framework = arduino

with functionally empty src/main.cpp of

#include <Arduino.h>

void setup(){}
void loop(){}

and compile the project, I can inspect the start address of the ELF file by force-disassembling the first 20 ‘instructions’ in the ELF file by doing

>arm-none-eabi-objdump -D .pio\build\nucleo_l073rz\firmware.elf | head -n20

.pio\build\nucleo_l073rz\firmware.elf:     file format elf32-littlearm


Disassembly of section .isr_vector:

08000000 <g_pfnVectors>:
 8000000:       20005000        andcs   r5, r0, r0
 8000004:       08001c05        stmdaeq r0, {r0, r2, sl, fp, ip}

and so the the firmware starts at the regular 0x08000000. Now when I rewrite the platformio.ini as in…

; global build settings
[env]
platform = ststm32
board = nucleo_l073rz
framework = arduino

[env:nucleo_l073rz_bank1]
; no special options

[env:nucleo_l073rz_bank2]
board_upload.offset_address = 0x08018000
extra_scripts = set_bank2.py

with set_bank2.py as

Import("env")
offset = 0x18000 # from 0x8000000
env.Append(
    CPPDEFINES=[("VECT_TAB_OFFSET", "%s" % hex(offset))],
)
# remove old 0-offset, inject new one
linkflags = env["LINKFLAGS"]
linkflags = [x for x in linkflags if not str(x).startswith("-Wl,--defsym=LD_FLASH_OFFSET=")]
linkflags.append("-Wl,--defsym=LD_FLASH_OFFSET=%s" % hex(offset))
env["LINKFLAGS"] = linkflags

And try to compile, most annoyingly, there is a compile error caused by the provided Arduino-STM32Duino…

C:\Users\Max\.platformio\packages\framework-arduinoststm32\system\STM32L0xx/system_stm32l0xx.c:71:1: error: unknown type name 'define'
   71 | define USER_VECT_TAB_ADDRESS
      | ^~~~~~

This line has to be #define USER_VECT_TAB_ADDRESS to be fixed. Doing that, one gets a Bank2 firmware which…

>arm-none-eabi-objdump -D .pio\build\nucleo_l073rz_bank2\firmware.elf | head -n20

.pio\build\nucleo_l073rz_bank2\firmware.elf:     file format elf32-littlearm


Disassembly of section .isr_vector:

08018000 <g_pfnVectors>:
 8018000:       20005000        andcs   r5, r0, r0
 8018004:       08019c11        stmdaeq r1, {r0, r4, sl, fp, ip, pc}

starts at the right address ^-^. And as a side-effect, it also builds the firmware made for Bank1.

Now that firmware has a better chance of working. I’m not sure about the bank boot selection process, but if you’ve already figured that out so that it immediately starts executing at 0x08018000, that should also be taken care of.

1 Like