STM32F103的程序存储器、数据存储器、寄存器和IO端口被组织在同一个4GB的线性地址空间内。数据字节以小端模式存放在存储器中。即低地址中存放的是字数据的低字节,高地址中存放的是字数据的高字节
存储器指本身没有地址信息,对存储器分配地址的过程称为存储器映射
可访问的存储器空间被分成8个主要块,每个块为512MB。 其他所有没有分配给片上存储器和外设的存储器空间都是保留的地址空间
1.1 第一块(0x0000 0000 ~ 0x1FFF FFFF,512MB):
启动空间(0x0000 0000 ~ 0x0800 0000,128MB):代码区始终从0x0000 0000开始,通过ICode和DCode总线访问。
启动的执行流程:
内核复位之后:
(1)从地址 0x0000 0000 处获取出堆栈指针 MSP 的初始值,该值就是栈顶地址(中断向量表的第一项)
(2)从地址 0x0000 0004 处获取出程序计数器指针 PC 的初始值,该值是复位向量(中断向量表的第二项)
启动之后,CPU从地址0x0000 0000获取堆栈顶SP的地址,并从存储器的0x0000 0004指示的地址(程序计数器指针PC)执行代码

之所以产生上述步骤,则因为不同厂商可能会把0x0000 0000以及0x0000 0004地址映射到其他地址。因此,根据映射到不同地址分为不同的启动方式(由BOOT引脚决定)
在系统复位后,SYSCLK的第4个上升沿,BOOT引脚的值将被锁存。用户可以通过设置BOOT1 和BOOT0引脚的状态,来选择在复位后的启动模式
启动模式1:从Flash开始启动,正常的下载启动程序
启动模式2:从系统存储器(存储BOOTLoader程序,用于串口下载,将下载好的程序刷新到Flash位置)开始启动,由于系统存储器存储串口下载程序,通过这种启动方式可以通过串口将程序下载到Flash。串口程序下载完成后,需要设置为从Flash启动,这样复位后才能正常运行程序(只能通过USART1下载)
启动模式3:SRAM用来存储程序运行过程中的临时变量,不能存储程序,所以该方式只用于调试程序

启动文件介绍:
复位中断函数:主要用来执行SystemInit()和main()
被WEAK修饰的函数,称为弱函数。允许用户可以在其他地方重新定义该函数
Flash(0x0800 0000 ~ 0x0801 FFFF,128KB):存储编译后的程序代码
系统存储区(0x1FFF F000 ~ 0x1FFF F800,8KB):存储用于串口下载程序,即BootLoader
系统存储器,存储BOOTLoader程序,用于串口下载,将下载好的程序刷新到Flash位置。当从该位置启动,其实是执行串口下载程序,BOOTLoder会将下载的程序存放进Flash。串口程序下载完成后,需要设置为从Flash启动,这样复位后才能正常运行程序
选项字节(0x1FFF F800 ~ 0x1FFF F80F,16B):存储一些独立于程序代码的配置参数
读保护字节、看门狗、停机或待机是否产生复位、用户字节数据(0x1FFF F804 ~ 0x1FFF F806 )(这两字节可供用户独立使用)、写保护字节(Flash的每几页)
作用:
(1)选项字节中的数据不随程序的更新而改变,可以存放一些
(2)用上位机可以很方便修改,可以用在产品中可供用户配置的参数
1.2 第二块(0x2000 0000 ~ 0x3FFF FFFF,512MB):

SRAM(0x2000 0000 ~ 0x2000 4FFF,20KB):存储程序运行过程中的临时变量
第三块(0x4000 0000 ~ 0x5FFF FFFF,512MB):

外设(0x4000 0000 ~ 0x4002 3FFF):外设寄存器空间地址
第八块(0xE000 0000 ~ 0xFFFF FFFF,512MB):
Cortex_M3内核外设(0xE000 0000 ~ 0xE010 0000)
其他存储器区域均保留
一、DMA简介
DMA(Direct Memory Access)直接存储器存取/直接存储器访问,可以提供外设与外设之间、外设与存储器之间、存储器和存储器之间的高速数据传输,无须CPU干预,节省了CPU的资源
在DMA传输前,CPU把总线控制权交给DMA控制器,在结束DMA传输后,DMA控制器立即把总线控制权交回CPU
DMA过程:DMA请求、DMA响应、DMA传输、DMA结束
12个独立可配置的通道: DMA1(7个通道), DMA2(5个通道)
每个通道都支持软件触发和特定的硬件触发
STM32F103C8T6 DMA资源:DMA1(7个通道)
二、DMA结构

(1)每个通道都直接连接
专用的硬件DMA请求,每个通道都
同样支持软件触发。这些功能通过
软件来配置。
(2)在同一个DMA模块上,多个请求间的优先权可以通过软件编程设置(共有四级:很高、高、
中等和低),优先权相等时由硬件决定(请求0优先于请求1,依此类推) 。
(3)独立数据源和目标数据区的传输宽度(字节、半字、全字),模拟打包和拆包的过程。源和目
标地址必须按数据传输宽度对齐。
(4)循环模式/非循环模式
(5)每个通道都有3个事件标志(DMA半传输、DMA传输完成和DMA传输出错),这3个事件标志
逻辑或成为一个单独的中断请求。
(6)可编程的数据传输数目:最大为65535
DMA是AHB总线上的外设,有两个AHB端口:一个是从端口,用于配置DMA;另一个是主端口,用于设备间的数据传输。所以,DMA既是总线矩阵的主动单元,可以读写各种存储器;又是AHB总线上的被动单元,可被CPU进行配置
STM32的Cortex-M3内核和DMA控制器通过总线矩阵连接到Flash控制总线、SRAM总线和AHB总线,进而通过AHB总线连接到AHB总线服务外设
DMA的工作流程:
(1)DMA传送
当外设发送DMA请求,DMA控制器根据通道的优先权来处理请求。当DMA控制器开始访问外设时,DMA控制器首先向外设发送一个应答信号,外设得到应答信号后立即撤销请求,DMA控制器同时撤销应答信号
(2)仲裁器
根据优先级管理各通道的请求以及启动外设/存储器访问的顺序
软件:最高、高、中等、低
硬件:如果两个通道请求的优先级相同,则低编号的通道有高优先级
(3)DMA通道
每个通道可以实现固定地址的外设寄存器和存储器地址之间的DMA传输。DMA传输的数据量是可编程的,最大达到65535,在每次传输后递减
(4)地址自增
外设和存储器的指针可以设置为在每次传输结束后自增
(5)中断
3个事件标志(DMA半传输、DMA传输完成和DMA传输出错),这3个事件标志逻辑或成为一个单独的中断请求
(6)循环模式
数据传输数目变为0时,将自动恢复为设置的初始值,DMA操作继续。循环模式用于处理循环缓冲区和连续的数据传输,例如,ADC的扫描模式
(7)存储器到存储器模式:不可以与循环模式同时使用
(8)DMA请求映射
从外设产生的7个请求,通过逻辑或输入到DMA控制器,这意味着某一时刻只有一个DMA请求有效(分时复用)
MEM2MEN(Memory to Memory,存储器到存储器),当此位为1时,由软件触发,不可以和循环模式同时使用
可编程的数据传输宽度、对齐方式和数据大小端
当源数据宽度 = 目标数据宽度,正常传输
当源数据宽度 < 目标数据宽度,高位补0
当源数据宽度 > 目标数据宽度,高位舍弃,只保留低位
三、DMA相关库函数
(1)初始化:DMA_Init()
(2)设置计数器:DMA_SetCurrDataCounter()
可以单独设置DMA_BufferSize的值,即传输计数器的值
四、DMA配置
(1)开启DMA时钟(AHB总线)
(2)配置DMA,完成初始化
DMA_InitTypeDef DMA_InitStruct;
DMA_InitStruct.DMA_PeripheralBaseAddr = source; //外设基地址
DMA_InitStruct.DMA_MemoryBaseAddr = destination; //内存基地址
DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Enable; //外设基地址是否递增:
DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable; //内存基地址是否递增:
DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; //外设数据宽度:一字节
DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; //内存数据宽度:一字节
DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralSRC; //外设作为数据来源or数据目的地:数据来源
DMA_InitStruct.DMA_BufferSize = number; //DMA缓存数据的大小:传输计数器的大小
DMA_InitStruct.DMA_Mode = DMA_Mode_Normal; //工作模式 是否循环:不循环
DMA_InitStruct.DMA_Priority = DMA_Priority_High; //优先级:高优先级
DMA_InitStruct.DMA_M2M = DMA_M2M_Enable; //内存到内存:使能
DMA_Init(DMA1_Channel1, &DMA_InitStruct);
(3)使能DMA
DMA工作的三个条件:
①DMA使能,打开开关
②传输计数器必须大于0
③必须有触发源
注:在写传输计数器的值时,必须关闭DMA
当STM32的DMA配置为Normal(即单次)模式时,在DMA第一次传输完成后,要启动第二次DMA传输,需先关闭该DMA通道,重新设置DMA传输数据个数,再开启DMA通道。
原理和定时器关闭自动重载一样,DMA传输完成后计数器为0。在Normal模式下,计数器寄存器会保持为0,在Circular模式下会自动重载原先初始化的值。当计数器为0时不管DMA通道是否开启都不会进行DMA传输。 而且计数器寄存器必须在DMA通道关闭的情况下才可以写,在DMA通道开启时只能读取计数器寄存器。所以在Normal模式下,想重启DMA传输,需先关闭DMA通道,然后设置通道计数器值,再开启DMA通道。
