内部写入at91sam7s256 flash

Write to at91sam7s256 flash internally

我目前正在为基于 Atmel 的 at91sam7s256 MCU 的设备开发一项功能。该功能是一个具有预设值的计数器,该值在某些点会减少。 我的想法是在内部闪存中实现这​​个计数器,因为大部分闪存 space 未被使用。

我在 ld 脚本中添加了一个单独的链接器部分,并在该部分中包含了一个变量。链接描述文件:

/*
    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 = .);
}

计数器递减时使用以下例程:

#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));
    }
}

但代码挂起 mc->MC_FCR = AT91C_MC_WRITE_KEY | AT91C_MC_FCMD_START_PROG | (page << 8);。永远不会到达下面的行,因为 MCU 跳入异常循环(向量 table 中的地址 0x60)。

无论如何,数据似乎是正确写入的,因为重置后计数器变量减一。

谁能告诉我我做错了什么?代码没有被打断。

代码导致异常,因为它在尝试对闪存编程时正在闪存外执行。一旦闪存模式寄存器被写入,就不能再从闪存中读取指令。编程flash的函数应该放在RAM中。