Search code examples
armatmelatsam3x

Atmel SAM3X dual bank switching not working


I'm currently working with an Atmel SAM3X8 ARM microcontroller that features a dual banked 2 x 256KB flash memory. I'm trying to implement a firmware update feature, that puts the new firmware into the currently unused flash bank, and when done swaps the banks using the flash remapping to run the new firmware.

The datasheet states to do so I need to set the GPNVM2 bit, then the MCU will remap the memory, so Flash 1 is now at 0x80000 and Flash 0 at 0xC0000. This will also lead to the MCU executing code beginning from Flash 1.

To cite the datasheet:

The GPNVM2 is used only to swap the Flash 0 and Flash 1. If GPNVM2 is ENABLE, the Flash 1 is mapped at address 0x0008_0000 (Flash 1 and Flash 0 are continuous). If GPNVM2 is DISABLE, the Flash 0 is mapped at address 0x0008_0000 (Flash 0 and Flash 1 are continuous).

[...]

GPNVM2 enables to select if Flash 0 or Flash 1 is used for the boot. Setting GPNVM bit 2 selects the boot from Flash 1, clearing it selects the boot from Flash 0.

But when I set GPNVM2, either via SAM-BA or my own firmware using flash_set_gpnvm(2) (ASF SAM Flash Service API), it will still boot from the program in Flash 0, and the new program will still reside at Flash 1's offset 0xC0000. The state of GPNVM2 has been verified by flash_is_gpnvm_set(2)

Flashing the firmware itself to Flash1 bank works flawlessly, that has been verified by dumping the whole flash memory with SAM-BA.

There is an errata from Atmel about an issue, that the flash remapping only works for portions smaller than 64KB. My code is less than that (40KB), so this shouldn't be an issue.

I've not found any other people having this issue, nor any example how to use it, so maybe somebody could tell me if I'm doing something wrong here, or what else to check.


Solution

  • I had the same issue (see here: Atmel SAM3X8E dual bank switching for booting different behaviour).

    After some more research I found an Application Note (Link: http://ww1.microchip.com/downloads/en/AppNotes/Atmel-42141-SAM-AT02333-Safe-and-Secure-Bootloader-Implementation-for-SAM3-4_Application-Note.pdf) which explains the boot behaviour of the SAM3X in a more clear way. The problem is that the datasheet is a bit misleading (at least I was confused too). The SAM3X has no ability to remap the the Flash banks. The booting behaviour is a bit different (see the picture in the link, it's a snipped from the Application note, page 33/34): Booting behaviour SAM3X

    Picture 3-9 shows the SAM3X's behaviour at the boot-up. The GPNVM bits 1 and 2 just determine which memory section (ROM/Flash0/Flash1) is mirrored to the boot memory (located at 0x00000000). The mapping of the Flash banks is not changed. Therefore Flash0 still is mapped to 0x00080000 and Flash1 to 0x000C0000).

    As the Application Note states some other Atmel microcontrollers are able to really remap the Flash banks (e.g. SAM3SD8 and SAM4SD32/16). These processors change the location of the Flash banks as you can see in picture 3-10.

    To be able to update your firmware it is therefore necessary to implement some kind of bootloader. I implemented one by myself and was able to update my firmware even without using the GPNVM bits at all. I also opend a support ticket at Microchip to clarify the booting behaviour. When I receive an answer I hope to tell you more.

    EDIT:

    Here's the answer from the Microchip support:

    Setting the GPNVM2 bit in SAM3X will merely make the CPU 'jump to' or start from flash bank 1 i.e. 0xC0000. No actual swap of memory addresses will take place.

    To use flash bank 1, you will need to change the linker file (flash.ld) to reflect the flash start address 0xC0000.

    For flash bank 0 application, change: rom (rx) : ORIGIN = 0x00080000, LENGTH = 0x00080000 /* Flash, 512K / to: rom (rx) : ORIGIN = 0x00080000, LENGTH = 0x00040000 / Flash, 256K */

    For flash bank 1 application, change: rom (rx) : ORIGIN = 0x00080000, LENGTH = 0x00080000 /* Flash, 512K / to: rom (rx) : ORIGIN = 0x000C0000, LENGTH = 0x00040000 / Flash, 256K */

    If this is not done, the reset handler in the flash 1 application will point to an address in the flash 0 application. So, although code will start execution in flash 1 (if GPNVM2 is set), it will jump back to the flash 0 application. The errata stating the 64kb limitation can be ignored.

    Therefore the Application Note is right and no actual change of the mmory mapping is performed.

    Cheers Lukas