Flashing compiled .bin from SD card to Due?

Hello forum :smiley:

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(GitHub - sebnil/DueFlashStorage: DueFlashStorage saves non-volatile data for Arduino Due. The library is made to be similar to the EEPROM library.) 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 :grin:

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.

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

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.

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.

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.

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.

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!

Nevermind :slight_smile:

I was able to resolve my issues and have a working process thanks to your firmware sample on github! GitHub - collin80/FirmwareReceiver

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 How possible compile a binary for Arduino Due that can run from flash BANK1? - Arduino Due - Arduino Forum 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

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. :wink:

Hello,

Has anyone been successful with creating a version of this bootloader for SD card? Please, I really need some assistance.

Thanks.

SAM3x errata:

49.1.1.3 Flash: Boot Flash Programming Mapping Is Wrong
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.
Problem Fix/Workaround
No fix required if the code size is less than 64Kbytes. Otherwise the software needs to take into account this
limitation if GPNVM2 is used.

@phr3ak - Thanks for the info.

It seems no one has this working (at least no one who is currently active on this forum). I'm working through it. Will post back when something happens (good or bad).

So, I successfully got this working... If anyone is interested, send me a PM. Not sure if or when I'll put it on GitHub.
Also don't know how many applications are using DUE these days. I like it for the dual CAN interfaces.

1 Like

---> Uup115

I am listening.
Loading a Due from uSD is a very useful thing.

Background:

I still lay down Mega footprints for bulk DIO and AIO, but since being spoiled by all the new chips. . .

ESP8266
SAMD21
SAMD51
SAM3x8e
nRF52. . . .

And the ease of connectivity over 2G/3G/4G/WiFi/BLE . ... and all the fun of interacting with databases like AWS and hardware like NFC on Androids....

I became complacent

All of my designs have at a minimum an RTC and a uSD and I now find myself wrangling with the prospect of maintaining remote systems that are running 3+ Arduino's on different hardware chips. (DOH!)

(A good Doh. You only have to solve it once and never think about it again.)

One could spend hours, days, even weeks exploring all the in's and outs of various hardware specific implementations. . . but at the core of it, if each "Arduino" (I love that abstraction) has a method or way to take a new flash from uSD - it is all solved.

Even if I have to task an Arduino with multiple UARTs with the job of flashing everybody*

I may be in a position to trade you some work for some work. I have things like AWS V4 Signature generator that, if run on a $17 feather, can pull and convert time from the cloud (parse from header) into AWS format

YYYYMMDDTHHMMSSZ

Then calculate all of the interactions to interface with AWS S3 and DynamoDB.

Stuff like that.

I have experience programming BLE and NFC between Arduino and Android... auto-launching Android applications upon contact with Arduino and securely transferring security tokens for communication.

Stuff like that.

I like collaborating - give and take. If it is something I did for someone else (for money) I can only give you pointers and tips toward the solve. If it is something I did on my own payroll I can zip and email running Unit Tests.

I will ping your PM

thanks,
-methods

Hey @Uup115, very cool you got this working. I'd love to give it a try for my project. I sent you a PM.

Uup115:
So, I successfully got this working... If anyone is interested, send me a PM. Not sure if or when I'll put it on GitHub.
Also don't know how many applications are using DUE these days. I like it for the dual CAN interfaces.

Hello, I wrote to you PM, but without response, are you got it? I am really interested in update by SD card.