背景
在访问极术社区时,偶然发现GD32F3苹果派开发板的评估活动,看GD32F303的硬件配置和技术规格,120MHz、支持 DSP指令运算。Cortex-M4 内核,在同主频下的代码执行效率相比市场同类 Cortex-M4 产品提高 10%~20%,相比 Cortex-M3 产品更提高 30%。I/O 口可承受 5V 电平,全新设计的电压域支持高级电压管理功能,电流仅为 380µA/MHz,电池供电时的 RTC 待机电
流仅为 0.8µA,实现了最佳的能耗比。
很荣幸,在第一批试用名单中被选中。
想法为:
当MCU 外部晶振因特殊环境导致晶振失效情况下,实现MCU自动切换内部晶振,实现正常工作,确保产品正常运行。
实现原理
通过人为短接MCU外部晶振引脚,实现外部晶振失效,模拟产品主板中的MCU 失效,从而程序进入void NMI_Handler(void) 函数,该函数用于处理非屏蔽中断(NMI,Non-Maskable Interrupt)的处理程序。NMI是一种特殊的中断,它不能被其他中断屏蔽或关闭,在这个里面启动内部晶振,提供各外设时钟源,保证MCU尽快恢复正常运行,从而实现产品稳定性。
拉取代码
int main(void)
{
systick_config();
rcu_hxtal_clock_monitor_enable();
gd_eval_com_init(EVAL_COM0);
usart_disable(EVAL_COM0);
gd_eval_com_init(EVAL_COM0);
_delay(1000);
gd_eval_com_init(EVAL_COM0);
rcu_periph_clock_enable(RCU_GPIOF);
gpio_init(GPIOF, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_0);
gpio_init(GPIOF, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_1);
gpio_init(GPIOF, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_2);
gpio_bit_reset(GPIOF, GPIO_PIN_0);
gpio_bit_reset(GPIOF, GPIO_PIN_1);
gpio_bit_reset(GPIOF, GPIO_PIN_2);
while(1){
printf("\r\nCK_SYS V3 is %d", rcu_clock_freq_get(CK_SYS));
gpio_bit_set(GPIOF, GPIO_PIN_0);
gpio_bit_set(GPIOF, GPIO_PIN_1);
delay_1ms(20);
gpio_bit_reset(GPIOF, GPIO_PIN_0);
gpio_bit_reset(GPIOF, GPIO_PIN_1);
delay_1ms(20);
ul_main_cnt++;
}
}
/*
通过IRC 8MHZ 将系统时钟切换到72M 方案0
*/
void switch_system_clock_to_72m_irc8m(void)
{
uint32_t timeout = 0U;
uint32_t stab_flag = 0U;
/* 选择IRC8M作为系统时钟源,反初始化RCU* */
rcu_system_clock_source_config(RCU_CKSYSSRC_IRC8M);
rcu_deinit();
/* enable IRC8M */
RCU_CTL |= RCU_CTL_IRC8MEN;
/* 等待IRC8M稳定或启动时间比IRC8M START_TIMOUT长 */
do{
timeout++;
stab_flag = (RCU_CTL & RCU_CTL_IRC8MSTB);
}
while((0U == stab_flag) && (IRC8M_STARTUP_TIMEOUT != timeout));
/* if fail 如果时钟还没有稳定说明时钟异常,则在这里死循环 */
if(0U == (RCU_CTL & RCU_CTL_IRC8MSTB)){
while(1){
}
}
/* AHB = SYSCLK */
RCU_CFG0 |= RCU_AHB_CKSYS_DIV1;
/* APB2 = AHB */
RCU_CFG0 |= RCU_APB2_CKAHB_DIV1;
/* APB1 = AHB */
RCU_CFG0 |= RCU_APB1_CKAHB_DIV1;
/* PLL = (IRC8M/2) * 18 = 72 MHz */
RCU_CFG0 &= ~(RCU_CFG0_PLLSEL | RCU_CFG0_PLLMF);
RCU_CFG0 |= (RCU_PLLSRC_IRC8M_DIV2 | RCU_PLL_MUL2);
/* enable PLL */
RCU_CTL |= RCU_CTL_PLLEN;
/* wait until PLL is stable */
while(0 == (RCU_CTL & RCU_CTL_PLLSTB));
/* select PLL as system clock */
RCU_CFG0 &= ~RCU_CFG0_SCS;
RCU_CFG0 |= RCU_CKSYSSRC_PLL;
/* wait until PLL is selected as system clock */
while(0 == (RCU_CFG0 & RCU_SCSS_PLL));
}
void NMI_Handler(void)
{
switch_system_clock_to_72m_irc8m();
// switch_system_clock_to_72m_irc8m_V1();
}