AnsweredAssumed Answered

DMA transfer using three ADC’s, 24 channels, and three streams

Question asked by davel on Aug 21, 2014
Latest reply on Aug 26, 2014 by Clive One

I am trying to get 24 ADC channels to transfer using DMA. The following code works for ADC2 and ADC3, but ADC1 the data stored in the DMA buffer is random. The data for ADC1 can sometimes appear correct, but the data is in the wrong position (e.g. ADCConvertedValue[0] data is located at ADCConvertedValue[3]). It is like the DMA is out of sync with the buffer positioning. ADC2 and ADC3 data appears valid and is not scrambled.

I have tried many different combinations of DMA and ADC settings, but can’t seem to get the whole thing working.

I don’t need an interrupt or an external trigger when the converstions are complete. I just need all 24 ADC channels continually transferring data to the DMA buffer in the background.

Any ideas on how to reliably get all 24 channels working? Why would the DMA transfer loose position synchronization with the data buffer?

Thanks in advance for any assistance.

 

const INT ADC_BUFFER_SIZE = 8; 
static __IO uint16_t ADCConvertedValue[ADC_BUFFER_SIZE*3] __attribute__((at(0x20002000)));
  
struct ADC_ConfigData
{
    uint16_t        GPIO_Pin;
    GPIO_TypeDef*   GPIO_Port;
    ADC_TypeDef*    ADCx;
    uint8_t         ADC_Channel;
};
  
// ADC1 configurations
const ADC_ConfigData ADC1_CONFIG[] =
{
    {GPIO_Pin_0, GPIOA, ADC1, ADC_Channel_0 },              
    {GPIO_Pin_1, GPIOA, ADC1, ADC_Channel_1 },          
    {GPIO_Pin_2, GPIOA, ADC1, ADC_Channel_2 },              
    {GPIO_Pin_3, GPIOA, ADC1, ADC_Channel_3 },           
    {GPIO_Pin_0, GPIOC, ADC1, ADC_Channel_10 },  
    {GPIO_Pin_1, GPIOC, ADC1, ADC_Channel_11 }, 
    {GPIO_Pin_2, GPIOC, ADC1, ADC_Channel_12 }, 
    {GPIO_Pin_3, GPIOC, ADC1, ADC_Channel_13 }      
};
  
// ADC2 configurations
const ADC_ConfigData ADC2_CONFIG[] =
{
    {GPIO_Pin_6, GPIOA, ADC2, ADC_Channel_6 },  
    {GPIO_Pin_7, GPIOA, ADC2, ADC_Channel_7 },  
    {GPIO_Pin_5, GPIOA, ADC2, ADC_Channel_5 },          
    {GPIO_Pin_4, GPIOA, ADC2, ADC_Channel_4 },          
    {GPIO_Pin_5, GPIOC, ADC2, ADC_Channel_15 },     
    {GPIO_Pin_0, GPIOB, ADC2, ADC_Channel_8 },      
    {GPIO_Pin_1, GPIOB, ADC2, ADC_Channel_9 },      
    {GPIO_Pin_4, GPIOC, ADC2, ADC_Channel_14 }
};
  
// ADC3 configurations
const ADC_ConfigData ADC3_CONFIG[] =
{
    {GPIO_Pin_5, GPIOF, ADC3, ADC_Channel_15 },     
    {GPIO_Pin_10,GPIOF, ADC3, ADC_Channel_8 },
    {GPIO_Pin_3, GPIOF, ADC3, ADC_Channel_9 },      
    {GPIO_Pin_4, GPIOF, ADC3, ADC_Channel_14 }, 
    {GPIO_Pin_6, GPIOF, ADC3, ADC_Channel_4 },  
    {GPIO_Pin_7, GPIOF, ADC3, ADC_Channel_5 },  
    {GPIO_Pin_8, GPIOF, ADC3, ADC_Channel_6 },
    {GPIO_Pin_9, GPIOF, ADC3, ADC_Channel_7 }        
};
  
static const INT ADC1_SENSORS = sizeof(ADC1_CONFIG)/sizeof(ADC_ConfigData);
static const INT ADC2_SENSORS = sizeof(ADC2_CONFIG)/sizeof(ADC_ConfigData);
static const INT ADC3_SENSORS = sizeof(ADC3_CONFIG)/sizeof(ADC_ConfigData);
  
//------------------------------------------------------------------------------
// AdcInitialize
//------------------------------------------------------------------------------
void AdcInitialize()
{
    DMA_Config();   
    ADC_Config();
}
  
//------------------------------------------------------------------------------
// ADC_Config
//------------------------------------------------------------------------------
static void ADC_Config()
{
    // Enable peripheral clocks
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_ADC2 | RCC_APB2Periph_ADC3, ENABLE);
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF | RCC_AHB1Periph_GPIOC | RCC_AHB1Periph_GPIOB | RCC_AHB1Periph_GPIOA, ENABLE); 
      
    // ADC common initialization
    ADC_CommonInitTypeDef ADC_CommonInitStructure;
    ADC_CommonInitStructure.ADC_Mode = ADC_TripleMode_RegSimult; 
    ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div4;
    ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_1; 
    ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;
    ADC_CommonInit(&ADC_CommonInitStructure);
  
    ADC_InitTypeDef ADC_InitStructure;
    ADC_StructInit(&ADC_InitStructure); 
    ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
    ADC_InitStructure.ADC_ScanConvMode = ENABLE;
    ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; 
    ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
    ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
      
    // Initialize all ADC's
    ADC_InitStructure.ADC_NbrOfConversion = ADC1_SENSORS;   
    ADC_Init(ADC1, &ADC_InitStructure); 
    ADC_InitStructure.ADC_NbrOfConversion = ADC2_SENSORS;   
    ADC_Init(ADC2, &ADC_InitStructure); 
    ADC_InitStructure.ADC_NbrOfConversion = ADC3_SENSORS;   
    ADC_Init(ADC3, &ADC_InitStructure);
  
    // Configure the GPIO pin for ADC input
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
      
    // Configure ADC1 GPIO's
    for (INT sensor=0; sensor<ADC1_SENSORS; sensor++)   
    {
        GPIO_InitStructure.GPIO_Pin = ADC1_CONFIG[sensor].GPIO_Pin;
        GPIO_Init(ADC1_CONFIG[sensor].GPIO_Port, &GPIO_InitStructure);      
        ADC_RegularChannelConfig(ADC1_CONFIG[sensor].ADCx, ADC1_CONFIG[sensor].ADC_Channel, sensor+1, ADC_SampleTime_15Cycles);
    }
  
    // Configure ADC2 GPIO's
    for (INT sensor=0; sensor<ADC2_SENSORS; sensor++)   
    {
        GPIO_InitStructure.GPIO_Pin = ADC2_CONFIG[sensor].GPIO_Pin;
        GPIO_Init(ADC2_CONFIG[sensor].GPIO_Port, &GPIO_InitStructure);      
        ADC_RegularChannelConfig(ADC2_CONFIG[sensor].ADCx, ADC2_CONFIG[sensor].ADC_Channel, sensor+1, ADC_SampleTime_15Cycles);
    }
      
    // Confifure ADC3 GPIO's
    for (INT sensor=0; sensor<ADC3_SENSORS; sensor++)
    {
        GPIO_InitStructure.GPIO_Pin = ADC3_CONFIG[sensor].GPIO_Pin;
        GPIO_Init(ADC3_CONFIG[sensor].GPIO_Port, &GPIO_InitStructure);      
        ADC_RegularChannelConfig(ADC3_CONFIG[sensor].ADCx, ADC3_CONFIG[sensor].ADC_Channel, sensor+1, ADC_SampleTime_15Cycles);
    }
      
    // Enable DMA request after last transfer 
    ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE);
    ADC_DMARequestAfterLastTransferCmd(ADC2, ENABLE);
    ADC_DMARequestAfterLastTransferCmd(ADC3, ENABLE);
  
    // Enable ADC DMA 
    ADC_DMACmd(ADC1, ENABLE);
    ADC_DMACmd(ADC2, ENABLE);
    ADC_DMACmd(ADC3, ENABLE);
  
    // Enable all ADC's
    ADC_Cmd(ADC1, ENABLE);
    ADC_Cmd(ADC2, ENABLE);
    ADC_Cmd(ADC3, ENABLE);
      
    // Start all ADC conversions
    ADC_SoftwareStartConv(ADC1);
    ADC_SoftwareStartConv(ADC2);
    ADC_SoftwareStartConv(ADC3);
}
  
//------------------------------------------------------------------------------
// DMA_Config
//------------------------------------------------------------------------------
static void DMA_Config(void)
{
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE); 
      
    DMA_InitTypeDef DMA_InitStructure;
    DMA_StructInit(&DMA_InitStructure);
  
    // ADC1, DMA2, Channel0, Stream0 configuration 
    DMA_DeInit(DMA2_Stream0);
    DMA_InitStructure.DMA_Channel = DMA_Channel_0;
    DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&ADCConvertedValue[0];
    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR;
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; 
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
    DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
    DMA_InitStructure.DMA_Priority = DMA_Priority_High;
    DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Enable; 
    DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
    DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
    DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
    DMA_InitStructure.DMA_BufferSize = ADC1_SENSORS; 
    DMA_Init(DMA2_Stream0, &DMA_InitStructure);
    DMA_Cmd(DMA2_Stream0, ENABLE);
      
    // ADC2, DMA2, Channel1, Stream2 configuration 
    DMA_DeInit(DMA2_Stream2);   
    DMA_InitStructure.DMA_Channel = DMA_Channel_1;
    DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&ADCConvertedValue[ADC_BUFFER_SIZE];
    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC2->DR;
    DMA_InitStructure.DMA_BufferSize = ADC2_SENSORS;
    DMA_Init(DMA2_Stream2, &DMA_InitStructure);
    DMA_Cmd(DMA2_Stream2, ENABLE);
      
    // ADC3, DMA2, Channel2, Stream1 configuration 
    DMA_DeInit(DMA2_Stream1);
    DMA_InitStructure.DMA_Channel = DMA_Channel_2;
    DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&ADCConvertedValue[ADC_BUFFER_SIZE*2];
    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC3->DR;
    DMA_InitStructure.DMA_BufferSize = ADC3_SENSORS;
    DMA_Init(DMA2_Stream1, &DMA_InitStructure);
    DMA_Cmd(DMA2_Stream1, ENABLE);
}

Outcomes