0

I seem to be reiterating this question from here and here. When I reboot my system after flashing firmware onto an opposing flash bank, the VTOR is 0 (meaning it does not boot from flash) and I cannot run the new firmware.

I use the EFC controller to program the firmware binary into the second flash bank. For example, the active firmware is at Flash0, located at 0x0008_0000. The implementation guide says that Flash1 is located at 0x000C_0000. I can see the complete firmware to be flashed is contained, without errors, at 0x000C_0000. Once the firmware is loaded and verified, I switch the GPNVM boot bank:

efc_perform_command(EFC0, EFC_FCMD_SGPB, 1); //set GPNVM bit 1
efc_perform_command(EFC0, EFC_FCMD_SGPB, 2); //set GPNVM bit 2
/* Now check to make sure the bit has flipped) */
efc_perform_command(EFC0, EFC_FCMD_GGPB, 0);
status = efc_get_result(EFC0);
printf("GPNVM is now %d\n", status);

/* Now set the VTOR to the flash1 start address) */
__DSB();
__ISB();
SCB->VTOR = ((uint32_t)FLASH1_ADDRESS & SCB_VTOR_TBLOFF_Msk);
/* Checking the VTOR value here shows a result of 0x000C_0000 */
__DSB();
__ISB();

/* Now reset the device by pulling NRSTB pin low */
reset_pull_NRSTB_low();
while(1); 

After executing this code, I again check the VTOR register at 0xE000_ED08 and the value is now 0x0000_0000. The firmware does not appear to load as the chip looks to address 0x0000_0000 to start the firmware.

Could it be that I have improperly set the GPNVM bits and it is looking for ROM vectors? If that is the case, what are the proper GPNVM bits to set? According to the table on page 33 of the bootloader document, the GPNVM bits should be "0b110" so that GPNVM[1] is 1 and GPNVM[2] is 1 - meaning that the firmware will start from Flash Bank 1. Is this a correct interpretation?

cooperised
  • 2,404
  • 1
  • 15
  • 18
Andrew
  • 43
  • 5
  • The arm core itself resets vtor so what you are saying is the processor is working correctly. If the chip vendor has additional features to dictate what is mapped into that address space, then that is something chip specific. What chip is this? – old_timer Dec 12 '18 at 15:18
  • What the chip vendor would do is have one or the other flash bank answer to the requests at and near address zero. Often meaning that from the arms perspective flash0 shows up in the address space starting at 0x00080000 and flash1 at 0x000c0000 but one of them is also mapped into address 0x00000000 your reset vector would ideally contain a 0x0008xxxx or 0x000Cxxxx address to get you into your bootstrap then that code if needed changes the vtor, those kinds of implementations you often dont need to move vtor – old_timer Dec 12 '18 at 15:26
  • This is a SAM3X8E Chip. So if I understand correctly, the address should be correct just by setting the GPNVM bits. Which I thought initially as well, because the datasheet says: 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). – Andrew Dec 12 '18 at 19:49
  • But it seems as if, after resetting, the system tries to start itself from ROM (at memory location 0x0000_0000. Which, if true, means it has lost its state. Does there need to be another bootloader code at the ROM vector space? According to the guidelines, the memory pointer should be moved inside the continuous address space indicated by the setting of the GPNVM bits. – Andrew Dec 12 '18 at 19:55
  • by definition the processor boots using the vector table at address 0x00000000 that is how it works and is expected to work. that is ARM, the CHIP VENDOR (atmel/microchip in your case) determines what is mapped to that address and that doesnt have to be hardcoded, look at competing products and a I/O pin strapped high or low determines if the bootloader is mapped there or the application code. in this case these GPNVM bits should determine that so that the fetch to arms address space of 0x00000000 is mapped to one of the two flash banks. – old_timer Dec 12 '18 at 21:35
  • the question isnt what is the state of VTOR on a reset that is known, the question is what is the state of these GPNVM bits on a hard reset, have they been configured correctly... – old_timer Dec 12 '18 at 21:37
  • Boot Strategies The system always boots at address 0x0 (straight out of the sam3x8e manual) – old_timer Dec 12 '18 at 21:38
  • Setting GPNVM bit 1 selects the boot from the Flash, clearing it selects the boot from the ROM. Asserting ERASE clears GPNVM bit 1 and thus selects the boot from the ROM by default. 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. – old_timer Dec 12 '18 at 21:38
  • what you need to do is put something in the vector table that is easy to tell one flash image from another. reset, examine 0x00000000, 0x00080000, 0x000C0000 which one is mapped to address 0x00000, and what are the GPNVM bits set to. then try to change the gpnvm bits and try again. did the gpnvm bits survive the reset (They are non-volatile so they should, but did you actually change them) and does the image mapped at 0x00000000 match. also there is a bit that determines rom from flash... – old_timer Dec 12 '18 at 21:42
  • I dont have any of these parts laying around,dont like the atmel arms as much as a couple other brands and really dont like microchip...I do have some atsamd20 or 21 parts somewhere, would have to dig them out. they dont have a sam-ba rom monitor you have to roll your own and the so called flash protection mechaism is trivial to break and wipe out the rom, so that is useless. I dont know if those have a dual flash thing,would have to read up on that and it might not be implemented the same way as the part you are working on so I am limited to what I can read in the datasheet as far as helping – old_timer Dec 12 '18 at 21:46
  • I appreciate your help, thought and assistance. As you can see, I am setting and checking the value of the GPNVM bits right before resetting: `efc_perform_command(EFC0, EFC_FCMD_SGPB, 1); //set GPNVM bit 1 efc_perform_command(EFC0, EFC_FCMD_SGPB, 2); //set GPNVM bit 2 /* Now check to make sure the bit has flipped) */ efc_perform_command(EFC0, EFC_FCMD_GGPB, 0); status = efc_get_result(EFC0); printf("GPNVM is now %d\n", status);` – Andrew Dec 12 '18 at 22:29
  • I'm not sure how to check the GPNVM bits using the debug inspector. I thought they reside in the 0 address space next to the stack pointer, but the debugger does not show me this register. From what I gather, the mapping should be clear from the vector table. The addresses 0x00080000 and 0x000C0000 contain the entirety of the firmware binaries. Is there a way to tell which one of these registers is mapped at startup? When I have the firmware running on Bank0, I can examine the VTOR at 0xE000ED08 and it shows 0x00080000. But after reset this register reads 0x00000000 – Andrew Dec 12 '18 at 22:34
  • write a program that reads them and leaves them in ram, write two programs one with one something near the vector table another with something else. program the flashes. read the ram. write a program that reads the bits and sends the values out the uart in hex form so you can read it on a dumb terminal, write that program to both flash banks... – old_timer Dec 12 '18 at 22:40
  • I have made a little progress but still not quite there. I changed the linker (flash.ld) to reflect the bank values from `rom (rx) : ORIGIN = 0x00080000, LENGTH = 0x00080000` to `rom (rx) : ORIGIN = 0x000C0000, LENGTH = 0x00040000`. At this point I have written the same firmware (different linkers) into both flash banks, but no matter which GPNVM bit is set, it still boots the original firmware I set from Atmel Studio. – Andrew Dec 13 '18 at 18:36
  • hmm that seems backward the primary address from the docs was 0x00080000, but either way the GPNVM bits are supposed to flip that so one is at one and one at the other...what that will do is have one partition boot the other hoping that you have the same image on both, otherwise it may not work. – old_timer Dec 13 '18 at 21:33
  • your debugger should at least let you see what is mirrored to 0x00000000 – old_timer Dec 13 '18 at 21:39
  • According to the datasheet, _The VTOR indicates the offset of the vector table base address from memory address 0x00000000. See the register summary in Table 10-30 on page 165 for its attributes._ When I check this register is says 0x0008_0000. Which makes sense because GPNVM is simply a mapping. So even at 0x000C_0000 it should be mapped to 0x0008_0000. But either way I have now put the same firmware in both flash banks and it still boots the old one! – Andrew Dec 15 '18 at 03:14
  • Hm, I have discovered something in the Errata section of the datasheet. My firmware is 135kb, and this is on page 1443: GPNVM2 enables to select if Flash0 or Flash1 is used for the boot. But when GPNVM2 is set, only the first 64 Kbytes of the Flash 1 are seen in the Boot Memory. The rest of the Boot memory corresponds to Flash 0 content. – Andrew Dec 17 '18 at 01:57
  • do they mean when viewed from 0x00000000 or from 0x00008000. What do you see when you use your debugger and compare that to your binary? Would have been much much easier if you had tried a small 20 word program on each first...then tried something bigger...one problem at a time rather than multiple at the same time. – old_timer Dec 17 '18 at 03:12
  • Actually I did have this code working about 6 months ago. But I was using an Arduino Due variant - now I have written my own kernel in ASF. I'm not sure if Arduino attaches a bootloader to it somehow or modifies the vector tables. Since I am booting from Flash0 initially, it makes sense that when I try to write to Flash0, I get thrown a hard fault. But somehow, after switching the bootloader twice and writing to Flash0 again (and it still reports the same version), it allows me to write to Flash0 and still operate. – Andrew Dec 18 '18 at 02:15
  • I found a thread with a similar problem. It seems as if the solution was to put in a modified bootloader. I imagine I could add a bootloader somewhere that loads the firmware from either bank. As the person mentioned here, they do not need to use the GPNVM bits. But I do not know where to start to modify the bootloader as SAM-BA is hardcoded into the chip. https://stackoverflow.com/questions/47078293/atmel-sam3x-dual-bank-switching-not-working – Andrew Dec 18 '18 at 07:03
  • This has been driving me crazy. Today, I compiled the firmware binaries - identical firmwares except for the location provided in the linker script. And after a binary hexdump and a diff of the map files, they are the exact identical file! So if the GPNVM bit is truly pointing to one flash location or another, why is the PC, which is the second word in memory after the SP, the same, when they are supposed to lie in different memory locations? – Andrew Dec 19 '18 at 20:41
  • you seem to be chasing your tail and sounds like making problems for yourself. LONG before your binary got to be over 64K you should have worked this out. And as suggested, make a project to work out how the boot works. maybe something like a 100 byte program (times 2) that just does enough to figure out how this part works. master that, then apply that knowledge to the main project. Also try to figure out why your programs are so huge. – old_timer Dec 19 '18 at 20:46
  • I thought I had it figured out in the very early stages. But I have since changed kernels and platforms. This project started out on an Arduino Due and I had been using the Arduino IDE. Somehow when doing these re-flashes I did not have the same issue as I did here. On a side note, the programs are huge because of the number of connected devices and state machines that are required to run. It would be very difficult to reduce the size. – Andrew Dec 20 '18 at 01:39
  • Can I ask you where is the official definition of EFC_FCMD_SGPB and other flash commands? – Gábor Aug 14 '20 at 09:34

1 Answers1

0

Ok, of course I knew that finding the solution would make me feel stupid. But here you go... I ultimately changed the linker script in the Device_Startup folder as provided by Atmel and compiled it twice; each with the FLASH0 and FLASH1 addresses respectively in place, with no other changes to the firmware. And...the firmware binaries were identical! But that shouldn't be the case according to Atmel.

I had been confused because it says that the memories are mirrored, which led me to believe that setting the GPNVM only pointed to the start of the flash bank at the same address and remapped the latter half based on GPNVM2. Instead, it seems as if it actually loads the vector table from the second word of the firmware binary (SP and then PC).

So it does need to be told where to jump inside the contiguous flash bank. I went into the ASF solution properties to find the ARM/GNU Linker preferences and found the real linker file in the tag section. It is not the one that seems to be referenced in my project. I changed it based on the guidelines I mentioned above and it switched over successfully to run the firmware on the opposite bank.

Easy solution to a seemingly obscure hardware problem. Thanks for your help!

Andrew
  • 43
  • 5