文章目录
- 四、内核功能接口
- 4.1 NVIC功能接口
- 4.1.1 配置优先级分组
- 4.1.2 获取优先级分组
- 4.1.3 关闭使能相应的中断(IRQ,非系统错误)
- 4.1.4 获取中断挂起(IRQ,非系统错误)
- 4.1.5 设置外部中断挂起(IRQ,非系统错误)
- 4.1.6 清除外部中断挂起(IRQ,非系统错误)
- 4.1.7 获取外部中断的活动位(IRQ,非系统错误)
- 4.1.8 设置中断优先级(系统异常+外部中断)
- 4.1.9 获取中断优先级(系统异常+外部中断)
- 4.1.10 对中断优先级编码
- 4.1.11 对中断优先级解码
- 4.1.12 使能相应的中断(IRQ,非系统错误)
- 4.2 SysTick功能接口
- 4.2.1 初始化并启动SysTick计数器和它的中断
- 4.3 Reset功能接口
- 4.3.1 发起系统复位请求
- 4.4 调试输入输出功能接口
- 4.4.1 输出字符在ITM通道0
- 4.4.2 用ITM_RxBuffer接收字符
- 4.4.3 通过变量 ITM_RxBuffer 检查字符是否可用
四、内核功能接口
内核功能接口主要包括:
- NVIC接口;
- SysTick接口;
- Reset接口。
4.1 NVIC功能接口
4.1.1 配置优先级分组
/*** @brief Set the Priority Grouping in NVIC Interrupt Controller** @param PriorityGroup is priority grouping field** Set the priority grouping field using the required unlock sequence.* The parameter priority_grouping is assigned to the field * SCB->AIRCR [10:8] PRIGROUP field. Only values from 0..7 are used.* In case of a conflict between priority grouping and available* priority bits (__NVIC_PRIO_BITS) the smallest possible priority group is set.*/
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;
}
注意点:
- 配置优先级分组,需要配置SCB_AIRCR寄存器。
- SCB_AIRCR寄存器提供了处理模式需要的优先级分组、数据访问的端状态和系统的复位控制。
- SCB_AIRCR寄存器需要特权等级访问。
- 写SCB_AIRCR寄存器前需要写
0x5FA
给VECTKEY,否则处理器写无效。 - 注意优先级有效位
__NVIC_PRIO_BITS
。
接口功能解析:
- 保留输入有效值;
- 用定义的掩码清零
VECTKEY
和PRIGROUP
区域; - 打开写保护的同时配置优先级分组。
4.1.2 获取优先级分组
/*** @brief Get the Priority Grouping from NVIC Interrupt Controller** @return priority grouping field ** Get the priority grouping from NVIC Interrupt Controller.* priority grouping is SCB->AIRCR [10:8] PRIGROUP field.*/
static __INLINE uint32_t NVIC_GetPriorityGrouping(void)
{return ((SCB->AIRCR & SCB_AIRCR_PRIGROUP_Msk) >> SCB_AIRCR_PRIGROUP_Pos); /* read priority grouping field */
}
接口功能解析:
- 移位返回。
4.1.3 关闭使能相应的中断(IRQ,非系统错误)
/*** @brief Get the Priority Grouping from NVIC Interrupt Controller** @return priority grouping field ** Get the priority grouping from NVIC Interrupt Controller.* priority grouping is SCB->AIRCR [10:8] PRIGROUP field.*/
static __INLINE uint32_t NVIC_GetPriorityGrouping(void)
{return ((SCB->AIRCR & SCB_AIRCR_PRIGROUP_Msk) >> SCB_AIRCR_PRIGROUP_Pos); /* read priority grouping field */
}
注意:
- IRQn >= 16。
- NVIC_ICERx不包括0~15系统错误。
4.1.4 获取中断挂起(IRQ,非系统错误)
/*** @brief Read the interrupt pending bit for a device specific interrupt source* * @param IRQn The number of the device specifc interrupt* @return 1 = interrupt pending, 0 = interrupt not pending** Read the pending register in NVIC and return 1 if its status is pending, * otherwise it returns 0*/
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 */
}
接口功能解析:
- 使用三目运算符判断挂起寄存器。
4.1.5 设置外部中断挂起(IRQ,非系统错误)
/*** @brief Set the pending bit for an external interrupt* * @param IRQn The number of the interrupt for set pending** Set the pending bit for the specified interrupt.* The interrupt number cannot be a negative value.*/
static __INLINE void NVIC_SetPendingIRQ(IRQn_Type IRQn)
{NVIC->ISPR[((uint32_t)(IRQn) >> 5)] = (1 << ((uint32_t)(IRQn) & 0x1F)); /* set interrupt pending */
}
4.1.6 清除外部中断挂起(IRQ,非系统错误)
/*** @brief Clear the pending bit for an external interrupt** @param IRQn The number of the interrupt for clear pending** Clear the pending bit for the specified interrupt. * The interrupt number cannot be a negative value.*/
static __INLINE void NVIC_ClearPendingIRQ(IRQn_Type IRQn)
{NVIC->ICPR[((uint32_t)(IRQn) >> 5)] = (1 << ((uint32_t)(IRQn) & 0x1F)); /* Clear pending interrupt */
}
4.1.7 获取外部中断的活动位(IRQ,非系统错误)
/*** @brief Read the active bit for an external interrupt** @param IRQn The number of the interrupt for read active bit* @return 1 = interrupt active, 0 = interrupt not active** Read the active register in NVIC and returns 1 if its status is active, * otherwise it returns 0.*/
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 */
}
4.1.8 设置中断优先级(系统异常+外部中断)
/*** @brief Set the priority for an interrupt** @param IRQn The number of the interrupt for set priority* @param priority The priority to set** Set the priority for the specified interrupt. The interrupt * number can be positive to specify an external (device specific) * interrupt, or negative to specify an internal (core) interrupt.** Note: The priority cannot be set for every core interrupt.*/
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 */
}
注意:
- 用正负判断系统异常和外部中断。
4.1.9 获取中断优先级(系统异常+外部中断)
/*** @brief Read the priority for an interrupt** @param IRQn The number of the interrupt for get priority* @return The priority for the interrupt** Read the priority for the specified interrupt. The interrupt * number can be positive to specify an external (device specific) * interrupt, or negative to specify an internal (core) interrupt.** The returned priority value is automatically aligned to the implemented* priority bits of the microcontroller.** Note: The priority cannot be set for every core interrupt.*/
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 */
}
4.1.10 对中断优先级编码
/*** @brief Encode the priority for an interrupt** @param PriorityGroup The used priority group* @param PreemptPriority The preemptive priority value (starting from 0)* @param SubPriority The sub priority value (starting from 0)* @return The encoded priority for the interrupt** Encode the priority for an interrupt with the given priority group,* preemptive priority value and sub priority value.* In case of a conflict between priority grouping and available* priority bits (__NVIC_PRIO_BITS) the samllest possible priority group is set.** The returned priority value can be used for NVIC_SetPriority(...) function*/
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))));
}
4.1.11 对中断优先级解码
/*** @brief Decode the priority of an interrupt** @param Priority The priority for the interrupt* @param PriorityGroup The used priority group* @param pPreemptPriority The preemptive priority value (starting from 0)* @param pSubPriority The sub priority value (starting from 0)** Decode an interrupt priority value with the given priority group to * preemptive priority value and sub priority value.* In case of a conflict between priority grouping and available* priority bits (__NVIC_PRIO_BITS) the samllest possible priority group is set.** The priority value can be retrieved with NVIC_GetPriority(...) function*/
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);
}
4.1.12 使能相应的中断(IRQ,非系统错误)
/*** @brief Enable Interrupt in NVIC Interrupt Controller** @param IRQn The positive number of the external interrupt to enable** Enable a device specific interupt in the NVIC interrupt controller.* The interrupt number cannot be a negative value.*/
static __INLINE void NVIC_EnableIRQ(IRQn_Type IRQn)
{NVIC->ISER[((uint32_t)(IRQn) >> 5)] = (1 << ((uint32_t)(IRQn) & 0x1F)); /* enable interrupt */
}
4.2 SysTick功能接口
4.2.1 初始化并启动SysTick计数器和它的中断
/*** @brief Initialize and start the SysTick counter and its interrupt.** @param ticks number of ticks between two interrupts* @return 1 = failed, 0 = successful** Initialise the system tick timer and its interrupt and start the* system tick timer / counter in free running mode to generate * periodical interrupts.*/
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 */
}
接口功能解析:
- 参数检查;
- 配置重载寄存器;
- 配置SysTick中断优先级;
- 计数器现值清零;
- 配置时钟源为处理器时钟AHB;
- 使能时钟中断;
- 启动时钟;
4.3 Reset功能接口
4.3.1 发起系统复位请求
/*** @brief Initiate a system reset request.** Initiate a system reset request to reset the MCU*/
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.4 调试输入输出功能接口
内核调试接口包括:
- 内核调试输入/输出功能;
- 内核调试定义;
- 内核调试变量。
extern volatile int ITM_RxBuffer; /*!< variable to receive characters */
#define ITM_RXBUFFER_EMPTY 0x5AA55AA5 /*!< value identifying ITM_RxBuffer is ready for next character */
4.4.1 输出字符在ITM通道0
/*** @brief Outputs a character via the ITM channel 0** @param ch character to output* @return character to output** The function outputs a character via the ITM channel 0. * The function returns when no debugger is connected that has booked the output. * It is blocking when a debugger is connected, but the previous character send is not transmitted. */
static __INLINE uint32_t ITM_SendChar (uint32_t ch)
{if ((CoreDebug->DEMCR & CoreDebug_DEMCR_TRCENA_Msk) && /* Trace enabled */(ITM->TCR & ITM_TCR_ITMENA_Msk) && /* ITM enabled */(ITM->TER & (1ul << 0) ) ) /* ITM Port #0 enabled */{while (ITM->PORT[0].u32 == 0);ITM->PORT[0].u8 = (uint8_t) ch;} return (ch);
}
4.4.2 用ITM_RxBuffer接收字符
/*** @brief Inputs a character via variable ITM_RxBuffer** @return received character, -1 = no character received** The function inputs a character via variable ITM_RxBuffer. * The function returns when no debugger is connected that has booked the output. * It is blocking when a debugger is connected, but the previous character send is not transmitted. */
static __INLINE int ITM_ReceiveChar (void) {int ch = -1; /* no character available */if (ITM_RxBuffer != ITM_RXBUFFER_EMPTY) {ch = ITM_RxBuffer;ITM_RxBuffer = ITM_RXBUFFER_EMPTY; /* ready for next character */}return (ch);
}
4.4.3 通过变量 ITM_RxBuffer 检查字符是否可用
/*** @brief Check if a character via variable ITM_RxBuffer is available** @return 1 = character available, 0 = no character available** The function checks variable ITM_RxBuffer whether a character is available or not. * The function returns '1' if a character is available and '0' if no character is available. */
static __INLINE int ITM_CheckChar (void) {if (ITM_RxBuffer == ITM_RXBUFFER_EMPTY) {return (0); /* no character available */} else {return (1); /* character available */}
}