打印
[其他ST产品]

STM32 F429 DMA传输1-串口(外设)DMA传输

[复制链接]
608|15
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
原来是wjc|  楼主 | 2023-1-31 20:23 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
主要内容

本文主要是我自己记录DMA配置过程函数以及参数细节,同时与需要的人分享学习,对于DMA的作用、定义之类的在这不进行阐述,有需要者参考中文手册。

为方便对比学习,我分三部分分享我在正点原子f429板子上写的关于DMA的程序,从官方历程到扩展使用分别为:
1、由内存向串口(外设)DMA传输;
2、由ADC采集数据(内存)向内存DMA传输;
3、定时器下ADC采集向内存双缓冲DMA传输;
本文只对第一部分进行讲解。

使用特权

评论回复
评论
原来是wjc 2023-1-31 20:23 回复TA
———————————————— 版权声明:本文为CSDN博主「小朱一定要快速**文」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/qq_43745917/article/details/119679235 
沙发
原来是wjc|  楼主 | 2023-1-31 20:23 | 只看该作者
如何配置

要实现串口(外设)DMA传输需要四部配置
1)使能 DMA2 时钟。
2) 初始化 DMA参数。
3)使能串口 的 DMA 发送
4)使能 DMA 数据流 ,启动传输。
配置过程官方历程讲的已经非常清晰了这里我把代码粘一下,各行都有注释

使用特权

评论回复
板凳
原来是wjc|  楼主 | 2023-1-31 20:23 | 只看该作者
void myDMA_init(DMA_Stream_TypeDef *DMAa_Streamb, u32 chx)
{
                if((u32)DMAa_Streamb>(u32)DMA2)//得到当前stream是属于DMA2还是DMA1
        {
        __HAL_RCC_DMA2_CLK_ENABLE();//  第一步初始化DMA2时钟使能       
        }else
        {
        __HAL_RCC_DMA1_CLK_ENABLE();//DMA1时钟使能
        }
   __HAL_LINKDMA(&UART1_Handler,hdmatx,DAM_Handal);    //将DMA与USART1联系起来(发送DMA)
       
  /*     配置DMA各个参数     */
        DAM_Handal.Instance                          = DMAa_Streamb;  //寄存器基地址 设置DMA数据流
        DAM_Handal.Init.Channel                      = chx;    //通道
  DAM_Handal.Init.Direction                      = DMA_MEMORY_TO_PERIPH;          //dma传输方向 内存到外设
        DAM_Handal.Init.PeriphInc                    = DMA_PINC_DISABLE;   //外设(非)增量模式
        DAM_Handal.Init.MemInc                       = DMA_MINC_ENABLE;     //使能存储器地址递增
        DAM_Handal.Init.PeriphDataAlignment          = DMA_PDATAALIGN_BYTE;   //设置外设数据宽度
  DAM_Handal.Init.MemDataAlignment               = DMA_MDATAALIGN_BYTE;   //设置外设数据宽度
  DAM_Handal.Init.Mode                           =DMA_NORMAL;             //外设普通模式
        DAM_Handal.Init.Priority                     =DMA_PRIORITY_MEDIUM;      //中等优先级
        DAM_Handal.Init.FIFOMode                     =DMA_FIFOMODE_DISABLE;       //fifo模式
        DAM_Handal.Init.FIFOThreshold                =DMA_FIFO_THRESHOLD_FULL;    //FIFO阀值设置
        DAM_Handal.Init.MemBurst                     =DMA_MBURST_SINGLE;                 //存储器突发单次传输
        DAM_Handal.Init.PeriphBurst                  =DMA_PBURST_SINGLE;              //外设突发单次传输
       
                  HAL_DMA_Init(&DAM_Handal);
       
}

使用特权

评论回复
地板
原来是wjc|  楼主 | 2023-1-31 20:24 | 只看该作者
void MYDMA_USART_Transmit(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
{
    HAL_DMA_Start(huart->hdmatx, (u32)pData, (uint32_t)&huart->Instance->DR, Size);//开启DMA传输
   
    huart->Instance->CR3 |= USART_CR3_DMAT;             //使能串口DMA发送


}          

使用特权

评论回复
5
原来是wjc|  楼主 | 2023-1-31 20:27 | 只看该作者
其中对于DMA串口传输函数可以使用HAL_DMA_Start,但是必须进行 huart->Instance->CR3 |= USART_CR3_DMAT; 使能串口DMA发送,同时也可以使用HAL_UART_Transmit_DMA函数进行传输,此函数内包含使能串口DMA发送,其参数是一样的,后两部分

    2、由ADC采集数据(内存)向内存DMA传输;
    3、定时器下ADC采集向内存双缓冲DMA传输;

均使用的是HAL_ADC_Start_DMA函数进行DMA传输,过程与HAL_UART_Transmit_DMA类似,所以推荐使用。

使用特权

评论回复
6
原来是wjc|  楼主 | 2023-1-31 20:28 | 只看该作者
各参数含义及配置细节

对于DMA配置的各个参数出代码注释以为需要注意的还有:
1)
DAM_Handal.Init.Direction = DMA_MEMORY_TO_PERIPH;
dma传输方向 有自己写的字符串传输到串口方向是内存到外设,初学者学习不要直接搬用参数而不知道什么意思就直接搬用。

使用特权

评论回复
7
原来是wjc|  楼主 | 2023-1-31 20:29 | 只看该作者
2)
DAM_Handal.Init.PeriphInc = DMA_PINC_DISABLE;
用于设置外设地址是否使能递增,即每完成一次传输,外设地址自增,增加的大小由参数PeriphDataAlignment (外设数据宽度)决定,也就是说如果你只用了一个外设,那么就不能使能递增,否者使能,很明显这里只用了一个串口传输。

使用特权

评论回复
8
原来是wjc|  楼主 | 2023-1-31 20:29 | 只看该作者
3)成员MemInc
用于设置存储器地址是否使能递增,即每完成一次传输,存储器地址自增,增加的大小由参数 MemDataAlignment 决定,与2)类似。

使用特权

评论回复
9
原来是wjc|  楼主 | 2023-1-31 20:29 | 只看该作者
4)成员 PeriphDataAlignment
用于设置外设支持的数据宽度,可以选择字节,半字和字进行传输。

使用特权

评论回复
10
原来是wjc|  楼主 | 2023-1-31 20:29 | 只看该作者
5)成员MemDataAlignment
用于设置存储器支持的数据宽度,可以选择字节,半字和字进行传输。

使用特权

评论回复
11
原来是wjc|  楼主 | 2023-1-31 20:29 | 只看该作者
6)成员Mode 用于设置正常模式、循环模式和流控制,Normal 正常模式 适合用于单次传输,比如存储器到存储器的数据复制粘贴,又比如串口的数据单次发送,下次还需要 发送的时候,使能下即可。
Circular 循环模式 适合用于需要连续传输的场合,比如定时器触发BDMA实现任意 IO 的 PWM输出。特别注意,循环模式不可用于存储器到存储器模式。

使用特权

评论回复
12
原来是wjc|  楼主 | 2023-1-31 20:29 | 只看该作者
另外需要注意的还有传输源地址和目的地址的数据宽度可以不同,但是数据地址必须要跟其数据类型对齐 比如源地址是uint32 类型的,那么此数组的地址必须 4 字节对齐。

使用特权

评论回复
13
原来是wjc|  楼主 | 2023-1-31 20:29 | 只看该作者
在函数HAL_DMA_Start和HAL_UART_Transmit_DMA进行传输时,参数是一样的,各参数分别为UART_HandleTypeDef结构的指针指定配置信息,pData: 目的缓冲区地址,Length: 传输数据长度,在这是内存传输到外设的数据长度。

使用特权

评论回复
14
原来是wjc|  楼主 | 2023-1-31 20:30 | 只看该作者
中断标志
 DMA_FLAG_TCIFx 传输完成标志。
 DMA_FLAG_HTIFx 半传输完成标志。
 DMA_FLAG_TEIFx 传输错误标志。
 DMA_FLAG_DMEIFx 直接模式错误标志。
 DMA_FLAG_FEIFx FIFO错误标志。

使用特权

评论回复
15
原来是wjc|  楼主 | 2023-1-31 20:30 | 只看该作者
需要注意的是DMA_FLAG_FEIF0_4,表示DMA1或者DMA2的Stream0和Stream4的标志,而不是Stream0 到 Stream4,同理 1 和 5 就是 Srteam1 和 Stream5

使用特权

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

本版积分规则

78

主题

994

帖子

0

粉丝