STM32F103ZE单片机在WWDG窗口看门狗的EWI中断中喂狗导致系统复位的原因及解决办法(中断

2019-04-15 14:45发布

程序开启了WWDG的Early wakeup(EWI)中断,在中断中喂狗,但系统不停地复位。 HCLK=72MHz, PCLK1=4.5MHz, PCLK2=72MHz
程序如下: #include #include int fputc(int ch, FILE *fp) { if (fp == stdout) { if (ch == ' ') { while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET); USART_SendData(USART1, ' '); } while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET); USART_SendData(USART1, ch); } return ch; } int main(void) { GPIO_InitTypeDef gpio; USART_InitTypeDef usart; RCC_PCLK1Config(RCC_HCLK_Div16); RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE); // 打开WWDG的时钟后, 计数器就开始空转 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_USART1, ENABLE); gpio.GPIO_Mode = GPIO_Mode_AF_PP; gpio.GPIO_Pin = GPIO_Pin_9; gpio.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &gpio); USART_StructInit(&usart); usart.USART_BaudRate = 115200; usart.USART_Mode = USART_Mode_Tx; USART_Init(USART1, &usart); USART_Cmd(USART1, ENABLE); if (RCC_GetFlagStatus(RCC_FLAG_PINRST) == SET) printf("PIN reset! "); if (RCC_GetFlagStatus(RCC_FLAG_PORRST) == SET) printf("POR reset! "); if (RCC_GetFlagStatus(RCC_FLAG_WWDGRST) == SET) printf("WWDG reset! "); RCC_ClearFlag(); WWDG_Enable(94); // 启动看门狗并在没有窗口值的情况下喂狗 WWDG_SetPrescaler(WWDG_Prescaler_8); WWDG_SetWindowValue(74); // 设置窗口值 WWDG_EnableIT(); NVIC_EnableIRQ(WWDG_IRQn); while (1); } void WWDG_IRQHandler(void) { WWDG_ClearFlag(); WWDG_SetCounter(94); } 不过只要去掉RCC_PCLK1Config(RCC_HCLK_Div16)这句话,让PCLK1回到默认的36MHz,系统就不再复位了。
于是配置DBGMCU_Config(DBGMCU_WWDG_STOP, ENABLE),设置调试时WWDG暂停。然后打开ST-Link调试,发现系统复位前WWDG_IRQHandler中断函数连续执行了两次,第一次执行时T=0x40,正常喂狗,紧接着又再次重入了中断,T=0x5e,这个时候喂狗就引发了系统复位,因为此时计数值T>窗口值W。 问题的原因找到了,这是因为程序的执行速度(HCLK)太快,而中断标志位EWIF的清除需要一定的时间(PCLK1),前者的速度是后者的16倍,虽然在中断函数里面调用了清除中断标志位的函数,但是到了中断执行完毕后EWIF都还未来得及清除,所以中断又再次重入了,第二次喂狗就引发了系统复位。 解决办法就是,清除标志位后等待一下标志位真正清除,然后再喂狗,退出中断。保证中断只执行一次。 void WWDG_IRQHandler(void) { WWDG_ClearFlag(); while (WWDG_GetFlagStatus() == SET); // 等待中断标志位真正清除, 防止中断重入 WWDG_SetCounter(94); }当HCLK=2*PCLK2时不需要等待,因为标志位的清除速度能够跟得上中断的执行速度。
程序一开始的时候就在RCC中打开了WWDG外设的时钟,这时WDGA=0,窗口看门狗未启用但处于空转状态,EWIF的置位规律如下: T=127 T=126 T=125 ... T=66 T=65 T=64 *** EWIF置位, 手动清除标志位 T=63 ... T=2 T=1 T=0 *** EWIF置位, 手动清除标志位 T=127 T=126 ... T=66 T=65 T=64 *** EWIF置位, 手动清除标志位 T=63 ...在一个计数周期内EWIF会自动置位两次。但在窗口看门狗启动之前(WDGA=0),即使打开了EWI中断,也不会进入中断函数WWDG_IRQHandler执行。只有WDGA=1且EWIF=1时才会触发中断。