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

相关文章

SpringBoot基于注解实现数据库字段回填的完整方案

《SpringBoot基于注解实现数据库字段回填的完整方案》这篇文章主要为大家详细介绍了SpringBoot如何基于注解实现数据库字段回填的相关方法,文中的示例代码讲解详细,感兴趣的小伙伴可以了解... 目录数据库表pom.XMLRelationFieldRelationFieldMapping基础的一些代

Spring的基础事务注解@Transactional作用解读

《Spring的基础事务注解@Transactional作用解读》文章介绍了Spring框架中的事务管理,核心注解@Transactional用于声明事务,支持传播机制、隔离级别等配置,结合@Tran... 目录一、事务管理基础1.1 Spring事务的核心注解1.2 注解属性详解1.3 实现原理二、事务事

Java JDK Validation 注解解析与使用方法验证

《JavaJDKValidation注解解析与使用方法验证》JakartaValidation提供了一种声明式、标准化的方式来验证Java对象,与框架无关,可以方便地集成到各种Java应用中,... 目录核心概念1. 主要注解基本约束注解其他常用注解2. 核心接口使用方法1. 基本使用添加依赖 (Maven

java 恺撒加密/解密实现原理(附带源码)

《java恺撒加密/解密实现原理(附带源码)》本文介绍Java实现恺撒加密与解密,通过固定位移量对字母进行循环替换,保留大小写及非字母字符,由于其实现简单、易于理解,恺撒加密常被用作学习加密算法的入... 目录Java 恺撒加密/解密实现1. 项目背景与介绍2. 相关知识2.1 恺撒加密算法原理2.2 Ja

Nginx屏蔽服务器名称与版本信息方式(源码级修改)

《Nginx屏蔽服务器名称与版本信息方式(源码级修改)》本文详解如何通过源码修改Nginx1.25.4,移除Server响应头中的服务类型和版本信息,以增强安全性,需重新配置、编译、安装,升级时需重复... 目录一、背景与目的二、适用版本三、操作步骤修改源码文件四、后续操作提示五、注意事项六、总结一、背景与

Android实现图片浏览功能的示例详解(附带源码)

《Android实现图片浏览功能的示例详解(附带源码)》在许多应用中,都需要展示图片并支持用户进行浏览,本文主要为大家介绍了如何通过Android实现图片浏览功能,感兴趣的小伙伴可以跟随小编一起学习一... 目录一、项目背景详细介绍二、项目需求详细介绍三、相关技术详细介绍四、实现思路详细介绍五、完整实现代码

SpringBoot AspectJ切面配合自定义注解实现权限校验的示例详解

《SpringBootAspectJ切面配合自定义注解实现权限校验的示例详解》本文章介绍了如何通过创建自定义的权限校验注解,配合AspectJ切面拦截注解实现权限校验,本文结合实例代码给大家介绍的非... 目录1. 创建权限校验注解2. 创建ASPectJ切面拦截注解校验权限3. 用法示例A. 参考文章本文

SpringBoot 获取请求参数的常用注解及用法

《SpringBoot获取请求参数的常用注解及用法》SpringBoot通过@RequestParam、@PathVariable等注解支持从HTTP请求中获取参数,涵盖查询、路径、请求体、头、C... 目录SpringBoot 提供了多种注解来方便地从 HTTP 请求中获取参数以下是主要的注解及其用法:1

深度解析Java @Serial 注解及常见错误案例

《深度解析Java@Serial注解及常见错误案例》Java14引入@Serial注解,用于编译时校验序列化成员,替代传统方式解决运行时错误,适用于Serializable类的方法/字段,需注意签... 目录Java @Serial 注解深度解析1. 注解本质2. 核心作用(1) 主要用途(2) 适用位置3

Java利用@SneakyThrows注解提升异常处理效率详解

《Java利用@SneakyThrows注解提升异常处理效率详解》这篇文章将深度剖析@SneakyThrows的原理,用法,适用场景以及隐藏的陷阱,看看它如何让Java异常处理效率飙升50%,感兴趣的... 目录前言一、检查型异常的“诅咒”:为什么Java开发者讨厌它1.1 检查型异常的痛点1.2 为什么说