怎么用大淘客做网站,多媒体展厅的互动展示,长沙公众号开发公司,山东省建设工程质量安全协会网站目录 一、DMA简介
二、DMA实现过程
1.框图编辑
2.DMA的处理过程 3.DMA仲裁器
4.DMA通道 5.DMA寄存器
1DMA中断状态寄存器(DMA_ISR)
2DMA中断标志清除寄存器(DMA_IFCR)
3DMA通道x配置寄存器(DMA_CCRx)(x 1…7)
4DMA通道x传输数量寄存器(DMA_CNDTRx)(x 1…7)
5D…目录 一、DMA简介
二、DMA实现过程
1.框图编辑
2.DMA的处理过程 3.DMA仲裁器
4.DMA通道 5.DMA寄存器
1DMA中断状态寄存器(DMA_ISR)
2DMA中断标志清除寄存器(DMA_IFCR)
3DMA通道x配置寄存器(DMA_CCRx)(x 1…7)
4DMA通道x传输数量寄存器(DMA_CNDTRx)(x 1…7)
5DMA通道x存储器地址寄存器(DMA_CMARx)(x 1…7)
6DMA通道x外设地址寄存器(DMA_CPARx)(x 1…7) 6.DMA配置结构图
三、库函数使用 一、DMA简介
直接存储器存取(DMA)用来提供在外设和存储器之间或者存储器和存储器之间的高速数据传输。无须CPU干预数据可以通过DMA快速地移动这就节省了CPU的资源来做其他操作。两个DMA控制器有12个通道(DMA1有7个通道 DMA2有5个通道)每个通道专门用来管理来自于一个或多个外设对存储器访问的请求。还有一个仲裁器来协调各个DMA请求的优先权。
最大传输量是65535因为DMA_CNTR寄存器是16位有效的 1 DMA2仅存在于大容量产品和互联型产品。 2 SPI/I2S3、 UART4、 TIM5、 TIM6、 TIM7和DAC的DMA请求仅存在于大容量产品和互联型产品。 3 ADC3、 SDIO和TIM8的DMA请求仅存在于大容量产品 二、DMA实现过程
1.框图 由上图可知DMA是AHB上的SRAMFLASH外设都能申请DMA传输DMA有多个通道 2.DMA的处理过程
在发生一个事件后外设向DMA控制器发送DMA请求DMA根据通道优先级处理请求。当DMA开始访问发送请求的外设是会给外设一个应答外设得到应答后就会立刻释放请求与此同时DMA撤销应答信号以便于处理下一个请求开始下一个DMA传输。
总之每次DMA传送由三个操作组成 1.从外设数据寄存器或者从我们指示的地址取数据第一次开始地址是DMA_CPARx或 DMA_CMARx寄存器指定的外设基地址或存储器单元。 2.存数据到外设数据寄存器或者当前外设/存储器地址寄存器指示的存储器地址第一次传输 时的开始地址是DMA_CPARx或DMA_CMARx寄存器指定的外设基地址或存储器单元。 3.执行一次DMA_CNDTRx寄存器的递减操作该寄存器包含未完成的操作数目。 3.DMA仲裁器
仲裁器顾名思义就是在众多请求中选择一个最合适的。
DMA仲裁器依靠着通道的请求优先级来选择优先级又分为软件和硬件优先级
硬件优先级看排序例如通道1通道2
软件优先级分为最高高中等低 四个优先级在DMA_CCRx寄存器中配置 注意在大容量产品和互联型产品中 DMA1控制器拥有高于DMA2控制器的优先级 4.DMA通道 DMA1有7个通道可以实现P-M,M-P,M-M DMA2有5个通道可以实现P-M,M-P,M-M只存在大容量或者互联型 P:外设 M:闪存(flash,只读 存储器)、 SRAM M-M时所有的通道都能使用 下图是各个外设的DMA通道具体配置在下面讲解寄存器和库函数时进行 5.DMA寄存器
1DMA中断状态寄存器(DMA_ISR) TEIF是传输错误标志位HEIF是通道的半传输标志位TCIF是通道x的传输完成标志位 这三个都是在事件发生时会由硬件自动置1表示事件发生我们可以通过DMA_IFCR寄存器相应位写入1来消除这些标志位 GIF是通道x的全局中断标志位当上面三个事件发生其中一个时就会被硬件自动置1也是写入MDA_IFCR寄存器相应位为1来清除 2DMA中断标志清除寄存器(DMA_IFCR) CTEIFx清除通道x的传输错误标志 CHTIFx清除通道x的半传输标志 CTCIFx清除通道x的传输完成标志 CGIFx 清除通道x的全局中断标志 均是写入1清除标志位 3DMA通道x配置寄存器(DMA_CCRx)(x 1…7) EN使能位 TCIEHTIETEIE都是中断使能位给1使能 DIR用来配置数据传输方向即从哪读取数据0外设1存储器 CIRC配置循环模式就是进行完一次DMA传输之后是否继续进行下一次的传输 PINCMINC配置地址增量模式即传输和存储的地址是否需要递增例如我们使用 M- M模式自己定义了两个数组那么两个数组的地址都需要自动递增 才能实现对应存储。若我们使用的是数据寄存器因为数据寄存器只有一 个地址所以不递增 PSIZEMSIZE数据宽度有81632位 少传多高位补零多传少舍弃高位 PL设置通道优先级 MEM2MEM选择是M-M,还是P-M,M-P 以上这些都可以用库函数进行直接配置 4DMA通道x传输数量寄存器(DMA_CNDTRx)(x 1…7) 5DMA通道x存储器地址寄存器(DMA_CMARx)(x 1…7)
6DMA通道x外设地址寄存器(DMA_CPARx)(x 1…7) 6.DMA配置结构图 传输计数器递减减到零后自增的地址就会返回到起始地址。写入传输计数器的时候 必须先关闭使能DMA再写入--DMA_CNDTRx 自动重装器是否恢复传输计数器的最初的值即是否循环转运数据自减每传输一个 就自减一直到减到0表示传输完成 软件触发以最快的速度连续不断的转运数据一般用于存储器到存储器的转运一般不 与循环模式同时使用 硬件触发一般是外设这些转运需要一定的时机比如ADC转换完成串口收到数据 定时时间…… 开关控制DMA_Cmd函数 数据宽度少传多高位补零多传少舍弃高位 三、库函数使用
#include bsp_dma.h//const使变量存放在flash中非易失性存储器
const uint32_t aSRC_Const_Buffer[BUFFER_SIZE] { 0x12345678,0x12345677,0x11111111,0x32165478,0x22554433,0x22335544,0x33554488,0x22333111,0x54646546};//原始数据-Source //stm32的变量存放在内部SRAM中易失性存储器
uint32_t aDST_Buffer[BUFFER_SIZE]; void MtM_DMA_Config()
{DMA_RCC(DMA1_CLK,ENABLE);//开启AHB时钟DMA_InitTypeDef DMA_InitStruct;DMA_InitStruct.DMA_PeripheralBaseAddr (uint32_t)aSRC_Const_Buffer;//外设基地址数组本质上可以看作指针我们需要给他强制类型转换为32位的地址 DMA_InitStruct.DMA_MemoryBaseAddr (uint32_t)aDST_Buffer;//存储器基地址DMA_InitStruct.DMA_DIR DMA_DIR_PeripheralSRC;//外设当作Source即传输方向为外设到寄存器DMA_InitStruct.DMA_BufferSize BUFFER_SIZE;//传输的数据个数DMA_InitStruct.DMA_PeripheralInc DMA_PeripheralInc_Enable;//外设地址递增DMA_InitStruct.DMA_MemoryInc DMA_MemoryInc_Enable;//存储器地址递增DMA_InitStruct.DMA_PeripheralDataSize DMA_PeripheralDataSize_Word;//以一个字节接收DMA_InitStruct.DMA_MemoryDataSize DMA_MemoryDataSize_Word;//以一个字节发送DMA_InitStruct.DMA_Mode DMA_Mode_Normal;//不循环模式DMA_InitStruct.DMA_Priority DMA_Priority_VeryHigh;//配置优先级DMA_InitStruct.DMA_M2M DMA_M2M_Enable;//使能M-MDMA_Init(DMA1_Channel1,DMA_InitStruct);DMA_ClearFlag(DMA1_FLAG_TC1);//可以先清除传输完成标志位以避免其他错误DMA_Cmd(DMA1_Channel1,ENABLE);
}
#ifndef __BSP_DMA_H
#define __BSP_DMA_H#include stm32f10x.h#define BUFFER_SIZE 9#define DMA_RCC RCC_AHBPeriphClockCmd
#define DMA1_CLK RCC_AHBPeriph_DMA1
#define DMA2_CLK RCC_AHBPeriph_DMA2extern uint32_t aDST_Buffer[BUFFER_SIZE];
extern const uint32_t aSRC_Const_Buffer[BUFFER_SIZE];
void MtM_DMA_Config(void);
uint8_t Buffercmp(const uint32_t *Tra,uint32_t *Rec,uint32_t Num);#endif 为了检测是否传输的数据正确可以进行判断 uint8_t Buffercmp(const uint32_t *Tra,uint32_t *Rec,uint32_t Num)
{while(Num--){if(*Tra ! *Rec){return 10;}Tra;Rec;}return 255;
} 补充一点