1.间接
DMA:Direct Memory Access,直接存储访问,实现数据在外设与存储器或存储器之间高速访问,数据移动过程无需CPU操作控制,因此可以大大解放CPU负担。
外设(ADC、SPI、I2C、DCMI等外设的数据寄存器),存储器(片内SRAM、外部存储器、片内Flash等等)。外设到存储器,例如将AD转换的数据转移到所定义的存储区中。存储器到外设多用于外设的发送通信,例如串口不定长数据的输入输出。
STM32F7xx系列有2个DMA控制器,每个控制器具有8个数据流(stream),每个数据流有8个通道(channel),对应如下:
每个外设请求占用一个数据流通道,相同外设请求可以占用不同数据流通道。数据流的传输依靠仲裁器进行管理和判断,包括软件(例如初始化中mydma2.Init.Priority=DMA_PRIORITY_MEDIUM)和硬件(数据流编号越低,优先权越高)。DMA传输有FIFO模式和直接模式,直接模式在每个外设请求时立即启动对存储器传输,FIFO模式为源数据传输到目标地址前将数据临时存放在FIFO(先进先出存储器缓冲区)中。FIFO模式对于要求源地址和目标地址数据宽度不同时很有用,同时可用于突发传输。
存储器到存储器传输必须使用DMA2,但对数据流编号和通道没有硬性要求。
DMA2的存储器端口和外设端口都连接到AHB,但DMA的存储区端口没有AHB2外设的访问权,同时外设端口只连接到APB1外设,所以DMA1不能实现存储器到存储器传输。
2.DMA相关函数解析
关于DMA,ST官方提供了HAL库(封装函数)和LL库(直接操作寄存器)。和GPIO定义类似,需要先使能相关时钟,定义句柄结构体DMA_HandleTypeDef mydma2,随后进行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 (* 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;
typedef struct
{
uint32_t Channel; //通道
uint32_t Direction; //方向
uint32_t PeriphInc; //外设递增
uint32_t MemInc; //内存递增
uint32_t PeriphDataAlignment; //外设数据宽度
uint32_t MemDataAlignment; //内存数据宽度
uint32_t Mode; //模式选择
uint32_t Priority; //优先级
uint32_t FIFOMode; //FIFO模式
uint32_t FIFOThreshold; //FIFO阈值
uint32_t MemBurst; //内存突发传输
uint32_t PeriphBurst; //外设突发传输
}DMA_InitTypeDef;
3.DMA初始化及配置
HAL库中,基本上都是结合XXX_HandleTypeDef 结构体和XXX_InitTypeDef 结构体进行初始化配置。
#include "dma.h"
#include "stm32f7xx_hal.h"
uint32_t DMA_Result;
DMA_HandleTypeDef Mydma1;
void MyDMA_Config(void){
__HAL_RCC_DMA2_CLK_ENABLE(); //时钟使能
Mydma1.Instance=DMA2_Stream0; //数据流
Mydma1.Init.Channel=DMA_CHANNEL_0; //通道
Mydma1.Init.Direction=DMA_PERIPH_TO_MEMORY; //传输方向
Mydma1.Init.PeriphInc=DMA_PINC_DISABLE; //外设是否递增
Mydma1.Init.MemInc=DMA_MINC_DISABLE; //内存是否递增
Mydma1.Init.PeriphDataAlignment=DMA_PDATAALIGN_HALFWORD; //外设数据宽度半个字节
Mydma1.Init.MemDataAlignment=DMA_MDATAALIGN_HALFWORD; //内存数据宽度半个字节
Mydma1.Init.Mode=DMA_CIRCULAR; //循环模式
Mydma1.Init.Priority=DMA_PRIORITY_MEDIUM; //优先级中等
Mydma1.Init.FIFOMode=DMA_FIFOMODE_DISABLE; //是否使能FIFO模式
Mydma1.Init.PeriphBurst=DMA_PBURST_SINGLE; //外设突发传输
Mydma1.Init.MemBurst=DMA_MBURST_SINGLE; //内存突发传输
HAL_DMA_Init(&Mydma1); //初始化
HAL_DMA_Start(&Mydma1,ADC1_BASE,DMA_Result,2400); //启动DMA
}
随后还需进行相关外设的配置:如串口,AD采样等。
4.DMA中断
中断配置,中断函数调用,回调函数覆盖。
上一篇:12-HAL库串口通信总结
下一篇:14-HAL库之I2C通信
推荐阅读最新更新时间:2024-11-11 02:35