基础架构
- 存储器映像空间(最大4GB)

- MMIO映射区域(不是真实的存储器)
- BOOT区
- 总线仲裁器发现要访问BOOT区时,会通过总线仲裁(主FLASH、系统FLASH、SRAM三选一),然后转接到对应地址
- 核外设备寄存器
- 总线仲裁器发现要访问该区时,会转接到外设端口
- 核内设备寄存器
- 总线仲裁器发现要访问该区时,会转接到内设端口
- Bit-Band区(位段/位带)与Bit-Band别名区
- SRAM和FLASH中各有一个位带区,这个区域内可以支持对bit操作
- 位带操作:访问位带别名区的对应byte==访问位带区的对应bit(注意不能直接对位带区操作)
- 进行位带操作时,必须使用volatile:否则可能因为优化产生一个缓存,导致不能立即进行写入。
- 位带与位带别名区的映射:$位带别名地址 = 位带别名基址 + (字节偏移 × 32) + (位编号 × 4)$
- ROM:主FLASH、系统FLASH(SystemMemory)、选项字节FLASH
-
RAM:SRAM
-
内存外存分类
- 内存:片内RAM,片内FLASH(主FLASH、系统FLASH、选项字节FLASH),核内设备寄存器
-
外存:FMC存储(片外RAM、片外FLASH),核外设备寄存器
-
总线结构
- ICode总线(ICache):FLASH
- DCode总线(DCache):FLASH
- System总线:总线仲裁器(master访问总线矩阵中连接的slave(直连的内设/外设总线))
- AHB总线(高速外设):高速外设SDIO、RCC、APB总线
- APB2总线(中速外设):ADC、GPIO、SPI、TIM、USART的高速端口
- APB1总线(低速外设):ADC、GPIO、SPI、TIM、USART的低速端口
-
DMA总线:总线仲裁器
-
主FLASH与SRAM构成
- 主FLASH:初始化段、只读数据段(.rodata)、代码段
- 初始化段:待初始化的.data和.bss段
- 只读数据段:存放常量
- 代码段
- 读取FLASH的方式
- 若读取bootloader代码,则只能使用XIP硬件移动(前提是代码段存在FLASH中,否则可以使用软件移动)
- 若读取普通代码/数据,则可以:软件移动 / XIP硬件移动 至SRAM的data段再读写
- SRAM:数据段(.data)、BSS段(.bss)、堆段、共享段、栈段
- 系统栈段:存放进程上下文和局部变量
- 共享段:存放多进程共享的库函数、用共享区域实现进程通信
- 系统堆段:由malloc/free分配
- BSS段:存放未初始化的全局变量和静态变量
- 数据段:存放初始化的全局变量和静态变量
- 选项字节FLASH
- 用于配置读/写保护、硬件参数、用户自定义参数
系统上电过程
- 流程:上电硬件复位->bootROM->(一级Bootloader)->二级Bootloader(SystemInit、__main)->用户程序
-
一级Bootloader是可选的
-
上电硬件复位
- bootROM:硬件编程的启动代码,不在内存映像中
- 用于初始化硬件
- 最后通过BOOT区仲裁,跳转到一级bootloader/二级bootloader
- 一级Bootloader==内置==:存在于系统FLASH中
- 用于初始化CPU核心
- 最后跳转至二级Bootloader
- 二级Bootloader==用户reset_handler==:存在于主FLASH的SystemInit()中
- 用于初始化SoC
- 最后跳转至__main()
- __main()用户reset_handler:存在于主FLASH的__main()中
- 用于复制flash的.data段,移动flash的.bss段、堆栈初始化
- 最后跳转至用户程序main()
分散加载文件(链接文件)
- 单片机内存布局管理:sct分散加载详解_arm sct-CSDN博客
- STM32的内存布局在链接文件.sct指定
- LMA与VMA
- LMA:文件存储时的位置(比如.data预先存储在flash中)
- VMA:文件加载的位置(比如.data会被__main()从flash移动至sram)
- 文件格式解析:待补充
位运算
- 置1:a |= 00000111([2:0]置为1)
- 置0:a &= 11111001([2:1]置为0)
- 取反:a ^= 00010000([4:4]取反)
配置部件的思路
- 初始化:与Init、Config相关
- 用结构体进行初始化的过程:先用StructInit将结构体赋默认值,然后将需要用的成员进行修改
- 运行:与get/read、set/Generate/write、clear/reset相关
- 注意事项
- 对于会产生数据覆盖的场景:需要使用轮询机制/中断机制(手动中断、睡眠等)
- 对于会产生死循环的场景:在循环中加入timeout倒计时,或者使用中断
1. 配置NVIC
- 注:NVIC无需挂载到RCC树上
- 初始化NVIC:优先级分组设置、写中断函数等 + 中断系统初始化
- 运行NVIC:改变中断优先级、读写某个通道的中断位/中断挂起位
2. 配置EXTI
-
注:EXTI无需挂载到RCC树上
-
初始化EXTI:外部中断系统初始化
- 运行EXTI:读写外部中断位(IT)/外部事件位(FLAG)
2. 配置GPIO
-
注:将GPIO和AFIO看作GPIO系统中的两个模块,未用到AFIO时可以忽略AFIO
-
总线时钟配置(将GPIO和AFIO挂载到RCC树)
- 初始化GPIO:AFIO功能复用配置等 + 输入输出初始化
- 配置EXTI(可选)
- 配置NVIC(可选)
- 运行GPIO:读写DR
3. 配置TIM
- 总线时钟配置(将TIM挂载到RCC树)、计数时钟配置
- 初始化TIM:模式配置等 + OC、IC、时基单元初始化
- 配置NVIC(可选)
- 运行TIM:运行控制、读写ARR和CCR、读写时钟中断位(IT)/时钟事件位(FLAG)
4. 配置DMA
- 总线时钟配置(将DMA挂载到RCC树)
- 初始化DMA:通道中断配置等 + DMA初始化
- 配置NVIC(可选)
- 运行DMA:运行控制、读写CNT、读写DMA中断位(IT)/DMA事件位(FLAG)
5. 配置USART
- 总线时钟配置(将USART挂载到RCC树)
- 初始化USART:USART传输模式配置等 + USART初始化
- 配置NVIC(可选)
- 配置GPIO(可选)
- 运行USART:运行控制、读写DR、读写USART中断位(IT)/USART事件位(FLAG)
6. 配置硬件I2C
- 总线时钟配置(将I2C挂载到RCC树)
- 初始化I2C:I2C应答配置、校验配置等 + I2C初始化
- 配置GPIO(可选)
- 运行I2C:运行控制、读写ACK、读写DR、读写I2C中断位(IT)/I2C事件位(FLAG)
7. 配置硬件SPI
- 总线时钟配置(将SPI挂载到RCC树)
8. 配置BKP
- 总线时钟配置(将PWR和BKP挂载到RCC树)
- 初始化BKP:侵入检测配置等 + BKP初始化(即在PWR处对BKP进行使能)
- 运行BKP:运行控制、读写RTCR、读写BKPR、读写BKP中断位(IT)/BKP事件位(FLAG)
9. 配置RTC
- 总线时钟配置(将PWR和BKP挂载到RCC树)、计数时钟配置
- 初始化RTC:计数配置等 + RTC初始化(即在PWR处对BKP进行使能)
- 运行RTC:读写CNT、读写ALARM、读写分频寄存器、等待同步操作、读写RTC中断位(IT)/RTC事件位(FLAG)