cancel
Showing results for 
Search instead for 
Did you mean: 

Two remaining questions on dual bank flash on STM32L152

Lynn Linse
Associate III
Posted on February 14, 2017 at 21:39

I've read through AN4767, AN4808 and several others. I think I understand how nBFB2 can cause BANK 2 to be addressed as 0x0800000 & BANK1 aliases to 0x0804000 (L152 has 512K, so 2x256k banks). First a great shout-out to

Turvey.Clive.002

http://userbadge

, who makes the forum worth searching & asking at :-]. Hope you get a pay raise this year & every year!

My remaining questions:

1) Does this swap also affect EEPROM? AN4808 (& others) say code running in BANK1 should use EEPROM BANK2, and vis-vera since the banks share HW controllers & this allows code to run/read while writing EEPROM. So are the EEPROM banks swapped as well, or should the 'aliased' image at 0x08000000 always use EEPROM BANK2 as-if code was BANK1?

2) The 'Ping-Pong' effect - someone else asked this, but wasn't directly answered.

2a) I understand if I start running my FWv1 in HW-BANK1 & HW-BANK2 empty (BFB2 can be anything). So field upgrade to FWv2 means I copy to 0x08040000 (V-BANK2), then I do my own CRC & confirmation that upgrade worked. If my confirmation fails, I erase that bank & wait to try FW upgrade again. If it works, with BFB2=0, then a reboot means we'll run FWv2 in HW-BANK2 which looks like V-BANK1.

2b) I also assume now if we do FWv3, erasing/writing 0x0804000 is actually writing into HW-BANK1, while we're running FWv2 in HW-BANK2.

2c) so my ping-pong question - do I need to set BFB2=1, so a reboot returns to FWv3 in HW-BANK1 and ignores old FWv2 in HW-BANK2? I assume if BFB2=0, we'll always/only run FWv2 in HW-BANK2 since it has correct SRAM in first word ... unless I erase first page, which kills/disables any fall-back to older FWv2.

2d) rewording my question, do I manually need to twiddle BFB2 to select 'odd' or 'even' revisions of my FW, which toggle between 'forcing HW-BANK1' and 'auto-picking HW-BANK2 while fall-back to HW-BANK1'?

3) Last question, with BFB2 set to 0, what is the safest absolute way to know which HW-BANK is 0x08000000 & which is 0x0804000? For example, of first word of BANK2 was 0, then we're running HW-BANK1; if first word of BANK2 was SRAM, then we're running HW-BANK2. So what's best way to know which HW-BANK is 'the other one' - for my Ping-Pong management?

#dual-bank #bfb2 #dual-boot #stm32l152
1 ACCEPTED SOLUTION

Accepted Solutions
Posted on February 28, 2017 at 15:38

Okay, solution - the STM32L152 does NOT support bank swapping. To use nBFB2, you must link the image in BANK2 to run based on 0x08040000 not 0x08000000.

Clive's comment about 'System Loader would need a way of swapping the banks' got me thinking. While L0 and L4 docs talk about the dual banks and the virtual bank usage, the L1 doesn't. It just has the nBFB2 bit, saying you can boot from BANK2, but never says it works like the L0/L4 (or F4) do.

So I rebuilt my BANK2 image, linking it to run at 0x08040000 instead of 0x08000000, then my L152 works as expected. If nBFB2 = 1, the BANK1 image runs. If nBFB2 = 0, the BANK2 image runs. So there is no swap. I assume before, when nBFB2=0 that the MCU loaded the reset vector 0x08001799 from BANK2 address 0x08040003 and then happily ran the image in BANK1, which happened to have the same reset-vector value.

This is actually ironic, because our FIRST design was to load a factory image in BANK1 (based at 0x08000000), which included all rev 1 function and the ability to reflash BANK2. This would be write-protected & the FW itself would have no code to unlock or change BANK1 - BANK1 would only be changed during manufacturing. Then to always put field FW into BANK2. So one could also 'factory reset' by running BANK1 and erasing BANK2. If a FW update of BANK2 failed, we'd erase and fall back to the 'factory image'. There are Pros/Cons to such a design - as there are to always replacing old code with new code. But all design is a series of trade-offs.

View solution in original post

7 REPLIES 7
Posted on February 14, 2017 at 22:14

I don't work for ST, I occasionally get contributions from participants here. You could lobby ST to more actively fund too.

3) There should be a SYSCFG mapping register which you can read and make a determination. If the code were carefully placed, say within the Reset Handler, one could make a determination of which firmware image is newer (ie sequence number, date, etc) and basically swap-and-fork by mapping the most recent into the 0x08000000 space and continuing execution. One could also use a small loader placed at the front of both banks, which doesn't get erased, and validates the images. The loader method would significantly reduce the chance of bricking during field updates.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Lynn Linse
Associate III
Posted on February 27, 2017 at 21:28

Hmm, just out of curiosity ... in case the function is 'opposite' ... I confirmed via ST-LINK that I had valid images in BANK1 and BANK2, plus set BFB2 to 0, to enable the auto-sense of BANK2 before running BANK1.

Running from BANK1, I had a test option to blow away the FIRST page of BANK1 (so HAL_FLASHEx_Erase() one page at 0x08000000U), then call HAL_NVIC_SystemReset().

As feared, the erase worked but the code crashed. A manual reset also failed to start running, so clearly the check of BANK2 wasn't happening. ST-LINK was able to reload the same BANK2 code in BANK1, & it ran happily.

Posted on February 27, 2017 at 20:34

Thanks for the reply.

On the L152, there doesn't seem to be a bit within SYSCFG_MEMRMP for that - apparently the L4xx serial has a FB_MODE mode for this, but not the L1. I have been experimenting with the STM32 ST-LINK Utility, which allows me to set/clear the nBFB2 directly (under the Target->Option Bytes menu). Since it is in ST-LINK, I assume my processor does support nBFB2, and that ST-LINK is correctly setting/clearing it.

Via ST-LINK, I could place 2 fw images:

  • The one in true bank1, via JTAG output, does claim to be:
    • FW.DAT  = 2017-02-27 18:24:43  (firmware build date, UTC)
    • FW.VER  = 01.02.00192 (firmware version as major.minor.build)
  • The one in true bank2, via JTAG output, would - if it ran - claim to be:
    • FW.DAT  = 2017-02-27 18:57:36  (firmware build date, UTC)
    • FW.VER  = 01.02.00193 (firmware version as major.minor.build)

When I use ST_LINK to make nBFB2 'normal', which is 1, my code (in BANK1, build 192) prints this:

  • D:BOOT0 = 0, BOOT1 = 0, nBFB2 = 1, so normal boot bank1
  • D:OB->USER   (0x1FF80004) = 0x00F8 (bit 0x0080 = nBFB2)
  • D:FLASH->OBR (0x00F800AA) = 0x00F800AA
  • D:MEM_REMAP  (0x40010000) = 0x00000000 (main flash boot, main flash = 0x00000000)
  • D:FLASH BANK1(0x08000000) = 0x20014000 (valid SRAM stack)
  • D:FLASH BANK2(0x08040000) = 0x20014000 (valid SRAM stack)

When I use ST_LINK to make nBFB2 'active', which is 0, THEN RESET or POWER CYCLE, my code (still in BANK1, build 192) prints this. So the nBFB2 is being recognized, and system memory is active (aka: the bootloader?):

  • D:BOOT0 = 0, BOOT1 = 0, nBFB2 = 0, so try bank2, then bank1
  • D:OB->USER   (0x1FF80004) = 0x0078 (bit 0x0080 = nBFB2)
  • D:FLASH->OBR (0x007800AA) = 0x007800AA
  • D:MEM_REMAP  (0x40010000) = 0x00000001 (main flash boot, system flash = 0x00000000)
  • D:FLASH BANK1(0x08000000) = 0x20014000 (valid SRAM stack)
  • D:FLASH BANK2(0x08040000) = 0x20014000 (valid SRAM stack)

But the build 193 is not running, so we're still running in BANK1 despite the conditions being correct for the running from BANK2 (per reference manual RM0038, section 3.9.8 (FLASH_OBR) and table 6, boot modes.)

Posted on February 27, 2017 at 21:51

I'm not using this specific part, or have access to a sample.

The System Loader would need a way of swapping the banks, and the most probable place to look would be undocumented/reserved bits of SYSCFG_MEMRMP.

I'd disassemble the loader and verify I understood what it was doing, and what conditions would preclude it from behaving as desired. Likely to run you a couple of hours of engineering time.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Posted on February 27, 2017 at 22:26

Actually, since I'm stuck, I've been reading deep into other posts. I ran across one by

‌, which uses L4XX (with the expected dual bank behavior), and he ALSO uses the L152 and says this:

      For the 'L152 we do have a small, 1KB bootloader that transfers flash bank 2 to flash bank 1 if EEPROM flags are set.  The image is downloaded as part of the app, which keeps the bootloader very simple.  The 'L152 also has dual flash banks but doesn't have the address remap option, so we have to transfer the image to the first bank in order to start it.

Hmm, that seems pretty odd, since the L152 has the nBFB2 bit ... but maybe it doesn't work? I'll look into jack's method - writing my code to BANK2, decrypting as I go, and confirming hashes. Then once complete, run a small 'booter' from SRAM to copy BANK2 to BANK1 & reboot. (our device has home-land security issues, so we use a secure encrypted memory 'token' - aka: a special flash dongle to reflash & set ROP to block normal JTAG or serial boot loader.).

Posted on February 27, 2017 at 22:42

I did a bunch of analysis of how the original F4 2MB dual bank devices functioned. UNIX style forking was possible here, without breaking the ART cache, or depending on third-party code in ROM to be run.

Most of the people I deal with want 2MB of monolithic code, not two 1MB banks of the same/similar stuff

The problem with the L1 is that the documentation seems to be missing some salient/specific detail about how this is achieved. Disassembling the ROM would provide some details.

The ROM/OTP seems to be a primary vector of attack for breaking RDP

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Posted on February 28, 2017 at 15:38

Okay, solution - the STM32L152 does NOT support bank swapping. To use nBFB2, you must link the image in BANK2 to run based on 0x08040000 not 0x08000000.

Clive's comment about 'System Loader would need a way of swapping the banks' got me thinking. While L0 and L4 docs talk about the dual banks and the virtual bank usage, the L1 doesn't. It just has the nBFB2 bit, saying you can boot from BANK2, but never says it works like the L0/L4 (or F4) do.

So I rebuilt my BANK2 image, linking it to run at 0x08040000 instead of 0x08000000, then my L152 works as expected. If nBFB2 = 1, the BANK1 image runs. If nBFB2 = 0, the BANK2 image runs. So there is no swap. I assume before, when nBFB2=0 that the MCU loaded the reset vector 0x08001799 from BANK2 address 0x08040003 and then happily ran the image in BANK1, which happened to have the same reset-vector value.

This is actually ironic, because our FIRST design was to load a factory image in BANK1 (based at 0x08000000), which included all rev 1 function and the ability to reflash BANK2. This would be write-protected & the FW itself would have no code to unlock or change BANK1 - BANK1 would only be changed during manufacturing. Then to always put field FW into BANK2. So one could also 'factory reset' by running BANK1 and erasing BANK2. If a FW update of BANK2 failed, we'd erase and fall back to the 'factory image'. There are Pros/Cons to such a design - as there are to always replacing old code with new code. But all design is a series of trade-offs.