Go Down

Topic: how to write and read arduino due internal flash memory? (Read 11984 times) previous topic - next topic

riddik00

hello,
I need to store data in arduino due after the power down.
what i need is, to take an IR code from a remote and store in the arduino DUE internal flash memory.
i can't find any reference anywhere to how to do that, all say to write to EEPROM but on arduino DUE there is not EEPROM.

Palliser

Hello riddik00,
I use the following library:
https://github.com/sebnil/DueFlashStorage

You can save/retrieve data from the internal Flash of Due. You will not lost the data even when power is down. The only way to lost the data is when you reprogram Due.

Caveat: You can 'brick' your Arduino Due if lack of power during writing/retrieving on flash. Regards,

p

acherian

Dear Palliser,

I am trying to use the DueFlashStorage. I am fairly new to arduino, so had few questions on this library.
1.  I am using this with ethernet shield and Due. My code is currently 32,120 (6%) of storage space. This will go up. Do you know how to change the offset of the flash page in this lib so it is not conflicting with the program itself?
2. If I use the native usb port to program, after the first time if I reprogram, IDE shows error saying flash is locked. have you come across this issue? it works ok with programming port though.

I would appreciate any inputs on this. kind regards,

MorganS

1. Don't do that. The library already has that offset built in.
2. Then use the port which works.
"The problem is in the code you didn't post."

acherian

MorganS,

Thanks for the comment. The library already has an offset: True, but that (according to SebNil, the author) is a fixed offset. It worked for him, and it may work for me, but on his blog page, he has replied to someone that it is user's responsibility to calculate offset based on the code. So I just wanted to know how to do that in case needed.

And yes, I am using the port that works for now. This does require a second processor (for future designs if we go that way). It would be nice to keep the design simple hence I was wondering what causes the flash lock on the native programming port.

exedor

There some predefined constants that are already defined.  The Due has two banks of flash memory that I *think* are 256K each.  There are constants defined called IFLASH0_ADDR and IFLASH1_ADDR, and a few others.

Those are the base address of the two banks of flash memory.  To calculate the write address, assuming you want to put your stuff at the very back (opposite end of program memory) of the flash address space, then you would calculate it like this:

Code: [Select]
byte *writeAddr = (byte *)(IFLASH1_ADDR + IFLASH1_SIZE - sizeof(whatever_structure_you_want_store));


However, the best idea is probably to put it at the beginning of the first page that will give you the space you need.  In which case you would do something like this:

Code: [Select]
u_int pages = sizeof(whatever_you_want_stored) / IFLASH1_PAGE_SIZE;
if (sizeof(whatever_you_want_stored) % IFLASH1_PAGE_SIZE > 0) pages++;
byte *writeAddr = (byte *)(IFLASH1_ADDR + IFLASH1_SIZE - IFLASH1_PAGE_SIZE * pages);


These are absolute addresses.  After looking at his library it looks like address 0 is probably the same as IFLASH1_ADDR.  That being the case, you would use this for the writeAddr definition:

Code: [Select]
byte *writeAddr = (byte *)(IFLASH1_SIZE - IFLASH1_PAGE_SIZE * pages);

earx

*bump*

this sounds like a great library. recently did this on the NXP LPC2468 and it works like a charm. however, the brick part scares me. what if the user is a moron and decides to power down while the thing is writing? and how long does the write of, say, 100 bytes, cost anyhow? on the NXP it was done in under 200 ms.. also i'm curious as to how exactly the bricking would work?

pepelevamp

Apologies for reviving the zombie thread.
But the answer to this last question is: use a supercapacitor to hold charge for a moment after power has been pulled. My 3D printer does this. During the unfortunate event of a short power cut, it will store its position/status into eeeprom and resume work as if nothing happened. It can only handle very short power cut periods say 1 second but yeah.

I like to spend a lot of time & money on finding ways to save time & money.

trev_vb

I'll keep up this 'new trend' of replying to a 'zombie thread' by asking another (probably inane and insane?) question... <Grins>
Firstly, some quick background for y'all. (which you MIGHT want to bypass... If so, skip to "<QUESTION>"
I'm using a Due in a truly 'bare-iron' mode
i.e. There's absolutely NO Arduino code in there at all...  I take control right from Reset_Handler () exception and bring it up from 'cold' (and before anyone asks... Yes, I _AM_ switching it over to a PLL derived 84MHz clock!)
Furthermore, during startup, I 'relocate' all of the code from Flash into the 32kB SRAM1 bank (less wait states = slightly faster? LOL)
The application is mildly automotive in nature (specifically drag racing)
During any given 'race', the Due will be logging a bunch of data into the 64kB SRAM0 bank... (And it _COULD_ consume the whole 64kB bank in 'abnormal' circumstances!)
I need to make sure this log info gets stored into non-volatile memory (a.k.a. Flash Bank 1) before some idiot (a.k.a. the teenage driver) turns the thing off.
My 'gut instinct' is a simple 5.5V 1.5Farad supercap (as mentioned above) on the Due +5V rail (since it's 'quasi-safe' to backfeed a Due through the +5V rail - That's how they work when powered by USB!).
The supercap would charge from this same rail (through a 'low-ish' value resistor), and then backfeed the Due through a Schottky diode when the Due loses the Vin supply.  (The Due will KNOW that it's lost Vin within 0.01-0.02 seconds by way of the ADC and the SysTick timer which I've set for 100Hz operation).
<QUESTION>
I cannot find anything in the SAM3X8E datasheet telling me how much time it needs to write data out to flash using the EEFC peripheral.  Given that I might need to write up to 64kB, I'm unsure if a 1.5F supercap is going to give me enough time.  (There's also 16 digital inputs with internal pullups enabled which doesn't exactly help my cause... LOL).
Has anybody here got any 'timing' knowledge of writing to the SAM3X8E FLASH

westfw

2.3 ms per page, without auto-erase.

See the data sheet section on "ac characteristics" (46.10.10 in my relatively old copy.)

ard_newbie

#10
Apr 20, 2019, 11:01 am Last Edit: Apr 20, 2019, 11:01 am by ard_newbie
Furthermore, during startup, I 'relocate' all of the code from Flash into the 32kB SRAM1 bank (less wait states = slightly faster? LOL)
The DUE is optimized for reading from Flash, reading code from SRAM is a bit slower. You want to locate your code in SRAM only when this is mandatory (read Unique ID for example), or if you want to reduce wear in Flash….

Why not power the DUE with a battery pack (from 7V to 12V is OK)?

There is the DueFlashStorage library to store data in Flash. However, you should know that some users have had issues with this library : after writing data to the Flash, they can't upload a new sketch (Flash page is lock message) with the regular arduino IDE. Search in recent threads in the DUE sub forum for some "possible" ways to unlock Flash regions. Note that for some users, even these workarounds do not clear definitely the Flash lock bit.

I think, but this is only a guess, that there is some mismatch during a write in Flash if an interrupt occurs at the same time (e.g. Systick fires an interrupt 1000 times per second), and this could be a workaround:

Just before writing into the Flash with this library, write: __set_FAULTMASK(1); // 1 = Disable all interrupts, except NMI; 0=Enable previous interrupts

Just after writing into the Flash, write: __set_FAULTMASK(0);  So that you can Serial print, use micros(), millis() and delay() again.



trev_vb

I _thought_ I had scanned my eyes through the ENTIRE 1450+ page datasheet looking for that info, but there it is!!!
As for the SAM3XiE running faster in FLASH than in RAM, I'm somewhat surprised.
However, I've now got to PROVE that to myself so that it 'sticks' in my ancient old cranium.

My problem(s) with powering it from the existing 12V battery in the vehicle are:
1: Every such race vehicle MUST have a 'battery kill' switch (for safety)
2: The young lass who drives it could easily turn it off at any time
3: As with anything automotive, the 12V rail is kinda 'nominal' and could easily jump around a 100% or so... <Grins>  I don't think the onboard 5V SMPS of a Due would 'appreciate' getting a 24V 'whack' on Vin
I guess another 'option' now that I know the FLASH write speed would be to use an external 'pre-regulator' with its own isolated reservoir capacitor to keep the due running AFTER the battery is switched off.  (I'm already sensing Battery Voltage at the 100Hz data logging rate so I'd know when it's turned off)

As for using the DueFlashStorage library.
There's no fun in that!
Did I mention I'm going 'bare iron'?
I'll roll my own thx <Hehe>
And I'll make sure it's kept isolated from spurious interrupts.... Good tip there on FAULTMASK!
MY SysTick is configured to only fire 100 times a second...  It was all I needed and it keeps one more TC channel 'free' for future use.
As for millis(), Serial.Print() etc, all those 'Arduino' things are WAY outta scope.
If I were coding any lower, I'd have to fire up the assembler!
(There's NO crt0, crtbegin etc code linked into my binary...  Don't want em, don't need em!)

Anyway, I can now safely start writing my FLASH I/O routines....
Thanks a bunch to both of you!

BTW, if anyone starts telling me about the 10k cycle life on the FLASH (@ 85C), I'm not even mildly concerned.
In total, she would do somewhere around 100 races in a season so I'm good for the next 100 years! 1 year was enough for me!
I am not even going to bother 'sharing' the load within the 256kB bank. (Sheer laziness on my part)

trev_vb

Here's some additional questions for y'all...
Firstly, yes, I have tried to find the answer in the 11057 Atmel datasheet, but perhaps I am BLIND again like I was with the FLASH write timing that Westfw kindly pointed me to (BTW, thanx HEAPS again!)
Secondly, I've also browsed through all the source I have access to in order to answer my own questions, but I found that they kinda 'cheat' by using the IAP code that's resident in the on-chip ROM.  (If I am forced to, I might even have to disassemble that ROM code to be certain)

I'll start with some background:
The datasheet states that there are two instances of the Enhanced Embedded Flash Controller (EFC) inside the SAM3X8E (named EFC0 and EFC1).  It also states that there are two * 256kb flash regions (and within CMSIS these are named IFLASH0 and IFLASH1)
Initially, I had assumed (ugh - what a horrible word... LOL) that EFC0 exclusively controlled IFLASH0 and EFC1 exclusively controlled IFLASH1, but then I realized that I've not been able to see that linkage explicitly mentioned within the datasheet.
1: Does this mean that EFC0 can be used to write to BOTH IFLASH0 and IFLASH1? (and same for EFC1)
2: This raises an implication that there is only a single 256 byte page write buffer that is inherently 'shared' by EFC0 and EFC1.  Is this accurate?  This confuses me as I cannot see why there's a need for a second EEFC controller?  Is it technically possible to use EFC0 and EFC1 simultaneously?  Within the same 256kB of FLASH?  I seriously doubt that is likely!

All of the above become perfectly logical to me if EFC0 is 'solely responsible' for IFLASH0 (the first 256kB) and EFC1 is 'solely responsible' for IFLASH1 (the second 256kB).
- They would each have their own independent 256 byte page write buffer (selected by the actual FLASH address used)
- It would be technically feasible to use BOTH EFC0 and EFC1 simultaneously (assuming code is running from RAM or ROM)

ard_newbie

#13
May 13, 2019, 04:31 pm Last Edit: May 13, 2019, 04:35 pm by ard_newbie
You just can't write in Flash from Flash, either from Flash Bank0 or Flash Bank1: You want to write in Flash from SRAM.

You will be using each EFCx to select, e.g. the number of wait states for the corresponding EFCx, not the other one.

There is an interesting Application Note from Atmel: Atmel AT02333: Safe and Secure Bootloader Implementation for SAM3/4.

Read Sam3x datasheet errata section page 1442.

AFAIK, you are free to use IAP function in ROM or EFC registers, except for reading the Unique ID (see the example sketch below):

Code: [Select]

/*********************************************************************/
/*          Read Unique ID and Get Flash Descriptor Functions        */
/*********************************************************************/

#define EEFC0 ((Efc*) 0x400E0A00U)
#define EEFC1 ((Efc*) 0x400E0C00U)
#define GPNVM0    0b1
#define GPNVM1    0b10
#define GPNVM2    0b100
#define EEFC_FKEY 0x5A
#define IFLASH1_ADDR ( IFLASH0_ADDR + IFLASH_SIZE / 2 )
#define CHIP_FLASH_IAP_ADDRESS (IROM_ADDR + 8)
#define EEFC0 EFC1
#define EEFC_FKEY 0x5A
#define EEFC_FMR_SCOD   (0x1ul << 16)
#define IFLASH0_ADDR  0x00080000                               // Flash memory begins at 0x00080000
#define IFLASH1_ADDR ( IFLASH0_ADDR + IFLASH_SIZE / 2 )        // IFLASH1_ADDR  = 0x000C0000


__attribute__ ((section (".ramfunc")))
void ReadUniqueID( uint32_t * latch_buffer )
{
  char __FWS;

  // Set bit 16 of EEFC_FMR : See chap. 49.1.1.2 page 1442
  EFC0->EEFC_FMR |= EEFC_FMR_SCOD;                              // Sequential code optimization disable

  __FWS = (EFC0->EEFC_FMR & EEFC_FMR_FWS_Msk) >> EEFC_FMR_FWS_Pos ; // Save FWS value
  EFC0->EEFC_FMR &= ~ EEFC_FMR_FWS_Msk;
  EFC0->EEFC_FMR |= EEFC_FMR_FWS(6);                            // 6+1 wait states for read and write operations

  //EFC0->EEFC_FMR &= ~EEFC_FMR_FAM;                              // 128-bit access in read Mode only, to enhance access speed.

  while (!(EFC0->EEFC_FSR & EEFC_FSR_FRDY));                    // Send the  STUI command if FRDY bit is high to begin reading in flash
  EFC0->EEFC_FCR = EEFC_FCR_FKEY(EEFC_FKEY) | EFC_FCMD_STUI ;
  //Wait till FRDY falls down
  while (EFC0->EEFC_FSR & EEFC_FSR_FRDY);
  // The Unique Identifier is located in the first 128 bits of
  // the Flash bank 0 in between 0x080000 and 0x08000C (and of the Flash bank 1 in between 0X0C0000 and 0x0C000C ??)
  memcpy(latch_buffer, (void*)IFLASH0_ADDR, 16);                // Read first 128 bits ( 16 first bytes) in one shot beginning at address IFLASHIndex_ADDR

  // Send the SPUI command to stop reading in flash
  EFC0->EEFC_FCR = EEFC_FCR_FKEY(EEFC_FKEY) | EFC_FCMD_SPUI ;
  // Wait till FRDY rises up
  while (!(EFC0->EEFC_FSR & EEFC_FSR_FRDY));

  // Clear bit 16 of EEFC_FMR : See chap. 49.1.1.2 page 1442
  EFC0->EEFC_FMR &= ~EEFC_FMR_SCOD;                             // Sequential code optimization enable

  EFC0->EEFC_FMR &= ~ EEFC_FMR_FWS_Msk;                         // Restore FWS value
  EFC0->EEFC_FMR |= EEFC_FMR_FWS(__FWS);

}
void GetFlashDescriptor( uint32_t * latch_buffer2 )
{
  boolean val;

  //The In Application Programming feature is a function located in ROM that can be called by any software application.
  //When called, this function sends the desired FLASH command to the EEFC and waits for the Flash to be ready
  //The IAP function does NOT work for the Read Unique Identifier commands  !!!

  static uint32_t (* IAP_function) (uint32_t, uint32_t);

  IAP_function = (uint32_t(*)(uint32_t, uint32_t)) * ((uint32_t *) CHIP_FLASH_IAP_ADDRESS);

  //Select reading from Flash Bank 0 or Flash Bank 1
  //val = 0 for EFC0, val = 1 for EFC1
  IAP_function(/*val = */0, EEFC_FCR_FKEY(EEFC_FKEY) | EEFC_FCR_FARG(0) | EEFC_FCR_FCMD(EFC_FCMD_GETD ));

  // If val = 0, select EFC0 else EFC1
  for (byte b = 0; b < 5 ; b++) memcpy(latch_buffer2++, (void*)&EFC0->EEFC_FRR, 4); // Copy 20 bytes from flash to RAM

}
void setup ()
{
  Serial.begin (250000) ;
  /***********   Read Unique ID  ***************************/
  uint32_t latch_buffer[4];
  ReadUniqueID( latch_buffer ) ;

  printf(
    "                                                                  \n"
    "Reading of the 128 bits unique identifier:\n ID = %08X%08X%08X%08X\n",
    latch_buffer[0],
    latch_buffer[1],
    latch_buffer[2],
    latch_buffer[3]
  );

  uint32_t FL_PLANE[2];
  uint32_t FL_ID, FL_SIZE, FL_PAGE_SIZE, FL_NB_PLANE;
  GetFlashDescriptor( latch_buffer ) ;
  Serial.println("Getting Flash Descriptor :");

  for (byte b = 0 ; b < 5 ; b++)
  {
    uint32_t val;
    switch (b) {
      case 0:
        FL_ID = latch_buffer[b];
        val = FL_ID;
        Serial.print("FL_ID = ");
        break;
      case 1:
        FL_SIZE = latch_buffer[b] / 1024;
        val = FL_SIZE;
        Serial.print("FL_SIZE (K bytes)= ");
        break;
      case 2:
        FL_PAGE_SIZE = latch_buffer[b];
        val = FL_PAGE_SIZE;
        Serial.print("FL_PAGE_SIZE (Bytes)= ");
        break;
      case 3:
        FL_NB_PLANE = latch_buffer[b];
        val = FL_NB_PLANE;
        Serial.print("FL_NB_PLANE = ");
        break;
      case 4:
        FL_PLANE[b % 4] = latch_buffer[b] / 1024;
        val = FL_PLANE[b % 4];
        Serial.print("FL_PLANE (K Bytes)["); Serial.print(b % 4); Serial.print("] = ");
        break;
    }
    Serial.println(val, DEC);
  }

}

void loop() {}





trev_vb

Thx Ard_Newbie.
You just can't write in Flash from Flash, either from Flash Bank0 or Flash Bank1: You want to write in Flash from SRAM.
My mistake for not having explicitly declared that all of my code is already RAM-resident.
(FYI, if I was to have used the ROM-Based IAP routine, then it would 'bypass' that issue altogether since the actual update is run from the ROM-based function in that case).

This entire project is partially a 'self-challenge' and part of that challenge is to run the whole thing from RAM.  Therefore I have used a significantly 'customized' linker script rather than the flash.ld version used by the Arduino IDE.
A second part of that self-challenge has been to make sure that every single instruction executed on the Due was written by ME rather than some 'unknown third party'.  My project 'takes control' right at the Reset_Handler() entry point and never relinquishes that control to anything else... Ever!  (And that is why I want to avoid using the ROM-Based IAP function to write data into FLASH).
In my version of Reset_Handler, all of the actual application code is copied from FLASH into RAM.
After that, the interrupt vector table is relocated (using SCB->VTOR) to point to the new table in RAM.
Finally, execution branches over to the newly RAM-resident code.
(It's interesting to note that calling a RAM-based project-mainline from code running in FLASH requires a 'veneer' since the ARM branch-with-link (bl) instruction is unable to encode such a large 'relative' branch from FLASH to RAM.)

In a prior post, you mentioned that execution from RAM is s-l-o-w-e-r than from FLASH which kinda surprised me.  I still intend to confirm that detail for myself in due course.  I readily accept that execution from FLASH can overcome MOST of the inherent slowdown (wait states) due to the wider path employed, but this still leaves the non-sequential code execution (eg: any branch instructions) that will incur the wait-state penalties.

I mentioned in a prior post that this is a truly 'bare-iron' project.  I should have repeated that so mea culpa.
You will be using each EFCx to select, e.g. the number of wait states for the corresponding EFCx, not the other one.
There is an interesting Application Note from Atmel: Atmel AT02333: Safe and Secure Bootloader Implementation for SAM3/4.
Yep, that's all quite logical and is explicitly mentioned in the datasheet. Thx
However, I've not found anything in the datasheet that fully describes the 256 byte page-write buffer.  Is there a single buffer 'shared' by EFC0 and EFC1 as is implied by the fact that it wraps around throughout the 1MB of Flash address space (See 18.4.1)  If true, then applications code CANNOT simultaneously write to FLASH using both EFCs (eg: In alternate execution 'threads')
Nor have I explicitly read whether each EFC can encompass the ENTIRETY of FLASH or just one 256kB half.
It actually gets even MORE confusing when the datasheet seems to imply that EFC0 and EFC1 are actually used during execution for opcode fetch!  (And this implies that system firmware can inadvertently potentially 'corrupt' program execution by setting the number of wait states within EFCn to a value that is too low for reliable operation at the current MCLK speed!)
Lastly, there's even a place in the datasheet that I may need to refer back to Atmel / Microchip.as 'datasheet errata'.  (Take a look at tables 7.2 within 7.2.3.1 Flash overview.  The footnote states:
The Flash contains a 128 byte write buffer, accessible through a 32-bit interface'
Everywhere else in the datasheet, the write buffer is referred to as a 256 byte buffer which corresponds to a single Flash 'page'
Read Sam3x datasheet errata section page 1442.
For others out there, this is a very valid point!
Specifically, the errata advises to set the wait-states to 6 when writing FLASH.to avoid corrupt writes to FLASH.
AFAIK, you are free to use IAP function in ROM or EFC registers, except for reading the Unique ID (see the example sketch below):
I agree that I could simply use the ROM-based IAP function, but that would slightly negate part of my 'self-learning' goal of this project (to write the whole thing as a truly 'bare-iron' project)

In summary, I think that I'm just going to have to 'probe' things myself to conclusively determine the answers I need and that's going to take some time.
If anyone is interested, I guess I can report back to this forum

Go Up