V71 - Read/Write to user signature section of flash (pretty close but not quite there)

1 post / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0


Hello everyone!

 

I am trying to be able to write to the user signature section of the flash on an ATSAMV71Q21B chip in Atmel Studio 7 using the Atmel Start framework:

 

(From datasheet)

 

I managed to get some working code to be able to write to the first long of the user signature section, which is shown below:

 

#define IFLASH_ADDR              _U_(0x00400000)       /**< IFLASH base address (type: flash)*/

/-----------------------------------------------------------------------------
__attribute__ ((noinline))
__attribute__ ((section(".ramfunc")))
void efc_command(int command, int argument)
{
  __disable_irq();

  EFC->EEFC_FCR = EEFC_FCR_FKEY_PASSWD | EEFC_FCR_FARG(argument) |
      EEFC_FCR_FCMD(command);

  while (0 == (EFC->EEFC_FSR & EEFC_FSR_FRDY));

  __enable_irq();
}

//-----------------------------------------------------------------------------
void user_signature_erase(void)
{
  return efc_command(EEFC_FCR_FCMD_EUS, 0);
}

//-----------------------------------------------------------------------------
void user_signature_write(uint32_t *data)
{
  uint32_t *flash = (uint32_t *)IFLASH_ADDR;

  for (int i = 0; i < (int)(IFLASH_PAGE_SIZE / sizeof(uint32_t)); i++)
    flash[i] = data[i];

  efc_command(EEFC_FCR_FCMD_WUS, 0);
}

//-----------------------------------------------------------------------------
__attribute__ ((noinline))
__attribute__ ((section(".ramfunc")))
void user_signature_read(uint32_t *data)
{
  uint32_t *flash = (uint32_t *)IFLASH_ADDR;

  __disable_irq();

  EFC->EEFC_FMR |= EEFC_FMR_SCOD;

  EFC->EEFC_FCR = EEFC_FCR_FKEY_PASSWD | EEFC_FCR_FARG(0) |
      EEFC_FCR_FCMD(EEFC_FCR_FCMD_STUS);

  while (EEFC_FSR_FRDY == (EFC->EEFC_FSR & EEFC_FSR_FRDY));

  for (int i = 0; i < (int)(IFLASH_PAGE_SIZE / sizeof(uint32_t)); i++)
    data[i] = flash[i];

  EFC->EEFC_FCR = EEFC_FCR_FKEY_PASSWD | EEFC_FCR_FARG(0) |
      EEFC_FCR_FCMD(EEFC_FCR_FCMD_SPUS);

  while (0 == (EFC->EEFC_FSR & EEFC_FSR_FRDY));

  EFC->EEFC_FMR &= ~EEFC_FMR_SCOD;

  __enable_irq();
}

Overall, this worked well but it had the write location hardcoded (IFLASH_ADDR). 

 

I created two additional functions to be able to write/read the desired memory locations. 

 

Below is the source code I used for these two additional functions:

 

void NVM_user_signature_write_address(uint32_t *data, uint32_t *address)
{
	//uint32_t *flash = (uint32_t *)IFLASH_ADDR;

	for (int i = 0; i < (int)(IFLASH_PAGE_SIZE / sizeof(uint32_t)); i++)
	address[i] = data[i];

	NVM_efc_command(EEFC_FCR_FCMD_WUS, 0);
}

__attribute__ ((noinline))
__attribute__ ((section(".ramfunc")))
void NVM_user_signature_read_address(uint32_t *data, uint32_t *address)
{
	//uint32_t *flash = (uint32_t *)IFLASH_ADDR;

	__disable_irq();

	EFC->EEFC_FMR |= EEFC_FMR_SCOD;

	EFC->EEFC_FCR = EEFC_FCR_FKEY_PASSWD | EEFC_FCR_FARG(0) |
	EEFC_FCR_FCMD(EEFC_FCR_FCMD_STUS);

	while (EEFC_FSR_FRDY == (EFC->EEFC_FSR & EEFC_FSR_FRDY));

	for (int i = 0; i < (int)(IFLASH_PAGE_SIZE / sizeof(uint32_t)); i++)
	data[i] = address[i];

	EFC->EEFC_FCR = EEFC_FCR_FKEY_PASSWD | EEFC_FCR_FARG(0) |
	EEFC_FCR_FCMD(EEFC_FCR_FCMD_SPUS);

	while (0 == (EFC->EEFC_FSR & EEFC_FSR_FRDY));

	EFC->EEFC_FMR &= ~EEFC_FMR_SCOD;

	__enable_irq();
}

I called these functions with the following code:

 



#define IFLASH_ADDR_SOURCE_QTR			_U_(0x00400004)       /**< IFLASH base address (type: flash)*/

uint32_t spc_u32_temp_ulong =  2150137332;

NVM_user_signature_write_address( &spc_u32_temp_ulong, IFLASH_ADDR_SOURCE_QTR);
NVM_user_signature_read_address( &spc_u32_temp_ulong, IFLASH_ADDR_SOURCE_QTR );

Effectively, I'm trying to write the value of 2150137332  to address 0x00400004 and then read it back. 

 

The problem I ran into is when I try and read the data back, I get a different value than expected being returned.

 

When I set breakpoints in the NVM_user_signature_read_address() function, it shows the following when I hover over these variables:

 

data[i] -> *data = 2150137332 or data = 0x20401acc

flash[i] -> *address = 4196257 or address = 0x400004 (exception table + 4)

 

When I read the value of spc_u32_temp_ulong after running NVM_user_signature_read_address() (which I assume will just read back the value of 2150137332 that I stored in address 0x00400004.

 

Unfortunately, the value returned in spc_u32_temp_ulong was 3369849314.

 

I assume I'm doing something wrong but I'm having trouble seeing it. Maybe I'm calling the functions incorrectly or the way I'm implementing them is incorrect?  I think I'm pretty close but likely missing something really basic (I assume I have something implemented incorrectly in my functions, since it seemed to work for a single defined location using the initial code). 

 

Any help you can give me would be greatly appreciated.  Thanks, guys!