STM32F4X DMA
- 什么是DMA
- STM32F4X DMA
- DMA框图
- DMA通道
- DMA仲裁器
- DMA FIFO
- DMA传输模式
- DMA传输方向
- 存储器到存储器
- 存储器到外设
- 外设到存储器
- DMA循环模式和普通模式
- 循环模式(Circular)
- 普通模式(Normal)
- DMA源、目标寄存器增量模式
- DMA例程
- 存储器到存储器例程
- 存储器到外设例程
- 外设到存储器例程
什么是DMA
DMA又叫直接存储器访问,用于在外设与存储器之间以及存储器与存储器之间提供高速数据传输。可以在无需任何CPU操作的情况下通过DMA快速移动数据。这样节省的CPU资源可供其它操作使用。
STM32F4X DMA
DMA框图
DMA通道
STM32F4X的每一个DMA控制器有8个数据流,每个数据流又有8个通道。每个通道都会对应相关的外设。
DMA仲裁器
虽然STM32F4X的DMA控制器有8个数据流,当有多个数据流产生请求时,DMA控制器每次只能处理一个数据流,这时就需要DMA仲裁器的帮忙了。仲裁器可以理解成是优先级选择器,顾名思义就是根据数据流的优先级来决定处理哪个通道。其优先级选择关系如下。
- 在相同优先级的情况下,数据流编号低的优先级高,数据流编号高的优先级低。就是STR0>STR1>STR2>STR3>STR4>STR5>STR6>STR7。
- 用户可以通过软件设置数据流的优先级,分别是低优先级、中等优先级、高优先级和非常高优先级。
DMA FIFO
FIFO 用于在源数据传输到目标之前临时存储这些数据,可以加快DMA的传输速度。在STM32F4X中每个DMA数据流都会有一个独立的4字FIFO,也就是16字节的FIFO。STM32F4X的DMA FIFO可以配置它的阀值,具体如下图所示。
上图描述了STM32F4X的DMA FIFO的阀值配置,看似很复杂,其实根据下面的例子就我们就可以知道其配置规则。
MSIZE:外设或存储器数据大小,用户可以配置成字节、半字或者字。
MBURST = INCR4: 每次传输4 * MSIZE的大小且FIFO必须是此乘积的整数倍
MBURST = INCR8: 每次传输8 * MSIZE的大小且FIFO必须是此乘积的整数倍
MBURST = INCR16: 每次传输16 * MSIZE的大小且FIFO必须是此乘积的整数倍
我们假设DMA的外设和存储器数据大小为半字,也就是2个字节,MSIZE就为2。MBURST设置为INCR4。
MSIZE = 2
MBURST = INCR4
此时传输的数据量就为MSIZE * 4 = 8字节,那么此时FIFO的阀值只能是8 * 1 = 8或者8 * 2 = 16,也就是阀值为二分之一或者是满。
上面就是FIFO的阀值配置的具体计算,我们也可以根据上面的表格进行配置。
DMA传输模式
DMA有两种传输模式,分别是突发传输和单次传输。突发传输需要跟FIFO结合使用,每次传输4 个、8 个和 16个节拍。单次传输就每次传输一个节拍数。
DMA传输方向
DMA一共有3种传输方向,分别是存储器到存储器,存储器到外设和外设到存储器。这3种传输方向都需要配置源寄存器和目标寄存器。如果把DMA比作是一条公路,那么源寄存器就是起点,目标寄存器就是终点。
存储器到存储器
存储器到存储器可以理解成就是MCU内部数据之间的搬运。
在此模式下,我们需要将源寄存器设置为需要发送数据的存储器地址,目标寄存器设置为需要接收数据的存储器地址。要注意的是使用存储器到存储器模式时,不允许循环模式和直接模式。只有 DMA2 控制器能够执行存储器到存储器的传输。
存储器到外设
存储器到外设一般用于将存储器的数据发送到外设,外设可以是串口的发送寄存器,SPI的发送寄存器等。
在此模式下,我们需要将源寄存器设置为需要发送数据的存储器地址,目标寄存器设置为需要接收数据的外设地址。
外设到存储器
外设到存储器一般用于将外设的数据发送到存储器,外设可以是串口的接收寄存器,SPI的接收寄存器等。
在此模式下,我们需要将源寄存器设置为需要发送数据的外设地址,目标寄存器设置为需要接收数据的存储器地址。
DMA循环模式和普通模式
循环模式(Circular)
- 在循环模式下,DMA的传输是循环进行,当DMA完成一次传输后会自动进入下一次传输,形成一个循环。
- 在循环模式下,DMA把源数据寄存器中的数据搬到目标数据寄存器,当传输条件完成后,自动进行下一次传输
- 循环模式适用于那些周期性数据传输的场景,比如ADC的采集,音视频数据流的传输等。
普通模式(Normal)
- 在普通模式下,DMA的传输只会执行一次,当DMA完成一次传输后就会停止。
- 在普通模式下,DMA会把源数据寄存器中的数据搬到目标数据寄存器,当传输条件完成后,就会停止。
- 普通模式适用于那些只传输一次数据的场景,比如初始化传感器等。
DMA源、目标寄存器增量模式
DMA的源和目标寄存器有两个增量模式,分别是递增和固定
- 递增模式:每一次数据传输之后,其地址指针会递增(增量为用户设置的数据大小)
- 固定模式::每一次数据传输之后,其地址指针不变。
DMA例程
存储器到存储器例程
dma.c
void bsp_dma_u8_init(DMA_Stream_TypeDef* DMAy_Streamx,u32 dam_channel,u8 *src,u8 *dst,u32 len)
{DMA_InitTypeDef DMA_InitStructure;RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2 | RCC_AHB1Periph_DMA1,ENABLE); DMA_InitStructure.DMA_Channel = dam_channel; //通道选择DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)src; //DMA外设地址DMA_InitStructure.DMA_Memory0BaseAddr = (u32)dst; //DMA 存储器0地址DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToMemory; //存储器到外设模式DMA_InitStructure.DMA_BufferSize = len; //数据传输量 DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Enable; //外设非增量模式DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //存储器增量模式DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; //外设数据长度:8位DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; //存储器数据长度:8位DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; //使用普通模式 DMA_InitStructure.DMA_Priority = DMA_Priority_High; //中等优先级DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Enable; // 使能FIFODMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full; // FIFO阀值满DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_INC4; //DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_INC4; //DMA_Init(DMAy_Streamx, &DMA_InitStructure); while (DMA_GetCmdStatus(DMAy_Streamx) != DISABLE){}DMA_Cmd(DMAy_Streamx, ENABLE);}void bsp_dma_u16_init(DMA_Stream_TypeDef* DMAy_Streamx,u32 dam_channel,u16 *src,u16 *dst,u32 len)
{DMA_InitTypeDef DMA_InitStructure;RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2 | RCC_AHB1Periph_DMA1,ENABLE); DMA_InitStructure.DMA_Channel = dam_channel; //通道选择DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)src; //DMA外设地址DMA_InitStructure.DMA_Memory0BaseAddr = (u32)dst; //DMA 存储器0地址DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToMemory; //存储器到外设模式DMA_InitStructure.DMA_BufferSize = len; //数据传输量 DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Enable; //外设非增量模式DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //存储器增量模式DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; //外设数据长度:16位DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; //存储器数据长度:16位DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; //使用普通模式 DMA_InitStructure.DMA_Priority = DMA_Priority_High; //中等优先级DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Enable; // 使能FIFODMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;// FIFO阀值满DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_INC8; //存储器突发单次传输DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_INC8; //外设突发单次传输DMA_Init(DMAy_Streamx, &DMA_InitStructure); while (DMA_GetCmdStatus(DMAy_Streamx) != DISABLE){}DMA_Cmd(DMAy_Streamx, ENABLE);
}void bsp_dma_u32_init(DMA_Stream_TypeDef* DMAy_Streamx,u32 dam_channel,u32 *src,u32 *dst,u32 len)
{DMA_InitTypeDef DMA_InitStructure;RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2 | RCC_AHB1Periph_DMA1,ENABLE); DMA_InitStructure.DMA_Channel = dam_channel; //通道选择DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)src; //DMA外设地址DMA_InitStructure.DMA_Memory0BaseAddr = (u32)dst; //DMA 存储器0地址DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToMemory; //存储器到外设模式DMA_InitStructure.DMA_BufferSize = len; //数据传输量 DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Enable; //外设非增量模式DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //存储器增量模式DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word; //外设数据长度:32位DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word; //存储器数据长度:16位DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; //使用普通模式 DMA_InitStructure.DMA_Priority = DMA_Priority_High; //中等优先级DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Enable; // 使能FIFODMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;// FIFO阀值满DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_INC4; //存储器突发单次传输DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_INC4; //外设突发单次传输DMA_Init(DMAy_Streamx, &DMA_InitStructure); while (DMA_GetCmdStatus(DMAy_Streamx) != DISABLE){}DMA_Cmd(DMAy_Streamx, ENABLE);
}ErrorStatus compare_u8_buff(u8 *src,u8 *dst,u32 len)
{int i;for(i = 0;i < len;i++){if(src[i] != dst[i])return ERROR;}return SUCCESS;
}ErrorStatus compare_u16_buff(u16 *src,u16 *dst,u32 len)
{int i;for(i = 0;i < len;i++){if(src[i] != dst[i])return ERROR;}return SUCCESS;
}ErrorStatus compare_u32_buff(u32 *src,u32 *dst,u32 len)
{int i;for(i = 0;i < len;i++){if(src[i] != dst[i])return ERROR;}return SUCCESS;
}
dma_tset_data.h
u8 src_u8_buff[] =
{
//随机数个数:100;每行显示个数:10;取值范围:0到255148, 119, 56, 38, 124, 10, 219, 102, 125, 5,
53, 188, 144, 202, 43, 70, 236, 3, 212, 145,
125, 65, 139, 92, 146, 227, 66, 158, 214, 58,
25, 202, 129, 235, 47, 81, 207, 148, 183, 104,
178, 178, 79, 13, 195, 194, 142, 68, 127, 166,
220, 167, 176, 75, 135, 29, 41, 137, 19, 234,
182, 74, 209, 232, 83, 239, 179, 19, 156, 239,
94, 75, 133, 193, 129, 86, 75, 253, 101, 37,
171, 190, 198, 88, 81, 74, 226, 4, 147, 245,
207, 179, 95, 66, 17, 172, 114, 76, 108, 117,
};u16 src_u16_buff[] =
{//随机数个数:100;每行显示个数:10;取值范围:256到6553522787, 5224, 1902, 6448, 21531, 32946, 6422, 4832, 17488, 23689,
13175, 8272, 21386, 8319, 18916, 4179, 23261, 12460, 8750, 31562,
5051, 6408, 12149, 675, 26984, 26904, 3901, 10656, 32431, 29389,
23748, 11098, 15316, 28841, 20116, 29189, 30921, 22307, 21076, 4981,
6052, 21837, 6883, 30433, 9041, 18612, 21672, 2024, 18052, 10375,
29731, 6865, 12018, 11260, 21192, 26135, 12481, 12272, 3598, 13605,
15933, 8142, 23747, 14430, 1996, 26033, 20130, 5728, 22564, 9677,
10791, 8842, 32955, 18699, 23714, 23740, 27263, 6899, 12427, 7773,
7880, 32463, 15893, 6307, 23691, 32781, 18949, 2062, 3536, 16870,
1733, 16694, 12646, 4669, 27572, 31431, 3285, 9162, 5825, 30922,
};u32 src_u32_buff[] =
{//随机数个数:100;每行显示个数:10;取值范围:65535到10000088361, 75899, 94546, 97752, 82130, 75054, 97136, 68892, 98163, 83019,
76892, 94669, 66625, 86400, 70941, 89254, 86425, 83976, 97555, 68700,
77042, 70351, 78217, 77532, 68369, 71639, 95113, 92116, 68732, 70362,
96244, 73846, 73264, 66353, 77266, 66681, 70294, 78068, 81638, 86112,
83636, 68963, 97925, 87294, 75680, 94852, 80553, 87098, 76859, 67086,
74562, 72464, 71451, 82822, 80844, 97496, 70857, 94632, 68390, 70603,
68141, 67336, 97698, 92867, 75590, 82425, 77145, 95298, 70175, 96174,
66753, 94902, 81406, 89759, 94081, 79355, 82654, 88110, 68995, 86562,
84255, 97675, 72779, 78705, 89469, 95189, 68232, 78762, 82239, 84866,
92649, 70801, 68272, 93952, 78642, 66472, 76243, 91292, 69775, 68413,
};
main.c
u8 dst_u8_buff[sizeof(src_u8_buff)/ sizeof(src_u8_buff[0])];
u16 dst_u16_buff[sizeof(src_u16_buff) / sizeof(src_u16_buff[0])];
u32 dst_u32_buff[sizeof(src_u32_buff) / sizeof(src_u32_buff[0])];
int main(void)
{int i;NVIC_PriorityGroupConfig(2);system_tick_init();bsp_usart_init(115200);bsp_dma_u8_init(DMA2_Stream0,DMA_Channel_0,src_u8_buff,dst_u8_buff,sizeof(src_u8_buff)/ sizeof(src_u8_buff[0]));while(DMA_GetFlagStatus(DMA2_Stream0,DMA_FLAG_TCIF0) != SET);if(compare_u8_buff(src_u8_buff,dst_u8_buff,sizeof(src_u8_buff)/ sizeof(src_u8_buff[0])) == SUCCESS)printf("u8 success\r\n");elseprintf("u8 error\r\n");bsp_dma_u16_init(DMA2_Stream1,DMA_Channel_1,src_u16_buff,dst_u16_buff,sizeof(src_u16_buff)/ sizeof(src_u16_buff[0]));while(DMA_GetFlagStatus(DMA2_Stream1,DMA_FLAG_TCIF1) != SET);if(compare_u16_buff(src_u16_buff,dst_u16_buff,sizeof(src_u16_buff)/ sizeof(src_u16_buff[0])) == SUCCESS)printf("u16 success\r\n");elseprintf("u16 error\r\n");bsp_dma_u32_init(DMA2_Stream2,DMA_Channel_2,src_u32_buff,dst_u32_buff,sizeof(src_u32_buff)/ sizeof(src_u32_buff[0]));while(DMA_GetFlagStatus(DMA2_Stream2,DMA_FLAG_TCIF2) != SET);if(compare_u32_buff(src_u32_buff,dst_u32_buff,sizeof(src_u32_buff)/ sizeof(src_u32_buff[0])) == SUCCESS)printf("u32 success\r\n");elseprintf("u32 error\r\n");while(1){delay_ms(1000);}}
存储器到外设例程
void bsp_dma_init(DMA_Stream_TypeDef* DMAy_Streamx,u32 dam_channel,u32 src,u32 dst,u32 len)
{DMA_InitTypeDef DMA_InitStructure;RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2 | RCC_AHB1Periph_DMA1,ENABLE); DMA_InitStructure.DMA_Channel = dam_channel; //通道选择DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)dst; //DMA外设地址DMA_InitStructure.DMA_Memory0BaseAddr = (u32)src; //DMA 存储器0地址DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral; //存储器到外设模式DMA_InitStructure.DMA_BufferSize = len; //数据传输量 DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设非增量模式DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //存储器增量模式DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; //外设数据长度:8位DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; //存储器数据长度:8位DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; //使用普通模式 DMA_InitStructure.DMA_Priority = DMA_Priority_High; //中等优先级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_Init(DMAy_Streamx, &DMA_InitStructure); while (DMA_GetCmdStatus(DMAy_Streamx) != DISABLE){}DMA_Cmd(DMAy_Streamx, ENABLE);}const u8 text_to_send[]="HuJeZC2ERQ6UIRIJMCa0";
#define SEND_BUF_SIZE ((sizeof(text_to_send) + 2) * 1000) //发送数据长度,最好等于sizeof(TEXT_TO_SEND)+2的整数倍.
u8 string_buff[SEND_BUF_SIZE];
int main(void)
{int i,j,t,mask = 0;NVIC_PriorityGroupConfig(2);system_tick_init();bsp_usart_init(115200);j=sizeof(text_to_send); for(i=0;i<SEND_BUF_SIZE;i++)//填充ASCII字符集数据{if(t>=j)//加入换行符{if(mask){string_buff[i]=0x0a;t=0;}else {string_buff[i]=0x0d;mask++;} }else//复制TEXT_TO_SEND语句{mask=0;string_buff[i]=text_to_send[t];t++;} } bsp_dma_init(DMA2_Stream7,DMA_Channel_4,(u32)string_buff,(u32)&USART1->DR,(sizeof(string_buff) / sizeof(string_buff[0])));USART_DMACmd(USART1,USART_DMAReq_Tx,ENABLE);while(DMA_GetFlagStatus(DMA2_Stream7,DMA_FLAG_TCIF7) != SET);while(1){delay_ms(1000);}}
外设到存储器例程
#define NUM 10000 //采集次数extern u16 adc_value[2];
extern u16 translate_end ;
void ADC_GPIO_Config(void)
{GPIO_InitTypeDef GPIO_InitStruct;RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AN;GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0;GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;GPIO_Init(GPIOA,&GPIO_InitStruct);GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AN;GPIO_InitStruct.GPIO_Pin = GPIO_Pin_1;GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;GPIO_Init(GPIOA,&GPIO_InitStruct);GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AN;GPIO_InitStruct.GPIO_Pin = GPIO_Pin_4;GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;GPIO_Init(GPIOA,&GPIO_InitStruct);}void DMA_ADC_Config(void)
{ADC_CommonInitTypeDef ADC_CommonInitStruct,ADC_CommonInitStructure;ADC_InitTypeDef ADC_InitStruct,ADC_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);ADC_CommonInitStruct.ADC_Mode = ADC_Mode_Independent; //独立模式ADC_CommonInitStruct.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_20Cycles; //两个采样阶段之间的延迟x个时钟ADC_CommonInitStruct.ADC_DMAAccessMode = ADC_DMAAccessMode_1; //DMA使能(DMA传输下要设置使能)ADC_CommonInitStruct.ADC_Prescaler = ADC_Prescaler_Div4; //预分频4分频。ADCCLK=PCLK2/4=84/4=21Mhz,ADC时钟最好不要超过36Mhz ADC_CommonInit(&ADC_CommonInitStruct); //初始化 ADC_InitStruct.ADC_Resolution = ADC_Resolution_12b; //12位模式ADC_InitStruct.ADC_ScanConvMode =ENABLE; //扫描(开启DMA传输要设置扫描)ADC_InitStruct.ADC_ContinuousConvMode = ENABLE; //开启连续转换(开启DMA传输要设置连续转换)ADC_InitStruct.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None; //禁止触发检测,使用软件触发ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right; //右对齐 ADC_InitStruct.ADC_NbrOfConversion = 3; //有几个通道传输就写几 (DMA传输下要设置为通道数)ADC_Init(ADC1, &ADC_InitStruct); //ADC初始化ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_480Cycles); ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 2, ADC_SampleTime_480Cycles); ADC_RegularChannelConfig(ADC1, ADC_Channel_4, 3, ADC_SampleTime_480Cycles); ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE);ADC_DMACmd(ADC1, ENABLE);ADC_Cmd(ADC1, ENABLE); }void DMA_Config(void)
{DMA_InitTypeDef DMA_InitStructure;NVIC_InitTypeDef NVIC_InitStructure;RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2,ENABLE); DMA_InitStructure.DMA_Channel = DMA_Channel_0; //通道选择DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&ADC1->DR; //DMA外设地址DMA_InitStructure.DMA_Memory0BaseAddr = (u32)adc_value; //DMA 存储器0地址DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory; //存储器到外设模式DMA_InitStructure.DMA_BufferSize = 3; //数据传输量 DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设非增量模式DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //存储器增量模式DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; //外设数据长度:16位DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; //存储器数据长度:16位DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; //使用普通模式 DMA_InitStructure.DMA_Priority = DMA_Priority_High; //中等优先级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_Init(DMA2_Stream0, &DMA_InitStructure); DMA_ClearITPendingBit(DMA2_Stream0,DMA_IT_TCIF0);//DMA_ClearFlag(DMA2_Stream0,DMA_IT_TC);DMA_ITConfig(DMA2_Stream0,DMA_IT_TC,ENABLE);NVIC_InitStructure.NVIC_IRQChannel=DMA2_Stream0_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0x01; //抢占优先级NVIC_InitStructure.NVIC_IRQChannelSubPriority=0x01; //响应优先级NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;NVIC_Init(&NVIC_InitStructure);while (DMA_GetCmdStatus(DMA2_Stream0) != DISABLE){}DMA_Cmd(DMA2_Stream0, ENABLE);}void DMA2_Stream0_IRQHandler(void)
{if(DMA_GetITStatus(DMA2_Stream0,DMA_IT_TCIF0) == SET){translate_end = 1;DMA_ClearITPendingBit(DMA2_Stream0,DMA_IT_TCIF0);}
}u16 adc_value[3];
u32 adc_channel1_average_value = 0,adc_channel2_average_value = 0,adc_channel3_average_value = 0;
u16 translate_end = 0;
int main(void)
{int count = 0;float adc_temp_value1,adc_temp_value2,adc_temp_value3;NVIC_PriorityGroupConfig(2);system_tick_init();bsp_usart_init(115200);ADC_GPIO_Config();DMA_ADC_Config();DMA_Config();ADC_SoftwareStartConv(ADC1); while(1){if(translate_end){if(count <= NUM){adc_channel1_average_value += adc_value[0];adc_channel2_average_value += adc_value[1];adc_channel3_average_value += adc_value[2];count++;}else{count = 0;adc_temp_value1 = (float)(adc_channel1_average_value / NUM) * 3.3 / 4096;adc_temp_value2 = (float)(adc_channel2_average_value / NUM) * 3.3 / 4096;adc_temp_value3 = (float)(adc_channel3_average_value / NUM) * 3.3 / 4096;printf("ch1 %f ch2 %f ch3 %f\r\n", adc_temp_value1,adc_temp_value2,adc_temp_value3);adc_channel1_average_value = 0;adc_channel2_average_value = 0;adc_channel3_average_value = 0;}translate_end = 0;}}}