在RAM初始化之前使用#defined值

时间:2013-04-07 22:23:18

标签: c arm c-preprocessor linker-scripts

我正在编写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

2 个答案:

答案 0 :(得分:3)

直接回答您的问题 - #defined值不会存储在程序中的任何位置(除了可能在调试部分中)。宏在编译时被扩展,就好像你在函数中输入它们一样,如:

*((unsigned int *) 0xd0010000) = 0x800f800f;

这些值最终会在文本段中结束,作为已编译代码的一部分。

这里更有可能的是你还有其他错误。我的第一个猜测是你的堆栈没有正确初始化,或者位于一个尚不可用的内存区域。

答案 1 :(得分:1)

有几种方法可以解决这个问题。

  1. 使用PC相对数据访问。
  2. 使用自定义linker script
  3. 使用汇编程序。
  4. 使用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。这是一个相当昂贵/长时间运行的任务,您可以使用一些简短的汇编程序加快速度。