编程要点
1-初始化DMA初始化结构体。
2-熟读参考手册DMA章节(非常重要)
M To M 编程要点
1-在FLASH中定义好要传输的数据,在SRAM中定
义好用来接收FLASH数据的变量。
2-初始化DMA,主要是配置DMA初始化结构体。
3-编写比较函数。
4-编写main函数。
bsp_dma_mtm.c:
#include "bsp_dma_mtm.h"/* 定义aSRC_Const_Buffer数组作为DMA传输数据源* const关键字将aSRC_Const_Buffer数组变量定义为常量类型* 表示数据存储在内部的FLASH中*/
const uint32_t aSRC_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};
/* 定义DMA传输目标存储器* 存储在内部的SRAM中 */
uint32_t aDST_Buffer[BUFFER_SIZE];//typedef struct
//{
// uint32_t DMA_PeripheralBaseAddr; // 外设地址
// uint32_t DMA_MemoryBaseAddr; // 存储器地址
// 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_M2M; // 存储器到存储器模式
//}DMA_InitTypeDef;void MtM_DMA_Config(void) //配置DMA
{DMA_InitTypeDef DMA_InitStruct;RCC_AHBPeriphClockCmd(MTM_DMA_CLK, ENABLE); //开DMA1时钟DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)aSRC_Const_Buffer; //外设即数组FLASH地址DMA_InitStruct.DMA_MemoryBaseAddr = (uint32_t)aDST_Buffer; //存储器即内部SRAM地址DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralSRC; //方向P2MDMA_InitStruct.DMA_BufferSize = BUFFER_SIZE; //一次传输32个DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Enable; //发送数组,地址要增加DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word; //数据宽度-字DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable; //地址递增DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_Word; //也是字DMA_InitStruct.DMA_Mode = DMA_Mode_Normal; //模式:传一次DMA_InitStruct.DMA_Priority = DMA_Priority_High; //高优先级DMA_InitStruct.DMA_M2M = DMA_M2M_Enable; //M2M使能DMA_Init(MTM_DMA_CHANNEL, &DMA_InitStruct); //初始化 &取地址DMA_ClearFlag(MTM_DMA_FLAG_TC); //清楚标志位DMA_Cmd(MTM_DMA_CHANNEL, ENABLE); //使能DMA
}/** 比较函数* 判断指定长度的两个数据源是否完全相等,* 如果完全相等返回1,只要其中一对数据不相等返回0*/
uint8_t Buffercmp(const uint32_t* pBuffer, uint32_t* pBuffer1, uint16_t BufferLength)
{/* 数据长度递减 */while(BufferLength--){/* 判断两个数据源是否对应相等 */if(*pBuffer != *pBuffer1){/* 对应数据源不相等马上退出函数,并返回0 */return 0;}/* 递增两个数据源的地址指针 */pBuffer++;pBuffer1++;}/* 完成判断并且对应数据相对 */return 1;
}
bsp_dma_mtm.h:
#ifndef __BSP_DMA_MTM_H
#define __BSP_DMA_MTM_H#include "stm32f10x.h"// 要发送的数据大小
#define BUFFER_SIZE 32#define MTM_DMA_CLK RCC_AHBPeriph_DMA1
#define MTM_DMA_CHANNEL DMA1_Channel6
#define MTM_DMA_FLAG_TC DMA1_FLAG_TC6void MtM_DMA_Config(void);
uint8_t Buffercmp(const uint32_t* pBuffer, uint32_t* pBuffer1, uint16_t BufferLength);#endif /* __BSP_DMA_MTM_H */
main.c:
#include "stm32f10x.h"
#include "bsp_led.h"
#include "bsp_dma_mtm.h"extern const uint32_t aSRC_Const_Buffer[BUFFER_SIZE];
extern uint32_t aDST_Buffer[BUFFER_SIZE];#define SOFT_DELAY Delay(0x0FFFFF);void Delay(__IO u32 nCount); int main(void)
{ uint8_t status=0;/* LED 端口初始化 */LED_GPIO_Config();LED_YELLOW; //黄灯等待Delay(0xFFFFFF); //初始化延迟MtM_DMA_Config(); //DMA配置while( DMA_GetFlagStatus(MTM_DMA_FLAG_TC) == RESET ); //检查标志位 //传输是否完成status = Buffercmp(aSRC_Const_Buffer,aDST_Buffer,BUFFER_SIZE);if( status == 0 ){LED_RED; //红灯失败}else{LED_GREEN; //绿灯成功}while (1){}
}void Delay(__IO uint32_t nCount) //简单的延时函数
{for(; nCount != 0; nCount--);
}
M To P 编程要点
1-初始化串口(从现有的例程移植过来)
2-配置DMA初始化结构体。
3-编写主函数(开启串口发送DMA请求)。
bsp_dma_mtp.c:
#include "bsp_dma_mtp.h"uint8_t SendBuff[SENDBUFF_SIZE];/*** @brief USART GPIO 配置,工作参数配置* @param 无* @retval 无*/
void USART_Config(void) //配置串口
{GPIO_InitTypeDef GPIO_InitStructure;USART_InitTypeDef USART_InitStructure;// 打开串口GPIO的时钟DEBUG_USART_GPIO_APBxClkCmd(DEBUG_USART_GPIO_CLK, ENABLE);// 打开串口外设的时钟DEBUG_USART_APBxClkCmd(DEBUG_USART_CLK, ENABLE);// 将USART Tx的GPIO配置为推挽复用模式GPIO_InitStructure.GPIO_Pin = DEBUG_USART_TX_GPIO_PIN;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(DEBUG_USART_TX_GPIO_PORT, &GPIO_InitStructure);// 将USART Rx的GPIO配置为浮空输入模式GPIO_InitStructure.GPIO_Pin = DEBUG_USART_RX_GPIO_PIN;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;GPIO_Init(DEBUG_USART_RX_GPIO_PORT, &GPIO_InitStructure);// 配置串口的工作参数// 配置波特率USART_InitStructure.USART_BaudRate = DEBUG_USART_BAUDRATE;// 配置 针数据字长USART_InitStructure.USART_WordLength = USART_WordLength_8b;// 配置停止位USART_InitStructure.USART_StopBits = USART_StopBits_1;// 配置校验位USART_InitStructure.USART_Parity = USART_Parity_No ;// 配置硬件流控制USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;// 配置工作模式,收发一起USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;// 完成串口的初始化配置USART_Init(DEBUG_USARTx, &USART_InitStructure); // 使能串口USART_Cmd(DEBUG_USARTx, ENABLE);
}///重定向c库函数printf到串口,重定向后可使用printf函数
int fputc(int ch, FILE *f)
{/* 发送一个字节数据到串口 */USART_SendData(DEBUG_USARTx, (uint8_t) ch);/* 等待发送完毕 */while (USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_TXE) == RESET); return (ch);
}// Memory -> P (USART->DR) 发到串口DR寄存器配置
void USARTx_DMA_Config(void)
{DMA_InitTypeDef DMA_InitStruct;RCC_AHBPeriphClockCmd(USART_TX_DMA_CLK, ENABLE); //开时钟DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)USART_DR_ADDRESS; //串口地址DMA_InitStruct.DMA_MemoryBaseAddr = (uint32_t)SendBuff;DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralDST;DMA_InitStruct.DMA_BufferSize = SENDBUFF_SIZE;DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //地址不用增加DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; //字节单位DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;DMA_InitStruct.DMA_MemoryDataSize = DMA_PeripheralDataSize_Byte;DMA_InitStruct.DMA_Mode = DMA_Mode_Normal; //一次DMA_InitStruct.DMA_Priority = DMA_Priority_High;DMA_InitStruct.DMA_M2M = DMA_M2M_Disable; //no m2mDMA_Init(USART_TX_DMA_CHANNEL, &DMA_InitStruct);DMA_ClearFlag(USART_TX_DMA_FLAG_TC); //清除标志位DMA_Cmd(USART_TX_DMA_CHANNEL, ENABLE);
}
bsp_dma_mtp.h:
#ifndef __BSP_DMA_MTP_H
#define __BSP_DMA_MTP_H#include "stm32f10x.h"
#include <stdio.h>// 串口工作参数宏定义
#define DEBUG_USARTx USART1
#define DEBUG_USART_CLK RCC_APB2Periph_USART1
#define DEBUG_USART_APBxClkCmd RCC_APB2PeriphClockCmd
#define DEBUG_USART_BAUDRATE 115200// USART GPIO 引脚宏定义
#define DEBUG_USART_GPIO_CLK (RCC_APB2Periph_GPIOA)
#define DEBUG_USART_GPIO_APBxClkCmd RCC_APB2PeriphClockCmd#define DEBUG_USART_TX_GPIO_PORT GPIOA
#define DEBUG_USART_TX_GPIO_PIN GPIO_Pin_9
#define DEBUG_USART_RX_GPIO_PORT GPIOA
#define DEBUG_USART_RX_GPIO_PIN GPIO_Pin_10#define USART_TX_DMA_CLK RCC_AHBPeriph_DMA1
#define USART_TX_DMA_CHANNEL DMA1_Channel4
#define USART_TX_DMA_FLAG_TC DMA1_FLAG_TC4
#define USART_DR_ADDRESS (USART1_BASE+0x04)#define SENDBUFF_SIZE 5000 //发送5000个void USARTx_DMA_Config(void);
void USART_Config(void);
#endif /* __BSP_DMA_MTP_H */
main.c:
#include "stm32f10x.h"
#include "bsp_led.h"
#include "bsp_dma_mtp.h"extern uint8_t SendBuff[SENDBUFF_SIZE];#define SOFT_DELAY Delay(0x0FFFFF);void Delay(__IO u32 nCount); /*** @brief 主函数* @param 无 * @retval 无*/
int main(void)
{ uint16_t i=0;/* LED 端口初始化 */LED_GPIO_Config();USART_Config(); //配置串口for(i=0; i<SENDBUFF_SIZE; i++){SendBuff[i] = 'P'; //初始化成字符 P}USARTx_DMA_Config(); //配置DMA //在这一步,DMA等待串口请求USART_DMACmd(DEBUG_USARTx, USART_DMAReq_Tx, ENABLE); //串口请求发送while (1){LED1_TOGGLEDelay(0xFFFFF); }
}void Delay(__IO uint32_t nCount) //简单的延时函数
{for(; nCount != 0; nCount--);
}