STM32L475裸机例程学习 DMA实验

DMA实验

此文章仅限于记录个人知识盲区,没有指导作用,如果有任何疑问,欢迎在评论区提问讨论~

DMA

DMA,全称为:Direct Memory Access,即直接存储器访问。DMA 传输方式无需 CPU 直接 控制传输,也没有中断处理方式那样保留现场和恢复现场的过程,通过硬件为 RAM 与 I/O 设备 开辟一条直接传送数据的通路,能使 CPU 的效率大为提高。

STM32L475 最多有 2 个 DMA 控制器(DMA1 和 DMA2) ,共 14 个通道(每个控制器 7 个), 每一个 DMA 控制器都用于管理一个或多个外设的存储器访问请求。每个通道总共可以有多达 7 个请求。每个数据流通道都有一个仲裁器,用于处理 DMA 请求间的优先级。

STM32L475 的 DMA 有以下一些特性:

● 单 AHB 主总线架构

● 支持外设到内存、内存到外设、内存到内存和外设到外设的数据传输

● 所有的 DMA 通道均可独立配置

● 每个通道产生一个中断请求,每个中断请求都是由三个DMA事件中的任何一个引起的: 传输完成、半传输完成和传输错误

STM32L475有两个DMA控制器,DMA1和DMA2

在这里插入图片描述

DMA 控制器执行直接存储器传输:因为采用 AHB 主总线,它可以控制 AHB 总线矩阵来 启动 AHB 事务。它可以执行下列事务:

  • 外设到存储器的传输
  • 存储器到外设的传输
  • 存储器到存储器的传输
DMA1和DMA2的通道以及Requst number一览

在这里插入图片描述
在这里插入图片描述

仲裁器

仲裁器根据通道请求的优先级来启动外设/存储器的访问。

优先权管理分2个阶段:

软件:每个通道的优先权可以在DMA_CCRx寄存器中设置,有4个等级:最高优先级、高优先级、中等优先级、低优先级;
硬件:如果2个请求有相同的软件优先级,则较低编号的通道比较高编号的通道有较高的优先权。比如:如果软件优先级相同,通道2优先于通道4。
注意: 在大容量产品和互联型产品中,DMA1控制器拥有高于DMA2控制器的优先级。

实验流程

1)使能 DMA1时钟。

  1. 初始化 DMA1 通道 4,包括配置通道,外设地址,存储器地址,传输数据量等。

3)使能串口 1 的 DMA 发送

4)使能 DMA1 通道 4,启动传输。

5)查询 DMA 传输状态

实验用到的函数

1)使能DMA1时钟

 __HAL_RCC_DMA1_CLK_ENABLE();

2)初始化 DMA1 通道 4,包括配置通道,外设地址,存储器地址,传输数据量等。

DMA_HandleTypeDef  UART1TxDMA_Handler;  //DMA 句柄 
UART1TxDMA_Handler.Instance= DMA1_Channel4; //数据流选择 
UART1TxDMA_Handler.Init.Request=DMA_REQUEST_2;   //通道选择 
UART1TxDMA_Handler.Init.Direction=DMA_MEMORY_TO_PERIPH; //存储器到外设 
UART1TxDMA_Handler.Init.PeriphInc=DMA_PINC_DISABLE;   //外设非增量模式 
UART1TxDMA_Handler.Init.MemInc=DMA_MINC_ENABLE;       //存储器增量模式 
UART1TxDMA_Handler.Init.PeriphDataAlignment=DMA_PDATAALIGN_BYTE;//外设:8 位 
UART1TxDMA_Handler.Init.MemDataAlignment=DMA_MDATAALIGN_BYTE; //存储器:8 位 
UART1TxDMA_Handler.Init.Mode=DMA_NORMAL;               //普通模式 
UART1TxDMA_Handler.Init.Priority=DMA_PRIORITY_MEDIUM;  //中等优先级 

HAL 库为了处理各类外设的 DMA 请求,在调用相关函数之前,需要调用一个宏定义标识符,来连接 DMA 和外设句柄。例如要使用串口 DMA 发送,所以方式为:

__HAL_LINKDMA(&UART1_Handler,hdmatx,UART1TxDMA_Handler); 

其中 UART1_Handler 是串口初始化句柄,我们在 usart.c 中定义过了。UART1TxDMA_Handler 是 DMA 初始化句柄。hdmatx 是外设句柄结构体的成员变量,在这里实际就是 UART1_Handler 的 成员变量。在 HAL 库中,任何一个可以使用 DMA 的外设,它的初始化结构体句柄都会有一个 DMA_HandleTypeDef 指针类型的成员变量,是 HAL 库用来做相关指向的。Hdmatx 就是 DMA_HandleTypeDef 结构体指针类型。 这句话的含义就是把 UART1_Handler 句柄的成员变量 hdmatx 和 DMA 句柄 UART1TxDMA_Handler 连接起来,是纯软件处理,没有任何硬件操作。

进入函数的definition可以看到

#define __HAL_LINKDMA(__HANDLE__, __PPP_DMA_FIELD__, __DMA_HANDLE__)             
do{                              
(__HANDLE__)->__PPP_DMA_FIELD__ = &(__DMA_HANDLE__); (__DMA_HANDLE__).Parent = (__HANDLE__);              
} while(0)

其中parent来自于DMA的成员变量

typedef struct __DMA_HandleTypeDef {   
DMA_Stream_TypeDef         *Instance;                 
DMA_InitTypeDef            Init;                     
HAL_LockTypeDef            Lock;                       
__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                       (* XferErrorCallback)(  struct __DMA_HandleTypeDef * hdma);       
__IO uint32_t               ErrorCode;                     
uint32_t                    StreamBaseAddress;         
uint32_t                    StreamIndex;               
 }DMA_HandleTypeDef; 
  • 成员变量 Instance 是用来设置寄存器基地址,例如要设置为 DMA2 的数据流 7,那么取值 为 DMA2_Stream7。

  • 成员变量 Parent 是 HAL 库处理中间变量,用来指向 DMA 通道外设句柄。

  • 成员变量 XferCpltCallback(传输完成回调函数), XferHalfCpltCallback(半传输完成 回调函数), XferM1CpltCallback(Memory1 传输完成回调函数)和 XferErrorCallback(传输 错误回调函数)是四个函数指针,用来指向回调函数入口地址。

  • 成员变量 StreamBaseAddress 和 StreamIndex 是数据流基地址和索引号,这个是 HAL 库处 理的时候会自动计算,用户无需设置。

所以该语句就是把HAL库处理中间变量指向DMA通道外设句柄: USART1,把DMA句柄指向USART1成员变量,即把两者联系起来。

3)使能串口 1 的 DMA 发送

HAL_DMA_Init(&hdma_usart1_tx)

4)使能 DMA1 通道 4,启动传输。

HAL_UART_Transmit_DMA(&UART1_Handler, (u8*)SendBuff, SEND_BUF_SIZE); //启动传输

这个函数比较好理解,第一个参数是 DMA 句柄,第二个是传输源地址,第三个是传输的数据长度。

5)查询 DMA 传输状态

在 DMA 传输过程中,我们要查询 DMA 传输通道的状态,使用的方法是:等待DMA传输完成,完成后清除FLAG

__HAL_DMA_GET_FLAG(&UART1TxDMA_Handler,DMA_FLAG_TC4);
__HAL_DMA_CLEAR_FLAG(&hdma_usart1_tx, DMA_FLAG_TC4);

获取当前传输剩余数据量:

__HAL_DMA_GET_COUNTER(&UART1TxDMA_Handler); 
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值