使用中断开关实现全局变量互斥访问
最近在STM32F429平台上实现一套主从机串口库,在开发过程中,出现偶发性丢帧问题,反复核对关键代码,均未发现任何问题,一筹莫展。按照经验第一反应就是互斥访问导致的脏数据问题,但苦于无法锁定问题,因为只有在串口大量数据收发时,才出现偶发性丢帧,无法采取在线调试锁定问题,极其难以抓取。为了能够尽快找到问题关键采取了最费力的办法:
- 锁定问题代码,对所有全局变量互斥访问代码逐一注释,同时检测注释后是否停止丢帧:锁定问题代码位置;
- 在问题代码处添加调试代码,通过串口重定向打印相关全局变量;
虽然方法费时费力,但很快有了突破:打印出来的全局变量仅反复的进行加0操作,其未做任何改变,但仍发生丢帧,由此推论:串口丢帧是由于全局变量互斥访问引起的可能性极大。
解决方法:1、使用中断开关,在进行互斥访问前关闭中断,完成后再开启中断;2、使用LDREX/STREX指令;
为了最快地解决问题,先暂时采用方法一(以下是部分代码):
void uart_it_sw(FunctionalState state) { USART_ITConfig(USART, USART_IT_RXNE, state); } void USART1_IRQHandler(void) { uint8_t ucTemp; if(USART_GetITStatus(USART,USART_IT_RXNE)!=RESET) { ucTemp = USART_ReceiveData( USART ); push(ucTemp); } } static int front=0; static int rear=0; static int count=0; void push(unsigned char tmp) { recv_buf[rear]=tmp; rear++; rear%=MAX_QUEUE_LEN; if (count==MAX_QUEUE_LEN) { front++; front%=MAX_QUEUE_LEN; } else { count++; } } void pop(int len) { // if (len>0) { if (len>count) { len=count; } uart_it_sw(DISABLE); //互斥访问前关闭串口中断 front+=len; front%=MAX_QUEUE_LEN; count-=len; uart_it_sw(ENABLE); //互斥访问结束重新打开串口中断 } } void empty(void) { uart_it_sw(DISABLE); front=0; rear=0; count=0; uart_it_sw(ENABLE); }
结果:在开启互斥访问中断开关后,长时间大量测试下均未发生丢帧。
总结:如何锁定和确定问题和解决问题的最终方法一样的重要;其次大胆猜测,用后验逻辑去解决问题也不失为一种解决问题的好思路。