CMSIS CM3源码注解

2024-06-03 17:58
文章标签 源码 注解 cmsis cm3

本文主要是介绍CMSIS CM3源码注解,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文中截图摘自《Cortex_M3权威指南》

core_cm3.h

1 Memory Map

/* Memory mapping of Cortex-M3 Hardware */
#define SCS_BASE            (0xE000E000)                              /*!< System Control Space Base Address */
#define ITM_BASE            (0xE0000000)                              /*!< ITM Base Address                  */
#define CoreDebug_BASE      (0xE000EDF0)                              /*!< Core Debug Base Address           */
#define SysTick_BASE        (SCS_BASE +  0x0010)                      /*!< SysTick Base Address              */
#define NVIC_BASE           (SCS_BASE +  0x0100)                      /*!< NVIC Base Address                 */
#define SCB_BASE            (SCS_BASE +  0x0D00)                      /*!< System Control Block Base Address */#define InterruptType       ((InterruptType_Type *) SCS_BASE)         /*!< Interrupt Type Register           */
#define SCB                 ((SCB_Type *)           SCB_BASE)         /*!< SCB configuration struct          */
#define SysTick             ((SysTick_Type *)       SysTick_BASE)     /*!< SysTick configuration struct      */
#define NVIC                ((NVIC_Type *)          NVIC_BASE)        /*!< NVIC configuration struct         */
#define ITM                 ((ITM_Type *)           ITM_BASE)         /*!< ITM configuration struct          */
#define CoreDebug           ((CoreDebug_Type *)     CoreDebug_BASE)   /*!< Core Debug configuration struct   */#if defined (__MPU_PRESENT) && (__MPU_PRESENT == 1)#define MPU_BASE          (SCS_BASE +  0x0D90)                      /*!< Memory Protection Unit            */#define MPU               ((MPU_Type*)            MPU_BASE)         /*!< Memory Protection Unit            */
#endif

这里写图片描述

从图5.2可以看到, CM3的SCS的基地址为0xE000E000。

2 SCB

core_cm3.c

/** @addtogroup CMSIS_CM3_SCB CMSIS CM3 SCBmemory mapped structure for System Control Block (SCB)@{*/
typedef struct
{__I  uint32_t CPUID;                        /*!< Offset: 0x00  CPU ID Base Register                                  */__IO uint32_t ICSR;                         /*!< Offset: 0x04  Interrupt Control State Register                      */__IO uint32_t VTOR;                         /*!< Offset: 0x08  Vector Table Offset Register                          */__IO uint32_t AIRCR;                        /*!< Offset: 0x0C  Application Interrupt / Reset Control Register        */__IO uint32_t SCR;                          /*!< Offset: 0x10  System Control Register                               */__IO uint32_t CCR;                          /*!< Offset: 0x14  Configuration Control Register                        */__IO uint8_t  SHP[12];                      /*!< Offset: 0x18  System Handlers Priority Registers (4-7, 8-11, 12-15) */__IO uint32_t SHCSR;                        /*!< Offset: 0x24  System Handler Control and State Register             */__IO uint32_t CFSR;                         /*!< Offset: 0x28  Configurable Fault Status Register                    */__IO uint32_t HFSR;                         /*!< Offset: 0x2C  Hard Fault Status Register                            */__IO uint32_t DFSR;                         /*!< Offset: 0x30  Debug Fault Status Register                           */__IO uint32_t MMFAR;                        /*!< Offset: 0x34  Mem Manage Address Register                           */__IO uint32_t BFAR;                         /*!< Offset: 0x38  Bus Fault Address Register                            */__IO uint32_t AFSR;                         /*!< Offset: 0x3C  Auxiliary Fault Status Register                       */__I  uint32_t PFR[2];                       /*!< Offset: 0x40  Processor Feature Register                            */__I  uint32_t DFR;                          /*!< Offset: 0x48  Debug Feature Register                                */__I  uint32_t ADR;                          /*!< Offset: 0x4C  Auxiliary Feature Register                            */__I  uint32_t MMFR[4];                      /*!< Offset: 0x50  Memory Model Feature Register                         */__I  uint32_t ISAR[5];                      /*!< Offset: 0x60  ISA Feature Register                                  */
} SCB_Type;

3 NVIC

寄存器定义

typedef struct
{__IO uint32_t ISER[8];                      /*!< Offset: 0x000  Interrupt Set Enable Register           */uint32_t RESERVED0[24];__IO uint32_t ICER[8];                      /*!< Offset: 0x080  Interrupt Clear Enable Register         */uint32_t RSERVED1[24];__IO uint32_t ISPR[8];                      /*!< Offset: 0x100  Interrupt Set Pending Register          */uint32_t RESERVED2[24];__IO uint32_t ICPR[8];                      /*!< Offset: 0x180  Interrupt Clear Pending Register        */uint32_t RESERVED3[24];__IO uint32_t IABR[8];                      /*!< Offset: 0x200  Interrupt Active bit Register           */uint32_t RESERVED4[56];__IO uint8_t  IP[240];                      /*!< Offset: 0x300  Interrupt Priority Register (8Bit wide) */uint32_t RESERVED5[644];__O  uint32_t STIR;                         /*!< Offset: 0xE00  Software Trigger Interrupt Register     */
}  NVIC_Type;
ISER&ICER

中断的使能与除能分别使用各自的寄存器来控制——这与传统的,使用单一比特的两个状态来表达使能与除能是不同的。CM3中可以有240对使能位/除能位(SETENA位/CLRENA位),每个中断拥有一对。这240个对子分布在8对32位寄存器中(最后一对没有用完)。欲使能一个中断,我们需要写1到对应SETENA的位中;欲除能一个中断,你需要写1到对应的CLRENA位中。如果往它们中写0,则不会有任何效果。

这里写图片描述

ISPR&ICPR

如果中断发生时,正在处理同级或高优先级异常,或者被掩蔽,则中断不能立即得到响应。此时中断被悬起。中断的悬起状态可以通过“中断设置悬起寄存器(SETPEND)”和“中断悬起清除寄存器(CLRPEND)”来读取,还可以写它们来手工悬起中断。
悬起寄存器和“解悬”寄存器也可以有8对,其用法和用量都与前面介绍的使能/除能寄存器完全相同,见表8.2。
这里写图片描述

IP[240]

这里写图片描述

IABR[8]

每个外部中断都有一个活动状态位。在处理器执行了其ISR的第一条指令后,它的活动位就被置1,并且直到ISR返回时才硬件清零。由于支持嵌套,允许高优先级异常抢占某个ISR。然而,哪怕中断被抢占,其活动状态也依然为1(请仔细琢磨前文讲到的“直到ISR返回时才清零)。活动状态寄存器的定义,与前面讲的使能/除能和悬起/解悬寄存器相同,只是不再成对出现。它们也能按字/半字/字节访问,但他们是只读的,如表8.4所示
这里写图片描述

STIR

这里写图片描述

NVIC 函数/宏

优先级分组设置

下表为AIRCR的寄存器,AIRCR位于SCB中。
这里写图片描述
这里写图片描述

  • NVIC_SetPriorityGrouping这个函数实现就非常简单了,同时将VECTKEY和PRIGROUP就能完成优先级组的设置。
  • NVIC_GetPriorityGrouping是读出优先级组设置的函数,实现很简单,直接读AIRCR的PRIGROUP字段即可。
static __INLINE void NVIC_SetPriorityGrouping(uint32_t PriorityGroup)
{uint32_t reg_value;uint32_t PriorityGroupTmp = (PriorityGroup & 0x07);                         /* only values 0..7 are used          */reg_value  =  SCB->AIRCR;                                                   /* read old register configuration    */reg_value &= ~(SCB_AIRCR_VECTKEY_Msk | SCB_AIRCR_PRIGROUP_Msk);             /* clear bits to change               */reg_value  =  (reg_value                       |(0x5FA << SCB_AIRCR_VECTKEY_Pos) |(PriorityGroupTmp << 8));                                     /* Insert write key and priorty group */SCB->AIRCR =  reg_value;
}static __INLINE uint32_t NVIC_GetPriorityGrouping(void)
{return ((SCB->AIRCR & SCB_AIRCR_PRIGROUP_Msk) >> SCB_AIRCR_PRIGROUP_Pos);   /* read priority grouping field */
}
使能/除能中断
  • NVIC_EnableIRQ设置ISER中的某一个中断,计算方法也很简单,就是简单的bitmap操作。

  • NVIC_DisableIRQ设置ICER中的某一个中断,计算方法与NVIC_EnableIRQ一样。

static __INLINE void NVIC_EnableIRQ(IRQn_Type IRQn)
{NVIC->ISER[((uint32_t)(IRQn) >> 5)] = (1 << ((uint32_t)(IRQn) & 0x1F)); /* enable interrupt */
}static __INLINE void NVIC_DisableIRQ(IRQn_Type IRQn)
{NVIC->ICER[((uint32_t)(IRQn) >> 5)] = (1 << ((uint32_t)(IRQn) & 0x1F)); /* disable interrupt */
}
中断挂起/清除

以下三个函数非常分别获取中断挂起状态,设置中断挂起,清除中挂起。实际上就是去操作NVIC的ISPR和ICPR寄存器,看过上面寄存器定义看到这个代码就很好理解了。

static __INLINE uint32_t NVIC_GetPendingIRQ(IRQn_Type IRQn)
{return((uint32_t) ((NVIC->ISPR[(uint32_t)(IRQn) >> 5] & (1 << ((uint32_t)(IRQn) & 0x1F)))?1:0)); /* Return 1 if pending else 0 */
}static __INLINE void NVIC_SetPendingIRQ(IRQn_Type IRQn)
{NVIC->ISPR[((uint32_t)(IRQn) >> 5)] = (1 << ((uint32_t)(IRQn) & 0x1F)); /* set interrupt pending */
}static __INLINE void NVIC_ClearPendingIRQ(IRQn_Type IRQn)
{NVIC->ICPR[((uint32_t)(IRQn) >> 5)] = (1 << ((uint32_t)(IRQn) & 0x1F)); /* Clear pending interrupt */
}
激活中断状态

NVIC_GetActive操作NVIC中的IABR寄存器,其操作与其他NVIC的寄存器操作一样,类似bitmap。

static __INLINE uint32_t NVIC_GetActive(IRQn_Type IRQn)
{return((uint32_t)((NVIC->IABR[(uint32_t)(IRQn) >> 5] & (1 << ((uint32_t)(IRQn) & 0x1F)))?1:0)); /* Return 1 if active else 0 */
}
设置中断优先级

优先级设置会根据是IRQ还是系统内部异常设置不同的寄存器,如果是IRQ中断,设置NVIC的IP寄存器。否则设置SCB中SHP寄存器。下图就是SHP的寄存器,SHP位于SCB中。
这里写图片描述

static __INLINE void NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority)
{if(IRQn < 0) {SCB->SHP[((uint32_t)(IRQn) & 0xF)-4] = ((priority << (8 - __NVIC_PRIO_BITS)) & 0xff); } /* set Priority for Cortex-M3 System Interrupts */else {NVIC->IP[(uint32_t)(IRQn)] = ((priority << (8 - __NVIC_PRIO_BITS)) & 0xff);    }        /* set Priority for device specific Interrupts  */
}static __INLINE uint32_t NVIC_GetPriority(IRQn_Type IRQn)
{if(IRQn < 0) {return((uint32_t)(SCB->SHP[((uint32_t)(IRQn) & 0xF)-4] >> (8 - __NVIC_PRIO_BITS)));  } /* get priority for Cortex-M3 system interrupts */else {return((uint32_t)(NVIC->IP[(uint32_t)(IRQn)]           >> (8 - __NVIC_PRIO_BITS)));  } /* get priority for device specific interrupts  */
}
Encode/Decode优先级
  • NVIC_EncodePriority的计算方法如下:先根据优先级组设置PriorityGroup得到优先级是如何分布,即多少位表示抢占优先级,多少位表示次优先级。然后根据得到的位数分布分别将抢占优先级和次优先级填入一个字节中。

  • NVIC_DecodePriority 正好相反,根据优先级值和优先级组设置获取抢占优先级和次优先级。

static __INLINE uint32_t NVIC_EncodePriority (uint32_t PriorityGroup, uint32_t PreemptPriority, uint32_t SubPriority)
{uint32_t PriorityGroupTmp = (PriorityGroup & 0x07);          /* only values 0..7 are used          */uint32_t PreemptPriorityBits;uint32_t SubPriorityBits;PreemptPriorityBits = ((7 - PriorityGroupTmp) > __NVIC_PRIO_BITS) ? __NVIC_PRIO_BITS : 7 - PriorityGroupTmp;SubPriorityBits     = ((PriorityGroupTmp + __NVIC_PRIO_BITS) < 7) ? 0 : PriorityGroupTmp - 7 + __NVIC_PRIO_BITS;return (((PreemptPriority & ((1 << (PreemptPriorityBits)) - 1)) << SubPriorityBits) |((SubPriority     & ((1 << (SubPriorityBits    )) - 1))));
}static __INLINE void NVIC_DecodePriority (uint32_t Priority, uint32_t PriorityGroup, uint32_t* pPreemptPriority, uint32_t* pSubPriority)   
{                                                                                                                                          uint32_t PriorityGroupTmp = (PriorityGroup & 0x07);          /* only values 0..7 are used          */                                    uint32_t PreemptPriorityBits;                                                                                                            uint32_t SubPriorityBits;                                                                                                                PreemptPriorityBits = ((7 - PriorityGroupTmp) > __NVIC_PRIO_BITS) ? __NVIC_PRIO_BITS : 7 - PriorityGroupTmp;                             SubPriorityBits     = ((PriorityGroupTmp + __NVIC_PRIO_BITS) < 7) ? 0 : PriorityGroupTmp - 7 + __NVIC_PRIO_BITS;                         *pPreemptPriority = (Priority >> SubPriorityBits) & ((1 << (PreemptPriorityBits)) - 1);                                                  *pSubPriority     = (Priority                   ) & ((1 << (SubPriorityBits    )) - 1);                                                  
}                                                                                                                                          
系统复位

这个看AIRCR寄存器的定义就可以知道往AIRCR中的SYSRESETREQ就可以知道,往该位中写入1就能触发一次芯片复位。

static __INLINE void NVIC_SystemReset(void)
{SCB->AIRCR  = ((0x5FA << SCB_AIRCR_VECTKEY_Pos)      |(SCB->AIRCR & SCB_AIRCR_PRIGROUP_Msk) |SCB_AIRCR_SYSRESETREQ_Msk);                   /* Keep priority group unchanged */__DSB();                                                     /* Ensure completion of memory access */while(1);                                                    /* wait until reset */
}

4 SysTick

static __INLINE uint32_t SysTick_Config(uint32_t ticks)
{if (ticks > SysTick_LOAD_RELOAD_Msk)  return (1);            /* Reload value impossible */SysTick->LOAD  = (ticks & SysTick_LOAD_RELOAD_Msk) - 1;      /* set reload register */NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1);  /* set Priority for Cortex-M0 System Interrupts */SysTick->VAL   = 0;                                          /* Load the SysTick Counter Value */SysTick->CTRL  = SysTick_CTRL_CLKSOURCE_Msk |SysTick_CTRL_TICKINT_Msk   |SysTick_CTRL_ENABLE_Msk;                    /* Enable SysTick IRQ and SysTick Timer */return (0);                                                  /* Function successful */
}

core_cm3.c

这个文件里的实现都是封装了一些C语言没法操作的东西,代码都非常简单。

设置栈

__ASM uint32_t __get_PSP(void)
{mrs r0, pspbx lr
}__ASM void __set_PSP(uint32_t topOfProcStack)  
{                                              msr psp, r0                                  bx lr                                        
} __ASM uint32_t __get_MSP(void)
{mrs r0, mspbx lr
}__ASM void __set_MSP(uint32_t mainStackPointer)
{msr msp, r0bx lr
}                                             

设置PRIMASK

__ASM uint32_t __get_PRIMASK(void)
{mrs r0, primaskbx lr
}__ASM void __set_PRIMASK(uint32_t priMask)
{msr primask, r0bx lr
}

设置BASEPRI

__ASM uint32_t  __get_BASEPRI(void)
{mrs r0, basepribx lr
}/*** @brief  Set the Base Priority value** @param  basePri  BasePriority** Set the base priority register*/
__ASM void __set_BASEPRI(uint32_t basePri)
{msr basepri, r0bx lr
}

这篇关于CMSIS CM3源码注解的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1027707

相关文章

SpringCloud动态配置注解@RefreshScope与@Component的深度解析

《SpringCloud动态配置注解@RefreshScope与@Component的深度解析》在现代微服务架构中,动态配置管理是一个关键需求,本文将为大家介绍SpringCloud中相关的注解@Re... 目录引言1. @RefreshScope 的作用与原理1.1 什么是 @RefreshScope1.

Python实现无痛修改第三方库源码的方法详解

《Python实现无痛修改第三方库源码的方法详解》很多时候,我们下载的第三方库是不会有需求不满足的情况,但也有极少的情况,第三方库没有兼顾到需求,本文将介绍几个修改源码的操作,大家可以根据需求进行选择... 目录需求不符合模拟示例 1. 修改源文件2. 继承修改3. 猴子补丁4. 追踪局部变量需求不符合很

Spring事务中@Transactional注解不生效的原因分析与解决

《Spring事务中@Transactional注解不生效的原因分析与解决》在Spring框架中,@Transactional注解是管理数据库事务的核心方式,本文将深入分析事务自调用的底层原理,解释为... 目录1. 引言2. 事务自调用问题重现2.1 示例代码2.2 问题现象3. 为什么事务自调用会失效3

Java常用注解扩展对比举例详解

《Java常用注解扩展对比举例详解》:本文主要介绍Java常用注解扩展对比的相关资料,提供了丰富的代码示例,并总结了最佳实践建议,帮助开发者更好地理解和应用这些注解,需要的朋友可以参考下... 目录一、@Controller 与 @RestController 对比二、使用 @Data 与 不使用 @Dat

基于@RequestParam注解之Spring MVC参数绑定的利器

《基于@RequestParam注解之SpringMVC参数绑定的利器》:本文主要介绍基于@RequestParam注解之SpringMVC参数绑定的利器,具有很好的参考价值,希望对大家有所帮助... 目录@RequestParam注解:Spring MVC参数绑定的利器什么是@RequestParam?@

Spring 中 BeanFactoryPostProcessor 的作用和示例源码分析

《Spring中BeanFactoryPostProcessor的作用和示例源码分析》Spring的BeanFactoryPostProcessor是容器初始化的扩展接口,允许在Bean实例化前... 目录一、概览1. 核心定位2. 核心功能详解3. 关键特性二、Spring 内置的 BeanFactory

Spring Security注解方式权限控制过程

《SpringSecurity注解方式权限控制过程》:本文主要介绍SpringSecurity注解方式权限控制过程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、摘要二、实现步骤2.1 在配置类中添加权限注解的支持2.2 创建Controller类2.3 Us

Java中使用注解校验手机号格式的详细指南

《Java中使用注解校验手机号格式的详细指南》在现代的Web应用开发中,数据校验是一个非常重要的环节,本文将详细介绍如何在Java中使用注解对手机号格式进行校验,感兴趣的小伙伴可以了解下... 目录1. 引言2. 数据校验的重要性3. Java中的数据校验框架4. 使用注解校验手机号格式4.1 @NotBl

SpringBoot自定义注解如何解决公共字段填充问题

《SpringBoot自定义注解如何解决公共字段填充问题》本文介绍了在系统开发中,如何使用AOP切面编程实现公共字段自动填充的功能,从而简化代码,通过自定义注解和切面类,可以统一处理创建时间和修改时间... 目录1.1 问题分析1.2 实现思路1.3 代码开发1.3.1 步骤一1.3.2 步骤二1.3.3

Spring中@Lazy注解的使用技巧与实例解析

《Spring中@Lazy注解的使用技巧与实例解析》@Lazy注解在Spring框架中用于延迟Bean的初始化,优化应用启动性能,它不仅适用于@Bean和@Component,还可以用于注入点,通过将... 目录一、@Lazy注解的作用(一)延迟Bean的初始化(二)与@Autowired结合使用二、实例解