芯片设计上的BUG

描述

近期白嫖君在使用GD32这款芯片时候,发现了一个大概率是芯片设计上的BUG,贴出来和大家分享一下。

我们在使用串口发送数据时,无非是使用两种方法,一种是逐字节发送,另一种是DMA发送。

芯片

一般串口发送数据前,我们需要先查看TBE标志位,判断缓存区内是不是已经空了,如果空了我们才会往里填数据。

但是当发送缓存区为空时,并不代表我们的数据已经实际发完了,只是代表缓存区内的数据空了,这时物理意义上的发送可能还在进行中,如果你使用RS485器件,这时候把发送使能关断的话,就会丢失一个字节的数据。

因此,一般发送完成后,需要检查TC标志是不是已经被拉高了,以此来判断数据线上的数据是不是确实已经发结束了。

void usart_sendbuf(uint32_t usart_periph, uint8_t *Buffer , uint16_t ucSend_num)
{        
    unsigned int i;
    usart_flag_clear(usart_periph, USART_FLAG_TC);  //在发送前要先清除TC
    for(i = 0; i < ucSend_num; i++)
    {        
        while(usart_flag_get(usart_periph, USART_FLAG_TBE) == RESET); 
        usart_data_transmit(usart_periph, Buffer[i]);
    }
    while(usart_flag_get(usart_periph, USART_FLAG_TC) == RESET);      
}

这次白嫖君的程序就是还按照这个套路来写的,串口发送数据量比较大,在运行一段时间后,程序突然就死机了,查看一下,是死在了最后一行等待TC标志位这里。查看寄存器列表,TC始终为0。

芯片

下面是官方库函数手册上给出的说明:

芯片

TC标识是受单片机硬件控制的,并不受程序影响,这里无法拉高九成九就是芯片BUG了,于是白嫖君谷歌了一下,发现也有人遇到类似问题:

芯片

针对这种情况,硬件上无法做出改善,只能从软件上规避了:

void usart_sendbuf(uint32_t usart_periph, uint8_t *Buffer , uint16_t ucSend_num)
{        
    uint32_t i;
    uint32_t j = 0;
    
    usart_flag_clear(usart_periph, USART_FLAG_TC);  //为了使用TC,在发送前要先清除TC
    for(i = 0; i< ucSend_num; i++)
    {        
        while(usart_flag_get(usart_periph, USART_FLAG_TBE) == RESET); 
        usart_data_transmit(usart_periph, Buffer[i]);
    }
    while(usart_flag_get(usart_periph, USART_FLAG_TC) == RESET)
    {
        if(j++ >= 0xFFFF) //在这里加超时机制
        {
            break;
        }
    }        
}

引入超时机制,当等待时间超过设定阈值,则不再等待TC置位,以此来避免程序阻塞假死。

特别注意:出现这种情况目前来说可能GD全系都有可能存在这个问题,且不区分是USART0还是USARTx,同时似乎只在数据量较大时会出现此种情况。我以前用GD的片子也不少,从没遇见过这种情况。特此说明,避免抬杠嘛~

审核编辑 :李倩

 


打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分