当前位置: 首页 > news >正文

嵌入式学习日志————DMA直接存储器存取

前言

本篇内容为理论+实验方面的知识,如有问题,望指正!!

正文

参考手册的第10章——DMA控制器,第二章存储器和总线架构(存储器的映射)

1.DMA简介

  • DMA(Direct Memory Access)直接存储器存取

  • DMA可以提供外设和存储器或者存储器和存储器之间的高速数据传输,无须CPU干预,节省了CPU的资源

  • 12个独立可配置的通道: DMA1(7个通道), DMA2(5个通道)

  • 每个通道都支持软件触发和特定的硬件触发

  • STM32F103C8T6 DMA资源:DMA1(7个通道)

2.存储器映像

ROM是只读存储器,是一种非易失性、掉电不丢失的存储器

RAM是随机存储器,是一种易失性、掉电丢失额存储器

3.DMA框图

4.DMA基本结构

Flash中的数据只能读不能写入,在STM32中,使用const定义的变量存储在Flash里

DMA进行转运,有以下条件:

  • 第一,开关控制,DMA_Cmd必须使能

  • 第二,传输计数器必须大于零

  • 第三,触发源必须有触发信号(软件/硬件触发)

5.DMA请求

6.数据宽度与对齐

  • 小数据转大数据—>在高位补零

  • 大数据转小数据—>舍弃高位,保留低位

  • 数据宽度一样—>正常转运

7.实例(对应两个实验)

(1)数据转运+DMA

(2)ADC扫描模式+DMA

8.实验

(1)DMA数据转运

①配置步骤
  • RCC开启DMA时钟

  • 调用DMA_Init,初始化各个参数(外设和存储器站点的起始地址、数据宽度、地址是否自增、方向、传输计数器、是否需要自动重装、选择触发源、通道优先级)

  • 开关控制,DMA_Cmd给指定的通道使能

  • 如果需要DMA的中断,那就调用DMA_ITConfig,开启中断输出,再在NVIC里配置相应的中断通道,然后写中断函数

  • 当传输计数器自减为零后,还想给它赋值,就DMA失能->写传输计数器->DMA使能

②库函数

初始化

void DMA_Init(DMA_Channel_TypeDef* DMAy_Channelx, DMA_InitTypeDef* DMA_InitStruct);

结构体初始化

void DMA_StructInit(DMA_InitTypeDef* DMA_InitStruct);

使能

void DMA_Cmd(DMA_Channel_TypeDef* DMAy_Channelx, FunctionalState NewState);

终端输出使能

void DMA_ITConfig(DMA_Channel_TypeDef* DMAy_Channelx, uint32_t DMA_IT, FunctionalState NewState);

DMA设置当前数据寄存器:给传输计数器写数据

void DMA_SetCurrDataCounter(DMA_Channel_TypeDef* DMAy_Channelx, uint16_t DataNumber);

DMA获取当前数据寄存器:返回传输计数器的值

uint16_t DMA_GetCurrDataCounter(DMA_Channel_TypeDef* DMAy_Channelx);

获取标志位状态、清除标志位、获取中断状态、清除中断挂起位

FlagStatus DMA_GetFlagStatus(uint32_t DMAy_FLAG);
void DMA_ClearFlag(uint32_t DMAy_FLAG);
ITStatus DMA_GetITStatus(uint32_t DMAy_IT);
void DMA_ClearITPendingBit(uint32_t DMAy_IT);
③代码
main.c
#include "stm32f10x.h"                  // Device header
#include "delay.h"
#include "OLED.h"
#include "MyDMA.h"uint8_t DataA[] = {0x01,0x02,0x03,0x04};
uint8_t DataB[] = {0,0,0,0};int main( void)
{OLED_Init();MyDMA_Init((uint32_t)DataA,(uint32_t)DataB,4);OLED_ShowString(1,1,"DataA");OLED_ShowString(3,1,"DataB");OLED_ShowHexNum(1,8,(uint32_t)DataA,8);OLED_ShowHexNum(3,8,(uint32_t)DataB,8);OLED_ShowHexNum(2,1,DataA[0],2);OLED_ShowHexNum(2,4,DataA[1],2);OLED_ShowHexNum(2,7,DataA[2],2);OLED_ShowHexNum(2,10,DataA[3],2);OLED_ShowHexNum(4,1,DataB[0],2);OLED_ShowHexNum(4,4,DataB[1],2);OLED_ShowHexNum(4,7,DataB[2],2);OLED_ShowHexNum(4,10,DataB[3],2);while(1){DataA[0]++;DataA[1]++;DataA[2]++;DataA[3]++;OLED_ShowHexNum(2,1,DataA[0],2);OLED_ShowHexNum(2,4,DataA[1],2);OLED_ShowHexNum(2,7,DataA[2],2);OLED_ShowHexNum(2,10,DataA[3],2);OLED_ShowHexNum(4,1,DataB[0],2);OLED_ShowHexNum(4,4,DataB[1],2);OLED_ShowHexNum(4,7,DataB[2],2);OLED_ShowHexNum(4,10,DataB[3],2);Delay_ms(1000);MyDMA_Transfer();OLED_ShowHexNum(2,1,DataA[0],2);OLED_ShowHexNum(2,4,DataA[1],2);OLED_ShowHexNum(2,7,DataA[2],2);OLED_ShowHexNum(2,10,DataA[3],2);OLED_ShowHexNum(4,1,DataB[0],2);OLED_ShowHexNum(4,4,DataB[1],2);OLED_ShowHexNum(4,7,DataB[2],2);OLED_ShowHexNum(4,10,DataB[3],2);Delay_ms(1000);}	  
}    
MyDMA.c
#include "stm32f10x.h"uint16_t MyDMA_Size;void MyDMA_Init(uint32_t AddrA,uint32_t AddrB,uint16_t Size)
{MyDMA_Size =  Size;RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);	DMA_InitTypeDef DMA_InitStructure;DMA_InitStructure.DMA_PeripheralBaseAddr = AddrA;DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Enable;DMA_InitStructure.DMA_MemoryBaseAddr = AddrB;DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;DMA_InitStructure.DMA_BufferSize = Size;DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;DMA_InitStructure.DMA_M2M = DMA_M2M_Enable;DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;DMA_Init(DMA1_Channel1,&DMA_InitStructure);DMA_Cmd(DMA1_Channel1,DISABLE);
}void MyDMA_Transfer(void)
{DMA_Cmd(DMA1_Channel1,DISABLE);DMA_SetCurrDataCounter(DMA1_Channel1,MyDMA_Size);    DMA_Cmd(DMA1_Channel1,ENABLE);while (DMA_GetFlagStatus(DMA1_FLAG_TC1) == RESET);DMA_ClearFlag(DMA1_FLAG_TC1);
}
MyDMA.h
#ifndef __MYDMA_H
#define __MYDMA_Hvoid MyDMA_Init(uint32_t AddrA,uint32_t AddrB,uint16_t Size);
void MyDMA_Transfer(void);#endif

(2)DMA+AD多通道

开启DMA触发信号:连接ADC与DMA

void ADC_DMACmd(ADC_TypeDef* ADCx, FunctionalState NewState);
代码
main.c
#include "stm32f10x.h"                  // Device header
#include "delay.h"
#include "OLED.h"
#include "AD.h"int main(void)
{OLED_Init();AD_Init();OLED_ShowString(1,1,"AD0:");OLED_ShowString(2,1,"AD1:");OLED_ShowString(3,1,"AD2:");OLED_ShowString(4,1,"AD3:");while(1){OLED_ShowNum(1,5,AD_Value[0],4);OLED_ShowNum(2,5,AD_Value[1],4);OLED_ShowNum(3,5,AD_Value[2],4);OLED_ShowNum(4,5,AD_Value[3],4);Delay_ms(100);}	  
}    
AD.c
#include "stm32f10x.h"uint16_t AD_Value[4];void AD_Init(void)
{RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);RCC_ADCCLKConfig(RCC_PCLK2_Div6);GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA,&GPIO_InitStructure);ADC_RegularChannelConfig(ADC1,ADC_Channel_0,1,ADC_SampleTime_55Cycles5);ADC_RegularChannelConfig(ADC1,ADC_Channel_1,2,ADC_SampleTime_55Cycles5);ADC_RegularChannelConfig(ADC1,ADC_Channel_2,3,ADC_SampleTime_55Cycles5);ADC_RegularChannelConfig(ADC1,ADC_Channel_4,4,ADC_SampleTime_55Cycles5);//初始化ADCADC_InitTypeDef  ADC_InitStructure;ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;ADC_InitStructure.ADC_ScanConvMode = ENABLE;ADC_InitStructure.ADC_NbrOfChannel = 4;ADC_Init(ADC1,&ADC_InitStructure);DMA_InitTypeDef DMA_InitStructure;DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR;DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)AD_Value;DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;DMA_InitStructure.DMA_BufferSize = 4;DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;DMA_Init(DMA1_Channel1,&DMA_InitStructure);DMA_Cmd(DMA1_Channel1,ENABLE);ADC_DMACmd(ADC1,ENABLE);ADC_Cmd(ADC1,ENABLE);//对ADC进行校准ADC_ResetCalibration(ADC1);           //软件触发while (ADC_GetResetCalibrationStatus(ADC1)==SET);ADC_StartCalibration(ADC1);while (ADC_GetCalibrationStatus(ADC1)==SET);ADC_SoftwareStartConvCmd(ADC1,ENABLE);
}
AD.h
#ifndef __AD_H
#define __AD_Hextern uint16_t AD_Value[4];void AD_Init(void);#endif

距离返校还有7天!!!

http://www.dtcms.com/a/354292.html

相关文章:

  • 微信开发者工具中模拟调试现场扫描小程序二维码功能
  • Centos 7.6离线安装docker
  • 元宇宙+RWA:2025年虚拟资产与真实世界的金融融合实验
  • aiohttp模块如何使用
  • 开发避坑指南(39):Java List全null元素引发的空判断无效处理方案
  • 用LightRAG打造智能问答系统:知识图谱与RAG的融合应用实践
  • 如何在升级到S/4HANA后关闭SAP旧系统?
  • 3-4〔OSCP ◈ 研记〕❘ WEB应用攻击▸Burp Suite工具
  • MySQL中的InnoDB
  • pikachu-xss通关(1-8)
  • qt5+mingw64+opencv4.5.2搭建调试环境
  • FOC算法第二节 克拉克变换
  • mybatis-plus实现苍穹外卖项目-分类操作,不定期更新-day2
  • Hadoop(五)
  • AI、人工智能基础: 模型剪枝的概念与实践(PyTorch版)
  • uvloop深度实践:从原理到高性能异步应用实战
  • 死锁产生的条件是什么? 如何进行死锁诊断?
  • 本地部署DeepSeek大模型的基本方法
  • 自定义命令行补全机制的核心工具之compgen
  • web服务组件
  • MII的原理
  • 软件设计师备考-(三)操作系统基本原理
  • leetcode28. 找出字符串中第一个匹配项的下标
  • VR党建工作站-红色教育基地
  • 路由基础(三):静态路由、动态路由、默认路由
  • Linux系统 -- 线程(pthread)核心知识整理
  • 【golang长途旅行第33站】常量------补充知识点
  • 学习游戏制作记录(数据加密以及主菜单和画面优化)8.27
  • 运算电源抑制比(PSRR)测量及设计注意事项
  • 去哪里学AI?2025年AI培训机构推荐!