ARM开发的问题总结

来源:互联网 发布:java对象实例化 编辑:程序博客网 时间:2024/06/05 02:37

汇编代码要注意有些要顶格,有些要加空格,否则编译会有问题

 

(一)堆的设置问题

在启动代码 B__mian指令后,程序没有跳到main函数处,而是进入了异常中断。

原因:通过反汇编,可以看到,在执行B__mian指令后,并不是立即跳到main函数处,而是先跳到__main库函数入口,再执行一些堆栈的拷贝等初始化操作,最后跳到main函数处。出现异常,可能是堆或栈的设置有问题。(在一个例子中发现把堆得起始地址改小就可以了)

 

(二)ARM在RAM中调试问题

 

IROM1:0x4000000     0x10000    (必须将IROM1地址设置到RAM空间)

IRAM1:0x4010000      0x8000

 

RAM.ini 文件中

PC = 0x04000000;

 

(三)如何指定某段代码的运行空间

 选择该文件(*.c),鼠标右键(options for File '*.c')---->Memory Assignment 可指定该文件代码运行的空间(可以运行在FLASH,也可以指定在RAM)

 

(四)MDK生成bin文件

可以用ARM自带的fromelf.exe将*.axf文件转换成*.bin文件

 

Options for Target---->user---->run #1----->

 

C:/Keil/ARM/BIN31/fromelf.exe --bin -o ./output/Axf_To_Bin.bin ./output/Axf_To_Bin.axf

 

(四)编译后的代码含义

Program Size: Code=2356 RO-data=32 RW-data=28 ZI-data=1292 

 

================================================================================

    Total RO  Size (Code + RO Data)                 2388 (   2.33kB)
    Total RW  Size (RW Data + ZI Data)              1320 (   1.29kB)
    Total ROM Size (Code + RO Data + RW Data)       2416 (   2.36kB)

================================================================================

 

  Execution Region RW_IRAM1 (Base: 0x04000000, Size: 0x00000528, Max: 0x00018000, ABSOLUTE)

    Base Addr    Size         Type   Attr      Idx    E Section Name        Object

    0x04000000   0x0000001c   Data   RW           89    .data               main.o
    0x0400001c   0x00000004   PAD
    0x04000020   0x00000508   Zero   RW            1    STACK               str91x.o

 

Code表示程序代码量

RO-data 表示固定常量(const 变量)

RW-data 表示初始化常量(char gloab_test =5)

ZI -data 表示未初始化初始化常量,即是零(char gloab_test =0) 

烧写到FALSH的空间:Code + RO Data + RW Data

RAM空间: RW Data + ZI Data

启动代码中,显然有个RW Data 拷贝过程,其实还应该包括初ZI -data 清零过程,堆和栈的初始化过程,这些应该在B__mian指令后实现,只有通过反汇编可以看到

 

(五) 未对齐的数据指针

  C和C++编程标准规定,指向某一数据类型的指针,必须和该类型的数据地址对齐方式一致,所以ARM 编译器期望程序中的 C 指针指向存储器中字对齐地址,因为这可使编译器生成更高效的代码。

  比如,如果定义一个指向 int 数据类型的指针,用该指针读取一个字,ARM 编译器将使用LDR 指令来完成此操作。如果读取的地址为四的倍数(即在一个字的边界)即能正确读取。但是,如果该地址不是四的倍数,那么,一条 LDR 指令返回一个循环移位结果,而不是执行真正的未对齐字载入。循环移位结果取决于该地址向对于字的边界的偏移量和系统所使用的端序(Endianness)。例如,如果代码要求从指针指向的地址 0x8006 载入数据,即要载入 0x8006、0x8007、0x8008 和 0x8009 四字节的内容。但是,在 ARM 处理器上,这个存取操作载入了0x8004、0x8005、0x8006 和 0x8007 字节的内容。这就是在未对齐的地址上使用指针存取所得到的循环移位结果。

  因而,如果想将指针定义到一个指定地址(即该地址为非自然边界对齐),那么在定义该指针时,必须使用 __packed 限定符来定义指针: 例如,

  __packed int *pi; // 指针指向一个非字对其内存地址

  使用了_packed限定符限定之后,ARM 编译器将产生字节存取命令(LDRB或STRB指令)来存取内存,这样就不必考虑指针对齐问题。所生成的代码是字节存取的一个序列,或者取决于编译选项、跟变量对齐相关的移位和屏蔽。但这会导致系统性能和代码密度的损失。

  值得注意的是,不能使用 __packed 限定的指针来存取存储器映射的外围寄存器,因为 ARM 编译程序可使用多个存储器存取来获取数据。因而,可能对实际存取地址附近的位置进行存取,而这些附近的位置可能对应于其它外部寄存器。当使用了位字段(Bitfield)时, ARM 程序将访问整个结构体,而非指定字段。

 

 

(六) Ro Base设置

链接文件选项中,应将映像文件的Ro Base地址设置到映像文件实际运行的起始地址。例如,将Ro Base设置成0x30000000,把它下载到0x0地址开始执行是不正确,必须将该代码复制到0x30000000起始地址处才能开始正确执行,或者将Ro Base 设置到0x0地址

 

(七) __irq关键字

汇编调用C中断函数

 

汇编文件相关代码(*.s)

      IMPORT  IRQ_Handler    ;不能顶格写

 

IRQ_Addr        DCD     IRQ_Handler

 

 

C文件相关代码(*.c)

__irq void IRQ_Handler (void) {
  if (IRQSIG & 0x00000004) {        // Timer 0 Interrupt
    T0CLRI = 1;                     // Clear Timer 0 Interrupt
    T0_Tick++;                      // Increment Timer 0 Tick
  }
}

 

“__irq”专门用来声明IRQ中断服务程序,如果用“__irq”来声明一个函数,那么该函数表示一个IRQ中断服务程序,编译器便会自动在该函数内部增加中断现场保护的代码