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

相关文章

在 Spring Boot 中使用 @Autowired和 @Bean注解的示例详解

《在SpringBoot中使用@Autowired和@Bean注解的示例详解》本文通过一个示例演示了如何在SpringBoot中使用@Autowired和@Bean注解进行依赖注入和Bean... 目录在 Spring Boot 中使用 @Autowired 和 @Bean 注解示例背景1. 定义 Stud

Spring排序机制之接口与注解的使用方法

《Spring排序机制之接口与注解的使用方法》本文介绍了Spring中多种排序机制,包括Ordered接口、PriorityOrdered接口、@Order注解和@Priority注解,提供了详细示例... 目录一、Spring 排序的需求场景二、Spring 中的排序机制1、Ordered 接口2、Pri

Idea实现接口的方法上无法添加@Override注解的解决方案

《Idea实现接口的方法上无法添加@Override注解的解决方案》文章介绍了在IDEA中实现接口方法时无法添加@Override注解的问题及其解决方法,主要步骤包括更改项目结构中的Languagel... 目录Idea实现接China编程口的方法上无法添加@javascriptOverride注解错误原因解决方

Java中基于注解的代码生成工具MapStruct映射使用详解

《Java中基于注解的代码生成工具MapStruct映射使用详解》MapStruct作为一个基于注解的代码生成工具,为我们提供了一种更加优雅、高效的解决方案,本文主要为大家介绍了它的具体使用,感兴趣... 目录介绍优缺点优点缺点核心注解及详细使用语法说明@Mapper@Mapping@Mappings@Co

Java中注解与元数据示例详解

《Java中注解与元数据示例详解》Java注解和元数据是编程中重要的概念,用于描述程序元素的属性和用途,:本文主要介绍Java中注解与元数据的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参... 目录一、引言二、元数据的概念2.1 定义2.2 作用三、Java 注解的基础3.1 注解的定义3.2 内

Go中sync.Once源码的深度讲解

《Go中sync.Once源码的深度讲解》sync.Once是Go语言标准库中的一个同步原语,用于确保某个操作只执行一次,本文将从源码出发为大家详细介绍一下sync.Once的具体使用,x希望对大家有... 目录概念简单示例源码解读总结概念sync.Once是Go语言标准库中的一个同步原语,用于确保某个操

Java汇编源码如何查看环境搭建

《Java汇编源码如何查看环境搭建》:本文主要介绍如何在IntelliJIDEA开发环境中搭建字节码和汇编环境,以便更好地进行代码调优和JVM学习,首先,介绍了如何配置IntelliJIDEA以方... 目录一、简介二、在IDEA开发环境中搭建汇编环境2.1 在IDEA中搭建字节码查看环境2.1.1 搭建步

SpringBoot使用注解集成Redis缓存的示例代码

《SpringBoot使用注解集成Redis缓存的示例代码》:本文主要介绍在SpringBoot中使用注解集成Redis缓存的步骤,包括添加依赖、创建相关配置类、需要缓存数据的类(Tes... 目录一、创建 Caching 配置类二、创建需要缓存数据的类三、测试方法Spring Boot 熟悉后,集成一个外

使用@Slf4j注解,log.info()无法使用问题

《使用@Slf4j注解,log.info()无法使用问题》在使用Lombok的@Slf4j注解打印日志时遇到问题,通过降低Lombok版本(从1.18.x降至1.16.10)解决了问题... 目录@Slf4androidj注解,log.info()无法使用问题最后解决总结@Slf4j注解,log.info(

JAVA智听未来一站式有声阅读平台听书系统小程序源码

智听未来,一站式有声阅读平台听书系统 🌟&nbsp;开篇:遇见未来,从“智听”开始 在这个快节奏的时代,你是否渴望在忙碌的间隙,找到一片属于自己的宁静角落?是否梦想着能随时随地,沉浸在知识的海洋,或是故事的奇幻世界里?今天,就让我带你一起探索“智听未来”——这一站式有声阅读平台听书系统,它正悄悄改变着我们的阅读方式,让未来触手可及! 📚&nbsp;第一站:海量资源,应有尽有 走进“智听