STM32H743 单字节DMA发送问题,这个是否算芯片Bug?

2019-12-09 20:04发布

本帖最后由 saccapanna 于 2019-10-26 11:06 编辑

    I/D-Cache 都已经关闭。 main.c 主要功能,从 USART4 接收数据,然后原封不动返回相同数据。多字节 DMA 发送没有任何问题。 但是当 USART4 接收到一个字节时,把单个字节写入到 USART4 发送缓冲区,然后启动 DMA 数据传输,而 DMA 实际传输的是以前缓冲区的值,而不是新写入的值。 单字节写入后,延迟 10us,或者打断点等待一下,再启动 DMA 传输也没有问题。 这个问题我分析了好久,实在没有找到软件的问题,后来解决方法如下,在启动DMA前做一下判断,如果长度为1,写4次缓冲…… 这个算不算芯片的 Bug ?


     if( usart4_tx_dma_len == 1 ) {                                             // -- 如果是单字节发送,DMA会出问题
            temp = usart4_tx_buff[usart4_tx_sp];                            // -- 数据重写四次,问题解决了,重写三次都不行!!!
            usart4_tx_buff[usart4_tx_sp] = temp;                            //
            usart4_tx_buff[usart4_tx_sp] = temp;                            //
            usart4_tx_buff[usart4_tx_sp] = temp;                            //
            usart4_tx_buff[usart4_tx_sp] = temp;                            //
      }                                                                                      //



整个测试过程大概如下:
main()
{
     ……
    sub_usart4_init( 9600, 0 );                                    // 串口初始化
    while (1) {                                                           //
        i = sub_usart4_get_receive_buff_len();              // 从 USART4 接收数据,然后原封不动发送相同数据。
        if( i != 0 ) {                                                     //
        sub_usart4_read_receive_buff( test_buff, i );      // -- 如果 i==1,也就是从串口接收一个字节,
        sub_usart4_write_send_buff( test_buff, i );         // -- 单字节写入触发DMA传输,这个函数 DMA 传输出问题
    }                                                                        //
}


//==============================================================================================================
// 函数名称:sub_usart4_write_send_buff
// 函数功能:写数据到 usart4 发射缓冲区
//                 DMA1_Stream4:USART4_RX(63) --->    DMAMUX1_Channel_04  --->    DMA1_Stream4_Request
//                 DMA1_Stream5:USART4_TX(64) --->    DMAMUX1_Channel_05  --->    DMA1_Stream5_Request
// 入口参数:data:数据指针,length:数据长度
// 出口参数:BOOL_FALSE:数据太长,将导致缓冲区溢出,写入失败
//                 BOOL_TRUE:写入成功
// 程序版本:1.0
// 编写日期:2019-05-05
// 程序作者:
// 修改次数:
// 修改作者:
// 修改日期:
// 修改内容:
// 版本升级:
//==============================================================================================================
BOOLEAN sub_usart4_write_send_buff( const INT8U * data, INT16U length )
{
    INT16U  i;                                                                   //
    INT16U  usart4_tx_len;                                                //
   
    if( length > USART4_TX_BUFF ) {                                  // 检测写入数据长度
        return BOOL_FALSE;                                                //
    }                                                                                //
   
    ENTER_CRITICAL();                                                     //
    usart4_tx_len = usart4_tx_buff_len + length;                 //
    EXIT_CRITICAL();                                                        //
    if( usart4_tx_len > USART4_TX_BUFF ) {                       // 数据太长,写入失败
        return BOOL_FALSE;                                                //
    }                                                                                //

    for( i=0; i<length; i++ ) {                                            // 写数据到缓冲区
        usart4_tx_buff[usart4_tx_ep] = data;                     //
        usart4_tx_ep++;                                                     //
        if( usart4_tx_ep >= USART4_TX_BUFF ){                   //
            usart4_tx_ep = 0;                                                //
        }                                                                            //
    }                                                                                //
   
//  sub_system_raw_delay_10us(1);                                  // 如果使用延迟,DMA发送数据没有任何问题。
//  __asm("NOP");                                                           // 如果断点打在这里,然后再F5全速跑,DMA发送也没问题。
//  __asm("NOP");                                                           // 但是如果这里不延迟,不打断点,单字节启动DMA,
//  __asm("NOP");                                                           // DMA传输的数据,是之前 usart4_tx_buff 中的数据。
//  __asm("NOP");                                                           // 也就是说,新的数据没有真正的写入到 usart4_tx_buff 中。
//  __asm("NOP");                                                           //
//  __asm("NOP");                                                           // 说明:为了便于测试观看,buff 大小都只设置到了 16 字节。
//  __asm("NOP");                                                           //
//  __asm("NOP");                                                           //
   
    ENTER_CRITICAL();                                                                                        //
    usart4_tx_buff_len += length;                                                                    // 缓冲区长度增加
    if( ((DMA1_Stream5->CR) & DMA_SxCR_EN) == 0 ) {                                 // 开启 DMA 数据传输
        DMA1_Stream5->CR        = 0x00000000;                                              //
        DMA1_Stream5->FCR       = 0x00000000;                                                // -- 使用直接模式
        DMA1_Stream5->PAR       = (INT32U)(&(USART4->TDR));                     // -- 设置 外设 地址
        DMA1_Stream5->M0AR      = (INT32U)( usart4_tx_buff+usart4_tx_sp );  // -- 设置 Memory 地址
        if( usart4_tx_ep > usart4_tx_sp ) {                                                       //
            usart4_tx_dma_len = usart4_tx_ep - usart4_tx_sp;                            //
        }                                                                                                       //
        else {                                                                                                //
            usart4_tx_dma_len = USART4_TX_BUFF - usart4_tx_sp;                    //
        }                                                                                                       //
        DMA1_Stream5->NDTR      = usart4_tx_dma_len;                                 // -- 设置传输长度
        
    //  if( usart4_tx_dma_len == 1 ) {                                          // -- 如果是单字节发送,DMA会出问题
    //      temp = usart4_tx_buff[usart4_tx_sp];                            // -- 数据重写四次,问题解决了,重写三次都不行!!
    //      usart4_tx_buff[usart4_tx_sp] = temp;                            //
    //      usart4_tx_buff[usart4_tx_sp] = temp;                            //
    //      usart4_tx_buff[usart4_tx_sp] = temp;                            //
    //      usart4_tx_buff[usart4_tx_sp] = temp;                            //
    //  }                                                                                     //
        
        DMAMUX1_Channel5->CCR   = 64;                                                       // -- 选择触发信号
        DMA1_Stream5->CR       |= DMA_SxCR_MINC | DMA_SxCR_DIR_0;         // -- Memory 自增,01: Memory-to-peripheral,DMA优先级为低。
        DMA1->HIFCR             = DMA_HIFCR_CTCIF5 | DMA_HIFCR_CHTIF5;     // -- 清除传输完毕标识
        DMA1_Stream5->CR       |= DMA_SxCR_TCIE;                                       // -- 开启传输完毕中断
        DMA1_Stream5->CR       |= DMA_SxCR_EN;                                          // -- 启动 DMA 传输
        USART4->CR3            |= USART_CR3_DMAT;                                        //
    }                                                                                                            //
    EXIT_CRITICAL();                                                                                    //
    return BOOL_TRUE;                                                                                 //
}                                                                                                                //



测试工程文件:
STM32H743_USART4_DMA_ERR.rar (739.96 KB, 下载次数: 1) 2019-10-26 10:35 上传 点击文件名下载附件
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。