DMA(直接储存区访问,stm32f4xx):
DMA结构体
typedef struct
{
uint32_tDMA_Channel;
uint32_t DMA_PeripheralBaseAddr;
uint32_t DMA_Memory0BaseAddr;
uint32_t DMA_DIR;
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;
uint32_t DMA_FIFOThreshold;
uint32_t DMA_MemoryBurst;
uint32_t DMA_PeripheralBurst;}DMA_InitTypeDef;
DMA_Channel(DMA通道选择)
1)DMA_Channel_x,其中x为0~7
2)DMA_PeripheralBaseAddr;(DMA外设基地址)
3)DMA_Memory0BaseAddr (DMA内存基地址)
DMA_DIR;(传输方向选择)
1)DMA_DIR_PeripheralToMemory : P->M,外设到储存器
2)DMA_DIR_MemoryToPeripheral : M->P,储存器到外设
3)DMA_DIR_MemoryToMemory : M->M,储存器到储存器
DMA_BufferSize(传输数据数目)
DMA_PeripheralInc;(外设地址递增功能)
1)DMA_PeripheralInc_Enable(有递增功能)
2)DMA_PeripheralInc_Disable(无递增功能)
DMA_MemoryInc;(储存器地址递增功能)
1) DMA_MemoryInc_Enable(有递增功能)
2) DMA_MemoryInc_Disable(无递增功能)
DMA_PeripheralDataSize;(外设单个数据大小)
1) DMA_PeripheralDataSize_Byte(8位)
2) DMA_PeripheralDataSize_HalfWord(16位)
3) DMA_PeripheralDataSize_Word(32位)
DMA_MemoryDataSize;(储存器单个数据大小)
1)DMA_MemoryDataSize_Byte(8位)
2)DMA_MemoryDataSize_HalfWord (16位)
3)DMA_MemoryDataSize_Word (32位)
DMA_Mode(DMA传输模式选择)
1)DMA_Mode_Normal(一次传输)
2)DMA_Mode_Circular(循环传输)
DMA_Priority;(软件设置数据流优先级)
1) DMA_Priority_Low(低)
2) DMA_Priority_Medium(中等)
3) DMA_Priority_High(高)
4) DMA_Priority_VeryHigh(非常高)
DMA_FIFOMode;(FIFO模式使能)
1) DMA_FIFOMode_Disable(不使能FIFO)
2) DMA_FIFOMode_Enable(使能FIFO)
DMA_FIFOThreshold;(FIFO阈值选择,要在使能FIFO情况下才有效,四分之一为一个字即四个字节)
1) DMA_FIFOThreshold_1QuarterFull(四分之一)
2) DMA_FIFOThreshold_HalfFull(一半)
3) DMA_FIFOThreshold_3QuartersFull(四分之三)
4) DMA_FIFOThreshold_Full(满)
DMA_MemoryBurst;(储存器突发模式选择)
1) DMA_MemoryBurst_Single(单次模式)
2) DMA_MemoryBurst_INC4(4节拍的突发增量)
3) DMA_MemoryBurst_INC8(8节拍的突发增量)
4) DMA_MemoryBurst_INC16(16节拍的突发增量)
DMA_PeripheralBurst(外设突发选择模式)
1)DMA_PeripheralBurst_Single(单次模式)
2)DMA_PeripheralBurst_INC4(4节拍的突发增量)
3)DMA_PeripheralBurst_INC8(8节拍的突发增量)
4)DMA_PeripheralBurst_INC16(16节拍的突发增量)
两个储存器(FLASH和SRAM)的数据传输实验:
步骤:
1-在FLASH中定义好传输源,在SARM中定义好接收源
2-确定数据流和通道
3-初始化DMA,配置DMA结构体
4-编写比较函数,确定传输数据准确
5-编写main函数执行
例程:
#include "stm32f4xx.h"
#include "bsp_led.h"
/*=======================2-确定数据流和通道=================================================*/
#define DMA_STREAM DMA2_Stream0
#define DMA_CHANNEL DMA_Channel_0
#define DMA_STREAM_CLOCK RCC_AHB1Periph_DMA2
#define DMA_FLAG_TCIF DMA_FLAG_TCIF0
#define BUFFER_SIZE 32
#define TIMEOUT_MAX 10000
/*========================1-在FLASH中定义好传输源,在SARM中定义好接收源=========================*/
/*const表示常量,即定义在FLASH中*/
const uint32_taSRC_Const_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};
/* 定义变量,即在SARM中*/
uint32_t aDST_Buffer[BUFFER_SIZE];
/* 简单的延时函数 */
static void Delay(__IO uint32_t nCount)
{
for(;nCount != 0; nCount--);
}
/*========================3-初始化DMA,配置DMA结构体============================================*/
static void DMA_Config(void)
{
DMA_InitTypeDef DMA_InitStructure;
__IO uint32_t Timeout = TIMEOUT_MAX;
/* 使能DMA时钟 */
RCC_AHB1PeriphClockCmd(DMA_STREAM_CLOCK, ENABLE);
/* 复位初始化DMA数据流 */
DMA_DeInit(DMA_STREAM);
/* 确保DMA数据流复位完成 */
while (DMA_GetCmdStatus(DMA_STREAM) != DISABLE)
{
}
/* DMA数据流通道选择,通道0 */
DMA_InitStructure.DMA_Channel = DMA_CHANNEL;
/* 源数据地址 */
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)aSRC_Const_Buffer;
/* 目标地址 */
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)aDST_Buffer;
/* 存储器到存储器模式 */
DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToMemory;
/* 数据数目 */
DMA_InitStructure.DMA_BufferSize = (uint32_t)BUFFER_SIZE;
/* 使能自动递增功能 */
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Enable;
/* 使能自动递增功能 */
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
/* 源数据是字大小(32位) */
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;
/* 目标数据也是字大小(32位) */
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;
/* 一次传输模式,存储器到存储器模式不能使用循环传输 */
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
/* DMA数据流优先级为高 */
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
/* 禁用FIFO模式 */
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
/* 单次模式 */
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
/* 单次模式 */
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
/* 完成DMA数据流参数配置 */
DMA_Init(DMA_STREAM, &DMA_InitStructure);
/* 清除DMA数据流传输完成标志位 */
DMA_ClearFlag(DMA_STREAM,DMA_FLAG_TCIF);
/* 使能DMA数据流,开始DMA数据传输 */
DMA_Cmd(DMA_STREAM, ENABLE);
/* 检测DMA数据流是否有效并带有超时检测功能 */
Timeout = TIMEOUT_MAX;
while ((DMA_GetCmdStatus(DMA_STREAM) != ENABLE) && (Timeout--> 0))
{
}
/* 判断是否超时 */
if (Timeout == 0)
{
/* 超时就让程序运行下面循环:RGB彩色灯闪烁 */
while (1)
{
LED_RED;
Delay(0xFFFFFF);
LED_RGBOFF;
Delay(0xFFFFFF);
}
}
}
/*========================4-编写比较函数,确定传输数据准确==================================*/
uint8_t Buffercmp(const uint32_t*pBuffer,
uint32_t* pBuffer1, uint16_tBufferLength)
{
/* 数据长度递减 */
while(BufferLength--)
{
/* 判断两个数据源是否对应相等 */
if(*pBuffer != *pBuffer1)
{
/* 对应数据源不相等马上退出函数,并返回0 */
return 0;
}
/* 递增两个数据源的地址指针 */
pBuffer++;
pBuffer1++;
}
/* 完成判断并且对应数据相对 */
return 1;
}
/*========================5-编写main函数执行=================================================*/
int main(void)
{
/*定义存放比较函数比较结果变量 */
uint8_t TransferStatus;
/*LED 端口初始化 */
LED_GPIO_Config();
/*设置RGB彩色灯为紫色 */
LED_PURPLE;
/*简单延时函数*/
Delay(0xFFFFFF);
/*DMA传输配置*/
DMA_Config();
/*等待DMA传输完成 */
while(DMA_GetFlagStatus(DMA_STREAM,DMA_FLAG_TCIF)==DISABLE)
{
}
/*比较源数据与传输后数据 */
TransferStatus=Buffercmp(aSRC_Const_Buffer, aDST_Buffer, BUFFER_SIZE);
/* 判断源数据与传输后数据比较结果*/
if(TransferStatus==0)
{
/* 源数据与传输后数据不相等时RGB彩色灯显示红色 */
LED_RED;
}
else
{
/* 源数据与传输后数据相等时RGB彩色灯显示蓝色 */
LED_BLUE;
}
while(1)
{
}
}
储存器到外设(USART)的数据传输
1- 初始化USRAT
2- 初始化DMA
3- 配置传输数据
4- 编写主函数
例程:
uint8_t SendBuff[SENDBUFF_SIZE];
/*==================================1-初始化USART=====================================*/
void Debug_USART_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
RCC_AHB1PeriphClockCmd(DEBUG_USART_RX_GPIO_CLK|DEBUG_USART_TX_GPIO_CLK,ENABLE);
/* 使能 USART 时钟 */
RCC_APB2PeriphClockCmd(DEBUG_USART_CLK, ENABLE);
/* GPIO初始化 */
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
/* 配置Tx引脚为复用功能 */
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Pin = DEBUG_USART_TX_PIN ;
GPIO_Init(DEBUG_USART_TX_GPIO_PORT, &GPIO_InitStructure);
/* 配置Rx引脚为复用功能 */
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Pin = DEBUG_USART_RX_PIN;
GPIO_Init(DEBUG_USART_RX_GPIO_PORT, &GPIO_InitStructure);
/* 连接 PXx 到 USARTx_Tx*/
GPIO_PinAFConfig(DEBUG_USART_RX_GPIO_PORT,DEBUG_USART_RX_SOURCE,DEBUG_USART_RX_AF);
/* 连接 PXx 到USARTx__Rx*/
GPIO_PinAFConfig(DEBUG_USART_TX_GPIO_PORT,DEBUG_USART_TX_SOURCE,DEBUG_USART_TX_AF);
/* 配置串DEBUG_USART 模式 */
/* 波特率设置:DEBUG_USART_BAUDRATE */
USART_InitStructure.USART_BaudRate = DEBUG_USART_BAUDRATE;
/* 字长(数据位+校验位):8 */
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
/* 停止位:1个停止位 */
USART_InitStructure.USART_StopBits = USART_StopBits_1;
/* 校验位选择:不使用校验 */
USART_InitStructure.USART_Parity = USART_Parity_No;
/* 硬件流控制:不使用硬件流 */
USART_InitStructure.USART_HardwareFlowControl =USART_HardwareFlowControl_None;
/* USART模式控制:同时使能接收和发送 */
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
/* 完成USART初始化配置 */
USART_Init(DEBUG_USART, &USART_InitStructure);
/* 使能串口 */
USART_Cmd(DEBUG_USART, ENABLE);
}
/*==================================2-初始化DMA=====================================*/
void MtoP_DMA_Config(void)
{
DMA_InitTypeDefDMA_InitStructure;
/*开启DMA时钟*/
RCC_AHB1PeriphClockCmd(DEBUG_USART_DMA_CLK, ENABLE);
/* 复位初始化DMA数据流 */
DMA_DeInit(DEBUG_USART_DMA_STREAM);
/* 确保DMA数据流复位完成 */
while (DMA_GetCmdStatus(DEBUG_USART_DMA_STREAM) != DISABLE) {
}
/*usart1 tx对应dma2,通道4,数据流7*/
DMA_InitStructure.DMA_Channel = DEBUG_USART_DMA_CHANNEL;
/*设置DMA源:串口数据寄存器地址*/
DMA_InitStructure.DMA_PeripheralBaseAddr = DEBUG_USART_DR_BASE;
/*内存地址(要传输的变量的指针)*/
DMA_InitStructure.DMA_Memory0BaseAddr = (u32)SendBuff;
/*方向:从内存到外设*/
DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;
/*传输大小DMA_BufferSize=SENDBUFF_SIZE*/
DMA_InitStructure.DMA_BufferSize = SENDBUFF_SIZE;
/*外设地址不增*/
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
/*内存地址自增*/
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
/*外设数据单位*/
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
/*内存数据单位 8bit*/
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
/*DMA模式:不断循环*/
//DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
DMA_InitStructure.DMA_Mode= DMA_Mode_Normal;
/*优先级:中*/
DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;
/*禁用FIFO*/
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
/*存储器突发传输 单次传输*/
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
/*外设突发传输 单次传输*/
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
/*配置DMA2的数据流7*/
DMA_Init(DEBUG_USART_DMA_STREAM, &DMA_InitStructure);
/*使能DMA*/
DMA_Cmd(DEBUG_USART_DMA_STREAM, ENABLE);
/* 等待DMA数据流有效*/
while(DMA_GetCmdStatus(DEBUG_USART_DMA_STREAM) != ENABLE)
{
}
}
int main(void)
{
uint16_t i;
LED_GPIO_Config();
/*初始化USART 配置模式为 115200 8-N-1,中断接收*/
Debug_USART_Config();
/*==================================3-配置传输数据=====================================*/
for(i=0;i<SENDBUFF_SIZE;i++)
{
SendBuff[i] = 'A';
}
MtoP_DMA_Config();
USART_DMACmd(DEBUG_USART,USART_DMAReq_Tx, ENABLE);
while(1)
{
/*确定在数据传输时不占用CPU*/
LED1_TOGGLE
Delay(0xFFFFF);
}
}