【发布时间】:2015-12-08 13:14:13
【问题描述】:
我目前正在为基于 Atmel 的 at91sam7s256 MCU 的设备开发一项功能。该功能是一个具有预设值的计数器,该值在某些点会减小。 我的想法是在内部闪存中实现这个计数器,因为大部分闪存空间都没有使用。
我在 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 会跳入异常循环(向量表中的地址 0x60)。
无论如何,数据似乎被正确写入,因为在重置后计数器变量减一。
谁能告诉我我做错了什么?代码没有被中断。
【问题讨论】:
-
"Counter = Counter - 1" 尝试写入闪存中的地址,这很可能是只读区域。您没有粘贴链接描述文件。
-
变量链接到节开头的固定地址。这意味着(buffer-)变量是可写的,也可以通过调用写命令将其写入闪存。但不知何故它挂在这个命令虽然闪存已经写入。
-
我没有使用这个特定的 MCU,但根据文档:atmel.com/Images/doc6175.pdf 内部闪存介于 0x00100000 和 0x001FFFFF 之间。您的代码指示将变量“counter”放入“.flash”部分。您源代码中的注释指出,“.flash”位于 0x0013F000,实际上是内部闪存。本节很可能是只读的。如果没有看到您的链接器脚本,我无法提供更多帮助。
-
根据文档,对闪存的写操作被应用到一个缓冲区。一旦调用写入命令,该缓冲区就会立即写入实际的闪存。所以我所做的是获取一个特定的闪存页面(第 1008 页)并在其开头写入变量。然后我调用 write 命令并将页面缓冲区写入内存。正如我所说,数据实际上是写入的,甚至可以在复位后读出。但控制器进入异常状态。
-
啊哈,我明白了。那你读过doctort.org/adam/nerd-notes/arm-flash-memory.html吗?在 cmets 中也有人遇到过类似的问题。
标签: c arm embedded atmel flash-memory