STM32 F429 DMA传输1-串口(外设)DMA传输
主要内容
本文主要是我自己记录DMA配置过程函数以及参数细节,同时与需要的人分享学习,对于DMA的作用、定义之类的在这不进行阐述,有需要者参考中文手册。
为方便对比学习,我分三部分分享我在正点原子f429板子上写的关于DMA的程序,从官方历程到扩展使用分别为: 1、由内存向串口(外设)DMA传输; 2、由ADC采集数据(内存)向内存DMA传输; 3、定时器下ADC采集向内存双缓冲DMA传输; 本文只对第一部分进行讲解。
如何配置
要实现串口(外设)DMA传输需要四部配置 1)使能 DMA2 时钟。 2) 初始化 DMA参数。 3)使能串口 的 DMA 发送 4)使能 DMA 数据流 ,启动传输。 配置过程官方历程讲的已经非常清晰了这里我把代码粘一下,各行都有注释
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);
}
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发送
}
其中对于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 类似,所以推荐使用。
各参数含义及配置细节
对于DMA配置的各个参数出代码注释以为需要注意的还有: 1) DAM_Handal.Init.Direction = DMA_MEMORY_TO_PERIPH; dma传输方向 有自己写的字符串传输到串口方向是内存到外设,初学者学习不要直接搬用参数而不知道什么意思就直接搬用。 2) DAM_Handal.Init.PeriphInc = DMA_PINC_DISABLE; 用于设置外设地址是否使能递增,即每完成一次传输,外设地址自增,增加的大小由参数PeriphDataAlignment (外设数据宽度)决定,也就是说如果你只用了一个外设,那么就不能使能递增,否者使能,很明显这里只用了一个串口传输。 3)成员MemInc 用于设置存储器地址是否使能递增,即每完成一次传输,存储器地址自增,增加的大小由参数 MemDataAlignment 决定,与2)类似。 4)成员 PeriphDataAlignment 用于设置外设支持的数据宽度,可以选择字节,半字和字进行传输。 5)成员MemDataAlignment 用于设置存储器支持的数据宽度,可以选择字节,半字和字进行传输。 6)成员Mode 用于设置正常模式、循环模式和流控制,Normal 正常模式 适合用于单次传输,比如存储器到存储器的数据复制粘贴,又比如串口的数据单次发送,下次还需要 发送的时候,使能下即可。 Circular 循环模式 适合用于需要连续传输的场合,比如定时器触发BDMA实现任意 IO 的 PWM输出。特别注意,循环模式不可用于存储器到存储器模式。 另外需要注意的还有传输源地址和目的地址的数据宽度可以不同,但是数据地址必须要跟其数据类型对齐 比如源地址是uint32 类型的,那么此数组的地址必须 4 字节对齐。
在函数HAL_DMA_Start 和HAL_UART_Transmit_DMA 进行传输时,参数是一样的,各参数分别为UART_HandleTypeDef结构的指针指定配置信息,pData: 目的缓冲区地址,Length: 传输数据长度,在这是内存传输到外设的数据长度。
中断标志 ? DMA_FLAG_TCIFx 传输完成标志。 ? DMA_FLAG_HTIFx 半传输完成标志。 ? DMA_FLAG_TEIFx 传输错误标志。 ? DMA_FLAG_DMEIFx 直接模式错误标志。 ? DMA_FLAG_FEIFx FIFO错误标志。 需要注意的是DMA_FLAG_FEIF0_4,表示DMA1或者DMA2的Stream0和Stream4的标志,而不是Stream0 到 Stream4,同理 1 和 5 就是 Srteam1 和 Stream5
|