嵌入式学习之旅:STM32F103 第二篇(CM3基础)

一、Cortex-M3简述

        随着技术的进步,用户的要求越来越苛刻,一方面希望嵌入式CPU具有更低的成本与功耗,另一方面又希望它具有更高的运算速度与更强大的实时能力和功能模块。以Cortex-M3为内核的ARM处理器全面满足了用户的这些需求,一些原本要借助DSP(数字信号处理器)实现的高级功能也能在CM3上流畅运行,同时他的使用与调试过程也极为方便,这些使它在市场竞争中脱颖而出。

        CM3在不仅技术上是先进的在商业上也构建了极为成功的生态系统。英国的ARM公司只负责设计CM3内核,采用IP授权的方式,由合作伙伴根据不同的应用领域加入适当的外围电路,生产出自己的微处理器芯片进入市场。如Intel、Microsoft、华为等都使用ARM公司的授权。

        如图为STM32系列产品命名规则

图1.1

                                                                              

二、CM3处理器的结构

1、CM3内核

        1、因为ARM的内核是作为复杂片上系统的一个处理单元来应用的,所以必须要有一个ARM核与其他东西通讯的接口,为此ARM公司定义了AMBA总线规范,如图。

图2.1

                                                                             

(1)AHB:先进高性能总线,用于高性能系统模块的连接,支持突发数据传输和单个数据传输方式。

(2)APB:先进外设总线,用于较低性能外设的简单连接,一般是接在AHB系统总线上的第二级总线

        2、如下图所示,CM3在中央处理器内核上还集成了先进的系统外设,如中断控制、内存保护以及系统调试和跟踪功能。这些外设可由芯片公司进行自由配置。

图2.2

                                                                               

2、STM32F103处理器

        如图2.3是一个STM32F103非互联型芯片的系统架构图,STM32主系统由四个驱动单元与四个被动单元组成

        四个驱动单元:内核DCode总线、系统总线、通用DMA1、通用DMA2

        四个被动单元:AHB到APB的桥,连接所以APB设备;内部Flash闪存;内部SRAM(静态随机存取存储器);FSMC(可变静态存储控制器)。

图2.3
图2.3

                                                                      

图上的一些注释:

1、ICode总线:该总线将CM3内核指令总线和闪存指令接口相连,完成指令的预取

2、DCode总线:该总线将CM3内核的DCode总线(如图2.2)与闪存存储器的数据接口相连,完成常量加载和调试访问

3、系统总线:该总线连接CM3内核的系统总线到总线矩阵,总线矩阵协调内核和DMA间访问。

(1、2、3都是CM3内核与外部的通讯手段)

4、DMA总线:该总线将DMA(一种数据传送方式)的AHB主控接口与总线矩阵相连,总线矩阵协调CPU的DCode和DMA到SRAM、闪存和外设的访问。

5、总线矩阵:总线矩阵协调内核系统总线和DMA主控总线之间的访问仲裁,仲裁利用轮换算法。

(如图2.3、总线矩阵左侧连接内核和DMA起到协调这两者的作用,而右边连接这闪存、SRAM、和各种外设起到了内核的DCode总线与DMA和右边连接的东西之间的协调。可以对比图2.2和图2.3看)

6、AHB/APB桥:这两个桥在AHB和两个APB总线间提供同步(指时钟同步)连接,APB1操作速度限于36MHz,APB2操作为全速72MHz。

(APB2中的资源可在图2.3中看到,最多的是GPIO,可见通用资源往往要放在最高速的通道中,因为不知道它到底需要什么速度。)

三、CM3处理器的特点

(1)、32位处理器核

        CM3是一个32位的处理器核,内部数据总线是32位的,寄存器是32位的,存储器接口也是32位的。

(2)、哈佛结构

        哈佛结构拥有独立的指令总线和数据总线,可以让取指与数据访问并行进行。这样一来数据访问不在占用指令总线,从而提升了性能。但是,指令总线和数据总线共用一个存储空间。换句话说不是因为有两条总线,可寻址空间就变成了8GB了。

(3)、高性能的译码器ALU

        CM3包含一个支持硬件乘法和硬件除法的先进ALU、控制逻辑和用于连接处理器其他部件的接口。

(4)、分支预测的三级流水线技术

        CM3处理器中每条指令分取指、译码、执行三个阶段(三个阶段为一条指令,一条指令4个字节),分别在不同的功能部件上依次独立完成。在三级流水线下虽然每一条指令扔需3个时钟周期来完成,但通过多个部件并行执行,使处理器的吞吐率约为每个周期一条指令,提高了指令的处理速度。

        通过R15(寄存器)访问PC(程序计数器)会出现取指位置和执行位置不同的现象,这需要结合流水线来看。取指部件根据PC取指,取指完成后PC+4送到PC,并把取到的指令传递给译码部件,然后取指部件根据新的PC取指。因为每条指令4个字节所以PC值等于当前程序执行位置+8

        CM3CPU不仅利用流水线技术在单个周期内完成绝大多数指令的执行,还使用分支预测技术提高流水线管道使用率。当一个分支指令来临时,会进行一次预测性的装载,从而使得每个条件指令所有可能的结果都可得到立即执行,而不会对CPU性能产生负面冲击。最坏的情况也仅仅是,在某个非直接的分支里,预测性的装载无法进行,这是才需要刷新管道。管道技术成为了提升CM3 CPU整体性能的关键所在,而且用户不必为此增加代码。

详情看

分支预测详解_粉色挖掘机的博客-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/qq_30095921/article/details/128740727

(5)低成本与低功耗

(6)集成调试系统和跟踪功能

        CM3处理器通过几个集成部件用硬件本身实现调试技术,使调试在具备跟踪和分析,设置断点、观察点和代码修补功能的同时,调试速度也获得了提高。

CM3处理器包括以下组件:

1、FPB:实现硬件断点以及从代码空间到系统空间的修补访问,FPB有8个比较器。

2、DWT:数据观察点和跟踪、调试功能部件。

3、ITM:一个应用导向的跟踪源,支持应用事件跟踪和printf类型的调试。

4、ETM:支持指令跟踪的低成本跟踪宏单元。

5、TPIU:用作来自ITM和ETM(如果存在)的CM3内核跟踪数据与片外跟踪端口分析仪之间的桥梁。

6、SW/JTAG-DP:CM3处理器可配置为具有一个适用于低管脚数封装设备的2管脚串行线调试()调试端口SW–DP或传统的JTAG–DP调试端口的接口,或两者都有。这两个调试端口提供对包括处理器寄存器在内的所有寄存器和存储器的调试访问。

详情看:CM3内核调试组件_tpiu_无为扫地僧的博客-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/weixin_41080308/article/details/116713104

 调试需要这些硬件与仿真器相互配合。

四、CM3寄存器组

        如图4.1,CM3有R0~R15的寄存器组以及一些特殊功能的寄存器。其中R13作为堆栈指针(SP)。SP有两个,但同一时刻只能有一个可以看到,这就是所谓的备份寄存器。特殊功能寄存器有预定义功能,必须通过专用的指令来访问。

图4.1

 1、通用寄存器:

        R0~R12都是32位通用寄存器,用于数据操作。R0~R7也被称为低组寄存器,所有指令都能访问它们,复位后的初值不确定。R8~R12被称为高组寄存器,只有少量的16位Thumb指令能访问它们,32位的Thumb-2则不受限制,复位后的初值不确定。(一般用的都是低组寄存器)

2、连接寄存器R14

        R14是连接寄存器(LR)。当调用一个子程序时,由R14存储返回地址。ARM为了减少访问内存的次数(访问内存的操作往往需要3个以上的指令周期),把返回的地址直接存在寄存器中。这样足以使很多只有1级子程序调用的代码,在返回时无需访问堆栈内存,从而提高了子程序调用的效率。如果多于一级,则需要把前一级的R14值压入堆栈。

(R14只能管一级的跳转指令,如果是多级就要访问内存了,在ARM编程中,要尽量使用寄存器来保存中间结果,迫不得已时才访问内存)

关于访问内存为什么麻烦可参考:浅谈CPU和CPU对内存的访问方式_cpu访问内存时每次都是从内存起始地址开始吗_了不起的盖茨比。的博客-CSDN博客

图4.2:存储器系统的结构

3、程序计数器R15

        R15是程序计数器,在汇编代码中一般写作PC。CM3采用了三级流水线,因此指令分为三个阶段执行:取指、译码、执行。之前说过PC=当前程序执行位置+8。

        无论是直接写入PC(写入PC寄存器的操作)的值还是用分支指令,都必须保证了写入PC的数值是奇数(即LSB=1),用以表明这是在Thumb状态下执行,倘若写了0,则视为企图转入ARM模式,CM3将产生一个Fault异常。

        下面来欣赏“对不起我之前的回答仍然是错误的”     (艹皿艹 )

关于指令系统可参考:计算机组成原理学习笔记:四 指令系统 - 知乎 (zhihu.com)

关于指令、程序、指令系统的区别可参考:指令,程序,指令系统的区别? - 知乎 (zhihu.com)

4、特殊功能寄存器

        CM3出了通用寄存器以外,还在内核平台上搭载了若干特殊功能寄存器,包括程序状态寄存器组(PSRs或xPSR)、中断屏蔽寄存器组和控制寄存器组,如表4.3所示。

(1)、程序状态寄存器(PSRs)

        PSRs在用户级编程时用于存储条件码,包含条件码标志、中断禁止位、当前处理器模式以及其他状态和控制信息。

        程序状态寄存器在内部又分为三个字状态寄存器:应用程序PSR(APSR)、中断号PSR(IPSR)和异常PSR(EPSR),如下图所示:

(2)、控制寄存器(CONTROL)

        控制寄存器有两个作用,用于定义特权级别和选择堆栈指针,如下表所示:

        CONTROL[0]:异常情况下,处理器总是处于特权模式,CONTROL[O]位总是为0。在线程
模式(非异常)情况下,处理器既可以工作在特权级也可以工作在用户级,该位可为0或1。
        CONTROL[1]:为0时,只使用MSP,此时用户程序和异常共享同一个堆栈,处理器复位后默认的也是该模式。为1时,用户应用程序使用进程堆栈PSP,而中断仍然得使用主堆栈MSP。这种双堆栈机制特别适合在带有OS(操作系统)的环境下使用,只要OS内核在特权级下执行,而用户应用程序在用户模式下执行,就可很好地将代码隔离互不影响。

关于双堆栈机制:

关于操作模式与特权级别:

        CM3处理器支持两种处理器操作模式,还支持两级特权操作。

        这两种处理器操作模式是:处理者模式(Handler Mode)和线程模式(Thread Mode)。引入这两个模式是为了区分普通程序(线程模式)和异常服务例程(包括中断服务程序)(处理者模式)。

        两种特权操作是:特权级和用户级操作。在硬件内核把代码按照特权级和用户级分开对待有利于使系统的架构更加安全和健壮,使普通用户的代码不能意外的、甚至是恶意的执行及涉及要害的程序。处理器支持两种特权级也是一个基本的安全模型。

        它们组合起来有如下表的工作方式:

        

        在CM3运行主程序时(线程模式),即可以使用特权级也可以使用用户级,但是异常服务例程必须在特权级下执行。复位后处理器默认进入线程模式,特权级访问。

        特权级下,程序可以访问所有范围的存储器(如果有MPU(内存保护单元),还要在MPU规定的禁地之外),并且可以执行所有指令。在特权级下的程序可以通过修改CONRTROL寄存器切换到用户级。不过一旦进入用户级,用户级的程序不能通过直接改写CONTROL寄存器回到特权级,而必须先执行一条系统调用指令(SVC);这会触发SVC异常,然后由异常服务例程(通常是操作系统的一部分)接管,如果批准了进入,则异常服务例程修改CONTROL寄存器,才能在用户级的线程模式下重新进入特权级。事实上,从用户级到特权级的唯一途径就是异常:如果在程序执行过程中触发了一个异常,处理器总是先切换入特权级,并且在异常服务例程执行完毕退出时,返回先前的状态(也可以手工指定返回的状态)下图表示了CM3各种操作模式的转换方法。

关于MPU可参考什么是Cortex-M内核的MPU(内存保护单元)?_strongerHuang的博客-CSDN博客

 关于异常服务例程:

 五、堆栈与堆栈指针

1、堆栈的基本概念

        堆栈是一阵存取器的使用模型。它由一块连续的内存和一个栈顶指针SP组成,用于实现LIFO(后进先出)的缓冲区。最典型的应用就是在数据处理之前先保存寄存器的值,在处理完成后从中恢复之前保存的值。它由PUSH(压栈)POP(出栈)两种操作。

        一般来说,堆栈操作就是存储器的写或读操作,但访问地址由SP给出。在执行PUSH和POP操作时,SP的值由硬件自动修改。寄存器的PUSH和POP操作永远都是4字节对齐的,即它们的地址必须是0x04、0x08、0x0C..,在执行PUSH或POP时,每压入或弹出一个数据,SP值就减4(或加4)。

2、堆栈指针

        在CM3中,R13是堆栈指针,指示了栈顶的位置。在CM3中拥有两个堆栈指针,即主堆栈指针(MSP)进程堆栈指针(PSP),它们是备份寄存器,任一时刻只能使用其中的一个。当引用R13(即SP)时,引用的是当前正在使用的那一个,另一个必须用特殊的指令(MRS、MSR指令)来访问。
        主堆栈指针(MSP)是复位后缺省使用的堆栈指针,用于操作系统内核以及异常处理例
程操作,包括中断服务例程

        进程堆栈指针(PSP)由用户应用程序代码使用
        堆栈指针的最低两位永远是0,这意味着堆栈总是4字节对齐的。事实上,R13的最低
两位被硬线连接到0,并且总是读出0。

关于复位后缺省:

3、CM3的堆栈模型和应用

        CM3使用的堆栈是“向下生长的满栈”模型。向下生长指堆栈规模向较低的地址空间扩大,栈顶SP的值会减小。满栈则是指堆栈指针SP指向最后一个被压入堆栈的32位数值。在下一次压栈时,SP先自减4,在存入新的值。

 

        当CONTROL[1]=0时,如下图所示,只使用MSP,此时用户程序和异常操作共享一个堆栈。这也是复位后的缺省使用方式

 

        当CONTROL[1]=1时,如图,线程模式将不在使用MSP,而改用PSP(Handler模式永远使用MSP),因为,在使用OS的环境下,OS内核仅仅在Handler模式下执行,用户应用程序仅在用户模式下执行,以防止用户程序的堆栈错误破坏OS使用的堆栈。

 

六、复位序列

         如图所示,CPU退出复位后,CM3处理器会从存储器中读取下列两个32位整数值:

        从地址0x00000000处取出R13(MSP)的初始值

        从地址0x00000004中取出PC的初始值,这个值是复位向量,即程序执行的起始地址,LSB必须是1,以表明是Thumb状态。

(向量:指的是程序的地址;指针:指数据的地址)

        这点与传统的ARM处理器不同。传统的ARM架构总是从0地址开始执行第一条指令的,且0地址处存放的是跳转指令,而CM3中,0地址处存放的是MSP的初始值,紧接着是向量表,向量表的内容是32位的地址,而不是跳转指令。向量表第一个向量为复位向量,指向复位后应执行的第一条指令。

        由于CM3的压栈操作是递减的,因此,SP的初始值应设置为栈顶后的第一个存储器地址。例如,堆栈存储区域的范围为0x20007C00~0x20007FFF,则栈初始值应设为0x20008000。

七、CM3的存储器系统

   Cortex-M3的存储器系统与传统ARM构架有所不同。
(1)CM3的存储器映射是预定义了的,并且还规定好了哪个位置使用哪条总线,这个
特性使得在访问不同的设备时,处理器可以对这些访问进行优化。
(2)CM3的存储器系统支持“位带”操作,可以实现对某些特殊存储器区域或外设中的
位数据进行操作。
(3):CM3存储器系统还支持非对齐访问和互斥访问。
(4)CM3的存储器系统支持小端配置和大端配置
(5)比较复杂的应用可能需要更多的存储系统功能,为此CM3提供了一个可选的
MPU
,而且在需要的情况下也可以使用外部的Cache。

1、大于8位的数据的存储

        在计算机系统中,存储器是以字节为单位的,每个地址单元对应一个字节,一个字节为8位。但是实际中出了8位的char型外还有16位的short型、32位的long型。按什么顺序安排这些大于8位的数据,就出现了大端、小端存储模式以及对齐、非对齐的问题。

        小端存储:低位字节放内存的低地址,高放高。

        大端存储:低位字节放高地址,高放低。

        一般的操作系统都采用小端存储模式,而通讯协议则采用大端存储模式。CM3处理器有一个配置管脚BIGEND,能够使用它来选择小端模式或大端模式,该管脚复位时被采样,结束复位后存储模式不能修改。小端模式是ARM处理器默认的存储模式

2、非对齐存取

        大端和小端解决了存储时的顺序问题,而当多个长短不一的数据存放时又出现了对齐和非对齐问题。

        对齐访问会节约时间但浪费了空间,但是要节省空间有很多方法,通过压缩数据的地址,破坏对齐性不是一个非常好的选择。因此应养成好的习惯总是保持地址对齐,这也是让程序可以移植到其他ARM芯片上的必备条件。

        CM3中可以实现对齐的寻址方式,同时也可以使用非对齐存储方式。事实上,CM3在内部是把非对齐的访问自动转换成若干个对齐的访问,这种转换由处理器总线单元来完成,过程对程序员是透明的。

2、CM3存储器映射

        CM3处理器的存储映射方案是固定的(便于移植和资源共享),经过映射,其内部是一个线性的4GB地址空间。

        (1)、CM3存储器的基本结构

       

(2)、内核外设区映射

    

(3)、片上存储器映射与启动方式

        STM32不同的CPU其片上存储器容量虽有不同但是映射关系缺大同小异,下面是以配备256KB Flash储存器核64KB SRAM存储器的STM32F107为例子。其片上存储器映射如下图。

        内部SRAM区的大小是512MB,用于让芯片制造商连接片上的SRAM,这个区通过系统总线来访问。STM32F107的SRAM地址共计64KB,其下部还有一个1MB的区间,称为“位带区”。该位带区还有一个对应的32MB的“位带别名区”,容纳了8M个位变量。

        Flash存储区由三部分组成,首先是用户Flash区,从0x800_0000开始。其次是系统存储区,称为大端信息块。系统存储区是一个连续的4KB大小的Flash存储空间,里面存储着出厂启动引导(BootLoader)。最后一个部分称为小端信息块,含有一组可配置的字节,允许用户再次对STM32进行一些系统设置。

        如下表所示,改变STM32的两个外部引脚BOOT0和BOOT1的电平,STM32存储空间的起始地址会对齐到不同的内存空间上,这样就可以选择在用户Flash、内部SRAM或者系统存储区上运行代码,即可以配置它们来选择启动方式。

        

        系统投入使用后,BOOTO必须连接到GND上,从用户Flash启动,执行用户程序。

        在产品开发阶段,通过改变启动引脚的配置,STM32还可以从内部的SRAM启动,这样用户可以将程序下载到内部的SRAM并只在SRAM中运行。这不仅可以加速下载速度,而且也可减少反复擦写对Flash存储器造成的损耗。
        (就像手机的系统更新)而另个典型应用就是从系统存储区启动引导(Bootloader)启动,此后可以进行ISP编程,而USART1是ISP编程默认使用的通信接口,可用来从PC端下载和烧写代码,因此用户还需要相应地添加一个RS-232C驱动器件。
        Bootloader 的主要作用是允许用户通过USART1将代码下载进 STM32的RAM中,随后将这些代码写进内部用户Flash。要将STM32置于Bootloader模式,需要把外部的BOOT1和 BOOTO启动引脚分别置为低电平和高电平。这样设置启动引脚后,系统存储区将占用地址0x08000_0000。当STM32复位后,首先执行Bootloader 代码而不是用户Flash中的应用程序,这种方式称为ISP(In System Programming,在系统编程)。
        Bootloader 可以从ST官方网站下载得到。用户程序可以与Bootloader进行交互,也可以用来对用户Flash进行擦除和再编程。ST公司还提供了PC.端的Bootloader下载软件,用户可以使用它来向STM32写入自己编写的Bootloader,以支持对STM32进行现场升级及产品编程,这种方式称为IAP(In-Application Programming,在应用编程)。

关于内部SARM区:

关于内部Flash: 

3、位带操作 

        CM3中,有两个区实现了位带操作。其中一个是SRAM区的最低1MB范围,第二个则是片内外设区的最低1MB范围。

        

        这两个位带中的地址除了可以像普通的RAM一样使用外,它们还有自己的“位带别名区”,位带别名区把每个bit膨胀成一个32位的字。当通过位带别名区访问这些字时,就可实现对原始位的操作。

        遗憾的是,在C编译器中并没有直接支持位带操作。比如,C编译器并不知道同一块内存能够使用不同的地址来访问,也不知道对位带别名区的访问只对LSB有效。欲在C编泽器中使用位带操作,最简单的做法就是用#define宏定义一个位带别名区的地址。
 

  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值