一、问题描述
如下图所示,MSPM0G3507时钟树配置为使用外部HFXT(外部高速晶振)作为HSCLK时钟源。
配置结果MCLK = 40MHz。
另外配置PB22为输出模式,控制外部LED亮灭。
在main.c中主要代码如下:
主要完成延时并翻转LED控制引脚输出电平。
while (1) {delay_ms((1000));// delay_cycles(DELAY);DL_GPIO_togglePins(GPIO_LEDS_PORT, GPIO_LEDS_USER_LED_1_PIN);}
现象:
下载程序后,某些时候,LED能够实现翻转(表明晶振起振,时钟电路正常,程序运行正常)。
但是,如果把电路板电源断电后,重新上电,大多数时候,可能LED没反应!!!(即晶振不起振?单片机内部时钟不正常,导致程序没有正常运行起来)
二、解决办法
在官方技术指导手册中CKM(时钟模块)中有关于Startup Monitors的描述。
为应用软件提供的时钟启动监视器可用于确认 LFOSC、 LFXT/LFCLK_IN、 HFXT/HFCLK_IN、 SYSPLL 和HSCLK 源在由软件选择用于在系统中提供时钟之前处于活动状态。当一个时钟源已经成功启动并且准备就绪时,在 SYSCTL 的 CLKSTATUS 寄存器中会给出 GOOD 指示, 并产生中断。启动监视器仅在进行了时钟系统配置的相关更改时提供状态指示。当给出初始 GOOD 指示时, 启动监视器不会持续监控时钟。对于 LFCLK 和 MCLK,则会进行持续监控。
即 LFOSC、 LFXT、HFXT、HFCLK_IN、SYSPLL 、HSCLK 在各自启动之前,硬件提供启动监视,在它们稳定之后,在 SYSCTL 的 CLKSTATUS 寄存器中会给出 GOOD 指示, 并可产生中断。
所以,为了能够让时钟回路能够稳定运行,在启动阶段,通过时钟树配置并打开各自Startup Monitor功能后,可以监视时钟是否稳定工作。
2.1 使用外部高速晶振,不使用syspll例程
配置如下:
在SYSCTRL配置项中有个选项“Enable Check for Clock Stabilization”,通过这个选项,可以增加判断时钟是否准备好的初始化代码。
时钟初始化代码:
static const DL_SYSCTL_LFCLKConfig gLFCLKConfig = {.lowCap = false,.monitor = false,.xt1Drive = DL_SYSCTL_LFXT_DRIVE_STRENGTH_HIGHEST,
};
SYSCONFIG_WEAK void SYSCFG_DL_SYSCTL_init(void)
{//Low Power Mode is configured to be SLEEP0DL_SYSCTL_setBORThreshold(DL_SYSCTL_BOR_THRESHOLD_LEVEL_0);DL_SYSCTL_setFlashWaitState(DL_SYSCTL_FLASH_WAIT_STATE_2);DL_SYSCTL_setSYSOSCFreq(DL_SYSCTL_SYSOSC_FREQ_BASE);/* Set default configuration */DL_SYSCTL_disableHFXT();DL_SYSCTL_disableSYSPLL();DL_SYSCTL_setHFCLKSourceHFXTParams(DL_SYSCTL_HFXT_RANGE_32_48_MHZ,100, true);DL_SYSCTL_setULPCLKDivider(DL_SYSCTL_ULPCLK_DIV_2);DL_SYSCTL_setLFCLKSourceLFXT((DL_SYSCTL_LFCLKConfig *) &gLFCLKConfig);DL_SYSCTL_setMCLKSource(SYSOSC, HSCLK, DL_SYSCTL_HSCLK_SOURCE_HFCLK);}
SYSCONFIG_WEAK void SYSCFG_DL_SYSCTL_CLK_init(void) {while ((DL_SYSCTL_getClockStatus() & (DL_SYSCTL_CLK_STATUS_HFCLK_GOOD| DL_SYSCTL_CLK_STATUS_HSCLK_GOOD| DL_SYSCTL_CLK_STATUS_LFXT_GOOD))!= (DL_SYSCTL_CLK_STATUS_HFCLK_GOOD| DL_SYSCTL_CLK_STATUS_HSCLK_GOOD| DL_SYSCTL_CLK_STATUS_LFXT_GOOD)){/* Ensure that clocks are in default POR configuration before initialization.* Additionally once LFXT is enabled, the internal LFOSC is disabled, and cannot* be re-enabled other than by executing a BOOTRST. */;}
}
硬件初始化代码调用顺序
SYSCONFIG_WEAK void SYSCFG_DL_init(void)
{SYSCFG_DL_initPower();SYSCFG_DL_GPIO_init();/* Module-Specific Initializations*/SYSCFG_DL_SYSCTL_init();/* 等待时钟稳定 */SYSCFG_DL_SYSCTL_CLK_init();
}
2.2 使用外部高速晶振,使用SYSPLL例程
初始化代码:
static const DL_SYSCTL_SYSPLLConfig gSYSPLLConfig = {.inputFreq = DL_SYSCTL_SYSPLL_INPUT_FREQ_32_48_MHZ,.rDivClk2x = 1,.rDivClk1 = 0,.rDivClk0 = 0,.enableCLK2x = DL_SYSCTL_SYSPLL_CLK2X_DISABLE,.enableCLK1 = DL_SYSCTL_SYSPLL_CLK1_DISABLE,.enableCLK0 = DL_SYSCTL_SYSPLL_CLK0_ENABLE,.sysPLLMCLK = DL_SYSCTL_SYSPLL_MCLK_CLK0,.sysPLLRef = DL_SYSCTL_SYSPLL_REF_HFCLK,.qDiv = 3,.pDiv = DL_SYSCTL_SYSPLL_PDIV_1
};
static const DL_SYSCTL_LFCLKConfig gLFCLKConfig = {.lowCap = false,.monitor = false,.xt1Drive = DL_SYSCTL_LFXT_DRIVE_STRENGTH_HIGHEST,
};
SYSCONFIG_WEAK void SYSCFG_DL_SYSCTL_init(void)
{//Low Power Mode is configured to be SLEEP0DL_SYSCTL_setBORThreshold(DL_SYSCTL_BOR_THRESHOLD_LEVEL_0);DL_SYSCTL_setFlashWaitState(DL_SYSCTL_FLASH_WAIT_STATE_2);DL_SYSCTL_setSYSOSCFreq(DL_SYSCTL_SYSOSC_FREQ_BASE);/* Set default configuration */DL_SYSCTL_disableHFXT();DL_SYSCTL_disableSYSPLL();DL_SYSCTL_setHFCLKSourceHFXTParams(DL_SYSCTL_HFXT_RANGE_32_48_MHZ,100, true);DL_SYSCTL_configSYSPLL((DL_SYSCTL_SYSPLLConfig *) &gSYSPLLConfig);DL_SYSCTL_setULPCLKDivider(DL_SYSCTL_ULPCLK_DIV_2);DL_SYSCTL_setLFCLKSourceLFXT((DL_SYSCTL_LFCLKConfig *) &gLFCLKConfig);DL_SYSCTL_setMCLKSource(SYSOSC, HSCLK, DL_SYSCTL_HSCLK_SOURCE_SYSPLL);}
SYSCONFIG_WEAK void SYSCFG_DL_SYSCTL_CLK_init(void) {while ((DL_SYSCTL_getClockStatus() & (DL_SYSCTL_CLK_STATUS_SYSPLL_GOOD| DL_SYSCTL_CLK_STATUS_HFCLK_GOOD| DL_SYSCTL_CLK_STATUS_HSCLK_GOOD| DL_SYSCTL_CLK_STATUS_LFXT_GOOD))!= (DL_SYSCTL_CLK_STATUS_SYSPLL_GOOD| DL_SYSCTL_CLK_STATUS_HFCLK_GOOD| DL_SYSCTL_CLK_STATUS_HSCLK_GOOD| DL_SYSCTL_CLK_STATUS_LFXT_GOOD)){/* Ensure that clocks are in default POR configuration before initialization.* Additionally once LFXT is enabled, the internal LFOSC is disabled, and cannot* be re-enabled other than by executing a BOOTRST. */;}
}
2.3 总结
以上两种方式皆使用外部高速晶振作为内部主时钟源,区别是一种使用内部锁相环改变了最终频率,另外一个没有使用内部锁相环,最终都实现了高速时钟稳定工作。
:经过测试,其实Startup Monitors基本不影响系统建立稳定时钟的过程,主要还是SYSCTRL配置项中“Enable Check for Clock Stabilization”的复选框要打钩。这个才是重点!!!
大多数人可能比较熟悉STM32CUBEMX的使用,不过在STM32的时钟初始化函数配置选项中没有这些更多(更偏底层、更加详细)的选项,而在其库函数中,自动做了判断的处理。
但事实是,等待时钟稳定的等待过程本身是非常有必要的!!默认值应该是打钩的才对,O(∩_∩)O哈哈~