DMA简介
- 工作功能:实现外设与存储器/存储器与存储器之间的数据传输
- 工作资源:DMA1(7个通道)DMA2(5个通道)
- CT86资源:DMA1
- 存储地址:
| 类型 | 起始地址 | 存储器 | 用途 |
|---|---|---|---|
| ROM | 0x08000000 | 程序存储器Flash | 存储C语言编译后的程序代码 |
| ROM | 0x1FFFF000 | 系统存储器 | 存储BootLoader,用于串口下载 |
| ROM | 0x1FFF8000 | 选项字节 | 存储一些独立于程序代码的配置参数 |
| RAM | 0x20000000 | 运行内存SRAM | 存储运行过程中的临时变量 |
| RAM | 0x40000000 | 外设寄存器 | 存储各个外设的配置参数 |
| RAM | 0xE0000000 | 内核外设寄存器 | 存储内核各个外设的配置参数 |
- 配置步骤:
- 开启RCC时钟
- 配置DMA
- 双方的地址/数据宽度/是否自增(不增,数据一直存在一个位置,数据会覆盖)
- 传输方向:由谁向谁传输
- 缓存区大小
- 是否循环,配合ADC
- 选择传输类型:存储器到存储器/外设到存储器
- 也可以配置外部中断
- 使能DMA
- 配置代码:
//使能RCC-DMA1
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
/*配置DMA
*1.外设基地址
*2.外设数据宽度
*3.使能外设数据自增
*1.内存基地址
*2.内存数据宽度
*3.内存地址自增
*传输方向
*缓存区大小
*非循环模式
*存储器到存储器传输
*中等优先级
*/
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 = DMA_BufferSize;
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
DMA_InitStructure.DMA_M2M = DMA_M2M_Enable;
DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;
//初始化DMA
DMA_Init(DMA1_Channel1, &DMA_InitStructure);
//使能DMA
DMA_Cmd(DMA1_Channel1, ENABLE);- ADC+DMA配置代码:
/*
* 1. 使能时钟
* - 使能ADC1时钟
* - 使能GPIOA时钟(PA0-PA3作为模拟输入)
* - 使能DMA1时钟(用于数据传输)
*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
/*
* 2. 配置GPIO
* - PA0-PA3配置为模拟输入模式
* - 用于ADC通道0-3的信号输入
*/
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_InitStructure.GPIO_Pin =
GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/*
* 3. 配置DMA通道1
* - 外设基地址:ADC1数据寄存器
* - 数据宽度:16位(HalfWord)
* - 外设地址:固定
* - 内存地址:ADC_ConvertedValue缓冲区
* - 内存地址:自增
* - 传输方向:外设作为数据源
* - 缓冲区大小:4个通道
* - 模式:循环模式
* - 优先级:高
*/
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)ADC_ConvertedValue;
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_High;
DMA_Init(DMA1_Channel1, &DMA_InitStructure);
/*
* 4. 使能DMA通道1
*/
DMA_Cmd(DMA1_Channel1, ENABLE);
/*
* 5. 配置ADC1
* - ADC时钟分频:PCLK2/6
* - 规则通道配置:通道0-3,采样时间55.5周期
* - 工作模式:独立模式,右对齐,无外部触发
* - 转换模式:连续转换,扫描模式
* - 通道数量:4个
*/
RCC_ADCCLKConfig(RCC_PCLK2_Div6);
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_3, 4, ADC_SampleTime_55Cycles5);
ADC_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);
/*
* 6. 使能ADC1的DMA请求
*/
ADC_DMACmd(ADC1, ENABLE);
/*
* 7. 使能ADC1
*/
ADC_Cmd(ADC1, ENABLE);
/*
* 8. ADC校准
* - 重置校准寄存器
* - 等待重置完成
* - 开始校准
* - 等待校准完成
*/
ADC_ResetCalibration(ADC1);
while (ADC_GetResetCalibrationStatus(ADC1) == SET);
ADC_StartCalibration(ADC1);
while (ADC_GetCalibrationStatus(ADC1) == SET);
/*
* 9. 启动ADC转换
*/
ADC_SoftwareStartConvCmd(ADC1, ENABLE);