声明:以下内容均是自己学习心得。
一、基础知识
XTAL外部振荡器包括:外部高速振荡器(4~25MHZ)和外部低速振荡器(32.768KHZ)。
外部高速振荡器可为系统时钟提供更为精确时钟源。
外部低速振荡器可为系统时钟、实时时钟电路(RTC)提供更为精确时钟源。
本次实验所使用寄存器有:GPIO中的通用控制寄存器(PCRxy)、中断控制器(INTC)中INT_NMIFR(不可屏蔽中断标志寄存器)和INT_NMICFR(不可屏蔽中断标志清除寄存器)、时钟控制器(CMU)中的CMU_XTALSTDSR(CMU XTAL振荡故障状态寄存器)、CMU_XTALSTDCR(CMU XTAL振荡故障控制器)和CMU_XTALSTBCR(安定配置寄存器)
二、实验代码详解
硬件连接:PH1、PH0连接外部晶振。
实验目的:通过人为制造XTALSTOP故障,展示MUC的NMI_XTALSTOP中断功能。
只需要将PH1、PH0外部晶振相连接的电容短路用导线或者镊子短路即可。
mian.c中
#define DLY_MS (500UL)
static void NMI_Xtal_Init(void)
{
stc_nmi_init_t stcNmiInit;
stc_clock_xtalstd_init_t stcXtalStdInit;
stc_clock_xtal_init_t stcXtalInit;
GPIO_AnalogCmd(BSP_XTAL_PORT, BSP_XTAL_IN_PIN | BSP_XTAL_OUT_PIN, ENABLE);
(void)CLK_XtalStructInit(&stcXtalInit);
stcXtalInit.u8State = CLK_XTAL_ON;
stcXtalInit.u8StableTime = CLK_XTAL_STB_2MS;
(void)CLK_XtalInit(&stcXtalInit);
(void)CLK_XtalStdStructInit(&stcXtalStdInit);
stcXtalStdInit.u8State = CLK_XTALSTD_ON;
stcXtalStdInit.u8Int = CLK_XTALSTD_INT_ON;
(void)CLK_XtalStdInit(&stcXtalStdInit);
/* NMI interrupt configure */
(void)NMI_StructInit(&stcNmiInit);
stcNmiInit.u32Src = NMI_SRC_XTAL;
(void)NMI_Init(&stcNmiInit);
}
代码拆分来分析:
①
stc_nmi_init_t stcNmiInit; 配置NMI不可屏蔽中断结构体
stc_clock_xtalstd_init_t stcXtalStdInit; 配置CMU_XTALSTDCR(CMU XTAL振荡故障控制器)
stc_clock_xtal_init_t stcXtalInit; 配置XTAL时钟结构体
②
GPIO_AnalogCmd(BSP_XTAL_PORT, BSP_XTAL_IN_PIN | BSP_XTAL_OUT_PIN, ENABLE)
设置模拟输入,因为外部晶振无法发送信号。
③
配置XTAL时钟相关寄存器(CMU_XTALCFGR)
(void)CLK_XtalStructInit(&stcXtalInit);
stcXtalInit.u8State = CLK_XTAL_ON;
stcXtalInit.u8StableTime = CLK_XTAL_STB_2MS;
(void)CLK_XtalInit(&stcXtalInit);
我们来看看结构体成员有哪些:
typedef struct {
uint8_t u8State; /*!< 使能XTAL时钟 */
uint8_t u8Drv; /*!< XTAL驱动能力选择:将4~25MHZ分为:超小、小、中、高驱动能力 */
uint8_t u8Mode; /*!< 设置XTAL模式:振荡器模式,外部时钟输入模式 */
uint8_t u8SuperDrv; /*!< 设置XTAL超高驱动 */
uint8_t u8StableTime; /*!< 设定XTAL稳定时间 */
} stc_clock_xtal_init_t;
这里特别声明:XTAL稳定时间是通过对CMU_XTALSTBCR安定配置寄存器b3~b0操作实现的,稳定计数器的一个计数周期 = LRC周期/8。
④
配置XTAL故障检测相关寄存器(CMU_XTALSTDCR)
(void)CLK_XtalStdStructInit(&stcXtalStdInit);
stcXtalStdInit.u8State = CLK_XTALSTD_ON;
stcXtalStdInit.u8Int = CLK_XTALSTD_INT_ON;
(void)CLK_XtalStdInit(&stcXtalStdInit);
看看结构体成员有哪些:
typedef struct {
uint8_t u8State; /*!< 使能故障检测 */
uint8_t u8Mode; /*!< XTAL故障检测模式选择 */
uint8_t u8Int; /*!< 使能XTAL故障检测中断 */
uint8_t u8Reset; /*!< 重置XTAL故障检测选择 */
} stc_clock_xtalstd_init_t;
⑤
配置NMI不可屏蔽中断相关寄存器(INT_NMICR)
(void)NMI_StructInit(&stcNmiInit);
stcNmiInit.u32Src = NMI_SRC_XTAL;
(void)NMI_Init(&stcNmiInit);
看看结构体成员:
typedef struct {
uint32_t u32Src; /*!< 设置不可屏蔽中断触发源*/
uint32_t u32Edge; /*!< 设置不可屏蔽中断触发边沿 */
uint32_t u32Filter; /*!< 设能不可屏蔽中断滤波器 */
uint32_t u32FilterClock; /*!< 选择不可屏蔽中断滤波器的时钟 */
} stc_nmi_init_t;
特别声明:为什么NMI中断触发源能选择,因为华大提供了除NMI管脚作为不可屏蔽中断源以外,可以独立选择多种系统中断事件作为不可屏蔽中断。
⑥
中断回调函数:
void NMI_Handler(void)
{
NMI_XtalStop_IrqHandler();
}
static void NMI_XtalStop_IrqHandler(void)
{
if (SET == NMI_GetNmiStatus(NMI_SRC_XTAL)) {
NMI_ClearNmiStatus(NMI_SRC_XTAL);
CLK_ClearXtalStdStatus();
BSP_LED_Toggle(LED_RED);
BSP_LED_Off(LED_BLUE);
DDL_DelayMS(DLY_MS);
}
}
首先触发NMI的中断回调函数,再里面嵌套一个XTAL故障检测中断回调函数NMI_XtalStop_IrqHandler。
NMI_GetNmiStatus(NMI_SRC_XTAL) 用来判断INT_NMIFR(不可屏蔽中断标志寄存器)的b5位(XTALSTPFR检测主发振器停止中断标志),置1说明发生了XTAL故障。
NMI_ClearNmiStatus(NMI_SRC_XTAL) 用来清零INT_NMICFR(不可屏蔽中断标志清除寄存器)中b5位(XTALSTPCFR检测主发振器停止中断标志清除)。因为该位置1则无法进行下一次XTAL故障检测。
CLK_ClearXtalStdStatus() 用来清零CMU_XTALSTDSR(振荡故障状态寄存器)。置1:检测到XTAL振荡故障。原理同上。
⑦
主函数int32_t main(void) 就没有什么难点可讲的。
int32_t main(void)
{
/* Register write enable for some required peripherals. */
LL_PERIPH_WE(LL_PERIPH_EFM | LL_PERIPH_FCG | LL_PERIPH_GPIO | LL_PERIPH_PWC_CLK_RMU | LL_PERIPH_SRAM);
/* BSP LED initialize */
BSP_LED_Init();
/* NMI initialize */
NMI_Xtal_Init();
/* Register write protected for some required peripherals. */
LL_PERIPH_WP(LL_PERIPH_EFM | LL_PERIPH_FCG | LL_PERIPH_GPIO | LL_PERIPH_SRAM);
for (;;) {
BSP_LED_Off(LED_RED);
BSP_LED_Toggle(LED_BLUE);
DDL_DelayMS(DLY_MS);
}
}
实验现象就是:发生故障:蓝灯停止闪烁,红灯闪烁。
本次实验内容到此结束,有什么疑问可以私信我~