MCU内存到下载的诸多问题
- 芯片能访问的区域大小由什么决定?
芯片能访问的区域大小,取决与地址总线的宽度和单位存储空间的容量。例如:32位的MCU,其地址总线宽度为32位,单位存储空间容量为1Byte。理论上最大的访问范围是2^32=4GB。但实际上芯片内部的内存远小于4GB。
2.芯片访问的是逻辑地址吗?Core访问外设时是否有地址转换?
对于普通的MCU,芯片访问的是物理地址,不存在逻辑地址到物理地址转换的说法。逻辑地址的说法一般作用于具有mmu(内存管理单元)包括虚拟地址映射功能的高级芯片
4. 访问一个没有实际外设对应的物理地址会出现什么问题?
访问一个没有实际外设对应的物理地址,常常会出现Hardfault。常见的情况包括野指针,栈溢出。
5. 用户可以添加除芯片厂家自带的外设设备吗?
用户无法在芯片内部添加,除厂家提供之外的外设设备。但是可以通过MCU的通信接口如SPI、IIC、UART,与各个外设设备进行数据交互与控制。
6. 我们能通过地址总线来访问自行添加的外设设备吗?
可以,但需要硬件支持。如果MCU具备FMC模块,Core就可以通过地址总线和FMC,访问到外部LCD、RAM之类的并行设备。
7.我们所说的“逻辑地址”在MCU中到底指什么?
在没有MMU单元的MCU中,逻辑地址一般出现在链接过程中。例如:我定义了一个80个字节的数组,我们只能从逻辑知晓有一个开头和结尾相差80字节的数组,但并不知道放在哪个位置,这个就是逻辑地址。但是在链接脚本中,会给数据段指定一个起始位置,例如0x20000000。那么这个数组的起始位置就是0x20000000,结尾地址就是0x2000004F。这个就是物理地址。
8. 代码实际存放的地址是由链接器决定的吗?
代码实际存放的位置,是由链接脚本.ld所决定的。例如以下的.ld文件内容:声明了三个内存区域,分别是FLASH(rx只读的)从0x08000000开始,空间大小为128k。后面又分了RAM_EXEC(用于执行代码)和RAM_DATA(用于存放数据)。紧接着在.section中进行,各部分存储地址的分配,.isr_vector和 .text放在 RAM_EXEC(存放位置由末尾的“>RAM_EXEC”得出);
从.map中可看出,向量表.isr_vector就是放在 0x20010000(RAM_EXEC的起始位置)。
.stack ,.heap放在RAM_DATA中。
/* STM32F103 Linker Script for Code Execution in RAM at 0x20010000 */MEMORY{FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 128KRAM_EXEC (rwx) : ORIGIN = 0x20010000, LENGTH = 8KRAM_DATA (rwx) : ORIGIN = 0x20000000, LENGTH = 12K}ENTRY(Reset_Handler)SECTIONS{.isr_vector :{. = ALIGN(4);KEEP(*(.isr_vector))} >RAM_EXEC.text :{. = ALIGN(4);*(.text .text.*)*(.rodata .rodata.*)KEEP(*(.init))KEEP(*(.fini))} >RAM_EXEC.stack :{. = ALIGN(8);_sstack = .;. += 0x00000400;_estack = .;} >RAM_DATA.heap :{. = ALIGN(8);_sheap = .;. += 0x00000200;_eheap = .;} >RAM_DATA}
9. `.ld`文件是给谁看的?它的作用是什么?
.ld文件是给链接器看的,它告诉链接器可用的区域有哪些,每个区域有多大代码段.text,数据段.data放在哪些区域中。
10. Core最开始从哪里开始读取代码?它怎么知道代码在哪?
Core上电首先会在0x00000000地址处读取Stack_top栈顶的位置,然后在0x00000004地址处读取PC指针的值。有了PC指针,就能跳转到我们代码存放的位置。正常开始执行代码了。0x00000004地址一般存放Reset_Handler的起始地址。
11. 如果链接器真的把代码放在`0x00000000`,Core还会进行重映射吗?
重映射机制,是指Core依旧是从0x00000000开始读取Stack_Top和PC指针的值,但是实际上我们将这两个值放在了0x08000000的位置。由于额外的硬件结构,Core读取0x00000000会读到0x08000000存放的值。所以这样即使把代码放在0x08000000,Core依然能够顺利执行程序。在STM32中,重映射机制要与BOOT引脚匹配,如果你的BOOT引脚配置成,0x08000000,你把代码放在0x00000000也跑不起来。
12. 我们只能将代码段放在官方定义的区域吗?能否随意定义代码段起始地址?
我们可用随意更改代码段的起始位置,只要能够让Core通过PC寄存器值,得到代码段的起始位置,