我正在编写ARM CPU的启动代码。没有内部RAM,但有1GB的DDRAM连接到CPU,在初始化之前无法直接访问。代码存储在闪存中,初始化RAM,然后将自身和数据段复制到RAM并继续执行。我的节目是:
#define REG_BASE_BOOTUP 0xD0000000
#define INTER_REGS_BASE REG_BASE_BOOTUP
#define SDRAM_FTDLL_REG_DEFAULT_LEFT 0x887000
#define DRAM_BASE 0x0
#define SDRAM_FTDLL_CONFIG_LEFT_REG (DRAM_BASE+ 0x1484)
... //a lot of registers
void sdram_init() __attribute__((section(".text_sdram_init")));
void ram_init()
{
static volatile unsigned int* const sdram_ftdll_config_left_reg = (unsigned int*)(INTER_REGS_BASE + SDRAM_FTDLL_CONFIG_LEFT_REG);
... //a lot of registers assignments
*sdram_ftdll_config_left_reg = SDRAM_FTDLL_REG_DEFAULT_LEFT;
}
目前我的程序运行不正常,因为寄存器值最终被链接到RAM,并且在程序尝试访问它们时,只有闪存可用。
如何更改我的链接描述文件或程序,以便这些值在flash中具有地址?有没有办法在文本段中包含这些值?
在文件范围声明它们时,实际上是那些定义的值全局或静态数据吗?
编辑:
目标文件与以下链接描述文件链接:
MEMORY
{
RAM (rw) : ORIGIN = 0x00001000, LENGTH = 12M-4K
ROM (rx) : ORIGIN = 0x007f1000, LENGTH = 60K
VECTOR (rx) : ORIGIN = 0x007f0000, LENGTH = 4K
}
SECTIONS
{
.startup :
{
KEEP((.text.vectors))
sdram_init.o(.sdram_init)
} > VECTOR
...
}
从寄存器分配中反汇编:
*sdram_ftdll_config_left_reg = SDRAM_FTDLL_REG_DEFAULT_LEFT;
7f0068: e59f3204 ldr r3, [pc, #516] ; 7f0274 <sdram_init+0x254>
7f006c: e5932000 ldr r2, [r3]
7f0070: e59f3200 ldr r3, [pc, #512] ; 7f0278 <sdram_init+0x258>
7f0074: e5823000 str r3, [r2]
...
7f0274: 007f2304 .word 0x007f2304
7f0278: 00887000 .word 0x00887000
答案 0 :(得分:3)
直接回答您的问题 - #defined
值不会存储在程序中的任何位置(除了可能在调试部分中)。宏在编译时被扩展,就好像你在函数中输入它们一样,如:
*((unsigned int *) 0xd0010000) = 0x800f800f;
这些值最终会在文本段中结束,作为已编译代码的一部分。
这里更有可能的是你还有其他错误。我的第一个猜测是你的堆栈没有正确初始化,或者位于一个尚不可用的内存区域。
答案 1 :(得分:1)
有几种方法可以解决这个问题。
PC
相对数据访问。linker script
。PC
相对数据访问您使用此方法遇到的麻烦是您必须了解编译器将如何生成代码的详细信息。 #define register1 (volatile unsigned int *)0xd0010000UL
是存储为从链接的SDRAM地址加载的静态变量。
7f0068: ldr r3, [pc, #516] ; 7f0274 <sdram_init+0x254>
7f006c: ldr r2, [r3] ; !! This is a problem !!
7f0070: ldr r3, [pc, #512] ; 7f0278 <sdram_init+0x258>
7f0074: str r3, [r2]
...
7f0274: .word 0x007f2304 ; !! This memory doesn't exist.
7f0278: .word 0x00887000
你必须这样做,
void ram_init()
{
/* NO 'static', you can not do that. */
/* static */ volatile unsigned int* const sdram_reg =
(unsigned int*)(INTER_REGS_BASE + SDRAM_FTDLL_CONFIG_LEFT_REG);
*sdram_ftdll_config_left_reg = SDRAM_FTDLL_REG_DEFAULT_LEFT;
}
或者您可能更喜欢在汇编程序中实现它,因为它可能非常迟钝,您可以在这里做什么和不能做什么。上述C
代码的主要作用是计算每个事物或PC
相对。如果您选择不来使用链接描述文件,则必须如此。正如Duskwuff指出的那样,您也可能遇到堆栈问题。如果没有ETB内存等,可以用作临时堆栈,那么最好用汇编程序对它进行编码。
在这种情况下,请参阅gnu linker map...以及有关使用链接描述文件的许多其他问题。如果需要特定内容,则需要使用处理器使用的实际地址。使用此选项,您可以annotate your function指定它将居住的部分。例如,
void ram_init() __attribute__((section("FLASH")));
在这种情况下,您可以使用Gnu Linkers MEMORY
语句和AT
语句将此代码放在您希望从中运行的 flash地址。 / p>
汇编程序可让您完全控制内存使用。您可以保证不使用任何堆栈,不会生成非PC
相对代码,并且它可能会更快boot
。这是我用过的一些table
驱动的ARM汇编程序,用于描述的情况,初始化SDRAM控制器。
/* Macro for table of register writes. */
.macro DCDGEN,type,addr,data
.long \type
.long \addr
.long \data
.endm
.set FTDLL_CONFIG_LEFT, 0xD0001484
sdram_init:
DCDGEN 4, FTDLL_CONFIG_LEFT, 0x887000
1:
init_sdram_bank:
adr r0,sdram_init
adr r1,1b
1:
/* Delay. */
mov r5,#0x100
2: subs r5,r5,#1
bne 2b
ldmia r0!, {r2,r3,r4} /* Load DCD entry. */
cmp r2,#1 /* byte? */
streqb r4,[r3] /* Store byte... */
strne r4,[r3] /* Store word. */
cmp r0,r1 /* table done? */
blo 1b
bx lr
/* Dump literal pool. */
.ltorg
汇编程序有很多好处。您也可以清除bss
部分,并使用简单的例程设置stack
。互联网上有很多,我认为你可以自己编写代码。 gnu ld
脚本对汇编程序也很有用,因为您可以确保bss
之类的部分是对齐的,并且是4,8的倍数等。因此清算程序不需要特殊情况。此外,您必须在初始化后将code
从 flash 复制到SDRAM。这是一个相当昂贵/长时间运行的任务,您可以使用一些简短的汇编程序加快速度。