这里会显示出您选择的修订版和当前版本之间的差别。
两侧同时换到之前的修订记录 前一修订版 后一修订版 | 前一修订版 上一修订版 两侧同时换到之后的修订记录 | ||
dma实验_存储器到存储器的传输 [2020/07/04 14:28] zgf |
dma实验_存储器到存储器的传输 [2020/07/04 14:39] zgf [二、 实验设备及平台] |
||
---|---|---|---|
行 1: | 行 1: | ||
+ | |||
+ | | **银杏科技有限公司旗下技术文档发布平台** |||| | ||
+ | |技术支持电话|**0379-69926675-801**||| | ||
+ | |技术支持邮件|Gingko@vip.163.com||| | ||
+ | |技术论坛|http://www.eeschool.org||| | ||
+ | ^ 版本 ^ 日期 ^ 作者 ^ 修改内容 ^ | ||
+ | | V1.0 | 2020-07-04 | gingko | 初次建立 | | ||
+ | |||
===== 实验十一:DMA实验——存储器到存储器的传输 ===== | ===== 实验十一:DMA实验——存储器到存储器的传输 ===== | ||
行 9: | 行 17: | ||
- 掌握KEIL MDK 集成开发环境使用方法。 | - 掌握KEIL MDK 集成开发环境使用方法。 | ||
==== 二、 实验设备及平台 ==== | ==== 二、 实验设备及平台 ==== | ||
- | - iCore4 双核心板。 | + | - iCore4 双核心板[[https://item.taobao.com/item.htm?spm=a1z10.1-c-s.w4004-22598974120.15.5923532fsFrHiE&id=551864196684|点击购买]]。 |
- | - JLINK(或相同功能)仿真器。 | + | - JLINK(或相同功能)仿真器[[https://item.taobao.com/item.htm?id=554869837940|点击购买]]。 |
- Micro USB线缆。 | - Micro USB线缆。 | ||
- Keil MDK 开发平台。 | - Keil MDK 开发平台。 | ||
行 19: | 行 27: | ||
=== 1、DMA简介 === | === 1、DMA简介 === | ||
- | 直接存储器访问(DMA)用于在外设与存储器之间以及存储器与存储器之间提供高速数据传输。可以在无需任何CPU操作的情况下通过DMA快速移动数据。这样节省的CPU资源可供其它操作使用。DMA控制器基于复杂的总线矩阵架构,将功能强大的双AHB主总线架构与独立的FIFO结合在一起,优化了系统带宽。 | + | * 直接存储器访问(DMA)用于在外设与存储器之间以及存储器与存储器之间提供高速数据传输。可以在无需任何CPU操作的情况下通过DMA快速移动数据。这样节省的CPU资源可供其它操作使用。DMA控制器基于复杂的总线矩阵架构,将功能强大的双AHB主总线架构与独立的FIFO结合在一起,优化了系统带宽。 |
- | 两个DMA控制器总共有16个数据流(每个控制器8个),每一个DMA控制器都用于管理一个或多个外设的存储器访问请求。每个数据流总共可以有多达8个通道(或称请求)。每个通道都有一个仲裁器,用于处理DMA请求间的优先级。 | + | * 两个DMA控制器总共有16个数据流(每个控制器8个),每一个DMA控制器都用于管理一个或多个外设的存储器访问请求。每个数据流总共可以有多达8个通道(或称请求)。每个通道都有一个仲裁器,用于处理DMA请求间的优先级。 |
=== 2、DMA的主要特性 === | === 2、DMA的主要特性 === | ||
行 55: | 行 63: | ||
* DMA传输由给定数目的数据传输序列组成。要传输的数据项的数目及其宽度(8位、16位或32位)可用软件编程。每个DMA传输包含三项操作: | * DMA传输由给定数目的数据传输序列组成。要传输的数据项的数目及其宽度(8位、16位或32位)可用软件编程。每个DMA传输包含三项操作: | ||
- | * 通过DMA_SxPAR或DMA_SxM0AR寄存器寻址,从外设数据寄存器或存储器单元中加载数据 | + | * 通过DMA_SxPAR或DMA_SxM0AR寄存器寻址,从外设数据寄存器或存储器单元中加载数据 |
- | * 通过DMA_SxPAR或DMA_SxM0AR寄存器寻址,将加载的数据存储到外设数据寄存器或存储器单元 | + | * 通过DMA_SxPAR或DMA_SxM0AR寄存器寻址,将加载的数据存储到外设数据寄存器或存储器单元 |
- | * DMA_SxNDTR计数器在数据存储结束后递减,该计数器中包含仍需执行的事务数 | + | * DMA_SxNDTR计数器在数据存储结束后递减,该计数器中包含仍需执行的事务数 |
* 在产生事件后,外设会向DMA控制器发送请求信号。DMA控制器根据通道优先级处理该请求。只要DMA控制器访问外设,DMA控制器就会向外设发送确认信号。外设获得DMA控制器的确认信号后,便会立即释放其请求。一旦外设使请求失效,DMA控制器就会释放确认信号。如果有更多请求,外设可以启动下一个事务。 | * 在产生事件后,外设会向DMA控制器发送请求信号。DMA控制器根据通道优先级处理该请求。只要DMA控制器访问外设,DMA控制器就会向外设发送确认信号。外设获得DMA控制器的确认信号后,便会立即释放其请求。一旦外设使请求失效,DMA控制器就会释放确认信号。如果有更多请求,外设可以启动下一个事务。 | ||
* DMA (直接存储器访问)传输不需要占用CPU,可以在存储器至存储器实现高速的数据传输。本实验采用DMA2控制器的数据流0,选用通道0进行数据传输。通过LED的颜色来判断传输是否成功。 | * DMA (直接存储器访问)传输不需要占用CPU,可以在存储器至存储器实现高速的数据传输。本实验采用DMA2控制器的数据流0,选用通道0进行数据传输。通过LED的颜色来判断传输是否成功。 | ||
行 77: | 行 85: | ||
dma.initialize(); | dma.initialize(); | ||
//测试DMA,测试成功蓝色灯闪烁,测试失败,红色灯闪烁 | //测试DMA,测试成功蓝色灯闪烁,测试失败,红色灯闪烁 | ||
- | //初始化DMA2 | + | //初始化DMA2 |
hdma_memtomem_dma2_stream0.Instance = DMA2_Stream0; | hdma_memtomem_dma2_stream0.Instance = DMA2_Stream0; | ||
hdma_memtomem_dma2_stream0.Init.Channel = DMA_CHANNEL_0;//通道0 | hdma_memtomem_dma2_stream0.Init.Channel = DMA_CHANNEL_0;//通道0 | ||
hdma_memtomem_dma2_stream0.Init.Direction = DMA_MEMORY_TO_MEMORY; | hdma_memtomem_dma2_stream0.Init.Direction = DMA_MEMORY_TO_MEMORY; | ||
- | //传输方向,存储器到存储器 | + | //传输方向,存储器到存储器 |
hdma_memtomem_dma2_stream0.Init.PeriphInc = DMA_PINC_ENABLE; | hdma_memtomem_dma2_stream0.Init.PeriphInc = DMA_PINC_ENABLE; | ||
- | //外设增量模式 | + | //外设增量模式 |
hdma_memtomem_dma2_stream0.Init.MemInc = DMA_MINC_ENABLE;//存储器增量模式 | hdma_memtomem_dma2_stream0.Init.MemInc = DMA_MINC_ENABLE;//存储器增量模式 | ||
hdma_memtomem_dma2_stream0.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD; //外设数据大小 | hdma_memtomem_dma2_stream0.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD; //外设数据大小 | ||
hdma_memtomem_dma2_stream0.Init.Mode = DMA_NORMAL; //正常模式 | hdma_memtomem_dma2_stream0.Init.Mode = DMA_NORMAL; //正常模式 | ||
hdma_memtomem_dma2_stream0.Init.Priority = DMA_PRIORITY_HIGH; | hdma_memtomem_dma2_stream0.Init.Priority = DMA_PRIORITY_HIGH; | ||
- | //DMA优先级:高 | + | //DMA优先级:高 |
hdma_memtomem_dma2_stream0.Init.FIFOMode = DMA_FIFOMODE_ENABLE; | hdma_memtomem_dma2_stream0.Init.FIFOMode = DMA_FIFOMODE_ENABLE; | ||
- | //FIFO模式开启 | + | //FIFO模式开启 |
- | hdma_memtomem_dma2_stream0.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; //FIFO阈值完整配置 | + | hdma_memtomem_dma2_stream0.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; //FIFO阈值完整配置 |
hdma_memtomem_dma2_stream0.Init.MemBurst = DMA_MBURST_SINGLE; | hdma_memtomem_dma2_stream0.Init.MemBurst = DMA_MBURST_SINGLE; | ||
- | //存储器突发模式:单次传输 | + | //存储器突发模式:单次传输 |
hdma_memtomem_dma2_stream0.Init.PeriphBurst = DMA_PBURST_SINGLE; | hdma_memtomem_dma2_stream0.Init.PeriphBurst = DMA_PBURST_SINGLE; | ||
- | //外设触发模式:单次传输 | + | //外设触发模式:单次传输 |
if(HAL_DMA_Init(&hdma_memtomem_dma2_stream0) != HAL_OK) //初始化DMA | if(HAL_DMA_Init(&hdma_memtomem_dma2_stream0) != HAL_OK) //初始化DMA | ||
{ | { | ||
行 101: | 行 109: | ||
} | } | ||
/* 开始DMA传输 */ | /* 开始DMA传输 */ | ||
- | HAL_DMA_Start(&hdma_memtomem_dma2_stream0,(unsigned long int)src_buffer,(unsigned long int)dst_buffer,(unsigned long int)BUFFER_SIZE); | + | HAL_DMA_Start(&hdma_memtomem_dma2_stream0,(unsigned long int)src_buffer,(unsigned long int)dst_buffer,(unsigned |
+ | long int)BUFFER_SIZE); | ||
while(__HAL_DMA_GET_FLAG(&hdma_memtomem_dma2_stream0,DMA_FLAG_TCIF0_4) == SET); | while(__HAL_DMA_GET_FLAG(&hdma_memtomem_dma2_stream0,DMA_FLAG_TCIF0_4) == SET); | ||
for(i = 0;i < BUFFER_SIZE;i++){ | for(i = 0;i < BUFFER_SIZE;i++){ | ||
行 135: | 行 144: | ||
static int initialize(void) | static int initialize(void) | ||
{ | { | ||
- | __HAL_RCC_DMA2_CLK_ENABLE(); //使能时钟 | + | _HAL_RCC_DMA2_CLK_ENABLE(); //使能时钟 |
return 0; | return 0; | ||
} | } | ||
行 142: | 行 151: | ||
=== 3、DMA开始传输函数 === | === 3、DMA开始传输函数 === | ||
<code c> | <code c> | ||
- | HAL_StatusTypeDef HAL_DMA_Start(DMA_HandleTypeDef *hdma, uint32_t SrcAddress, uint32_t DstAddress, uint32_t DataLength) | + | HAL_StatusTypeDef HAL_DMA_Start(DMA_HandleTypeDef *hdma,uint32_t SrcAddress,uint32_t DstAddress,uint32_t DataLength) |
{ | { | ||
HAL_StatusTypeDef status = HAL_OK; | HAL_StatusTypeDef status = HAL_OK; | ||
assert_param(IS_DMA_BUFFER_SIZE(DataLength)); /* 检查参数 */ | assert_param(IS_DMA_BUFFER_SIZE(DataLength)); /* 检查参数 */ | ||
- | __HAL_LOCK(hdma); /* 进程锁定 */ | + | _HAL_LOCK(hdma); /* 进程锁定 */ |
- | if(HAL_DMA_STATE_READY == hdma->State) | + | if(HAL_DMA_STATE_READY == hdma->State) |
- | { | + | { |
- | hdma->State = HAL_DMA_STATE_BUSY; /* 更改DMA外设状态 */ | + | hdma->State = HAL_DMA_STATE_BUSY; /* 更改DMA外设状态 */ |
- | hdma->ErrorCode = HAL_DMA_ERROR_NONE; /* 初始化错误代码 */ | + | hdma->ErrorCode = HAL_DMA_ERROR_NONE; /* 初始化错误代码 */ |
/* 配置源,目标地址和数据长度 */ | /* 配置源,目标地址和数据长度 */ | ||
DMA_SetConfig(hdma, SrcAddress, DstAddress, DataLength); | DMA_SetConfig(hdma, SrcAddress, DstAddress, DataLength); | ||
- | __HAL_DMA_ENABLE(hdma); /* 使能外围设备 */ | + | _HAL_DMA_ENABLE(hdma); /* 使能外围设备 */ |
} | } | ||
else | else | ||
{ | { | ||
- | __HAL_UNLOCK(hdma); /* 进程解锁 */ | + | _HAL_UNLOCK(hdma); /* 进程解锁 */ |
status = HAL_BUSY; /* 返回错误状态 */ | status = HAL_BUSY; /* 返回错误状态 */ | ||
} | } | ||
行 168: | 行 177: | ||
* 在DMA传输过程中,我们要查询DMA传输通道的状态,使用的方法是: | * 在DMA传输过程中,我们要查询DMA传输通道的状态,使用的方法是: | ||
<code c> | <code c> | ||
- | __HAL_DMA_GET_FLAG(&hdma_memtomem_dma2_stream0,DMA_FLAG_TCIF0_4 | + | _HAL_DMA_GET_FLAG(&hdma_memtomem_dma2_stream0,DMA_FLAG_TCIF0_4 |
</code> | </code> | ||
* 主函数中即是通过此方法查询DMA传输通道的状态。 | * 主函数中即是通过此方法查询DMA传输通道的状态。 |