Atmel SAM V71 - reading and writing non-volatile settings in Flash

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

Hi all

I am working on an application (based on Atmel START) with the SAM V71 Xplained board and things are running quite fine.

 

Now I am trying to use internal Flash memory for storing non-volatile application settings. Unfortunately I cannot find a decent overview of how to do this. The only generated example code I can find is this:

 

/**
 * Example of using FLASH_0 to read and write buffer.
 */
void FLASH_0_example(void)
{
	uint32_t page_size;
	uint16_t i;

	/* Init source data */
	page_size = flash_get_page_size(&FLASH_0);

	for (i = 0; i < page_size; i++) {
		src_data[i] = i;
	}

	/* Write data to flash */
	flash_write(&FLASH_0, 0x3200, src_data, page_size);

	/* Read data from flash */
	flash_read(&FLASH_0, 0x3200, chk_data, page_size);
}

But I want to declare variables in Flash and read/write at those locations. I found useful macros in hal\utils\include\utils.h:

/**
 * \brief Flash located data macros
 */
#if defined __GNUC__
#define PROGMEM_DECLARE(type, name) const type name
#define PROGMEM_T const
#define PROGMEM_READ_BYTE(x) *((uint8_t *)(x))
#define PROGMEM_PTR_T const *
#define PROGMEM_STRING_T const uint8_t *
#elif defined __ICCARM__
#define PROGMEM_DECLARE(type, name) const type name
#define PROGMEM_T const
#define PROGMEM_READ_BYTE(x) *((uint8_t *)(x))
#define PROGMEM_PTR_T const *
#define PROGMEM_STRING_T const uint8_t *
#elif defined __CC_ARM
#define PROGMEM_DECLARE(type, name) const type name
#define PROGMEM_T const
#define PROGMEM_READ_BYTE(x) *((uint8_t *)(x))
#define PROGMEM_PTR_T const *
#define PROGMEM_STRING_T const uint8_t *
#endif

OK, so I declare a variable and try writing it as follows:

pgm_vals_t pgm_obj;														// SRAM instance
PROGMEM_DECLARE(pgm_vals_t, pgm_obj_flash) = PGM_VALS_DEFAULT_MACRO;	// Flash instance
[...]
uint32_t flash_addr = (uint32_t)&pgm_obj_flash - IFLASH_ADDR;
uint8_t *pBuf = (uint8_t*)&pgm_obj;
uint32_t len = sizeof(pgm_obj);

#ifdef DEBUG_FLASH_SETTINGS_UPDATED
	io_write_string_variadic(&io_write_debug, "Flash settings updated; %d bytes at 0x%04x" ASCII_NEWLINE_STR, len, flash_addr);
#endif

int32_t result = flash_write(&FLASH_0, flash_addr, pBuf, len);

if (result != ERR_NONE)
{
	// TODO: indicate error somehow
	io_write_string_variadic(&io_write_debug, "Flash write failed! Error code %d" ASCII_NEWLINE_STR, result);
}

Subtracting IFLASH_ADDR from the address is something I figured out after getting error codes from flash_write(). The debug output is:

Flash settings updated; 104 bytes at 0x78b4

 

But it seems like this is corrupting my application itself. Every time a Flash update is done, the application seems to crash (becomes unresponsive, LED stops blinking etc). I suspect that the problem is that when the application data is written, the whole Flash page (which probably includes app code) is erased and then written. So I guess I must somehow declare my application data in its own Flash page. How is this done? Or is it something else that I must do?

This topic has a solution.

/Jakob Selbing

Last Edited: Fri. Jan 25, 2019 - 02:32 PM
This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

This ASF section is within the AVR not ARM part of this site so you may not find too many ARM users reading here.

 

The technique however is the same whether you use ARM or AVR and that is you probably want to use __attribute__((section(".yourname"))) to assign some area of flash to a named section then either the linker script of a -section-start to tell the linker where you want that data object to be located. Alternatively just hard code the flash addresses. Pick 0xB000 or whatever flash address makes sense and use this literal value (plus soffset) when you come to saying where the pages of flash data are to be written

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

Thanks, I found this site that gave an overview: http://blog.atollic.com/using-gn...

 

It seems it works fine now!

/Jakob Selbing

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

Yeah that site shows how to do it in a linker script modification. Personally I think that for something simple the n-section-start is possibly the easier approach. YMMV.

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

clawson wrote:

Personally I think that for something simple the n-section-start is possibly the easier approach.

Would you care to explain what that means?

 

BTW this is my modification to the linker script:


/* Memory Spaces Definitions */
MEMORY
{
    rom (rx)     : ORIGIN = 0x00400000, LENGTH = 0x001f0000 /* rom, 2097152K */
    flash_vars(x): ORIGIN = 0x005f0000, LENGTH = 0x00010000 /* *** MY CUSTOM SECTION: reserved for non-volatile application variables ***  */
    ram (rwx)    : ORIGIN = 0x20400000, LENGTH = 0x00060000 /* ram, 393216K */
}

// [...]

/* Section Definitions */
SECTIONS
{
    // [...]

    // My custom section
	.flash_vars :
	{
		*(.flash_vars*);
	} > flash_vars

	// [...]

And then my variable declaration:

#define FLASH_VAR_ATTRIBUTE	__attribute__ ((section (".flash_vars")))
// [...]

const pgm_vals_t FLASH_VAR_ATTRIBUTE pgm_obj_flash = PGM_VALS_DEFAULT_MACRO;	// Flash instance; stored in custom memory section to allow erase/write

 

/Jakob Selbing

Last Edited: Fri. Jan 25, 2019 - 03:16 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

If you want __attribue__((section(".foo"))) at address 0x1234 you basically have two options. One is to put an entry for ".foo" in the linker script, possibly specifying an exact location or maybe just let the linker position it "after the previous section" (though for flash writing you will want it aligned to a page boundary at least) or you can leave the linker script as it is and instead add to the linker options something like -Wl,-section-start=.foo=0x1234 to tell the linker where to put it (of course in this case the 1234 you choose might be in conflict with something the linker was already placing).