打印
[应用相关]

STM32的串口DMA收发以及双缓冲区的实现

[复制链接]
1043|8
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
gejigeji521|  楼主 | 2017-4-15 08:50 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
在使用STM32的UART的DMA功能总结如下:
首先上代码,这里采用STM32 的USART1作为Demo,RX的DMA为DMA1_Channel5,TX的DMA为DMA1_Channel4.初始化如下,红色的标记需要注意:
RX-DMA初始化
// DMA Rx
USART_DMACmd(USART1,USART_DMAReq_Rx,ENABLE);  
DMA_Cmd(DMA1_Channel5,DISABLE);
DMA_InitStruct.DMA_PeripheralBaseAddr = (u32)(&USART1->DR);
DMA_InitStruct.DMA_MemoryBaseAddr = (u32)RxBuf0;
DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralSRC;
DMA_InitStruct.DMA_BufferSize = 10;
DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
DMA_InitStruct.DMA_MemoryDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStruct.DMA_Mode = DMA_Mode_Circular;
DMA_InitStruct.DMA_Priority = DMA_Priority_High;
DMA_InitStruct.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMA1_Channel5,&DMA_InitStruct);
DMA_Cmd(DMA1_Channel5,ENABLE);

沙发
gejigeji521|  楼主 | 2017-4-15 08:50 | 只看该作者
中断的初始化如下:中断的初始化如下:DMA_ITConfig(DMA1_Channel5,DMA_IT_TC,ENABLE);
    NVIC_InitStruct.NVIC_IRQChannel = DMA1_Channel5_IRQn;
    NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStruct);

    //ENABLE DMA TX ISR
    DMA_ITConfig(DMA1_Channel4,DMA_IT_TC,ENABLE);
    NVIC_InitStruct.NVIC_IRQChannel = DMA1_Channel4_IRQn;
    NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStruct.NVIC_IRQChannelSubPriority = 2;
    NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStruct);

使用特权

评论回复
板凳
gejigeji521|  楼主 | 2017-4-15 08:51 | 只看该作者
TX发送函数如下:
void USART1_SendDMA(uint8_t* buf,int len)
{
    DMA_InitTypeDef DMA_InitStruct;
    DMA_ITConfig(DMA1_Channel4,DMA_IT_TC,ENABLE);

    DMA_Cmd(DMA1_Channel4,DISABLE);

    DMA_InitStruct.DMA_PeripheralBaseAddr = (u32)(&USART1->DR);
    DMA_InitStruct.DMA_MemoryBaseAddr = (u32)buf;
    DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralDST;
    DMA_InitStruct.DMA_BufferSize = len;
    DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;
    DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
    DMA_InitStruct.DMA_MemoryDataSize = DMA_PeripheralDataSize_Byte;
    DMA_InitStruct.DMA_Mode = DMA_Mode_Normal;
    DMA_InitStruct.DMA_Priority = DMA_Priority_VeryHigh;
    DMA_InitStruct.DMA_M2M = DMA_M2M_Disable;
    DMA_Init(DMA1_Channel4,&DMA_InitStruct);

   DMA_Cmd(DMA1_Channel4,ENABLE);    
}

使用特权

评论回复
地板
gejigeji521|  楼主 | 2017-4-15 08:57 | 只看该作者
两个服务函数如下:
RX-DMA中断函数,实现RX的双缓冲区功能。值得注意的是,你的DMA设置成Normal模式的时候,在中断函数中就得设置DMABufferSize,应为Normal模式完成一次传输之后,BufferSize直接清零,设置成Circle模式就不会存在这个问题,下面的中断就是设置成Circle模式的。
void DMA1_Channel5_IRQHandler()
{
    if(DMA_GetITStatus(DMA1_IT_TC5))
  {
      if(using_buf0 ==0)
    {
      DMA1_Channel5->CMAR = (u32)RxBuf0;
         using_buf0 = 1;
    }
    else
    {
         DMA1_Channel5->CMAR = (u32)RxBuf1;
         using_buf0 = 0;
    }
    recv_flag = 1;
    DMA_ClearITPendingBit(DMA1_IT_TC5);
  }   

}






TX-DMA中断函数
void DMA1_Channel4_IRQHandler()
{
    if(DMA_GetITStatus(DMA1_IT_TC4))
    {
        //TODO:Add code here
        DMA_ClearITPendingBit(DMA1_IT_TC4);
    }   
}




使用特权

评论回复
5
LyCrystal| | 2017-4-15 09:22 | 只看该作者
学习学习。一直都用的Normal,还没了解过circle

使用特权

评论回复
6
gejigeji521|  楼主 | 2017-4-15 18:03 | 只看该作者
几点说明

1)这里采用双缓冲区的方式,对于大数据量的时候是很有效的,在处理一个缓冲区数据的时候,另外一个缓冲区能够正常接收数据

2)TX的DMA中断,可以采用类似于操作系统中互斥量的操作,当一个数组还在发送的时候,另外一个数组如果检测到一个在发送,则不能够进行发送,不然这样子数据会乱掉;

3)如果DMA接收想采用循环缓冲区的方式,可以直接将RX-DMA设置成Circle方式,然后数据就会硬件上自动实现环形缓冲区的功能,省了不少时间。

4)DMA在采用Normal模式的时候,当一次任务完成后,DMA->DMA_BufferSize自动清零,并且DMA自动停止。如果想再次设置DMA的BufferSize的话,必须要进行如下操作:

   step1:DMA_CMD(DMAx_Channely,DISABLE);

   step2: 设置DMA_BufferLen

   step3:DMA_CMD(DMAx_Channely,ENABLE)

5)DMA采用Circle模式的时候,在发送或者接受完成之后,仍然保存着BufferSize,并且DMA还处于使能状态,一直连续工作,直到用户停止DMA

使用特权

评论回复
7
mmuuss586| | 2017-4-15 20:02 | 只看该作者
谢谢分享

使用特权

评论回复
8
gejigeji521|  楼主 | 2017-4-15 21:31 | 只看该作者
好的东西我都会看到之后分享过来的。

使用特权

评论回复
9
yiy| | 2017-4-16 14:31 | 只看该作者
DMA设置成Normal模式的时候,在中断函数中就得设置DMABufferSize,应为Normal模式完成一次传输之后,BufferSize直接清零,设置成Circle模式就不会存在这个问题

使用特权

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

本版积分规则

180

主题

2250

帖子

8

粉丝