本帖最后由 电子烂人 于 2024-5-5 16:58 编辑
最近在做RTC和LCD的时候发现U0的MSI时钟很有意思,值得单拎出来写一篇补充文章:
1.MSI的介绍:
MSI(Multispeed internal RC oscillator,全称多速内部RC振荡器),是由一个RC电路组成,RC电路由一个电阻(R)和一个电容(C)组成,能够在微控制器内部产生稳定的时钟信号。"Multispeed"这个术语意味着这种振荡器能够提供多种不同的时钟频率,这样设计是为了允许微控制器在不同的工作模式下运行,以优化功耗和性能。这样设计的初衷是为了在低成本的情况下灵活开发时钟频率,在低功耗模式和高速模式下分别用不同的频率工作。
在U0手册的系统图里可以看到更为完整的组成:(图片不完整,省略了下半部分)
最新的MSI应用手册是U5系列的,可供参考:How to calibrate internal RC oscillators on STM32U5 Series - Application note
2.配置MSI:
在STM32U0的时钟配置界面,可以看到MSI是完全可以作为系统时钟多路复用器来配置主频(U083单片机最大48MHZ)。
另外也可以经过PLL锁相环以提升频率:
以前一种情况为例,生成示例工程。
3.低功耗模式
STM32U0有Sleep,Low-power run mode,Low-power sleep mode,stop,standy,shutdown六种模式,足以应对实际开发中的各种使用情况。
其中提及到MSI的仅有stop和shutdown两种模式,且这两种模式下MSI皆为关闭状态
停止模式更加多样化,有三种子模式,对应不同情况下的选择:
本项目实际的开发中,特别是靠电池运行的情况下,STOP停止模式更加常见,相比standy和shutdown两种模式下,在省电的情况下还能保留关键数据,且RTC持续工作,故以停止模式为例演示;
STOP模式有两种唤醒方式中断(Interruption)和事件(Event),对应参数在STM32u0xx_hal_pwr.h中:
/** @defgroup PWR_STOP_mode_entry PWR STOP mode entry
* @{
*/
#define PWR_STOPENTRY_WFI ((uint8_t)0x01)/*!< Wait For Interruption instruction to enter Stop mode */
#define PWR_STOPENTRY_WFE ((uint8_t)0x02)/*!< Wait For Event instruction to enter Stop mode */
/**
* @}
*/
三种停止模式的API分别为:
void HAL_PWREx_EnterSTOP0Mode(uint8_t STOPEntry)//STOP0
void HAL_PWREx_EnterSTOP1Mode(uint8_t STOPEntry)//STOP1
void HAL_PWREx_EnterSTOP2Mode(uint8_t STOPEntry)//STOP2
//注:STOP0模式没有找到该函数,暂不清楚原因,可能是调用与另外两种不同
其中以STOP1模式举例,代码定义如下:(来自文件stm32u0xx hal_pwr_ex.c)
void HAL_PWREx_EnterSTOP1Mode(uint8_t STOPEntry)
{
/* Check the parameters */
assert_param(IS_PWR_STOP_ENTRY(STOPEntry));
/* Stop 1 mode with Low-Power Regulator */
MODIFY_REG(PWR->CR1, PWR_CR1_LPMS, PWR_CR1_LPMS_0);
/* Set SLEEPDEEP bit of Cortex System Control Register */
SET_BIT(SCB->SCR, ((uint32_t)SCB_SCR_SLEEPDEEP_Msk));
/* Select Stop mode entry --------------------------------------------------*/
if (STOPEntry == PWR_STOPENTRY_WFI)
{
/* Request Wait For Interrupt */
__WFI();
}
else
{
/* Request Wait For Event */
__SEV();
__WFE();
__WFE();
}
/* Reset SLEEPDEEP bit of Cortex System Control Register */
CLEAR_BIT(SCB->SCR, ((uint32_t)SCB_SCR_SLEEPDEEP_Msk));
}
4.编写代码并观察现象
在主函数中添加代码:
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
for(i=0;;i++)
{
count=count+1;//设置一个计数器
HAL_Delay(1000);
BSP_LED_Toggle(LED_GREEN);
if(count==9)//计数器9秒后进入STOP模式
{
HAL_PWREx_EnterSTOP1Mode(PWR_STOPENTRY_WFI);
HAL_Delay(10000);//停止10秒
SystemClock_Config();//重新配置时钟
break;//退出STOP模式,继续计数
}
}
实验现象为:绿灯闪烁9秒后,进入停止模式,停止10秒再退出停止模式,整个过程使用MSI作为时钟源。
meeting_01