打印
[STM32F4]

串口uart使用DMA收发数据发送正常接收乱码

[复制链接]
453|19
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
zyf部长|  楼主 | 2021-1-18 21:21 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
正在调试STM32F429使用DMA来收发串口USART的数据,目前USART1使用DMA收发是正常的,波特率为256000,但是使用相同的串口配置及DMA配置,单独开usart2或者usart3的DMA收发,当只收不发数据时,串口DMA接收数据正确;但当同时进行DMA收发时,接收到的数据就是错误的

使用特权

评论回复
沙发
zhuhuis| | 2021-1-18 21:23 | 只看该作者

还有什么现象?能再详细描述下吗?

使用特权

评论回复
板凳
zyf部长|  楼主 | 2021-1-18 21:25 | 只看该作者
通过PC串口向MCU发送固定的数据,在仿真下查看DMA接收buffer里的数据是乱的,查看USART2->DR寄存器的值发现接收的数据就是错误的

使用特权

评论回复
地板
zwll| | 2021-1-18 21:34 | 只看该作者
相关配置及代码看下

使用特权

评论回复
5
zyf部长|  楼主 | 2021-1-18 21:36 | 只看该作者

1.基本信息
USART2:256000,8,1,no parity,
DMA_TX:DMA1_Stream6,Direct mode,normal mode...
DMA_RX:DMA1_Stream5,Double buffer,circular mode...

2.详细代码
(1)串口usart2及DMA初始化
void Usart2DmaInit(void)
{   
    NVIC_InitTypeDef NVIC_InitStructure ;  
    GPIO_InitTypeDef GPIO_InitStructure;  
    USART_InitTypeDef USART_InitStructure;
    DMA_InitTypeDef DMA_InitStructure;  
        
    //设置IO口及时钟        
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
    GPIO_PinAFConfig(GPIOD, GPIO_PinSource5, GPIO_AF_USART2);
    GPIO_PinAFConfig(GPIOD, GPIO_PinSource6, GPIO_AF_USART2);

    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
    GPIO_Init(GPIOD, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
    GPIO_Init(GPIOD, &GPIO_InitStructure);
/////////////////////////////////////////////////////////////////////////
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE);
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);        
/////////////////////////////////////////////////////////////////////////
    //串口收DMA配置           
    DMA_DeInit(DMA1_Stream5);  
    DMA_InitStructure.DMA_Channel = DMA_Channel_4;      
    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(&(USART2)->DR);     
    DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)(UART2_DMA_RX0);
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;   
    DMA_InitStructure.DMA_BufferSize = UART_RX_BUFFER_SIZE;      
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;  
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;  
    DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;  
    DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;   
    DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;   
    DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
    DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;   
    DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;      
      
    DMA_Init(DMA1_Stream5, &DMA_InitStructure);    //配置DMA1的通道  
    DMA_MemoryTargetConfig(DMA1_Stream5,(uint32_t)UART2_DMA_RX1,DMA_Memory_1);        
    DMA_Cmd(DMA1_Stream5,ENABLE);                    //使能DMA接收通道

    NVIC_InitStructure.NVIC_IRQChannel = DMA1_Stream5_IRQn;    //通道设置为串口中断   
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;       //中断占先等级  
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;                 //中断响应优先级   
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;                 //打开中断   
    NVIC_Init(&NVIC_InitStructure);   
//////////////////////////////////////////////////////////////////////////////////
    //串口发DMA配置        
    DMA_DeInit(DMA1_Stream6);                                                           //DMA通道配置        
    DMA_InitStructure.DMA_Channel = DMA_Channel_4;                            //DMA发送通道
    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(&(USART2)->DR); //外设地址         
    DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)UART2_DMA_TX;     //内存地址               
    DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;                  //dma传输方向        
    DMA_InitStructure.DMA_BufferSize = 100;                                    //设置DMA在传输时缓冲区的长度        
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;         //设置DMA的外设递增模式,一个外设        
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;    //设置DMA的内存递增模式  
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;  //外设数据字长
    DMA_InitStructure.DMA_MemoryDataSize = DMA_PeripheralDataSize_Byte;     //内存数据字长
    DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;                                    //设置DMA的传输模式        
    DMA_InitStructure.DMA_Priority = DMA_Priority_High;                                     //设置DMA的优先级别  
    DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;                     //指定如果FIFO模式或直接模式将用于指定的流 : 不使能FIFO模式        
    DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;         //指定了FIFO阈值水平                         DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;                  //指定的Burst转移配置内存传输        
    DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;  //指定的Burst转移配置外围转移 //        
    DMA_Init(DMA1_Stream6, &DMA_InitStructure);                          //配置DMAx的通道        
    DMA_ITConfig(DMA1_Stream6,DMA_IT_TC,ENABLE);                 //使能中断     

    NVIC_InitStructure.NVIC_IRQChannel = DMA1_Stream6_IRQn;  
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;  
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;  
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;  
    NVIC_Init(&NVIC_InitStructure);         
///////////////////////////////////////////////////////////////////////////////
    //串口参数配置
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;   
    USART_InitStructure.USART_StopBits = USART_StopBits_1;   
    USART_InitStructure.USART_Parity = USART_Parity_No;   
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;   
    USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;      
    USART_InitStructure.USART_BaudRate = 256000;   
    USART_Init(USART2,&USART_InitStructure);  
  
    //配置中断
    NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;               //通道设置为串口中断   
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;       //中断占先等级  
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;                  //中断响应优先级   
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;                 //打开中断   
    NVIC_Init(&NVIC_InitStructure);     
      
    USART_DMACmd(USART2,USART_DMAReq_Tx,ENABLE);
    USART_DMACmd(USART2,USART_DMAReq_Rx,ENABLE);  
  
    //中断配置
    USART_ITConfig(USART2,USART_IT_TC,DISABLE);  
    USART_ITConfig(USART2,USART_IT_RXNE,DISABLE);  
    USART_ITConfig(USART2,USART_IT_TXE,DISABLE);  
    USART_ITConfig(USART2,USART_IT_IDLE,DISABLE);

    USART_Cmd(USART2, ENABLE);      
}

(2)DMA接收中断
void DMA1_Stream5_IRQHandler(void)                    // uart2 rx
{
    if (DMA_GetITStatus(DMA1_Stream5, DMA_IT_TCIF5) != RESET)
    {
        DMA_ClearITPendingBit(DMA1_Stream5, DMA_IT_TCIF5);
    }

    if (DMA_GetITStatus(DMA1_Stream5, DMA_IT_TEIF5) != RESET)
    {
        DMA_ClearITPendingBit(DMA1_Stream5, DMA_IT_TEIF5);
    }
}

(3)DMA发送中断
void DMA1_Stream6_IRQHandler(void)                     //com6 uart2 tx
{
        if (DMA_GetITStatus(DMA1_Stream6, DMA_IT_TCIF6) != RESET)  //transfer complete interrupt flag
        {               
                DMA_ClearITPendingBit(DMA1_Stream6, DMA_IT_TCIF6);               
               
                DMA_Cmd(DMA1_Stream6,DISABLE);                                // stop DMA transmit

                Tmpbsy = 0;
               
                USART_ITConfig(USART1,USART_IT_TC,ENABLE);        //open usart transfer complete interrupt,to send the last 2 bytes.
        }                        
                                                
        if (DMA_GetITStatus(DMA1_Stream6, DMA_IT_HTIF6) != RESET)   //half transfer interrupt flag
        {
                DMA_ClearITPendingBit(DMA1_Stream6, DMA_IT_HTIF6);
        }                                
}

(4)主循环
void main(void)
{
    //Initilized functions
    //...
    //...


    while(1)
    {
        if(Tmpbsy==0)
        {
            Tmpbsy = 1;
            DMA_SetCurrDataCounter(DMA1_Stream6,100);
            DMA_Cmd(DMA1_Stream6,ENABLE);
        }   
    }
}

使用特权

评论回复
6
renyaq| | 2021-1-18 21:38 | 只看该作者
DMA的配置是正确的

使用特权

评论回复
7
houcs| | 2021-1-18 21:40 | 只看该作者
有可能是硬件的问题

使用特权

评论回复
8
zyf部长|  楼主 | 2021-1-18 21:42 | 只看该作者
串口的波特率有问题,可能是硬件问题

使用特权

评论回复
9
hanwe| | 2021-1-18 21:43 | 只看该作者
怎么配置的问题?

使用特权

评论回复
10
lium| | 2021-1-18 21:46 | 只看该作者
共地了吗?

使用特权

评论回复
11
yufe| | 2021-1-18 21:50 | 只看该作者
正常的都是需要电源的地连接在一起。

使用特权

评论回复
12
langgq| | 2021-1-18 21:52 | 只看该作者
估计是缓冲区在编译后冲突了。

使用特权

评论回复
13
zyf部长|  楼主 | 2021-1-18 21:56 | 只看该作者

好的,我明天去单位试一下,多谢各位大侠了哈        

使用特权

评论回复
14
kxsi| | 2021-2-4 23:28 | 只看该作者
还有256000的波特率?

使用特权

评论回复
15
nawu| | 2021-2-4 23:34 | 只看该作者
有时候调试dma怪麻烦的

使用特权

评论回复
16
qcliu| | 2021-2-4 23:37 | 只看该作者
缓冲区怎么会冲突呢

使用特权

评论回复
17
tfqi| | 2021-2-4 23:40 | 只看该作者
查看一下波特率的设置就知道了

使用特权

评论回复
18
wiba| | 2021-2-4 23:41 | 只看该作者
楼主捋出来头绪了吗

使用特权

评论回复
19
Prry| | 2021-2-6 10:19 | 只看该作者
参考STM32F1DMA收发实现,1.5M波特率不翻车:https://acuity.blog.csdn.net/article/details/108367512

使用特权

评论回复
20
Prry| | 2021-2-6 10:19 | 只看该作者
wiba 发表于 2021-2-4 23:41
楼主捋出来头绪了吗

参考STM32F1DMA收发实现,1.5M波特率不翻车:https://acuity.blog.csdn.net/article/details/108367512

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

694

主题

7102

帖子

8

粉丝