Go Down

Topic: Flashing compiled .bin from SD card to Due? (Read 2968 times) previous topic - next topic

CSharpLover

May 22, 2016, 12:30 pm Last Edit: May 22, 2016, 01:24 pm by CSharpLover
Hello forum :D


I'm making a game console like thing with Arduino Due. Firstly I decided to make an interpreter to load game code from SD card.


But... Making a interpreter and running game from it lacks using new / another Arduino libraries. My interpreter will support DueVGA (many thanks to stimmer), Audio and SD libraries but someone can want to use another library.


I saw sebnil's DueFlashStorage(https://github.com/sebnil/DueFlashStorage) library that able to write data to Due's 512 KB flash. I used IDE's "Export compiled binary" option and took the .bin file, I'm not sure how much of that file that needs to be flashed into flash, too...


Then I started to make a bootloader that reads the data from SD card and writes to flash, then jumps to that code.


Reading data from SD card and writing to flash looks easy, but I'm not sure how can I jump to that code. What can I do?


AVRs can't execute code from SRAM, but can an ARM do that? Can reading the program data into an unsigned char* and jumping to here using something like ((void (*)(void)) address)();


AVRs have a bootloader called 2boot for doing this job, but I couldn't find a way to do it with Due.



Many thanks :smiley-mr-green:

ard_newbie


Hello CSharpLover


You can execute some code from SRAM using this:   __attribute__ (( section (".ramfunc")))  before.


To upload a new firmware in Flash from SRAM, you can set the General Purpose Non Volatile Memory  (GPNVM) bit 2 and upload the new firmware in Flash Bank 1 . After an erase, the GPNVM bit 1 is set and GPNVM bit 2 is cleared and your firmware runs from Flash Bank 0.

Afeter setting GPNVM bit 2 and uploading your new firmware in Flash Bank 1, reset and your code will run from fromFlash Bank 1.

CSharpLover

I tried running code from RAM with jumping to the loaded file, but it didn't work, just program crashed.

ard_newbie

The Flash memory is divided into two banks of 256 KBytes and each banck is divided in pages of
256 Bytes.

To copy your new firmware from SD card, provided you have already uploaded a first firmware , this first firmware, running from Flash bank 0, will have to copy page by page the new firmware in Flash bank 1 (begins at IFLASH1_ADDR). The bootloader sets the gpnvm bit 1 so you have the possibility to run code from Flash bank 0 or 1 by setting the gpnvm bit 2 yourself.

You have 2 copies of your bootloader loaded at the beginning of each Flash bank (see Atmel application Note AT02333: Safe and Secure Bootloader implementation).

Use the command WP (see datasheet  Sam3x  18.4.3) inside a Write subroutine preceded with  the Ram Function attribute, or use the IAP function.
The In Application Programming feature is a function located in ROM that can be called by any software application ( at address IROM + 8, see datasheet 20.4.4). When called, this function sends the desired FLASH command to the EEFC and waits for the Flash to be ready. Inside the subroutine, disable interruptions at entrance, and re_enable the previous enabled interruptions at exit (get Primask, disable irq, set primask).

Once your new firmware uploaded in Flash bank 1, set the gpnvm bit 2 with the command SGPB
(see datasheet 18.4.3.5) using the IAP function the same way as previously, then read the gpnvm bits 0 to 2 with the command GGPB to ensure they are properly set. Then reset manually your board and it should automatically run from Flash bank 1.

Show your code if any pending questions with this.



CSharpLover

#4
May 23, 2016, 03:42 pm Last Edit: May 23, 2016, 03:48 pm by CSharpLover
The Flash memory is divided into two banks of 256 KBytes and each banck is divided in pages of
256 Bytes.

To copy your new firmware from SD card, provided you have already uploaded a first firmware , this first firmware, running from Flash bank 0, will have to copy page by page the new firmware in Flash bank 1 (begins at IFLASH1_ADDR). The bootloader sets the gpnvm bit 1 so you have the possibility to run code from Flash bank 0 or 1 by setting the gpnvm bit 2 yourself.

You have 2 copies of your bootloader loaded at the beginning of each Flash bank (see Atmel application Note AT02333: Safe and Secure Bootloader implementation).

Use the command WP (see datasheet  Sam3x  18.4.3) inside a Write subroutine preceded with  the Ram Function attribute, or use the IAP function.
The In Application Programming feature is a function located in ROM that can be called by any software application ( at address IROM + 8, see datasheet 20.4.4). When called, this function sends the desired FLASH command to the EEFC and waits for the Flash to be ready. Inside the subroutine, disable interruptions at entrance, and re_enable the previous enabled interruptions at exit (get Primask, disable irq, set primask).

Once your new firmware uploaded in Flash bank 1, set the gpnvm bit 2 with the command SGPB
(see datasheet 18.4.3.5) using the IAP function the same way as previously, then read the gpnvm bits 0 to 2 with the command GGPB to ensure they are properly set. Then reset manually your board and it should automatically run from Flash bank 1.

Show your code if any pending questions with this.



Thanks really. I'm not sure how can I set the GPNVM bit 2. I looked at libraries but I really don't know how can or what can I do...

Looks sebnil's DueFlashStorage library writes to Flash Bank 1, then can I write my compiled program with DueFlashStorage?

Just setting GPNVM bit 2 will make start program from Flash Bank 1, but I don't know how can I set it.

lev_vayner

The Flash memory is divided into two banks of 256 KBytes and each banck is divided in pages of
256 Bytes.

To copy your new firmware from SD card, provided you have already uploaded a first firmware , this first firmware, running from Flash bank 0, will have to copy page by page the new firmware in Flash bank 1 (begins at IFLASH1_ADDR). The bootloader sets the gpnvm bit 1 so you have the possibility to run code from Flash bank 0 or 1 by setting the gpnvm bit 2 yourself.

You have 2 copies of your bootloader loaded at the beginning of each Flash bank (see Atmel application Note AT02333: Safe and Secure Bootloader implementation).

Use the command WP (see datasheet  Sam3x  18.4.3) inside a Write subroutine preceded with  the Ram Function attribute, or use the IAP function.
The In Application Programming feature is a function located in ROM that can be called by any software application ( at address IROM + 8, see datasheet 20.4.4). When called, this function sends the desired FLASH command to the EEFC and waits for the Flash to be ready. Inside the subroutine, disable interruptions at entrance, and re_enable the previous enabled interruptions at exit (get Primask, disable irq, set primask).

Once your new firmware uploaded in Flash bank 1, set the gpnvm bit 2 with the command SGPB
(see datasheet 18.4.3.5) using the IAP function the same way as previously, then read the gpnvm bits 0 to 2 with the command GGPB to ensure they are properly set. Then reset manually your board and it should automatically run from Flash bank 1.

Show your code if any pending questions with this.



I am following this pattern/process, but I do not have a successful boot after the restart. Quite honestly, I am not sure what is happening. Do you think you can help?

I am writing to flash1 from sd, then validate, then disabling IRQ, setting bit 1 in GPNVM register, then setting bit 2 to boot from FLASH 1. After restart, nothing happens.

Relevant code (pulled from samples found elsewhere)

__disable_irq();


//Adapted from code found in Reset.cpp in Arduino core files for Due
//GPNVM bits are as follows:
//0 = lock bit (1 = flash memory is security locked)
//1 = Booting mode (0 = boot from ROM, 1 = boot from FLASH)
//2 = Flash ordering (0 = normal ordering FLASH0 then FLASH1, 1 = Reverse so FLASH1 is mapped first)
const int EEFC_FCMD_GGPB = 0x0D; //read bit
const int EEFC_FCMD_CGPB = 0x0C; //clear bit
const int EEFC_FCMD_SGPB = 0x0B; //set bit
const int EEFC_KEY = 0x5A;


//while ((EFC0->EEFC_FSR & EEFC_FSR_FRDY) == 0);
//// Set bootflag to run from FLASH instead of ROM
//EFC0->EEFC_FCR =
// EEFC_FCR_FCMD(EEFC_FCMD_GGPB) |
// EEFC_FCR_FARG(2) |
// EEFC_FCR_FKEY(EEFC_KEY);

//while ((EFC0->EEFC_FSR & EEFC_FSR_FRDY) == 0);

// Set bootflag to run from FLASH instead of ROM
EFC0->EEFC_FCR =
EEFC_FCR_FCMD(EEFC_FCMD_SGPB) |
EEFC_FCR_FARG(1) |
EEFC_FCR_FKEY(EEFC_KEY);
while ((EFC0->EEFC_FSR & EEFC_FSR_FRDY) == 0);
//// Set bootflag to run from FLASH1
EFC0->EEFC_FCR =
EEFC_FCR_FCMD(EEFC_FCMD_SGPB) |
EEFC_FCR_FARG(2) |
EEFC_FCR_FKEY(EEFC_KEY);
while ((EFC0->EEFC_FSR & EEFC_FSR_FRDY) == 0);



// Force a hard reset
const int RSTC_KEY = 0xA5;
RSTC->RSTC_CR =
RSTC_CR_KEY(RSTC_KEY) |
RSTC_CR_PROCRST |
RSTC_CR_PERRST;

while (true);// bye cruel world!

lev_vayner

Nevermind :)

I was able to resolve my issues and have a working process thanks to your firmware sample on github! https://github.com/collin80/FirmwareReceiver

sam_j

Hi lev_vayner

Can you share how you resolved this. I am trying to do the same thing.

I tried following the FirmwareReceiver library but the library has two examples and I cannot understand which example does what.

How do you process the .bin file and how do u load it to FLASH1.

All I have confirmed is that I can program flash0 or flash1 from arduino after modifying some files following http://forum.arduino.cc/index.php?topic=364565.0  and I can boot to FLASH 1 from FLASH0 and vice versa.

How were you able to read from sd card to program FLASH1??

Thanks

AdderD

First of all, keep in mind that I wrote a CANbus based firmware flasher so you will need to do quite a bit of modification to make it work for loading from an SDCard.

But, the general concept is the same. Yes, there are two examples for the FirmwareReceiver project. One of them is not exactly an example sketch per-se. It is an example bootloader. You see, the general idea is that your main sketch runs and monitors for a request to upload firmware. When this happens the main sketch reboots to the bootloader. What I'd do is put the bootloader sketch in FLASH1 and the user sketch in FLASH0. So, you reboot the board into FLASH1 and you're in the bootloader now. The bootloader can now freely write anything it wants to FLASH0 as they're separate and one can write to the other without any problems. So, the bootloader rewrites FLASH0 then it reboots to FLASH0 and you're in the new sketch. That's the basic idea. It's reasonably simple and it works pretty well. You can replace my CAN bootloader with an SDCard bootloader. Just put it into FLASH1. Then you reference the other example for how it calls the FirmwareReceiver where code sets up for a reboot. That's the only part you need - the set up for a reboot to FLASH1.

So, general overview:
1. Grab the reboot routine from FirmwareReceiver.cpp. This routine you shouldn't need to change. Be sure you keep the ramfunc part.

2. Modify the bootloader so it grabs firmware from an sdcard instead of over CAN. Note that the bootloader sketch has a routine very similar to the one above. It's subtly different and reboots to FLASH0 so make sure you keep them straight.

3. Flash that bootloader to FLASH1

4. Now your sketches can compile as normal and go to FLASH0. But, they need to call the reboot routine when it is time to update firmware.

That's it. Basically that project on Github is a template you can use to do what you want. It is complete as-is if you wanted to flash over CAN but can be modified to flash from any source. And, I've already banged my head into the desk trying to make it all work so you don't have to. ;)

Go Up