I am currently developing a feature for a device based on Atmel's at91sam7s256 MCU. The feature is a counter with a pre-set value, which is decreased at some points. My Idea was to implement this counter in the internal flash memory, since most of the flash space is unused.
I added a separate linker section to the ld script and included a variable into this section. The linker script:
/*
FLASH is reserved for internal settings
*/
MEMORY
{
CODE (rx) : ORIGIN = 0x00100000, LENGTH = 252k
FLASH (rx) : ORIGIN = 0x0013F000, LENGTH = 4k
DATA (rwx) : ORIGIN = 0x00200000, LENGTH = 64k
}
__FIRST_IN_RAM = ORIGIN(DATA);
__TOP_STACK = ORIGIN(DATA) + LENGTH(DATA);
/* Section Definitions */
SECTIONS
{
/* first section is .text which is used for code */
. = ORIGIN(CODE);
.text :
{
KEEP(*(.vectorg))
. = ALIGN(4);
KEEP(*(.init))
*(.text .text.*) /* remaining code */
*(.gnu.linkonce.t.*)
*(.glue_7)
*(.glue_7t)
*(.gcc_except_table)
*(.rodata) /* read-only data (constants) */
*(.rodata.*)
*(.gnu.linkonce.r.*)
. = ALIGN(4);
} >CODE
. = ALIGN(4);
/* .ctors .dtors are used for c++ constructors/destructors */
.ctors :
{
PROVIDE(__ctors_start__ = .);
KEEP(*(SORT(.ctors.*)))
KEEP(*(.ctors))
PROVIDE(__ctors_end__ = .);
} >CODE
.dtors :
{
PROVIDE(__dtors_start__ = .);
KEEP(*(SORT(.dtors.*)))
KEEP(*(.dtors))
PROVIDE(__dtors_end__ = .);
} >CODE
. = ALIGN(4);
_etext = . ;
PROVIDE (etext = .);
/* .data section which is used for initialized data */
.data : AT (_etext)
{
_data = . ;
KEEP(*(.vectmapped))
. = ALIGN(4);
*(.fastrun .fastrun.*)
. = ALIGN(4);
SORT(CONSTRUCTORS)
. = ALIGN(4);
*(.data)
*(.data.*)
*(.gnu.linkonce.d.*)
. = ALIGN(4);
} >DATA
. = ALIGN(4);
_edata = . ;
PROVIDE (edata = .);
/* .bss section which is used for uninitialized data */
.bss (NOLOAD) :
{
__bss_start = . ;
__bss_start__ = . ;
*(.bss)
*(.bss.*)
*(.gnu.linkonce.b.*)
*(COMMON)
. = ALIGN(4);
} >DATA
. = ALIGN(4);
__bss_end__ = . ;
.flash :
{
. = ORIGIN(FLASH);
*(.flash*)
. = ALIGN(4);
} >FLASH
_end = .;
PROVIDE (end = .);
}
The following routine is used when the counter is decremented:
#define INTERNAL_FLASH __attribute__((section(".flash")))
#define AT91C_MC_WRITE_KEY ((unsigned)0x5A << 24) // Magic number
INTERNAL_FLASH uint32_t Counter = 30; // The section .flash begins at 0x0013F000
void prepaid_decrement(void)
{
if(Counter > 0) {
// write into buffer
Counter = Counter - 1;
volatile AT91PS_MC mc = AT91C_BASE_MC;
// set flash mode (timing)
mc->MC_FMR = AT91C_MC_FWS_1FWS | ((1 + (((MCK * 15) / 10000000))) << 16);
uint32_t page = ((uint32_t)&Counter - (uint32_t)AT91C_IFLASH) / (uint32_t)AT91C_IFLASH_PAGE_SIZE;
// start writing
mc->MC_FCR = AT91C_MC_WRITE_KEY | AT91C_MC_FCMD_START_PROG | (page << 8);
if(0 != (mc->MC_FSR & AT91C_MC_PROGE)) {TRACE("error!");}
while (!(AT91C_BASE_MC->MC_FSR & AT91C_MC_FRDY));
}
}
But the code hangs in
mc->MC_FCR = AT91C_MC_WRITE_KEY | AT91C_MC_FCMD_START_PROG | (page << 8);
. The lines below are never reached, because the MCU jumps into an exception loop (address 0x60 in the vector table).
Anyway, the data seems to be written correctly because after a reset the counter variable is decreased by one.
Can anyone tell me what I am doing wrong? The code is not being interrupted.