stm32 DMA缓冲区 详细传输过程 ,stm32 ADC多通道传输与DMA缓冲区 详细传输过程

查阅大量资料和各个论坛 都没有得到一个全面详尽的答案  

ADC多通道采集和DMA缓冲区传输数据的详细过程

ADC采集工作在多通道连续扫描模式和连续转换模式  ADC_InitStructure.ADC_ScanConvMode = ENABLE; ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;

DMA配置中 开启连续传输 (DMA_InitStructure.DMA_Mode = DMA_Mode_Circular  ;)

首先DMA传输三个大致步骤 1.外设请求DMA传输   2.DMA传输数据到内存  3.传输完成进行下次传输或者停止传输(根据是否配置连续传输)

经过测试发现 

1.DMA连续传输模式下 DMA产生中断请求后  进入中断函数后 DMA传输依然持续 除非ADC停止请求DMA传输 

2.DMA是传输一次是传输整个DMA缓冲区   还是外设申请一次传一次  ?完成整个传输后产生中断标志:

手册中说

stm32 DMA缓冲区 详细传输过程 ,stm32 ADC多通道传输与DMA缓冲区 详细传输过程

stm32 DMA缓冲区 详细传输过程 ,stm32 ADC多通道传输与DMA缓冲区 详细传输过程

DMA_CNDTRx 寄存器对应 DMA_InitStructure.DMA_BufferSize = sizeof(DMA_Adc)/sizeof(vu16);  数据量大小为  30个u16

volatile u16 DMA_Adc[M][N];    //M=10 N=3

DMA_InitStructure.DMA_BufferSize = sizeof(DMA_Adc)/sizeof(vu16);  缓冲区大小为  30个u16

ADC1的通道1 完成一次扫描  ADC1转换完成后 申请DMA传输  ADC1将其12位数据寄存器的数据 存到DMA的缓存区 

ADC1的通道2 完成一次扫描  ADC1转换完成后 申请DMA传输  ADC1将其12位数据寄存器中数据 存到DMA的缓存区  

缓存区存满后 DMA传输数据到内存区 传输完成产生中断 这样的话就不高效 违背了DMA的初衷 而且手册中并未提到DMA可以缓存 

所以DMA只是个桥接作用不起缓存作用  ADC1的通道1 完成一次扫描  ADC1转换完成后 申请DMA传输 DMA传输数据到内存

DMA_CNDTRx 寄存器减一  减到0 产生中断请求

 

有错误的地方还请指教

stm32 DMA缓冲区 详细传输过程 ,stm32 ADC多通道传输与DMA缓冲区 详细传输过程

stm32 DMA缓冲区 详细传输过程 ,stm32 ADC多通道传输与DMA缓冲区 详细传输过程

 

stm32 DMA缓冲区 详细传输过程 ,stm32 ADC多通道传输与DMA缓冲区 详细传输过程

stm32 DMA缓冲区 详细传输过程 ,stm32 ADC多通道传输与DMA缓冲区 详细传输过程

主函数就只有基本的初始化和while空循环和ADC_SoftwareStartConvCmd(ADC1, ENABLE);//ADC开始采集的启动函数

#include "adc.h"

volatile u16 DMA_Adc[M][N]; // M= 10 N=3 3¸öͨµÀ ÿ¸öͨµÀ²É¼¯10´Î volatile u16==vu16
u16 ADC_Value[N];
vu8 flag=0;
void ADC_Init_User()

     ADC_InitTypeDef ADC_InitStructure; 
    GPIO_InitTypeDef GPIO_InitStructure;
    DMA_InitTypeDef DMA_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;            /* Configure the NVIC Preemption Priority Bits */ 

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA |RCC_APB2Periph_ADC1    , ENABLE );      //ʹÄÜADC1ͨµÀʱÖÓ
  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

    RCC_ADCCLKConfig(RCC_PCLK2_Div6);   //ÉèÖÃADC·ÖƵÒò×Ó6 72M/6=12,ADC×î´óʱ¼ä²»Äܳ¬¹ý14M

    //PA1 ×÷ΪģÄâͨµÀÊäÈëÒý½Å                         
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3; //¶ÔÓ¦adcͨµÀµÄ1 2 3
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;        //Ä£ÄâÊäÈëÒý½Å
    GPIO_Init(GPIOA, &GPIO_InitStructure);    
    
        
  //DMA1 Configuration ADC1¹ÒÔØÔÚDMA1µÄͨµÀ1
    DMA_DeInit(DMA1_Channel1);   //¸´Î»DMA1ͨµÀ1
    DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&ADC1->DR;//ÍâÉèADC1×÷Ϊ»ùµØÖ· &USART1->DR ÍâÉè´®¿Ú×÷Ϊ»ùµØÖ·
    DMA_InitStructure.DMA_MemoryBaseAddr = (u32)DMA_Adc; //¶¨ÒåDMA1µÄͨµÀµÄÄÚ´æ»ùµØÖ·
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; //DMA´«Êä·½Ïò(ÍâÉèµ½ÄÚ´æ)
    DMA_InitStructure.DMA_BufferSize = sizeof(DMA_Adc)/sizeof(vu16); //¶¨ÒåÖ¸¶¨DMAͨµÀµÄDMA»º´æ´óС
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //É趨ÍâÉèµØÖ·¼Ä´æÆ÷µÝÔöÓë·ñ£¬²»±ä£¬Disable
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //É趨ÍâÉèµØÖ·¼Ä´æÆ÷µÝÔöÓë·ñ£¬µÝÔö£¬Enable
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord ; //ÍâÉèÊý¾Ýµ¥Î»
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord ;    //ÄÚ´æÊý¾Ýµ¥Î»
    DMA_InitStructure.DMA_Mode = DMA_Mode_Circular  ; //DMAģʽ£ºÑ­»·Ä£Ê½
    DMA_InitStructure.DMA_Priority = DMA_Priority_High ; //¸ÃͨµÀÓÅÏȼ¶£º¸ß
    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;   //½ûÖ¹ÄÚ´æµ½ÄÚ´æµÄ´«Êä
    DMA_Init(DMA1_Channel1, &DMA_InitStructure);  //³õʼ»¯DMA1ͨµÀ1
    
    DMA_Cmd(DMA1_Channel1,ENABLE);//Æô¶¯DMA1µÄͨµÀ1    
    DMA_ITConfig(DMA1_Channel1,DMA_IT_TC,ENABLE); //¿ªÆô´«Êä½áÊøÖжÏ
    
        //ÖжÏÓÅÏȼ¶NVICÉèÖÃ
    NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel1_IRQn;  //TIM3ÖжÏ
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;  //ÏÈÕ¼ÓÅÏȼ¶0¼¶
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;  //´ÓÓÅÏȼ¶3¼¶
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQͨµÀ±»Ê¹ÄÜ
    NVIC_Init(&NVIC_InitStructure);  //³õʼ»¯NVIC¼Ä´æÆ÷
    

  //ADC1 Configuration  ×¢ ADC1 2 3 ¸÷¸öͨµÀ¶ÔÓ¦µÄIO»ù±¾¶¼ÊÇÒ»ÖµÄ
    ADC_DeInit(ADC1);  //¸´Î»ADC1 
    ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;    //ADC¹¤×÷ģʽ:ADC1ºÍADC2¹¤×÷ÔÚ¶ÀÁ¢Ä£Ê½
    ADC_InitStructure.ADC_ScanConvMode = ENABLE;    //DISABLE=Ä£Êýת»»¹¤×÷ÔÚµ¥Í¨µÀģʽ
    ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;    //DISABLE=Ä£Êýת»»¹¤×÷ÔÚµ¥´Îת»»Ä£Ê½
    ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;    //ת»»ÓÉÈí¼þ¶ø²»ÊÇÍⲿ´¥·¢Æô¶¯
    ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;    //ADCÊý¾ÝÓÒ¶ÔÆë =µÍ12λÓÐЧ ×ó¶ÔÆë ¸ßÊ®¶þλÓÐЧ
    ADC_InitStructure.ADC_NbrOfChannel = 3;    //˳Ðò½øÐйæÔòת»»µÄADCͨµÀµÄÊýÄ¿ ¼¸¸öͨµÀ¾ÍÊǼ¸
    ADC_Init(ADC1, &ADC_InitStructure);    //¸ù¾ÝADC_InitStructÖÐÖ¸¶¨µÄ²ÎÊý³õʼ»¯ÍâÉèADCxµÄ¼Ä´æÆ÷   
    
    ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 1, ADC_SampleTime_13Cycles5);//
    ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 2, ADC_SampleTime_13Cycles5);//
    ADC_RegularChannelConfig(ADC1, ADC_Channel_3, 3, ADC_SampleTime_13Cycles5);//
    
    
    ADC_DMACmd(ADC1,ENABLE); //¿ªÆôADCÓëDMAµÄÖ§³Ö
    ADC_Cmd(ADC1, ENABLE);    //ʹÄÜÖ¸¶¨µÄADC1
    
    ADC_ResetCalibration(ADC1);    //ʹÄܸ´Î»Ð£×¼  
     
    while(ADC_GetResetCalibrationStatus(ADC1));    //µÈ´ý¸´Î»Ð£×¼½áÊø
    
    ADC_StartCalibration(ADC1);     //¿ªÆôADУ׼
 
    while(ADC_GetCalibrationStatus(ADC1));     //µÈ´ýУ׼½áÊø
 
//    ADC_SoftwareStartConvCmd(ADC1, ENABLE);        //ʹÄÜÖ¸¶¨µÄADC1µÄÈí¼þת»»Æô¶¯¹¦ÄÜ

}        

void DMA1_Channel1_IRQHandler(void)
{
    u8 i,j;    
    int sum;
            for(i=0;i<N;i++)
    {
        sum=0;
        for(j=0;j<M;j++)
        {
            sum+=DMA_Adc[j][i];
        }
        ADC_Value[i]=sum/10;//(float)sum/(10*4096)*3.3;
        //ADC_Value[i]=(float)sum/10;
     if(flag>0)
     {
        while(1){
        OLED_ShowNum(1,2,DMA_Adc[0][0],4,12);
        OLED_ShowNum(1,4,DMA_Adc[0][1],4,12);
        OLED_ShowNum(1,6,DMA_Adc[1][0],4,12);
            ADC_SoftwareStartConvCmd(ADC1, DISABLE);//¿ªÊ¼²É¼¯
            ADC_Cmd(ADC1, DISABLE);    //ʹÄÜÖ¸¶¨µÄADC1
        }
     }
     else{
        OLED_ShowNum(1,2,DMA_Adc[0][0],4,12);
        OLED_ShowNum(1,4,DMA_Adc[0][1],4,12);
        OLED_ShowNum(1,6,DMA_Adc[1][0],4,12);
    DMA_ClearFlag(DMA1_FLAG_TC1);
     }
     flag++;
    }
}