您现在的位置是:首页 >技术教程 >嵌入式系统知识点网站首页技术教程

嵌入式系统知识点

繁芜~ 2024-06-14 17:20:28
简介嵌入式系统知识点

嵌入式系统知识点(小题)

嵌入式系统概念和特点

  • 嵌入式系统概念:“嵌入式系统就是“嵌入到对象体系中、专用的计算机系统”
  • 嵌入式系统特点:特点
  • 嵌入式分类以及英文缩写含义:

嵌入式控制器(MCU) 嵌入式微处理器(MPU) 嵌入式数字信号处理器(DSP) 嵌入式片上系统(SOC)System on Chip

  • 其他英文缩写含义:
  • ARM的全称Advanced RISC Machines中,"RISC"是“Reduced Instruction Set Computing”的缩写,指的是一种精简指令集架构。ARM架构采用了精简指令集架构(RISC),以提高性能和能效比。
  • NVIC的全称是Nested Vectored Interrupt Controller,即嵌套向量中断控制器。它是一种用于处理器中断的控制器,可以在多个中断请求同时到达时,按照优先级进行处理。嵌套向量中断控制器可以管理各种类型的中断请求,包括外部中断、DMA请求、软件中断等,通过对中断请求的优先级排序和中断服务程序(ISR)的执行,实现对中断的快速响应和可靠处理。嵌套向量中断控制器是嵌入式系统中非常重要的组成部分,可以提高系统的可靠性和稳定性。
  • FPU的全称是Floating-Point Unit,即浮点运算单元
  • MMU的全称是Memory Management Unit,即内存管理单元
  • 嵌入式架构的四个层:
    在这里插入图片描述
    嵌入式系统组成:
    在这里插入图片描述

ARM架构-cortexM3/M4 纯知识点和芯片没关系

  • 实验室的STM32F07ZGT6属于ARMV7-cortex-M4系列
  • 该系列支持Thumb2指令集
  • 这里常见的缩写:

RISC 精简指令集 cortex-A-应用处理器 cortex-R 实时控制器 cortex-M 微控制器

  • 内存保护单元:

Memory Protection Uint
支持嵌套中断
支持向量中断
支持动态修改优先级
中断屏蔽

  • cortex-M3特性:

32位微处理器:
内部的数据路径是32位的,寄存器是32位的,存储器接口也是32位的。
4GB存储空间
指令总线和数据总线共享同一个存储器空间。
哈佛结构:指令和数据访问可以同时进行
一个可选的存储保护单元
支持大端和小端两种存储模式
包含多个固定的内部调试部件

  • 操作模式和特权等级:
  • 两种操作模式:处理者模式(handler mode)和线程级模式(thread mode)
    作用:用于区别普通应用程序的代码和异常服务例程的代码
    两种特权等级:特权级用户级
    用户级作用:提供一种存储器访问的保护机制,防止普通应用程序的代码作恶。
  • 理一理四个的关系:等级在上,分为特权级和用户级,然后特权级(CONTROL[0]=0)可以搭配处理者(handler)模式和线程模式(thread)使用:

在特权状态,程序可以访问所有的存储器区域(被MPU设置为禁止的除外),而且可以使用所有支持的指令。

  • 等级在上,分为特权级和用户级,然后用户级(CONTROL[0]=1)不可以搭配处理者(handler)模式,必须搭配线程模式(thread)使用:

在线程模式+用户模式下,对系统控制空间的访问将被阻止——该空间包含了配置寄存器及调试组件寄存器;禁止访问特殊功能寄存器,APSR例外。若访问了这些寄存器,将产生FAULT异常。
当处理器在线程模式下,即可以使用特权级,也可使用用户级;handler模式总是特权级。

  • PPT图片如下:
    *在这里插入图片描述
  • 三种模式的转换和注意事项:

1 、复位后,CM3/4默认进入特权级线程模式
2、从特权级切换到用户级,修改CONTROL寄存器即可
3、用户级切换回特权级,必须出发某种异常,如执行指令SVC,触发SVC异常,才能回到特权级;
4、处理异常服务例程必须使用特权级HANDLEER模式。
5、由特权级线程模式触发异常,异常处理完成后依然回到特权级线程模式;由用户级线程模式触发异常,异常处理完成后依然回到用户级线程模式。
在这里插入图片描述

  • R13(MSP主堆栈指针,PSP进程栈指针) R14(连接寄存器) R15(PC程序计数器)
  • 特权级CONTROL[0]=0时使用MSP,用户级CONTROL[0]=1时使用PSP
  • MSP(主栈指针):被操作系统(OS)内核 、异常处理以及所有需要特权访问的应用程序使用。上电后,处理器硬件在读取向量表后会被自动初始化。
    PSP(进程栈指针):被用户应用程序代码使用。PSP不会被自动初始化,需要在使用前由软件初始化。
    这样即使用户的程序错误导致堆栈崩溃,也可将其隔离在内核之外,不至于引起内核崩溃。堆栈指针永远时字对齐。
  • R14寄存器用于存储函数的返回地址
  • R15,又称为PC,程序指针寄存器,程序可以直接对此寄存器进行操作,从而改变程序流程。
  • R13与处理器模式:特权级下用MSP,用户级下用PSP
    在这里插入图片描述
  • R13堆栈指针是满递减操作,存储地址往上增长,堆栈指针堆栈指针减一,出栈SP出一个就加一。
  • 流水线:

CM3/4的流水线
CM3/4为三级流水线架构
取指(Fetch)——用来计算下一个预取指令的地址,从指令空间中取出指令,或者自动加载中断向量。
译码(Decode)——译码指令,产生操作数的地址,产生LR寄存器值
执行(Execute)——执行指令,产生回写与执行结果,以及进行逻辑运算并产生分支跳转。

  • 重点:PC计数器总是指向下一个预处理指令,提高效率

    执行指令
    0x1000:MOV R0,PC
    后,pc=?

执行指令0x1000:MOV R0,PC后,PC寄存器中的值会被复制到R0寄存器中。由于ARM指令集采用指令预取技术,即在执行当前指令时已经开始预取下一条指令,因此PC寄存器的值实际上是指向下一条指令的地址。因此,在执行完指令0x1000后,PC寄存器中的值将指向0x1004,即下一条指令的地址。

  • 在这里插入图片描述
  • 分支预测:

CM3/4内核的流水线——分支预测
Cortex-M3/M4内核采用了三级流水线(Fetch-Decode-Execute),其中Fetch阶段主要负责指令的读取,Decode阶段主要负责指令解码,Execute阶段则是指令的执行。
在CM3/4内核中,分支指令(如B、BL等)会破坏流水线,因为在执行分支指令之前,CPU并不知道下一条指令的地址,因此需要清空流水线并重新开始指令的读取和解码过程,这会导致CPU的性能下降。
为了解决这个问题,CM3/4内核采用了分支预测技术。具体来说,当执行分支指令时,CPU会根据历史执行记录和分支指令的条件(如跳转的地址是否在当前指令的前面或后面等)来预测下一条指令的地址,并将其放入流水线中。如果预测成功,CPU则可以继续执行流水线中的指令,从而避免了清空流水线的开销。如果预测失败,则需要清空流水线并重新开始指令的读取和解码过程。
CM3/4内核还采用了动态分支预测技术,即根据每个分支指令的历史执行记录来动态调整分支预测算法,以提高分支预测的准确性。同时,CM3/4内核还支持指令重排技术,即在保证程序正确性的前提下,将一些指令的执行顺序重新排列,以进一步提高CPU的性能。

  • CPU复位进入启动代码的操作

STM32CPU复位后会按照一定的顺序执行启动代码,其标准动作如下:
(1)复位向量:当复位信号被触发时,CPU会自动跳转到内部Flash中的复位向量(0x00000000),即复位中断服务程序的入口地址。
(2)复位中断服务程序:CPU执行复位中断服务程序,这个程序通常由芯片厂商提供,用于初始化CPU、外设、时钟和系统内存等设置。
(3)初始化系统时钟:复位中断服务程序会初始化系统时钟,并配置时钟树,以确保系统能够正常工作。
(4)初始化堆栈:复位中断服务程序会初始化堆栈指针(SP)并设置堆栈大小,以确保程序能够正常运行。
(5)初始化数据段:复位中断服务程序会将数据段(.data)从Flash中复制到RAM中,以确保全局变量和静态变量能够正常初始化。
(6)初始化bss段:复位中断服务程序会将未初始化的全局变量和静态变量(.bss)清零。
(7)跳转到主函数:复位中断服务程序会调用main()函数,并将控制权交给用户程序。
总之,在STM32中,复位向量会将控制权传递给复位中断服务程序,该服务程序会初始化系统并将控制权传递给用户程序。这是STM32CPU复位后进入启动代码的标准动作。

; Reset handler
Reset_Handler    PROC
                 EXPORT  Reset_Handler             [WEAK]
        IMPORT  SystemInit
        IMPORT  __main

                 LDR     R0, =SystemInit
                 BLX     R0
                 LDR     R0, =__main
                 BX      R0
                 ENDP

总结:复位后进入复位向量处,也就是复位中断入口地址,随后进入中断服务例程,在例程中初始化各种设置,然后跳转到主函数,进入用户程序。

  • 启动代码由什么组成和作用:

STM32启动代码由以下几个部分组成:
处理器的初始化:包括设置栈指针、设置中断向量表、设置系统时钟等。
外设时钟的使能:根据工程需要,使能和配置所需的外设时钟。
C库的初始化:初始化C语言运行时所需的全局变量等。
main函数的调用:最终将控制权交给main函数,开始执行用户程序。
其作用是初始化STM32芯片,为后续程序的运行做好准备。其中,处理器的初始化是最基本的部分,它设置了栈指针、中断向量表和系统时钟等关键参数,确保了程序能够正确地运行。外设时钟的使能和C库的初始化则为后续程序的运行提供了必要的支持。最后,启动代码将控制权交给main函数,用户程序从此开始运行。

总结:初始化系统并提供中断向量表然后进入MAIN程序也就是用户程序。

ARM存储系统

  • 三种总线:

AMBA标准中定义了三种总线:
AHB(Advanced High-performance Bus)、
ASB(Advanced System Bus)
APB(Advanced Peripheral Bus)。

  • ARM存储区:
    在这里插入图片描述

注意:位带区有两个分别位于片上SRAM(0x20000000-0X21FFFFFF)和片上外设(0x40000000-0x41FFFFFFF)
位带别名区两个也是位于片上SRAM和片上外设

  • 程序代码可以位于 片上SRAM片外RAM代码区
  • 位带操作:

位带操作就是利用位带别名区去控制位带区的操作,位带别名区一个字对应位带区的一个位,对位带别名区的一个字操作就是对位带区的一个位操作,提升了CPU执行效率。
在这里插入图片描述

  • 代码操作:往0X20000000的第二位置1
    在这里插入图片描述
  • 代码操作:读取0X20000000的第二位
    在这里插入图片描述
  • 位带操作注意:

对位带别名区的字操作相当于对位带中的某一位进行操作。
对位带别名区的字的bit[0]位写入0时,相当于将对位带中对应的位清零。
对位带别名区的字的bit[0]位写入1时,相当于将对位带中对应的位置1。
对位带别名区的字的bits[31:1]位的值并不会影响位带中对应的位。
例如:对位带别名区的字写入0x01或0xFF,其对位带的对应位的影响是相同的。

  • 位带操作的优势:

一般操作是读—改—写的方式,而位带别名区是写操作。
位带操作可以把代码缩小,速度更快,效率更高,更安全。
一般操作要6条指令,而使用位带别名区的操作只需4条指令。

  • ARM公司设计的寻址空间和STM32设计的寻址空间区别

ARM公司设计的处理器寻址空间是一个通用的概念,它可以表示各种不同的寻址空间大小,例如32位处理器的寻址空间大小为4GB。而STM32系列微控制器是基于ARM Cortex-M处理器内核设计的,其寻址空间大小由具体的型号和所使用的内存配置决定。
在STM32微控制器中,通常会使用闪存、SRAM和外部存储器等不同类型的存储器,并且不同型号的微控制器所支持的存储器大小和类型也不尽相同。例如,STM32F103系列微控制器的闪存大小可以从64KB到512KB不等,SRAM大小可以从20KB到64KB不等,而STM32F407系列微控制器的闪存大小可以从512KB到1MB不等,SRAM大小可以从192KB到196KB不等。因此,STM32的寻址空间大小是与具体的微控制器型号和内存配置相关的,而不同的型号和内存配置所支持的寻址空间大小也会有所不同。

ARM中断系统

  • 中断的定义:

中断:当CM3/4内核的外部发生某一事件,产生触发信号,引起CPU暂停当前执行的程序,转到相应的事件中断处理程序去执行。
中断是一种异步事件
外部按键产生中断
内部定时器产生中断
通信接口的数据收发产生中断

  • 异常与中断的区别

中断与异常名称概念相似,如不特别说明,两者不加以区分。
异常与中断的区别:中断对CM3/4内核来说是意外突发事件,请求信号来自外部;异常是CM3/4内核产生的,即在执行指令或存取中产生的。

  • CORTEX-M3可以支持多个系统异常和外部中断:

编号1-15的异常为系统异常,是ARM公司设定的。
16以上则为外部中断输入,是芯片厂商设定的。
理论上,外部中断最多可达240个,但一般厂商不会设定240个中断。

  • BASEPRI中断屏蔽寄存器:

要将basepri寄存器配置为取消所有中断屏蔽,可以将其设置为0,因为basepri寄存器的值越小,表示允许屏蔽的中断级别越高。因此,将basepri寄存器的值设置为0,表示不屏蔽任何中断,即取消所有中断屏蔽。

设置方法如下:

__set_BASEPRI(0);

或者

plaintext
Copy code
asm("MOV  R0, #0");
asm("MSR  BASEPRI, R0");

在Cortex-M处理器中,BASEPRI寄存器是一个8位的寄存器,用于控制可屏蔽中断的优先级,其值越小,表示允许屏蔽的中断级别越高。当BASEPRI寄存器的值为0时,所有中断都是可屏蔽的,因此不会发生中断屏蔽。

  • cortex-m3中断编号和向量地址:
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
  • STM32F407的中断编号和地址(芯片的中断比ARM公司的要少很多):
/**
 * @brief STM32F4XX Interrupt Number Definition, according to the selected device 
 *        in @ref Library_configuration_section 
 */
typedef enum IRQn
{
/******  Cortex-M4 Processor Exceptions Numbers ****************************************************************/
  NonMaskableInt_IRQn         = -14,    /*!< 2 Non Maskable Interrupt                                          */
  MemoryManagement_IRQn       = -12,    /*!< 4 Cortex-M4 Memory Management Interrupt                           */
  BusFault_IRQn               = -11,    /*!< 5 Cortex-M4 Bus Fault Interrupt                                   */
  UsageFault_IRQn             = -10,    /*!< 6 Cortex-M4 Usage Fault Interrupt                                 */
  SVCall_IRQn                 = -5,     /*!< 11 Cortex-M4 SV Call Interrupt                                    */
  DebugMonitor_IRQn           = -4,     /*!< 12 Cortex-M4 Debug Monitor Interrupt                              */
  PendSV_IRQn                 = -2,     /*!< 14 Cortex-M4 Pend SV Interrupt                                    */
  SysTick_IRQn                = -1,     /*!< 15 Cortex-M4 System Tick Interrupt                                */
/******  STM32 specific Interrupt Numbers **********************************************************************/
  WWDG_IRQn                   = 0,      /*!< Window WatchDog Interrupt                                         */
  PVD_IRQn                    = 1,      /*!< PVD through EXTI Line detection Interrupt                         */
  TAMP_STAMP_IRQn             = 2,      /*!< Tamper and TimeStamp interrupts through the EXTI line             */
  RTC_WKUP_IRQn               = 3,      /*!< RTC Wakeup interrupt through the EXTI line                        */
  FLASH_IRQn                  = 4,      /*!< FLASH global Interrupt                                            */
  RCC_IRQn                    = 5,      /*!< RCC global Interrupt                                              */
  EXTI0_IRQn                  = 6,      /*!< EXTI Line0 Interrupt                                              */
  EXTI1_IRQn                  = 7,      /*!< EXTI Line1 Interrupt                                              */
  EXTI2_IRQn                  = 8,      /*!< EXTI Line2 Interrupt                                              */
  EXTI3_IRQn                  = 9,      /*!< EXTI Line3 Interrupt                                              */
  EXTI4_IRQn                  = 10,     /*!< EXTI Line4 Interrupt                                              */
  DMA1_Stream0_IRQn           = 11,     /*!< DMA1 Stream 0 global Interrupt                                    */
  DMA1_Stream1_IRQn           = 12,     /*!< DMA1 Stream 1 global Interrupt                                    */
  DMA1_Stream2_IRQn           = 13,     /*!< DMA1 Stream 2 global Interrupt                                    */
  DMA1_Stream3_IRQn           = 14,     /*!< DMA1 Stream 3 global Interrupt                                    */
  DMA1_Stream4_IRQn           = 15,     /*!< DMA1 Stream 4 global Interrupt                                    */
  DMA1_Stream5_IRQn           = 16,     /*!< DMA1 Stream 5 global Interrupt                                    */
  DMA1_Stream6_IRQn           = 17,     /*!< DMA1 Stream 6 global Interrupt                                    */
  ADC_IRQn                    = 18,     /*!< ADC1, ADC2 and ADC3 global Interrupts                             */

#if defined (STM32F40_41xxx)
  CAN1_TX_IRQn                = 19,     /*!< CAN1 TX Interrupt                                                 */
  CAN1_RX0_IRQn               = 20,     /*!< CAN1 RX0 Interrupt                                                */
  CAN1_RX1_IRQn               = 21,     /*!< CAN1 RX1 Interrupt                                                */
  CAN1_SCE_IRQn               = 22,     /*!< CAN1 SCE Interrupt                                                */
  EXTI9_5_IRQn                = 23,     /*!< External Line[9:5] Interrupts                                     */
  TIM1_BRK_TIM9_IRQn          = 24,     /*!< TIM1 Break interrupt and TIM9 global interrupt                    */
  TIM1_UP_TIM10_IRQn          = 25,     /*!< TIM1 Update Interrupt and TIM10 global interrupt                  */
  TIM1_TRG_COM_TIM11_IRQn     = 26,     /*!< TIM1 Trigger and Commutation Interrupt and TIM11 global interrupt */
  TIM1_CC_IRQn                = 27,     /*!< TIM1 Capture Compare Interrupt                                    */
  TIM2_IRQn                   = 28,     /*!< TIM2 global Interrupt                                             */
  TIM3_IRQn                   = 29,     /*!< TIM3 global Interrupt                                             */
  TIM4_IRQn                   = 30,     /*!< TIM4 global Interrupt                                             */
  I2C1_EV_IRQn                = 31,     /*!< I2C1 Event Interrupt                                              */
  I2C1_ER_IRQn                = 32,     /*!< I2C1 Error Interrupt                                              */
  I2C2_EV_IRQn                = 33,     /*!< I2C2 Event Interrupt                                              */
  I2C2_ER_IRQn                = 34,     /*!< I2C2 Error Interrupt                                              */
  SPI1_IRQn                   = 35,     /*!< SPI1 global Interrupt                                             */
  SPI2_IRQn                   = 36,     /*!< SPI2 global Interrupt                                             */
  USART1_IRQn                 = 37,     /*!< USART1 global Interrupt                                           */
  USART2_IRQn                 = 38,     /*!< USART2 global Interrupt                                           */
  USART3_IRQn                 = 39,     /*!< USART3 global Interrupt                                           */
  EXTI15_10_IRQn              = 40,     /*!< External Line[15:10] Interrupts                                   */
  RTC_Alarm_IRQn              = 41,     /*!< RTC Alarm (A and B) through EXTI Line Interrupt                   */
  OTG_FS_WKUP_IRQn            = 42,     /*!< USB OTG FS Wakeup through EXTI line interrupt                     */
  TIM8_BRK_TIM12_IRQn         = 43,     /*!< TIM8 Break Interrupt and TIM12 global interrupt                   */
  TIM8_UP_TIM13_IRQn          = 44,     /*!< TIM8 Update Interrupt and TIM13 global interrupt                  */
  TIM8_TRG_COM_TIM14_IRQn     = 45,     /*!< TIM8 Trigger and Commutation Interrupt and TIM14 global interrupt */
  TIM8_CC_IRQn                = 46,     /*!< TIM8 Capture Compare Interrupt                                    */
  DMA1_Stream7_IRQn           = 47,     /*!< DMA1 Stream7 Interrupt                                            */
  FSMC_IRQn                   = 48,     /*!< FSMC global Interrupt                                             */
  SDIO_IRQn                   = 49,     /*!< SDIO global Interrupt                                             */
  TIM5_IRQn                   = 50,     /*!< TIM5 global Interrupt                                             */
  SPI3_IRQn                   = 51,     /*!< SPI3 global Interrupt                                             */
  UART4_IRQn                  = 52,     /*!< UART4 global Interrupt                                            */
  UART5_IRQn                  = 53,     /*!< UART5 global Interrupt                                            */
  TIM6_DAC_IRQn               = 54,     /*!< TIM6 global and DAC1&2 underrun error  interrupts                 */
  TIM7_IRQn                   = 55,     /*!< TIM7 global interrupt                                             */
  DMA2_Stream0_IRQn           = 56,     /*!< DMA2 Stream 0 global Interrupt                                    */
  DMA2_Stream1_IRQn           = 57,     /*!< DMA2 Stream 1 global Interrupt                                    */
  DMA2_Stream2_IRQn           = 58,     /*!< DMA2 Stream 2 global Interrupt                                    */
  DMA2_Stream3_IRQn           = 59,     /*!< DMA2 Stream 3 global Interrupt                                    */
  DMA2_Stream4_IRQn           = 60,     /*!< DMA2 Stream 4 global Interrupt                                    */
  ETH_IRQn                    = 61,     /*!< Ethernet global Interrupt                                         */
  ETH_WKUP_IRQn               = 62,     /*!< Ethernet Wakeup through EXTI line Interrupt                       */
  CAN2_TX_IRQn                = 63,     /*!< CAN2 TX Interrupt                                                 */
  CAN2_RX0_IRQn               = 64,     /*!< CAN2 RX0 Interrupt                                                */
  CAN2_RX1_IRQn               = 65,     /*!< CAN2 RX1 Interrupt                                                */
  CAN2_SCE_IRQn               = 66,     /*!< CAN2 SCE Interrupt                                                */
  OTG_FS_IRQn                 = 67,     /*!< USB OTG FS global Interrupt                                       */
  DMA2_Stream5_IRQn           = 68,     /*!< DMA2 Stream 5 global interrupt                                    */
  DMA2_Stream6_IRQn           = 69,     /*!< DMA2 Stream 6 global interrupt                                    */
  DMA2_Stream7_IRQn           = 70,     /*!< DMA2 Stream 7 global interrupt                                    */
  USART6_IRQn                 = 71,     /*!< USART6 global interrupt                                           */
  I2C3_EV_IRQn                = 72,     /*!< I2C3 event interrupt                                              */
  I2C3_ER_IRQn                = 73,     /*!< I2C3 error interrupt                                              */
  OTG_HS_EP1_OUT_IRQn         = 74,     /*!< USB OTG HS End Point 1 Out global interrupt                       */
  OTG_HS_EP1_IN_IRQn          = 75,     /*!< USB OTG HS End Point 1 In global interrupt                        */
  OTG_HS_WKUP_IRQn            = 76,     /*!< USB OTG HS Wakeup through EXTI interrupt                          */
  OTG_HS_IRQn                 = 77,     /*!< USB OTG HS global interrupt                                       */
  DCMI_IRQn                   = 78,     /*!< DCMI global interrupt                                             */
  CRYP_IRQn                   = 79,     /*!< CRYP crypto global interrupt                                      */
  HASH_RNG_IRQn               = 80,     /*!< Hash and Rng global interrupt                                     */
  FPU_IRQn                    = 81      /*!< FPU global interrupt                                              */
#endif /* STM32F40_41xxx */

中断优先级

  • 复位、NMI、HardFault具有固定的优先级,其他异常优先级可通过编程确定;

CM3/4最多可支持256个优先级,多个中断可共享一个优先级。
大多数CM3/4芯片支持的优先级数较少。

  • 问题1:当一个低优先级的异常正在处理时,一个高优先级的异常发生了,CPU该如何处理?

在Cortex-M3处理器中,当一个低优先级的异常正在处理时,如果一个高优先级的异常发生了,CPU会立即中断当前的低优先级异常处理,并保存当前的现场,然后转而去处理高优先级的异常。处理完高优先级异常后,CPU再恢复之前被中断的低优先级异常的现场,并继续低优先级异常的处理。
这种处理方式叫做异常嵌套处理。Cortex-M3处理器支持最多12级的中断优先级,因此在处理低优先级异常时,如果发生了高优先级异常,会中断当前的异常处理,转而去处理高优先级异常。如果高优先级异常又被中断,就会重新进入低优先级异常处理,这样可以保证系统能够快速响应高优先级的事件,同时也确保了低优先级事件的处理。
需要注意的是,在中断嵌套处理时,需要使用正确的中断处理机制,避免出现中断嵌套错误或死锁等问题。此外,在设计中断服务程序时,也需要考虑中断优先级的关系,避免出现优先级反转等问题。

  • 问题2:当具有相同的优先级的异常发生时,CPU该如何处理?

在Cortex-M处理器中,当具有相同优先级的多个异常同时发生时,CPU会按照以下规则进行处理:
如果多个异常同时处于Pending状态,则根据它们的IRQ编号(也称为向量号)来确定优先级,IRQ编号越小的优先级越高,因此优先处理IRQ编号较小的异常。
如果多个异常的IRQ编号相同,则根据它们的优先级来确定处理顺序,优先级数值越低的异常优先级越高。
如果多个异常的IRQ编号和优先级都相同,则按照先后顺序进行处理,即先发生的异常先被处理。
需要注意的是,如果多个异常同时发生,CPU会依次处理它们,每次处理一个异常时,CPU都会保存当前的现场,并启动异常处理过程,直到处理完所有异常后再返回到主程序。在处理多个异常时,CPU会使用堆栈来保存每个异常的现场信息,避免不同异常之间的相互影响。
在设计系统时,需要考虑到不同异常之间的优先级关系,避免出现优先级反转、死锁等问题。此外,在编写异常处理程序时,也需要注意异常处理程序的可重入性和安全性,避免出现异常处理程序被重复调用或者数据被破坏等问题。

  • 配置优先级寄存器的IP寄存器,总共有240个,每个寄存器有8位,但是一般都是高位有效,多少位有效寄存器的值也是不同的:
    在这里插入图片描述
  • 多少位有效对应的寄存器配置也是不同的
    在这里插入图片描述
  • 抢占优先级和子优先级:CM3/4将优先级寄存器分为两个部分:抢占优先级和子优先级。

高位部分为抢占级,抢占级别高(数值低)的中断可以打断抢占级别低的中断;
低位部分为子优先级,在抢占级别相同的情况下,后被识别的中断,即使优先级比较高,也不能抢占正在被cpu服务的低优先级的中断。

  • 优先级分组:主要操作这个寄存器**应用程序中断及复位控制寄存器(AIRCR:0XE000_ED0C)**里面的三位寄存器
    在这里插入图片描述
    在这里插入图片描述

上图中PRIGOUP的寄存器就是8:10-位,可以配置成0-7个分组也就是8组分组方式,但是STM32芯片可能仅支持4种分组方式,0123。
代码示例:分为2组 就是8-9-10位分别为 010 对应AIRCR寄存器就是 0000 0000 0000 0000 0000 0010 0000 0000 =0X02<<8

NVIC->AIRCR&=~(0x07<<8) //清空8 9 10位
NVIC->AIRCR|=(0X02<<8) //置位
  • 中断寄存器以及对应的操作;
    在这里插入图片描述
    上面中断优先级分组有点问题:上述看代码才是正确的
  • 中断向量地址从0X00开始,往上每增加4字节就是一个中断向量起始地址。
    在这里插入图片描述
  • 中断请求 中断挂起 中断服务例程

中断开放请求后,中断触发后就回去请求中断,CPU响应后对中断进行挂起,然后开始执行中断服务例程,执行完后记得手动取消挂起该中断,不然该中断会一直挂起,只要CPU工作后就会响应它造成中断例程一直执行。在这里插入图片描述
问题:中断悬起状态不是硬件自动清除的,需要在中断服务期间进行手动清除。
考虑:1、如果不清除该位会怎样?
答:
如果不清除中断悬挂状态,系统会一直认为该中断请求仍然存在,因此每次该中断请求被触发时,中断服务程序都会被调用。这可能会导致系统出现异常行为,例如重复执行相同的操作、数据的错误处理等。如果中断服务程序不及时清除中断悬挂状态,可能会导致系统陷入死循环或崩溃的状态。
因此,在STM32中,必须在中断服务程序中手动清除中断悬挂状态,以确保系统正常运行。在清除中断悬挂状态之后,系统会正确地响应后续的中断请求,并执行相应的操作。

注意事项:即使中断被禁止了,中断依然可以发生,依然可以被挂起; 挂起的中断在中断使能后可以得到CPU的服务;

  • 中断压栈指针用MSP主堆栈针因为是特权handler模式
  • cortex-m3中断压栈是压哪个栈

在Cortex-M3架构中,中断处理过程中使用了两个栈指针(Stack Pointer,SP),即主栈指针(Main Stack Pointer,MSP)和进程栈指针(Process Stack Pointer,PSP)。其中,MSP用于处理异常和中断,而PSP用于处理线程模式下的堆栈。
当中断请求被触发时,Cortex-M3会自动将当前的寄存器状态(即现场保护)压入MSP指向的栈中,然后将MSP指向中断服务程序的栈空间。因此,在Cortex-M3架构中,中断压栈是压主栈(MSP)。
在中断服务程序执行完毕后,Cortex-M3会自动将MSP指向的栈中的现场保护数据弹出,然后将MSP指向之前保存的现场保护数据,从而恢复现场,继续执行被中断的代码。

  • CM3/4的中断处理的特点

支持中断嵌套,高优先级可打断低优先级的中断
采用中断向量表处理,直接由向量表载入ISR的入口地址给PC指针,无需查表载入跳转指令,再实现跳转的方式。
中断触发时自动保存现场,自动压栈,中断服务程序退出时自动退栈,恢复现场
获取向量与保存现场同时进行,最大限度节省中断响应时间。
支持中断的late-arrive机制和tail-chaining机制。

  • 外部中断的两种机制:

CM3/4的late-arrive机制(晚到机制)

一般来说一个优先级低的中断在处理,抢占优先级高的中断可以打断它并执行,但需要重新保存低优先级的现场
由于从中断信号被触发到开始执行ISR一般需要12个时钟周期保存现场,在此期间如果有高优先级的中断触发(不迟于低优先级中断的取向量操作),则本次操作可以变成高抢占优先级的中断。
在高抢占优先级中断结束的时候,恢复低优先级的中断服务,采用tail-chaining启动它的取指。
总结:就是高优先级抢断后不用重新出栈入栈,将低优先级的操作奉献高优先级

CM3/4的tail-chaining机制(连锁机制)

当内核正在处理一个中断1时,另外一个同级或低级的中断2触发,处于挂起状态等待前一中断1处理完毕。1处理完毕时,按正常流程需要恢复打断的现场,将寄存器出栈,再响应2中断,重新再将现场寄存器入栈操作。整个出栈/入栈大约需要30多个周期。
Tail-chaining机制简化了中间重复工作,使得无需重新出栈/入栈,仅进行新的中断取向量工作,将切换简化为6个周期
总结:就是两个同优先级或者差一级的中断同时触发,第一个触发中断的操作继承给第二个中断,将12周期的指令简短成4个周期。

操作系统知识点

初识操作系统

  • 什么是UCOSIII?

UCOS是一个抢占式(亦可叫占先式)实时轻量级操作系统(实时内核),系统内核时优先级调度法。基于优先级的调度法指CPU总是让处在就绪态的优先级最高的任务先运行。

  • 什么是任务:

简单回答:通常将“并行执行的基本逻辑单位”称之为“任务”

详细回答:
就是说任务是可以被分割为独立的且可并行执行的基本逻辑单位程序。
一个任务的程序是顺序执行的,而不同任务的程序却是并行执行的。
任务必须包括相互“独立”和“并行”执行两个方面。

  1. 任务属性:

任务属性1:相互独立

独立具体指任务不能彼此直接调用,也不能直接进行数据交换(不能相互调用 不能进行直接数据交换)

任务属性2:并行执行

想象相互独立的任务各自拥有一个CPU,每个CPU各自执行各自的任务,此即任务的并行执行。但实际上CPU只有一个,我们认为操作系统为每个任务虚拟了一个CPU

  1. 时间片轮转调度(顺势讲解滴答时钟和时钟节拍)

时间片调度:

当两个或两个以上任务有同样优先级,内核允许一个任务运行事先确定的一段时间,叫做时间额度(quantum),然后切换给另一个任务。
内核在满足以下条件时,把CPU控制权交给下一个任务就绪态的任务:
1)当前任务已无事可做。
2)当前任务在时间片还没结束时已经完成了。
3)时间片结束。

时钟节拍:

时钟节拍是特定的周期性中断。这个中断可以看作是系统心脏的脉动。
中断之间的时间间隔取决于不同应用,一般在10ms到200ms之间。
时钟的节拍式中断使得内核可以将任务延时若干个整数时钟节拍,以及当任务等待事件发生时,提供等待超时的依据。
时钟节拍率越快,系统的额外开销就越大。
时钟节拍来源:来源于滴答定时器的中断,具体时间得根据公式计算

  1. 什么时任务切换:

当多任务内核决定运行另外的任务时,它保存正在运行任务的当前状态(Context),把下一个将要运行的任务的状况从该任务的栈中重新装入CPU的寄存器,并开始下一个任务的运行。这个过程叫做任务切换。
任务切换过程增加了CPU的额外负荷。CPU的内部寄存器越多,额外负荷就越重。做任务切换所需要的时间取决于CPU有多少寄存器要入栈。

  1. 什么时代码临界区:

代码的临界段也称为临界区,是指那些必须连续运行,不可被打断的代码段。

  1. 什么时死锁:

死锁也称作抱死,指两个任务无限期地互相等待对方控制着的资源。

  1. 什么是同步:

为了实现各个任务之间的合作和无冲突的运行,在各任务之间必须建立一些制约机制。任务之间的这种制约性的合作运行机制即成为任务间的同步。

UCOS任务

  1. UCOS中的任务:

任务和main(函数不属于隶属关系,可以说是等同的关系
在main()函数开始之前要将任务的三要素任务堆栈任务控制块任务函数代码声明一下

裸机程序题

GPIO寄存器以及相关配置

例题:使用C语言将PE2引脚设置成上拉输入,并设置外部中断功能,并为为该中断优先级设置成抢占优先级为3,子优先级为2,
提示PE2对应的中断编号为EXTI2_IRQn。
答:

  1. 时钟使能寄存器介绍

RCC->AHB1ENR这个就为时钟使能寄存器,使用介绍,题目要求配置PA口,就这样操作RCC->AHB1ENR|=1<<0;
如果要求配置PE口,就这样操作1RCC->AHB1ENR|=1<<4
总结:A| = 1<<0 B|=1<<1 C| = 1<<2 D|=1<<3 E|=1<<4 以此类推

本题第一句代码:

//首先配置时钟寄存器使能PE口的时钟
RCC->AHB1ENR|=1<<4; //使能PORTE口时钟
  1. GPIO控制输入输出模式寄存器:GPIOX->MODER
    使用方法:将PE2设置成输入模式:

GPIOE->MODER &= ~(0X03<<2x2)就是将PE2设置成输入模式 以下依次类推·:
GPIOE->MODER &= ~(0X03<<2x3)就是将PE3设置成输入模式
GPIOE->MODER &= ~(0X03<<2x4)就是将PE4设置成输入模式
GPIOA->MODER &= ~(0X03<<2x2)就是将PA2设置成输入模式 以下依次类推·:
GPIOA->MODER &= ~(0X03<<2x3)就是将PA3设置成输入模式
GPIOA->MODER &= ~(0X03<<2x4)就是将PA4设置成输入模式

本题第二句代码:

//其次配置PE2为输入模式
GPIOE->MODER &= ~(0X03<<2*2) //就是将PE2设置成输入模式

3.GPIO控制输入输出模式寄存器:GPIOX->PUDER
使用方法:将PE2设置成输入模式:

GPIOE->PUDER |= (0X01<<2x2)就是将PE2设置成上拉模式 以下依次类推·:
GPIOE->PUDER |= (0X01<<2x3)就是将PE3设置成上拉模式
GPIOE->PUDER |= (0X01<<2x4)就是将PE4设置成上拉模式
GPIOA->PUDER |= (0X01<<2x2)就是将PA2设置成上拉模式 以下依次类推·:
GPIOA->PUDER |= (0X01<<2x3)就是将PA3设置成上拉模式
GPIOA->PUDER |= (0X01<<2x4)就是将PA4设置成上拉模式
若改为下拉输入:0x01替换成0x02
若改为保留输入:0x01替换成0x03
若改为无上下拉输入:0x01替换成0x00

本题第三句代码:

//其次配置PE2为上拉输入模式
GPIOE->PUDER |= (0X01<<2*2)//就是将PE2设置成上拉模式

中断相关配置

本题第四句代码: 这段代码固定不变

RCC->APB2ENR|=1<<14;  						        /* 使能SYSCFG时钟 */ 
  • 绑定中断线

中断线分为四组,0-3号引脚为第一组,4-7为第二组,8-11为第三组,11-15为第四组
对应的数组为SYSCFG->EXTICR[0] SYSCFG->EXTICR[1] SYSCFG->EXTICR[2] SYSCFG->EXTICR[3]
操作方法:举一个例子:绑定中断线4和PE4引脚,PE4属于第二组第一个·,所以SYSCFG->EXTICR[1]|=0x04<<0这里的0X04是0X0100就是PE口引脚,PA口就是0x0000 接着 PB-0X0001 PC-0x010 PD-0x0011 PE-0x0100。接着左移0位是因为PE4在第二个数组的开头为4-7的4,所以左移0位,再来举一个例子,:绑定中断线2和PA2引脚,PA2属于第一组第3个·,所以SYSCFG->EXTICR[0]|=0x00<<2。其中0x00代表PA口,左移两位就是第一组0-3中的2.

  • 接下来这两句比较简单
    EXTI->IMR  |=1<<0|1<<2|1<<3|1<<4;                   /* 开放中断线2 3 4的请求 */
    EXTI->FTSR |=1<<2|1<<3|1<<4;                         /* 中断线2 3 4 配置成下降沿触发 */

第一句就是开放哪个线就1左移几位,上述就开放了234这三个线。下降沿触发也是一样的道理。

  • 第七句代码 固定不变的
 /* 设置NVIC寄存器分组为2 */
    aircr_value = SCB->AIRCR;
    aircr_value &= ~((uint32_t)0x0000F000);                  /* 读取当前寄存器数据 */
    aircr_value |= ((uint32_t)0x00004000);                   /* 设置分组为2,就是 0000 0000 0100 中8、9、10位为010=2 */
    SCB->AIRCR = aircr_value;                              /* 写回寄存器 */
  • 第八句代码
 /* 设置NVIC寄存器分组为2 */
    NVIC->ISER[0] |=(1<<(EXTI2_IRQn%32)|1<<(EXTI3_IRQn%32)|1<<(EXTI4_IRQn%32)|1<<(EXTI0_IRQn%32)); /* 使能EXTI2 EXTI3 EXTI4 EXTIO线上的中断 */ 

这段代码也简单,题目给了中断编号EXTI2IRQn直接带入进去就可以了。

  • 第句九代码
 NVIC->IP[EXTI2_IRQn]=0X0E<<4; /* 抢占3,子优先级2,组2 */

这段代码也简单,首先将中断编号EXTI2_IRQ代入进去,然后后面的你们就记死的结论

    0X0E<<4; /* 抢占3,子优先级2,组2 */
    0X0A<<4; /* 抢占2,子优先级2,组2 */
    0X06<<4; /* 抢占1,子优先级2,组2 */
    0X02<<4; /* 抢占0,子优先级2,组2 */
 NVIC->IP[EXTI2_IRQn]=0X0E<<4; /* 抢占3,子优先级2,组2 */
  • 总体代码
    这段代码也简单,首先将中断编号EXTI2_IRQ代入进去,然后后面的你们就记死的结论
RCC->AHB1ENR|=1<<4; //使能PORTE口时钟
GPIOE->MODER &= ~(0X03<<2*2) //就是将PE2设置成输入模式
GPIOE->PUDER |= (0X01<<2*2)//就是将PE2设置成上拉模式
RCC->APB2ENR|=1<<14; /* 使能SYSCFG时钟 */
SYSCFG->EXTICR[0]|=0x04<<2;/* 绑定中断线2 */
EXTI->IMR  |=1<<2;                   /* 开放中断线2的请求 */
EXTI->FTSR |=1<<2;                         /* 中断线2 配置成下降沿触发 */
/* 设置NVIC寄存器分组为2 */
aircr_value = SCB->AIRCR;
aircr_value &= ~((uint32_t)0x0000F000);                  /* 读取当前寄存器数据 */
aircr_value |= ((uint32_t)0x00004000);                   /* 设置分组为2,就是 0000 0000 0100 中8、9、10位为010=2 */
SCB->AIRCR = aircr_value;                              /* 写回寄存器 */
/* 设置NVIC寄存器分组为2 */
NVIC->ISER[0] |=(1<<(EXTI2_IRQn%32)); /* 使能EXTI2线上的中断 */
NVIC->IP[EXTI2_IRQn]=0X0E<<4; /* 抢占3,子优先级2,组2 */
  • 到此结束,代码都是有规律的!!!!!!!!
风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。