这里会显示出您选择的修订版和当前版本之间的差别。
两侧同时换到之前的修订记录 前一修订版 后一修订版 | 前一修订版 | ||
icore3_arm_hal_14 [2020/03/28 15:59] zgf |
icore3_arm_hal_14 [2022/03/18 15:06] (当前版本) sean |
||
---|---|---|---|
行 3: | 行 3: | ||
|技术支持电话|**0379-69926675-801**||| | |技术支持电话|**0379-69926675-801**||| | ||
|技术支持邮件|Gingko@vip.163.com||| | |技术支持邮件|Gingko@vip.163.com||| | ||
- | |技术论坛|http://www.eeschool.org||| | ||
^ 版本 ^ 日期 ^ 作者 ^ 修改内容 ^ | ^ 版本 ^ 日期 ^ 作者 ^ 修改内容 ^ | ||
| V1.0 | 2020-03-28 | gingko | 初次建立 | | | V1.0 | 2020-03-28 | gingko | 初次建立 | | ||
\\ | \\ | ||
\\ | \\ | ||
- | \\ | ||
- | |||
===== STM32CubeMX教程十四——DMA实验 ===== | ===== STM32CubeMX教程十四——DMA实验 ===== | ||
行 74: | 行 71: | ||
* DMA,全称为"Direct Memory Access",即直接存储器访问,是一种不经过CPU而直接从内存存取数据的数据交换模式。在DMA模式下,CPU只须向DMA控制器下达指令,让DMA控制器来处理数据的传送,数据传送完毕再把信息反馈给CPU,这样在很大程度上减轻了CPU资源占有率,可以极大地节省系统资源。DMA模式又可以分为Single-Word DMA(单字节DMA)和Multi-Word DMA(多字节DMA)两种。 | * DMA,全称为"Direct Memory Access",即直接存储器访问,是一种不经过CPU而直接从内存存取数据的数据交换模式。在DMA模式下,CPU只须向DMA控制器下达指令,让DMA控制器来处理数据的传送,数据传送完毕再把信息反馈给CPU,这样在很大程度上减轻了CPU资源占有率,可以极大地节省系统资源。DMA模式又可以分为Single-Word DMA(单字节DMA)和Multi-Word DMA(多字节DMA)两种。 | ||
* **DMA工作原理** | * **DMA工作原理** | ||
- | * DMA 允许不同速度的硬件装置来沟通,而不需要依于 CPU 的大量中断负载。否则,CPU 需要从来源把每一片段的资料复制到暂存器,然后把他们再次写回到新的地方。在这个时间中,CPU 对于其他的工作来说就无法使用。 | + | * DMA 允许不同速度的硬件装置来沟通,而不需要依于 CPU 的大量中断负载。否则,CPU 需要从来源把每一片段的资料复制到暂存器,然后把他们再次写回到新的地方。在这个时间中,CPU 对于其他的工作来说就无法使用。 |
- | * DMA 传输主要地将一个内存区从一个装置复制到另外一个。当 CPU 初始化这个传输动作,传输动作本身是由 DMA 控制器来实行和完成。典型的例子就是移动一个外部内存的区块到芯片内部更快的内存去。像是这样的操作并没有让处理器工作拖延,反而可以被重新排程去处理其他的工作。所以,DMA传输对于高效能嵌入式系统算法和网络是很重要的。 | + | * DMA 传输主要地将一个内存区从一个装置复制到另外一个。当 CPU 初始化这个传输动作,传输动作本身是由 DMA 控制器来实行和完成。典型的例子就是移动一个外部内存的区块到芯片内部更快的内存去。像是这样的操作并没有让处理器工作拖延,反而可以被重新排程去处理其他的工作。所以,DMA传输对于高效能嵌入式系统算法和网络是很重要的。 |
* **DMA类别** | * **DMA类别** | ||
* 按键主要有两种类型:单字节DMA、多字节DMA。 | * 按键主要有两种类型:单字节DMA、多字节DMA。 | ||
行 84: | 行 81: | ||
=== 1. 主函数 === | === 1. 主函数 === | ||
* 初始化之后,使用HAL_DMA_Start函数开启DMA;通过HAL_DMA_GET_FLAG函数判断DMA传输是否完成,待DMA传输完成后,判断DMA传输目标数据与DMA传输源数据是否一致,即dst_buffer数组中的内容与src_buffer数组中的内容是否相等。若不相等,则测试失败,红色LED闪烁;若相等,则测试成功,蓝色LED闪烁。 | * 初始化之后,使用HAL_DMA_Start函数开启DMA;通过HAL_DMA_GET_FLAG函数判断DMA传输是否完成,待DMA传输完成后,判断DMA传输目标数据与DMA传输源数据是否一致,即dst_buffer数组中的内容与src_buffer数组中的内容是否相等。若不相等,则测试失败,红色LED闪烁;若相等,则测试成功,蓝色LED闪烁。 | ||
- | + | <code c> | |
+ | int main(void) | ||
+ | { | ||
+ | HAL_Init(); | ||
+ | SystemClock_Config(); | ||
+ | MX_GPIO_Init(); //GPIO初始化 | ||
+ | MX_DMA_Init(); //DMA初始化 | ||
+ | dma2.initialize(); | ||
+ | |||
+ | HAL_DMA_Start(&hdma_memtomem_dma2_stream0,(unsigned long int)src_buffer,(unsigned long int)dst_buffer,(unsigned | ||
+ | long int)BUFFER_SIZE); | ||
+ | //等待DMA传输完成 | ||
+ | while(__HAL_DMA_GET_FLAG(&hdma_memtomem_dma2_stream0,DMA_FLAG_TCIF0_4) == SET); | ||
+ | |||
+ | for(i = 0;i < BUFFER_SIZE;i++){ | ||
+ | if(dst_buffer[i] != src_buffer[i]){ | ||
+ | while(1){ //测试失败 | ||
+ | HAL_Delay(500); | ||
+ | LED_RED_ON; | ||
+ | HAL_Delay(500); | ||
+ | LED_RED_OFF; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | while (1) //测试成功 | ||
+ | { | ||
+ | HAL_Delay(500); | ||
+ | LED_BLUE_ON; | ||
+ | HAL_Delay(500); | ||
+ | LED_BLUE_OFF; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | </code> | ||
* DMA外设基地址:在此定义src_buffer数组作为DMA传输数据源,const 关键字将src_buffer数组变量定义为常量类型,表示数据存储在内部FLASH中。 | * DMA外设基地址:在此定义src_buffer数组作为DMA传输数据源,const 关键字将src_buffer数组变量定义为常量类型,表示数据存储在内部FLASH中。 | ||
* DMA存储器地址:在此定义dst_buffer数组作为DMA传输目标存储器,存储在内部SDAM中。 | * DMA存储器地址:在此定义dst_buffer数组作为DMA传输目标存储器,存储在内部SDAM中。 | ||
- | + | <code c> | |
+ | //DMA外设基地址 | ||
+ | //定义src_buffer数组作为DMA传输数据源 | ||
+ | //const 关键字将src_buffer数组变量定义为常量类型,表示数据存储在内部FLASH中 | ||
+ | const unsigned long int src_buffer[BUFFER_SIZE] = | ||
+ | 0x01020304,0x05060708,0x090A0B0C,0x0D0E0F10, | ||
+ | 0x11121314,0x15161718,0x191A1B1C,0x1D1E1F20, | ||
+ | 0x21222324,0x25262728,0x292A2B2C,0x2D2E2F30, | ||
+ | 0x31323334,0x35363738,0x393A3B3C,0x3D3E3F40, | ||
+ | 0x41424344,0x45464748,0x494A4B4C,0x4D4E4F50, | ||
+ | 0x51525354,0x55565758,0x595A5B5C,0x5D5E5F60, | ||
+ | 0x61626364,0x65666768,0x696A6B6C,0x6D6E6F70, | ||
+ | 0x71727374,0x75767778,0x797A7B7C,0x7D7E7F80}; | ||
+ | //DMA存储器地址 | ||
+ | //定义dst_buffer数组作为DMA传输目标存储器,存储在内部SDAM中 | ||
+ | unsigned long int dst_buffer[BUFFER_SIZE] = {0}; | ||
+ | </code> | ||
=== 2. DMA相关结构体定义 === | === 2. DMA相关结构体定义 === | ||
+ | <code c> | ||
+ | DMA_HandleTypeDef hdma_memtomem_dma2_stream0; | ||
+ | </code> | ||
+ | * DMA的名称定义,这个结构体中存放了DMA所有用到的功能,后面的别名hdma_memtomem_dma2_stream0就是我们所用的DMA的别名,在此采用DMA2控制器的数据流0,选用通道0进行数据传输。 | ||
+ | <code c> | ||
+ | typedef struct __DMA_HandleTypeDef | ||
+ | { | ||
+ | DMA_Stream_TypeDef *Instance; | ||
+ | //DMA寄存器基地址 | ||
+ | DMA_InitTypeDef Init; //DMA通信参数 | ||
+ | HAL_LockTypeDef Lock; //DMA锁定参数 | ||
+ | __IO HAL_DMA_StateTypeDef State; | ||
+ | void *Parent; | ||
+ | void (* XferCpltCallback)( struct __DMA_HandleTypeDef * hdma); | ||
+ | void (* XferHalfCpltCallback)( struct __DMA_HandleTypeDef * hdma); | ||
+ | void (* XferM1CpltCallback)( struct __DMA_HandleTypeDef * hdma); | ||
+ | void (* XferM1HalfCpltCallback)( struct __DMA_HandleTypeDef * hdma); | ||
+ | void (* XferErrorCallback)( struct __DMA_HandleTypeDef * hdma); | ||
+ | void (* XferAbortCallback)( struct __DMA_HandleTypeDef * hdma); | ||
+ | __IO uint32_t ErrorCode; | ||
+ | uint32_t StreamBaseAddress; | ||
+ | uint32_t StreamIndex; | ||
+ | }DMA_HandleTypeDef; | ||
- | + | </code> | |
- | * DMA的名称定义,这个结构体中存放了DMA所有用到的功能,后面的别名 | + | |
- | * hdma_memtomem_dma2_stream0就是我们所用的DMA的别名,在此采用DMA2控制器的数据流0,选用通道0进行数据传输。 | + | |
* 上述DMA_HandleTypeDef包含了指向寄存器的指针、互斥锁、一个描述状态的变量、一个保存错误代码的变量、指向DMA结构体的指针等。所有对DMA进行操作的函数都使用这个结构体的指针作为参数。 | * 上述DMA_HandleTypeDef包含了指向寄存器的指针、互斥锁、一个描述状态的变量、一个保存错误代码的变量、指向DMA结构体的指针等。所有对DMA进行操作的函数都使用这个结构体的指针作为参数。 | ||
- | + | <code c> | |
+ | typedef struct | ||
+ | { | ||
+ | uint32_t DMA_Channel; //选择通道 | ||
+ | uint32_t DMA_PeripheralBaseAddr; //DMA外设基地址 | ||
+ | uint32_t DMA_Memory0BaseAddr; //DMA存储器地址 | ||
+ | uint32_t DMA_DIR; //DMA传输方向 | ||
+ | uint32_t DMA_BufferSize; //数据传输量 | ||
+ | uint32_t DMA_PeripheralInc; //外设增量模式选择 | ||
+ | uint32_t DMA_MemoryInc; //存储器增量模式 | ||
+ | uint32_t DMA_PeripheralDataSize; //设置外设数据宽度 | ||
+ | uint32_t DMA_MemoryDataSize; //设置存储器数据宽度 | ||
+ | uint32_t DMA_Mode; //运行模式选择 | ||
+ | uint32_t DMA_Priority; //优先级选择 | ||
+ | uint32_t DMA_FIFOMode; //FIFO模式选择 | ||
+ | uint32_t DMA_FIFOThreshold; //FIFO阀值 | ||
+ | uint32_t DMA_MemoryBurst; //存储器突发传输 | ||
+ | uint32_t DMA_PeripheralBurst; //外设突发传输 | ||
+ | }DMA_InitTypeDef; | ||
+ | |||
+ | </code> | ||
* DMA_Channel: DMA 请求通道选择,可选通道 0 至通道 7,每个外设对应固定的通道。 | * DMA_Channel: DMA 请求通道选择,可选通道 0 至通道 7,每个外设对应固定的通道。 | ||
* DMA_PeripheralBaseAddr:外设地址,一般设置为外设的数据寄存器地址,如果是存储器到存储器模式,则设置为其中一个存储区地址。 | * DMA_PeripheralBaseAddr:外设地址,一般设置为外设的数据寄存器地址,如果是存储器到存储器模式,则设置为其中一个存储区地址。 | ||
行 106: | 行 193: | ||
* DMA_PeripheralBurst:外设突发模式选择,可选单次模式、 4 节拍的增量突发模式、 8 节拍的增量突发模式或 16 节拍的增量突发模式。 | * DMA_PeripheralBurst:外设突发模式选择,可选单次模式、 4 节拍的增量突发模式、 8 节拍的增量突发模式或 16 节拍的增量突发模式。 | ||
=== 3. DMA相关函数 === | === 3. DMA相关函数 === | ||
- | * HAL_DMA_Start();开启DMA传输 | + | * HAL_DMA_Start();开启DMA传输。 |
- | * __HAL_DMA_GET_FLAG();获取DMA传输标志位 | + | * _HAL_DMA_GET_FLAG();获取DMA传输标志位 |
- | * __HAL_DMA_CLEAR_FLAG();清除DMA传输完成标志 | + | * _HAL_DMA_CLEAR_FLAG();清除DMA传输完成标志 |
- | * __HAL_DMA_GET_COUNTER();得到当前还剩余多少数据 | + | * _HAL_DMA_GET_COUNTER();得到当前还剩余多少数据 |
* DMA开始传输 | * DMA开始传输 | ||
<code c> | <code c> | ||
+ | HAL_StatusTypeDef HAL_DMA_Start(DMA_HandleTypeDef *hdma, uint32_t SrcAddress, uint32_t DstAddress, uint32_t DataLength) | ||
</code> | </code> | ||
* 参数: | * 参数: | ||
行 120: | 行 207: | ||
* uint32_t DataLength 发送的数据长度 | * uint32_t DataLength 发送的数据长度 | ||
* DMA获取传输标志位 | * DMA获取传输标志位 | ||
+ | |||
<code c> | <code c> | ||
+ | __HAL_DMA_GET_FLAG(&hdma_memtomem_dma2_stream0,DMA_FLAG_TCIF0_4) | ||
</code> | </code> | ||
* 参数: | * 参数: |