zoukankan      html  css  js  c++  java
  • stm32和cortex M3学习内核简单总结

    1.stm32综述

    2.寄存器组

    3.操作模式和特权级别

    4.存储器映射

    5.中断和异常

    6.其他

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

    Stm32综述

    这可以说是我第一款认真学习的单片机了,学完这个就要开启我通往arm9的大门了,接下来把我学到的东西做一个系统的概述:

     

    上图是stm32的系统结构。

     

    使用哈弗体系结构,取指和取数据分离,

     

    ICODE指令总线连接到flash闪存指令存储区,这个存储区的地址在0x00000000-0x1FFFFFFF之间,负责取指操作。

     

    DCODE数据总线负责在0x00000000-0x1FFFFFFF之间的数据访问操作。这个数据存储区可以是SPRAM也可以是闪存和外设。

     

    系统总线:负责在0x20000000-0xDFFFFFFF0xE0100000-0xFFFFFFFF之间所有的数据传送。

     

    注:看到这你可能会迷惑,M3内核不是只有指令总线和数据总线吗?对的,但是指令总线和ICODE指令总线不是一个,选取一张M3内核样例处理器的图就明白了:

     

    个人理解,D-code总线和系统总线都是来源于M3内核引出的数据总线。

     

    DMA通过总线矩阵直接和内存相连。

     

    总线矩阵协调内核和DMASPRAM,闪存,外设的访问。

     

    AHP总线桥接两个APB总线,两个APB总显得最高速度不同,APB1最高速度限于36MHzAPB2限于72MHz。两个APB总线上挂接着不同速率的设备。

     

    Stm32f10系列的静态SPRAM64K,起始地址为0x20000000.

     

     

     

     

     

    Stm32的启动方式有以下几种:

     

     

     

     

     

     

     

     

     

     

     

    下面的是stm32的时钟树stm32四个不同的时钟源

    1.HSE时钟:高速外部时钟信号,来自于外部晶振:可作为系统时钟源,也可被PLL倍频之后宫系统时钟使用。

    2.HSI时钟:高速内部时钟信号,来自于内部RC振荡器:可直接作为系统时钟,或者二分频之后作为PLL输入,倍频之后供系统使用。

    3.LSE时钟:低速外部时钟,来自于外部晶振:为定时时钟或者其他定时功能提供

    4.LSI时钟:低速内部时钟,来自于内部RC振荡器:在停机或者待机的模式下,为独立看门狗或者自动唤醒单元提供时钟。

     

    经过一些列倍频,分频得到了几个和开发有关的时钟:

    1.SYSCLK:系统时钟大部分时钟的来源

    2.HCLK:由AHB预分频器输出得到,高速总线AHB的时钟信号

    3.FCLK:由AHB预分频器输出得到,自由运行时钟。

    4.PCLK1:外设时钟,由APB1预分频器得到,最大36MHz

    5.PCLK2:外设时钟,由APB2预分频器得到,最大72MHz

    时钟树如下:

     

     

     

     

     

     

    Stm32GPIO8种模式:

    1GPIO_Mode_AIN 模拟输入 
    2GPIO_Mode_IN_FLOATING 浮空输入
    3GPIO_Mode_IPD 下拉输入 
    4GPIO_Mode_IPU 上拉输入 
    5GPIO_Mode_Out_OD 开漏输出
    6GPIO_Mode_Out_PP 推挽输出
    7GPIO_Mode_AF_OD 复用开漏输出 
    8GPIO_Mode_AF_PP 复用推挽输出

     

    4种输入:模拟输入和明显接受模拟信号,比如用于ADC,上拉输入和下拉输入就是默认时高电平和低电平。浮空输入在芯片内部既没有接上拉电阻也没有接下拉电阻,引脚电压是个不确定值,输入阻抗较大,常用语I2cUSART

     

    4种输出:分复用和非复用,复用为分配给片上外设,非复用为用作正常的IO口。推免输出为正常的输出,而在开漏输出模式,IO口可以由外部电路改变为低电平或不变。所以开漏模式可以读IO输入电平变化,实现C51IO双向功能。

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

    当年看不懂的东西,现在越发清晰。

     

    寄存器组

    这一部分就属于M3内核中的知识了。

    M3内核中的寄存器主要如下:

     

     

    下面挨个解释

     

     

     

     

    M3使用的是双堆栈,复位之后默认使用MSP,默认是特权级,如果想要切换需要手动修改。而上面的MSPPSP的用途只是一种推荐用途,并不是一定要那么用,比如说复位之后你可以不修改,那么你的常规代码就一直是特权级,使用MSP(我就是这样滴。。方便至上)。

     

          这个寄存器又叫LR寄存器,那么当函数是一级调用的时候,就可以将返回地址直接存到LR中,省去了访问内存,提高了效率,当函数调用高于一级,则需将前面的LR中的值压栈,以便存储新的值。

     

          当进入异常的时候,LR寄存器的值更新为特殊的EXE_RETURN

          

           

           

     

     

    就是PC嘛。。。。

     

         特殊功能寄存器一定要在特权级才能被访问(使用MSRMRS指令),至于是Thread    模式还是handler模式无所谓。

         详细功能如下:

     

        xPSR属于三合一寄存器,可以分出三个子状态寄存器

     

        通过MRSMSR这三个寄存器可以单独访问,也可以两两组合访问,也可以三合一访问,这个寄存器大致如下(看下就好):

     

     

     

        其实除了修改上面的寄存器可以开关中断,M3还有专门的开关中断指令:

     

     

     

     

        CONTROL寄存器功能如下:

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

    操作模式和特权等级

    操作模式分为Thread模式和Handler模式,特权等级分为特权级和用户级。用户的程序代码一定是Thread模式,而异常一定是handler模式,用户程序代码程序代码可以是特权级和用户级,但是异常只能是特权级。

     

     

    Thread模式+用户级,就不能访问系统控制空间(SCS)和特殊寄存器(除了APSR)

     

    特权级切换到用户级很容易,修改下control寄存器就好,用户级切换到特权级的方式只有触发一个异常,切换到handler模式,这个时候是特权级,然后修改control寄存器的零位,再返回就是特权级。

     

    下图是一个各种切换的示意图:

     

     

    这种设定的大致用意就是我们写普通代码的时候设置为用户级,这样的话可以防止对SCS和特殊寄存器这种敏感地带的误操作,想要访问这些的话就只能通过进入handler模式一步步去访问,而且这样的话异常是特权级用MSP,普通的用户代码使用户级用PSP,不会出现数据意外互相干扰和破坏,这样的话整个系统的可靠性就会很好,当然我们写小程序的时候不必这么拘谨,反正我一般都是一直特权级小程序。

     

     

     

     

     

     

     

     

     

    存储器映射

          M3将内存分为8个主块,每块512MB,先上一张M3内核的存储器映射:

     

         

         所谓的SCS如下:

     

     

     

         所谓的位带就是将位带区的1bit膨胀为位带别名区的32bit也就是一个字,通过访问位带别名区就能达到访问这个bit的目的,优势如下:

     

         当然位带还有一个明显的好处,就是在多任务的系统中,两个任务同时去修改一个共享寄存器其中的两个bit的话可能会出现“紊乱现象”,所以就需要将“读--写”三条指令加上临界区等手段,但是有了位段,M3直接去写那个bit的位带别名区就可以了,这样就成为了一个原子操作。

     

         不过上面的图确实是粗线条,下面上芯片手册的详细图片一张:

     

     

     

       M3有些数据传送指令支持非对齐数据传送,如LDR/LDRH/LDRSH。其他指令不支持。

    对按字传送来说,任何一个不能被4整除的地址都是非对齐的。而对于板子,任何一个不能被2整除的地址都是非对齐的。

     

       M3支持大端模式和小端模式,但是推荐使用小端模式M3的大端模式是“字节不变大端”。

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

    中断和异常

    异常是指任何打断程序顺序执行的事件。在很多时候,中断和异常这两个概念是不做区分的,所以我以下也就不作区分了。

     

    M3的异常系统简直就是它的精华所在。

     

    M3的异常分为系统异常和外部中断。

    系统异常如下(stm32沿用):

     

     

    外部中断M3内核支持240个,stm32只使用其中60个:

     

     

    所有的异常,除了复位,NMI,硬FAULT优先级为-3-2-1固定,剩下的都是可编程优先级。

     

     

    优先级:

    M3内核中优先级寄存器为8位,这8位不用全用到,最少用到3位(MSB对齐)stm32只用到其中高四位,所以stm32总共有16种优先级。

    M3内核中对于外部中断有抢占优先级和响应优先级,高抢占优先级的中断可以打断低抢占优先级的中断。抢占优先级相同的两个中断同时到达,响应响应优先级高的中断。如果两个中断一切相同,那么响应序列号更小的那个。

    因为外部中断的优先级寄存器总共八位,所以需要对其进行划分,响应优先级至少有一位,所以M3中外部中断抢占优先级最多其实是有128个而不是256。下图是从bit5开始划分,总共用到三位设置优先级:

     

     

     

    具体的芯片决定优先级用到多少位,以及从哪一位开始划分抢占和响应,stm32用到4位设置中断,有5种分组:组07bit划分(全部都是响应优先级),组16bit划分,组25bit划分,组34bit划分,组43bit划分(就是只用到抢占优先级)。

     

     

    向量表:

    当发生了异常需要响应的时候,M3需要定位其服务例程的入口地址,这些入口地址就存在所谓的“向量表”。缺省情况下,这张表存在0地址处(当然也可修改NVIC中的向量表偏移寄存器来重定位向量表),每一个表项占4字节。

    如下:

     

     

    首先向量表的开头是主堆栈的地址。

     

    可以看出,不论如何一个向量表至少包含下面4个表项:

    1.MSP初始值

    2.复位向量

    3.NMI

    4.fault服务例程

     

    中断的输入与挂起:

    当中断输入脚被置为有效后,该中断就被悬起,到了系统中它的优先级最高的时候,就会得到响应。

        但是当某个中断得到响应之前,其悬起位被清除,则中断被取消。(所以stm32都是在中断服务程序的最后清除中断标志位)

    当某中断的服务例程开始执行的时候,就称此中断进入了“活跃”状态,并且其悬起位会被自动清除。  

        

     

    SVCPENDSVC

    首先SVC(系统服务调用)和PENDSVC(可挂起系统服务调用)的区别在于SVC异常必须立即得到相应,而PENDSVC则不是,他可以像普通中断一样被挂起,知道其他重要任务完成才执行它,挂起PENDSVC的方式为:手工写入NVICPENDSVC挂起寄存器。

    SVC的用途:操作系统可以不让用户直接访问硬件,而是通过触发SVC异常来使用SVC系统调用来让用户程序简介访问硬件。好处:1.OS负责具体硬件,用户程序不必花费心思控制硬件。2.OS的代码应该是经过充分的测试的,所以整个系统可靠性高健壮性好。3.用户程序无需在特权级下执行,无需担忧因误操作让系统瘫痪。4.通过SVC机制,用户程序与硬件无关。

     

     

    PENDSVC的用处:上下文切换,如ucos上下文切换就是用到PENDSVC的。

     

     

     

    NVIC

    中断向量控制器,也就是控制中断向量的地方,每个外部中断(系统中断由SCB控制)都在其中的寄存器占有一席之地,寄存器列表如下:

        

     

         其中悬起寄存器可以系统自动设置,也可以手工修改以悬起一个中断。

     

         软件中断寄存器也蛮重要的,如下:

     

     

     

     

     

     

     

       

    中断的响应和返回:

         中断的响应:

           

            8个寄存器以及入栈顺序如下:

            

       

         中断的返回:

             首先触发中断返回的指令有三种:

             

              返回了之后,做如下两件事:

              1.出栈,回复现场

              2.更新NVIC寄存器

     

            

     

     

    咬尾中断:

       一图以蔽之:

     

    其他

    总结了一天,终于到了这一步,还有些零碎的知识点写上:

     

    M3的堆栈是向下生长的。

     

    M3取指,解码,执行三级流水,因为其采用哈弗体结构,所以取指和访存可以同时执行,M3内部有解码模块,所以构成了三级流水。

     

     





  • 相关阅读:
    静态联编和动态联编
    常用Oracle分析函数详解
    Web Service , 不详细的介绍
    Eclipse安装JSEclipse和Spket
    IE中页面不居中,火狐谷歌等正常
    ExtJS3 详解与实践 之 第二章
    IPV6正则
    很漂亮、兼容火狐的Js日期选择,自动填充到输入框
    使用googlecodeprettify高亮显示网页代码
    ExtJS3 详解与实践 之 第三章
  • 原文地址:https://www.cnblogs.com/dchipnau/p/5255509.html
Copyright © 2011-2022 走看看