当前位置:首页 > 单片机 > 单片机
[导读] 一、前言DMA会在不同的寄存器/ram/存储设备之间建立通道,自动传输数据,以达到解放CPU的目的。比如你想用DAC模块去输出一段特定的波形,就要让CPU将预设的数值不断写入DAC的寄存器。这时CPU被DAC任务长

一、前言

DMA会在不同的寄存器/ram/存储设备之间建立通道,自动传输数据,以达到解放CPU的目的。

比如你想用DAC模块去输出一段特定的波形,就要让CPU将预设的数值不断写入DAC的寄存器。这时CPU被DAC任务长期占用,系统处理其他任务和响应其他事件的能力被大幅降低。

在实际应用里,经常有一些繁重的读写操作。这些操作不需要经过计算,却依然占用了大量的CPU资源,遇到这种情况就要考虑使用DMA了。

我开发板上的stm芯片上共有7个dma通道,它可以建立7个DMA连接。但是DMA控制器只有一个,所以同时只能有一个DMA连接被相应。

二、DMA的初始化

针对每一个DMA频道,都要初始化它的控制寄存器,来看一下DMA的init结构体的原型:

/**

* @brief DMA Configuration Structure definition

*/

typedef struct

{

uint32_t Direction; /*!< Specifies if the data will be transferred from memory to peripheral,

from memory to memory or from peripheral to memory.

This parameter can be a value of @ref DMA_Data_transfer_direction */


uint32_t PeriphInc; /*!< Specifies whether the Peripheral address register should be incremented or not.

This parameter can be a value of @ref DMA_Peripheral_incremented_mode */


uint32_t MemInc; /*!< Specifies whether the memory address register should be incremented or not.

This parameter can be a value of @ref DMA_Memory_incremented_mode */


uint32_t PeriphDataAlignment; /*!< Specifies the Peripheral data width.

This parameter can be a value of @ref DMA_Peripheral_data_size */


uint32_t MemDataAlignment; /*!< Specifies the Memory data width.

This parameter can be a value of @ref DMA_Memory_data_size */


uint32_t Mode; /*!< Specifies the operation mode of the DMAy Channelx.

This parameter can be a value of @ref DMA_mode

@note The circular buffer mode cannot be used if the memory-to-memory

data transfer is configured on the selected Channel */


uint32_t Priority; /*!< Specifies the software priority for the DMAy Channelx.

This parameter can be a value of @ref DMA_Priority_level */


} DMA_InitTypeDef;

  • Direction的值表示通道类型,外设到ram、ram到外设、ram到ram。

  • PeriphInc和MemInc表示外设和ram地址要不要递增。像上述的DAC例子,ram的地址一定是递增的,而外设寄存器的地址则无需递增。

  • PeriphDataAlignment和MemDataAlignment表示外设和ram的字节宽度,有一个字节,半字和全字。这将决定上面的增量模式里,一次读取数据的大小。

  • Mode有两种,普通和循环。普通模式下一次DMA请求处理完成后就不再传输数据。

  • Priority是DMA频道的优先级,一共4个,如果优先级相同,频道号小的通道率先被响应。

这些属性被设置完毕后,在Init函数里会将它写入控制寄存器。


/* Get the CR register value */

tmp = hdma->Instance->CCR;


/* Clear PL, MSIZE, PSIZE, MINC, PINC, CIRC, DIR bits */

tmp &= ((uint32_t)~(DMA_CCR_PL | DMA_CCR_MSIZE | DMA_CCR_PSIZE |

DMA_CCR_MINC | DMA_CCR_PINC | DMA_CCR_CIRC |

DMA_CCR_DIR));


/* Prepare the DMA Channel configuration */

tmp |= hdma->Init.Direction |

hdma->Init.PeriphInc | hdma->Init.MemInc |

hdma->Init.PeriphDataAlignment | hdma->Init.MemDataAlignment |

hdma->Init.Mode | hdma->Init.Priority;


/* Write to DMA Channel CR register */

hdma->Instance->CCR = tmp;


三、DMA通道的建立

在初始化完毕后,只需要将源地址、起始地址、传输总长写入寄存器,再使能该频道即可。

HAL_StatusTypeDef HAL_DMA_Start (DMA_HandleTypeDef *hdma, uint32_t SrcAddress, uint32_t DstAddress, uint32_t DataLength);

HAL_StatusTypeDef HAL_DMA_Start_IT(DMA_HandleTypeDef *hdma, uint32_t SrcAddress, uint32_t DstAddress, uint32_t DataLength);

这个DMA_HandleTypeDef *hdma是用C实现面向对象设计的一个典型的例子。当我们创建一个DMA频道时,必须要先建立一个DMA_HandleTypeDef类型的结构体变量,这个行为实际上就是创建了一个DMA类的实例。

typedef struct __DMA_HandleTypeDef

{

DMA_Channel_TypeDef *Instance; /*!< Register base address */


DMA_InitTypeDef Init; /*!< DMA communication parameters */


HAL_LockTypeDef Lock; /*!< DMA locking object */


HAL_DMA_StateTypeDef State; /*!< DMA transfer state */


void *Parent; /*!< Parent object state */


void (* XferCpltCallback)( struct __DMA_HandleTypeDef * hdma); /*!< DMA transfer complete callback */


void (* XferHalfCpltCallback)( struct __DMA_HandleTypeDef * hdma); /*!< DMA Half transfer complete callback */


void (* XferErrorCallback)( struct __DMA_HandleTypeDef * hdma); /*!< DMA transfer error callback */


__IO uint32_t ErrorCode; /*!< DMA Error code */


} DMA_HandleTypeDef;

这个结构体除了包含有init结构体、锁、DMA寄存器指针、状态变量、错误变量之外,还包含了一些callback函数的指针。它甚至有一个父类指针,只要将该指针指向一些adc、uart等外设的handle类,就等于完成了继承。


除了有init和start函数外、HAL里还提供常规的DMA中断处理函数,等待DMA传输,获取DMA状态的一些函数,结构上与前面的adc、flash等类似,就不做叙述了。


四、例子


来看一个串口用dma收发的例子。

首先是写收发两个频道的控制寄存器:

/*##-3- Configure the DMA ########

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

从我们的直观感受来说,DMA并不是一个复杂的东西,要做的事情也很单纯直白。因此Linux kernel对它的抽象和实现,也应该简洁、易懂才是。不过现实却不甚乐观(个人感觉),Linux kernel dmaengine...

关键字: Linux dma

  吉利dma项目进展   为进一步扩大市场份额和开拓大客户市场,吉利汽车拟在梅山岛新建整车生产工业园,本项目总用地面积约1888亩,项目位于宁波市北仑区东南海滨的梅山岛。地块北侧为七星

关键字: dma 吉利

  吉利品牌包含BMA乘用车在内的三大项目此前已宣布落户成都,预计整车总产能将达60万台。近日网通社从成都市发改委获悉,吉利正推进成都BMA/PMA、宁波梅山DMA基地建设项目,未来将投产多款吉

关键字: dma 吉利

什么是8位微控制器STM8L050?它有什么作用?2019年1月16日 - 意法半导体推出了全新的8位微控制器STM8L050的推出,以提升低成本、低功耗8位微控制器(MCU)的功能集成度。作为超高能效的STM8L系列的...

关键字: dma MCU stm8l050

这是一篇指导驱动工程师如何使用DMA API的文档。

关键字: CPU dma

本文从计算机组成原理的层面详细介绍了DMA,以及Linux网络子系统的DMA机制是如何实现的。

关键字: dma Linux 编程

你知道嵌入式驱动程序关于设计层面的技术吗?无论学习什么都有需要掌握的要点与窍门,本文我们一起深入了解关于嵌入式驱动程序关于设计层面的窍门。每一个嵌入式应用软件都会在某些时候访问最底层的固件和进行一些硬件控制。 驱动的设计...

关键字: dma 嵌入式设计 usart驱动程序

今天,我将带您了解Linux内存管理。 对于精通CURD的学生,内存管理似乎离我们还很远,但是尽管这一知识点并不热门(据估计,很多人在学习后不会再使用它),但这无疑是基础。 虽然学完后没有看到即时的效果,但是它将对您将来...

关键字: dma Linux zone
关闭
关闭