年轻的lucien

2023-02-24 08:16

keil编译不能打开头文件

🏵️回顾一下,就是keil软件首先从启动文件开始执行程序。首先启动文件先开辟栈空间和堆空间,然后定义一个数据段RESET放中断向量表,然后再定义一个代码段.text放中断服务程序。并且第一个中断服务程序就是复位中断服务程序。复位后,就会进行浮点运算设置(对于F407而言),同时调用外部函数SystemInit进行系统初始化,然后寻找main这个词,如果找到了就生成__main函数初始化用户堆栈和变量,然后调用main函数。
🏵️__main函数找不到源代码。
🏵️在以前 ARM7/ARM9 内核的控制器在复位后,CPU 会从存储空间的绝对地址0x00000000取出第一条指令执行复位中断服务程序的方式启动,即固定了复位后的起始地址为 0x00000000(PC = 0x00000000),同时中断向量表的位置也是固定的。 而 Cortex-M3内核复位后的起始地址和中断向量表的位置可以被重映射。重映射的方法是通过启动模式的选择, 有以下 3 种情况:
🌵通过 boot 引脚设置可以将中断向量表定位于 SRAM 区,即起始地址为0x2000000,同时复位后 PC 指针位于 0x2000000 处;
🌵通过 boot 引脚设置可以将中断向量表定位于 FLASH 区,即起始地址0x8000000,同时复位后 PC 指针位于 0x8000000 处;
🌵通过 boot 引脚设置可以将中断向量表定位于内置 Bootloader 区,这种情况先不考虑。
🏵️Cortex-M3 内核规定,起始地址必须存放堆顶指针MSP,而第二个地址则必须存放复位中断入口向量地址,这样在 Cortex-M3 内核复位后,会自动从起始地址的下一个 32 位空间取出复位中断入口向量,跳转执行复位中断服务程序。
🏵️启动模式不同,启动的起始地址是不一样的,下面我们以代码下载到内部 FLASH 的情况举例,即代码从地址 0x0800 0000 开始被执行。

我们知道的复位方式有三种:上电复位,硬件复位和软件复位。当产生复位,并且离开复位状态后, CM3 内核做的第一件事就是读取下列两个 32 位整数的值:
(1)从地址 0x0800 0000 处取出堆栈指针 MSP 的初始值,该值就是栈顶地址。
(2)从地址 0x0800 0004 处取出程序计数器指针 PC 的初始值,该值指向复位后执行
的第一条指令。
🏵️注意,这与传统的 ARM 架构不同——其实也和绝大多数的其它单片机不同。传统
的 ARM 架构总是从 0 地址开始执行第一条指令。它们的 0 地址处总是一条跳转指令。 而在 CM3 内核中,0地址处提供 MSP 的初始值,然后就是向量表(向量表在以后还可以被移至其它位置)。向量表中的数值是 32 位的地址,而不是跳转指令。向量表的第一个条目指向复位后应执行的第一条指令,就是 Reset_Handler 这个函数。
🏵️因为 CM3 使用的是向下生长的满栈,所以 MSP 的初始值必须是堆栈内存的末地址加 1。举例来说,如果你的栈区域在 0x20000388‐ 0x20000787 之间,那么 MSP 的初始值就必须是 0x20000788。向量表跟随在 MSP 的初始值之后——也就是第 2 个表目。

👀这里比较容易钻进去,就是为什么要加1呀?费解。
🏵️R15 是程序计数器,在汇编代码中, 可以使用名字“PC”来访问它。 ARM 规定: PC最低两位并不表示真实地址,最低位 LSB 用于表示是 ARM 指令( 0)还是 Thumb 指令( 1),因为 CM3 主要执行 Thumb 指令,所以这些指令的最低位都是 1(都是奇数)。 因为 CM3 内部使用了指令流水线,读 PC 时返回的值是当前指令的地址+4。比如说:0x1000: MOV R0, PC ; R0 = 0x1004

👀wq,还这样?
🏵️如果向 PC 写数据,就会引起一次程序的分支(但是不更新 LR 寄存器)。 CM3 中的指令至少是半字对齐的,所以 PC 的 LSB 总是读回 0。然而,在分支时,无论是直接写 PC的值还是使用分支指令,都必须保证加载到 PC 的数值是奇数(即 LSB=1),表明是在Thumb 状态下执行。倘若写了 0,则视为转入 ARM 模式, CM3 将产生一个 fault 异常。

👀这段话估计我得学学汇编编程才能理解。唯一知道需要了解的事是PC得是奇数。
🏵️正 因 为 上 述 原 因 , 图中使用 0x080001CD 来 表 达 地 址 0x080001CC 。 当0x080001CD 处的指令得到执行后,就正式开始了程序的执行(即去到 C 的世界)。
举报