Dual bank compiling and linking for firmare upgrades

Go To Last Post
11 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I am using a SAM4C32 and I don't think I understand how the dual banks of flash memory work in terms of how you need to compile and link if you want to use the two banks ti run two separate firmware images.

 

As far as I see it, you can have your bootloader built into the main program and don't need a separate bootlader. So you can habve a program running in bank 0, it can program a new image into bank 1 and then switch to bank 1 when it has received a verified image. Then when you want to upgrade again, you are running bank 1's program which erases and programs bank 0 and when that is verified you switch back to bank 0 and so on,

 

If you have a program running in Bank 0 and that program receives a new image for Bank 1, the address of bank 1 starts at 0x1100000, whereas the code running in bank 0 starts at 0x1000000. So, if you want to run code in bank 1, does that mean at compile time, you have to specify that the code is to run in bank 1?

 

If that is the case I can see an issue if a device gets out of step with updates. So, let's imagine the following:

 

v1.0 is compile to work on Bank 0.

v1.1 to work in Bank 1

v1.2 to work in Bank 0

 

What happens if a device misses v1.1 and is running v1.0 to be presented with v1.2?

 

What would make sense to me is that you could program into either bank and set the start address of that bank to what you want. However, it doesn't look like that is possible.

 

Am I missing a an important point here?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You do ;) In fact you can run the programs linked exactly the same way from either bank. There is no difference !

After finally switching banks (GPNVM bit 2) the (new) current bank is remapped to the same base address. In other words the banks are flipped.

This part of the FW installation procedure is a bit tricky b/c this piece of code needs to run from RAM etc.

I'm using the toggle-bank FW installation and it works fine.

And as far as I remember this is sufficiently documented in the reference manual.

Last Edited: Thu. Apr 9, 2020 - 03:40 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Fab thanks very much. I am mighty glad I missed something, because having a recompile for different versions would have been a pain! :D

 

I greatly appreciate the reply.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I've got my bootloader loading the new image into Plane 1, while running out of plane 0. It's working a treat, my CRCs match per page and for the whole image, but I am at a loss as to how this bank switching works.

 

The manual says that there are three GPNVM bits and I would assume that bit two wants to be set. Is it the cse that if bit two is cleared, we're currently running out of plane 0 and if it's set, we're runing out of plane 1. I'm sure that must be the case.

 

If you are running out of plane 0, does just setting GPNVM 2 high, mean you run out of bank 1? The explanation in the safe and secure bootloader confuses the **** out of me.

 

I suppose in a nutshell I'm after two things.

 

1. Once I've downloaded the code into plane 1, what, exactly, do you need to do make plane 1 into plane 0. I assume once you do it, everything changes on reboot? Do you have to set EFC0's GPNVM bit 2 to bank 1 and ECF1's GPNVM bit 2 to bank 0? 

 

2. How do you actually change bit two? Are you writing 2 to FARG in the EEFC_FCR register with SGPB in the FCMD area? Is it that simple?

 

Thanks :)

Last Edited: Thu. Apr 30, 2020 - 02:49 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You're right. switch to 2nd Bank is done by setting GPNVM Bit 2 e.g. like this (running from RAM):

EFC0->EEFC_FCR = EEFC_FCR_FKEY_PASSWD | EEFC_FCR_FARG( 2 ) | EEFC_FCR_FCMD( EEFC_FCR_FCMD_SGPB );
while ( !(EFC0->EEFC_FSR & EEFC_FSR_FRDY) ); // wait for flash op. completion omitting error handling here

It's that simple and it's done exclusively with EFC0 b/c the GPNVM bits are unique / not dual-banked.
When done you can RESET or jump to the application as usual in bootloaders.

Beware that the flash address mapping to EFC(0/1) is also swapped !
I.e. when currently running from 2nd bank EFC1 is mapped to the 'lower' flash addresses.
Hint: I'm using a scheme with primary / secondary EFC (stored in variables) by reading the GPNVM bit 2 instead of using EFC0 / EFC1 defines.
Good luck !
 

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

OK, I must have some other issue then because I've definitely managed to set bit 2 and it just falls over. I've done exctly as you said command wise and run from RAM.

 

I'm not quite sure I see what you're saying about running from 2nd bank EFC1 is mapped to the 'lower' flash addresses. Maybe I've been doing something wrong here: If I'm programming flash in bank 1(ie the second "higher" bank), but running out of bank 0 I have used EFC1. I guess that must be correct as I can definitely see 0x1100000 is being correctly programmed. So, if the program is running out of bank 1, are you saying that to program bank 0 I'll still have to use EFC1 to program 0x1000000?

 

Actually, this brings up another issue that has been pricking the back of my mind. At the moment, I have programmed the addresses sent by the bootloader, but added 0x100000 to the address to be programmed (so I'm starting at 0x1100000 as that's where bank 1 is. If I am running out of bank 1, do I need to ensure that I do not add that offset and program into 0x1000000, not 0x1100000?

 

So, in other words, when the bootloader starts sending me a new image, I need to see whether bit 2 of the GPNVM bits is set and if it is NOT, program the data into 0x1100000 and onwards and if the bit 2 IS set, then program into 0x1000000?

 

My brain hurts! Many thanks again! :)

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

OK, I have it working. I think it's a bit of a mind **** and spectacularly badly described in the datasheet and safe and secure bootloader, so I'll try and explain how I see it for people coming across this in the future.

 

hs2 was spot on when he said that you can just use EFC0 for the GPNVM bits, so don't worry about which bank is in operation. If you always read using ECF0 you'll be fine.

 

You will read 0x02 if you are using bank 0 and 0x06 if using bank 1.

 

To write to a bit just write the BIT NUMBER in FARG. So, as the bank select us bit 2, write 2 for that. Same for clearing. The datasheet is really badly worded here. When you read back though, you read all three bits in a 32 bit word. Quite why it talks about reading it twice for more than 32 bits is beyond me when there are a lousy three bits in 32C and only two in smaller devices. That for a while made me think you had to read one for each bit. Atmel are usually really good at documentation, so it's surprising this is so ambiguous.

 

What really confused me for ages is that no matter what plane you are running from, you must always write to plane 1 addresses. ie 0x1100000 and above. This cost me a few hours working that out. As hs2 said, that weirdness is doubly confounded because even though you are writing to plane 1, if you are executing from plane 1 you have to use EFC0. This important point is shockingly poorly explained in documentation. Had hs2 not explained that to me, I'd still be getting nowhere.

 

Hopefully this will help people in the future.

Last Edited: Fri. May 1, 2020 - 03:37 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Ahh - good news DiBosco ! While I was going to re-read my sources and post some additional information you got it working :)

 

You're absolutely right that the docs are pretty poor and I also got mad while implementing this stuff...

 

Just to bring my post to an end as small of summary of our work:

2 things have to be taken into account: physical flash address to be programmed and selecting the right EFC instance.

  1. flash bank size has to be added as offset to the program/image base address to act on the other (secondary) bank
  2. program has to know from which bank it currently runs by reading the GPNVM bit 2 to select the right EFC instance
  3. select EFC1 when running from bank 0 (GPNVM bit 2 is not set) and vice versa to access the other bank i.e. the physical (high) flash addresses determined in 1.)
  4. after successfully programming the new application, GPNVM bit 2 has to be toggled which flips the flash bank address mapping
  5. the new application can be started from it's base address it's linked to

 

The code executing the low level flash controller commands (set FCR -> poll FSR for READY) must be run from RAM.

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I have one remaining issue with this. When I have swapped to the other bank, after reprogramming I have to power off and on again. I am sure I read that it should just reset and run from the new plane, but I am finding that FreeRTOS is getting stuck. Did you have any issues here? It may well be a FreeRTOS specific issue of course.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hmm. FreeRTOS shouldn’t be involved at that point anymore. When doing the final steps (running from RAM) after flashing you should have interrupts disabled before switching the banks and issue NVIC_SystemReset the code ripped from NVIC_SystemReset. At least I did it that way to ensure remaining in RAM. There might be other ways like making NVIC_SystemReset a RAM function.
Double check that you’re not unintentionally call code in flash after switching banks !

It’s also possible to start the new application bootloader style by invoking the Reset_Handler. This might require a bit more things to setup manually (e.g. disable all peripheral interrupts, setup MSP etc.) before launching the new application.

However, RESET should work. I don’t have my sources at hand but I can have look later/tomorrow..

 

Last Edited: Sat. May 23, 2020 - 06:29 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

hs2 wrote:

Double check that you’re not unintentionally call code in flash after switching banks !

 

That was is. I was switching the bank within RAM, but oif course, when I came out of that function it was immediately running within flash. All the functions, up to and including the jump to program start are now in RAM and it works.

 

Once more, many thanks.

Last Edited: Sun. May 24, 2020 - 11:20 AM