芯片异常复位问题(看门狗异常复位)
2026/7/18 20:48:38
网站开发
问题描述从 Bootloader 跳转到 APP 后执行GPIO_config()开启蓝牙导致芯片 3.3V 电压被微微拉低进而引发类似看门狗复位而注释掉串口打印usart_send_string后程序却能正常运行问题代码如下int main( void ) { nvic_vector_table_set(NVIC_VECTTAB_FLASH, 0x4000); //重映射向量表 /* 驱动初始化 */ BSP_Init(); // 注册 cJSON 内存接口到 FreeRTOS 线程安全堆 cJSON_Hooks hooks; hooks.malloc_fn pvPortMalloc; hooks.free_fn vPortFree; cJSON_InitHooks(hooks); fwdgt_counter_reload();//喂狗 W25Q128_Init(); RTC_BKP6 BKP_APP; //处于APP程序 RTC_BKP7 BKP_APP; //TBOX升级模式进入非升级模式---默认走CAN升级 usart_send_string(UART_PRINTF,Enter the APP1111111~\n); GPIO_config(); //提前配置蓝牙引脚会将芯片3.3V拉掉导致----现象像看门狗复位 #ifdef CAN0_EN /* initialize transmit message */ can_struct_para_init( CAN_TX_MESSAGE_STRUCT, g_transmit_message ); //存储发送帧结构体初始化 g_transmit_message.tx_sfid 0x00; //标准格式帧标识符 g_transmit_message.tx_efid 0x18FEEEBB; //扩展格式帧标识符 g_transmit_message.tx_ft CAN_FT_DATA; //帧类型数据帧/远程帧 g_transmit_message.tx_ff CAN_FF_EXTENDED; //帧格式标准帧/扩展帧 g_transmit_message.tx_dlen 8; //数据长度 /* initialize receive message */ can_struct_para_init( CAN_RX_MESSAGE_STRUCT, g_receive_message ); //接收帧结构体初始化 #endif xTaskCreate( ( TaskFunction_t )start_task, ( const char * )start_task, (uint16_t )128, (void* )NULL, (UBaseType_t )1, ( TaskHandle_t * )StartTask_Handler ); vTaskStartScheduler();//在 vTaskStartScheduler() 调用之前不能调用 xQueueSendFromISR()。 while( 1 ) { } }一、 原因分析1. 电源瞬态冲击与负载叠加Root Cause蓝牙启动的瞬间浪涌电流Inrush Current蓝牙模块在被拉高使能引脚PC10开启的一瞬间其内部射频电路启动以及外围旁路电容充电会产生一个较大的瞬态浪涌电流。串口发送的动态功耗当执行usart_send_string时USART0 发送引脚TX高频翻转且串口驱动电路、MCU 内部串口外设都在工作这会消耗一定的动态电流并在 3.3V 电源轨上引入高频噪声。负载叠加导致电压跌落Voltage Dip如果板载 3.3V LDO 或 DCDC 电源芯片的瞬态响应较差或者 MCU 附近的去耦电容容量不足那么在串口正处于发送/刚发送完的瞬态活跃期时紧接着拉高 PC10 开启蓝牙两者叠加的电流负载超出了电源系统的承载极限导致 3.3V 电压瞬时跌落。2. 为什么现象像“看门狗复位”3.3V 电压跌落可能并没有低到触发芯片硬件的欠压复位LVR/BOR阈值。但电压波动会导致 MCU 的高速时钟PLL 锁相环失锁或者导致Flash 在高频读取指令时出现校验/数据错误Flash Read Corruption。这会使 MCU 直接触发HardFault_Handler硬件陷入死循环或 CPU 挂起。因为 CPU 挂起无法继续喂狗最终导致看门狗FWDGT超时溢出引发复位。复位后程序重新运行再次走到该位置再次跌落形成“反复复位”的死循环。3. 为什么注释掉usart_send_string程序就正常了注释掉串口打印后在GPIO_config()执行时串口处于空闲状态TX 引脚保持高电平无动态开关损耗MCU 的整体功耗降到最低3.3V 电源轨处于非常稳定的状态。此时单凭蓝牙模块上电的瞬态冲击不足以将 3.3V 电压拉低到让 PLL 失锁或 Flash 出错的临界值因此系统能够顺利扛过这一波浪涌程序得以正常运行。二、 优化建议1. 软件优化策略错峰上电Power Sequencing避免在系统刚启动、外设初次初始化的敏感阶段开启大功耗外设。应将蓝牙模块的使能延时放在 FreeRTOS 调度器启动并稳定运行后例如延时 500ms再开启。无抖动 GPIO 配置在配置 GPIO 为输出模式前先向输出寄存器OCTL写入默认的电平值低电平关闭蓝牙避免在模式切换瞬间产生不需要的电平窄脉冲Glitch。复位源排查可以在main()入口处读取RCU_RSTFR寄存器判断究竟是看门狗复位FWDGTRST还是低电压/外部复位以便更精准地定位硬件表现。2. 硬件优化建议供参考在蓝牙模块的 VCC 输入端增加大容量低 ESR 的电容如 10μF ~ 47μF 贴片钽电容或多层陶瓷电容 MLCC用于吸收上电瞬间的浪涌电流。如果蓝牙模块使能引脚控制的是电源 MOSFET可在 MOSFET 的栅极Gate增加 RC 延迟电路以实现“软启动Soft-Start”减缓上电瞬间的电流变化率dI/dt。三、 预览代码不修改工程文件1. 修改 main.c 中的GPIO_config在初始化阶段将蓝牙引脚 PC10 配置为输出低电平默认关闭并且通过先写寄存器值的方式防止引脚配置瞬间产生高电平抖动。void GPIO_config() { /* 无线模组使能引脚 */ rcu_periph_clock_enable(RCU_GPIOB); gpio_bit_reset(GPIOB, GPIO_PIN_7); // 显式初始化输出寄存器为低 gpio_mode_set(GPIOB, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLDOWN, GPIO_PIN_7); gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_7); /* 无线模组供电引脚 */ gpio_bit_reset(GPIOB, GPIO_PIN_6); // 显式初始化输出寄存器为低 gpio_mode_set(GPIOB, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLDOWN, GPIO_PIN_6); gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_6); /* 蓝牙使能引脚 */ rcu_periph_clock_enable(RCU_GPIOC); gpio_bit_reset(GPIOC, GPIO_PIN_10); // ★ 核心改动 1配置输出前先将输出寄存器清零确保引脚默认输出低电平关闭蓝牙 gpio_mode_set(GPIOC, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_10); gpio_output_options_set(GPIOC, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_10); // ★ 核心改动 2此处注释掉立即开启蓝牙的代码改为后续在 RTOS 任务中延时开启 // gpio_bit_set(GPIOC, GPIO_PIN_10); }2. 修改 uTask.c 中的BLE_task在BLE_task启动后先进行一段延时避开主系统启动和串口打印造成的电流高峰然后再将 PC10 拉高使能蓝牙。static void BLE_task(void *pvParameters) { static uint8_t t_cnt 0; static uint16_t t_heart 0; WIRELESS_RXD wireless_rxxd {0}; // ★ 核心改动 3分步延时启动蓝牙实现错峰上电 vTaskDelay(pdMS_TO_TICKS(500)); // 1. 等待 RTOS 调度器运行稳定500ms gpio_bit_set(GPIOC, GPIO_PIN_10); // 2. 此时系统负载较轻拉高 PC10 开启蓝牙模块 vTaskDelay(pdMS_TO_TICKS(2500)); // 3. 继续延时 2.5s与原本的 3000ms 总延时保持一致不影响后续时序 // 蓝牙设备密钥查询等后续逻辑 BLE_Device_Key_Inquiry(Inquire_all, sizeof(Inquire_all)); while (1) { // 原有循环逻辑... } }