DMA transfer using three ADC’s, 24 channels, and three streams
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);
}