GD32F103单片机主从SPI通信异常问题处理
项目场景:
主板上有主从单片机,主单片机为STM32F103,从单片机为GD32F103RET6,它们之间通过SPI进行通信,相互发送数据。
问题描述
调试过程中发现,当重新通过仿真器对主单片机进行下载程序并仿真时,主从单片机之间的SPI通信就会发生异常,无法正常通信。但是对整个主板重新上电,主从单片机通信一直是正常的。
原因分析:
怀疑是在主板运行过程中,若单片机自身发生复位,会导致主从单片机之间SPI的通信出现异常,可能性最大的是CLK时钟错位。进一步对从单片机的程序进行仿真发现,SPI的SPI_STAT_TRANS标志位一直处于置位状态,也就是说处于忙状态,导致从单片机无法正常收发数据。
解决方案:
- SPI初始化时对SCK引脚增加外部中断检测配置,如下所示:
staticvoidSPI1_GPIO_Configuration(void){rcu_periph_clock_enable(RCU_GPIOB);rcu_periph_clock_enable(RCU_SPI1);rcu_periph_clock_enable(RCU_AF);/* SPI2_SCK(PB13), SPI1_MISO(PB14) and SPI1_MOSI(PB15) GPIO pin configuration */gpio_init(GPIOB,GPIO_MODE_IN_FLOATING,GPIO_OSPEED_10MHZ,GPIO_PIN_13);gpio_init(GPIOB,GPIO_MODE_IPU,GPIO_OSPEED_10MHZ,GPIO_PIN_15);gpio_init(GPIOB,GPIO_MODE_AF_PP,GPIO_OSPEED_10MHZ,GPIO_PIN_14);spi_nss_internal_low(SPI_PORT);/* enable and set key EXTI interrupt priority */nvic_irq_enable(EXTI10_15_IRQn,3,0);/* connect key EXTI line to key GPIO pin */gpio_exti_source_select(GPIO_PORT_SOURCE_GPIOB,GPIO_PIN_SOURCE_13);/* configure key EXTI line */exti_init(EXTI_13,EXTI_INTERRUPT,EXTI_TRIG_RISING);exti_interrupt_flag_clear(EXTI_13);}- 外部中断处理程序代码如下:
voidEXTI10_15_IRQHandler(void){if(RESET!=exti_interrupt_flag_get(EXTI_13)){exti_interrupt_flag_clear(EXTI_13);if(spi_i2s_flag_get(SPI_PORT,SPI_FLAG_TRANS)==RESET)SPI1_Busy_1ms=0;SPI1_Clk_1ms=0;}}- 添加监视SPI的busy状态的处理程序,若SPI_FLAG_TRANS置位(SPI1_Busy_1ms > 100),但却没有检测到SCK(即SPI1_Clk_1ms>100),则对SPI进行重新配置。如下所示:
voidSPI1_Monitor(void){if(System1msGetReady()){if(SPI1_Busy_1ms!=0xffff)SPI1_Busy_1ms++;if(SPI1_Clk_1ms!=0xffff)SPI1_Clk_1ms++;}if(spi_i2s_flag_get(SPI_PORT,SPI_FLAG_TRANS)==RESET){SPI1_Busy_1ms=0;SPI1_Clk_1ms=0;}if(SPI1_Busy_1ms>100&&SPI1_Clk_1ms>100){SPI1_Busy_1ms=0;SPI1_Configuration();}}- 优化 SPI 中断处理程序,并增加错误处理逻辑
voidSPI1_IRQHandler(void){/* 接收缓冲区非空中断 */if(spi_i2s_interrupt_flag_get(SPI_PORT,SPI_I2S_INT_FLAG_RBNE)==SET){struct_Uart_BUF*P_Uart;P_Uart=UartAll_Get(UART_NO_SPI1);P_Uart->RecBuf[P_Uart->RecBufWritePoint]=spi_i2s_data_receive(SPI_PORT);P_Uart->RecBufWritePoint=(P_Uart->RecBufWritePoint+1)%UART_BUFFER_SIZE;}/* 发送缓冲区空中断 */if(spi_i2s_interrupt_flag_get(SPI_PORT,SPI_I2S_INT_FLAG_TBE)==SET){if(SPI1_Int_SendR!=SPI1_Int_SendW){spi_i2s_data_transmit(SPI_PORT,SPI1_Int_SendBuffer[SPI1_Int_SendR]);SPI1_Int_SendR=(SPI1_Int_SendR+1)%SPI_SEND_BUFFER_SIZE;}else{IRQ_REQUEST_HIGH();spi_i2s_interrupt_disable(SPI_PORT,SPI_I2S_INT_TBE);}}/* 接收CRC错误 */if(spi_i2s_interrupt_flag_get(SPI_PORT,SPI_INT_FLAG_CRCERR)==SET){spi_crc_error_clear(SPI_PORT);}/* 接收过载错误 */if(spi_i2s_interrupt_flag_get(SPI_PORT,SPI_I2S_INT_FLAG_RXORERR)==SET){/* 先读SPI_DATA寄存器 */spi_i2s_data_receive(SPI_PORT);SPI_STAT(SPI_PORT);}}经过上述配置,问题可以得到解决。