cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F4 ADC1 + ADC3, dual or tripple mode?

mail2
Associate II
Posted on October 14, 2013 at 08:32

Hello,

I want to sample 3 channels on ADC1 and 2 channels on ADC3. Does i have the ADCs to use in dual or tripple mode? The following Code does not work :(

/*
Sample Temp, VRef, VBat and ports PF9, PF10 using DMA and 
trigger via Timer3 at 2 Hz
*/
#define BUFFERLENGTH 5
static __IO uint16_t ADCConvertedValues[BUFFERLENGTH];
__IO uint8_t g_Valid = 0;
void DMA2_Stream0_IRQHandler()
{
if (DMA_GetITStatus(DMA2_Stream0, DMA_IT_TCIF0) != RESET)
{
DMA_ClearITPendingBit(DMA2_Stream0, DMA_IT_TCIF0);
g_Valid = 1;
}
if (DMA_GetITStatus(DMA2_Stream0, DMA_IT_TEIF0) != RESET)
{
DMA_ClearITPendingBit(DMA2_Stream0, DMA_IT_TEIF0);
}
}
void SENSORS_Init (void)
{
NVIC_InitTypeDef NVIC_InitStructure;
DMA_InitTypeDef DMA_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; 
TIM_OCInitTypeDef TIM_OCInitStructure;
ADC_InitTypeDef ADC_InitStructure;
ADC_CommonInitTypeDef ADC_CommonInitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
/* Timer3, ADC1 und DMA2 clocks einschalten */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); 
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC3, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF, ENABLE);
/* PF9 und PF10 als Analog Eingang */
GPIO_StructInit(&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
GPIO_Init(GPIOF, &GPIO_InitStructure);
/* Interrupts im NVIC freigeben */
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream0_IRQn;
NVIC_Init(&NVIC_InitStructure);
/* DMA Aufsetzen */
/* DMA2 Stream0 channel0 Konfiguration */
/* Init auf Standardwerte setzen */
DMA_StructInit(&DMA_InitStructure);
DMA_DeInit(DMA2_Stream0);
/* Kanal 0 */
DMA_InitStructure.DMA_Channel = DMA_Channel_0;
/* Adresse des ADC Datenregisters (Quelle) */
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)0x40012308; // &ADC1->DR;
/* Adresse der Datenstruktur (Ziel) */
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t) ADCConvertedValues;
/* Richtung des Transfers */
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
/* Länge des Datentransfers */
DMA_InitStructure.DMA_BufferSize = BUFFERLENGTH;
/* Die Quelladresse ändert sich nicht */
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
/* Die Zieladresse muss sich mit jedem Wert ändern */
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
/* Größe einer Datenübertragung (Quelle, 16 Bit) */
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
/* Größe einer Datenübertragung (Ziel, 16 Bit) */
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
/* Datenübertragungen immer wieder von vorne anfangen */
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
/* Daten mit hoher Priorität übertragen */
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
/* Direkte Datenübertragung */
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Enable; 
/* Don't care, da Fifo abgeschaltet */
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
/* Werte einzeln in Speicher übertragen */
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
/* Werte einzeln vom ADC lesen */
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
/* DMA Initialisieren */
DMA_Init(DMA2_Stream0, &DMA_InitStructure);
/* DMA Interrupt aktivieren */
DMA_ITConfig(DMA2_Stream0, DMA_IT_TC, ENABLE);
/* DMA starten */
DMA_Cmd(DMA2_Stream0, ENABLE);
/* Timer aufsetzen */
// Timer aus
TIM_Cmd(TIM3, DISABLE);
TIM_ITConfig(TIM3, TIM_IT_Update, DISABLE); 
// Der 16 Bit Timer 3 hängt am APB1 mit 42MHz, Timertakt ist damit 84 MHz
// 84MHz / 7000 (Prescaler) = 12000 Hz
// 12000Hz / 6000 (Period) = 2Hz
TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
TIM_TimeBaseStructure.TIM_Period = 7000-1;
TIM_TimeBaseStructure.TIM_Prescaler = 6000-4;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
/* TIM3 channel2 configuration in PWM mode */
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; 
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; 
TIM_OCInitStructure.TIM_Pulse = 1; 
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low; 
TIM_OC1Init(TIM3, &TIM_OCInitStructure);
/* TIM3 enable counter */ 
TIM_Cmd(TIM3, ENABLE); 
/* ADC aufsetzen */
ADC_CommonStructInit(&ADC_CommonInitStructure);
ADC_DeInit();
ADC_CommonInitStructure.ADC_Mode = ADC_DualMode_RegSimult; // ADC_Mode_Independent;
ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2;
ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_1; // ADC_DMAAccessMode_Disabled;
/* Delay zwischen 2 Sampling Phasen */
ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;
ADC_CommonInit(&ADC_CommonInitStructure);
/* ADC1 Init */
ADC_StructInit(&ADC_InitStructure);
ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
ADC_InitStructure.ADC_ScanConvMode = ENABLE;
/* Kontinuierlich samplen */
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
/* Kein Trigger */
ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_Rising; // ADC_ExternalTrigConvEdge_None;
// ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T2_CC2;
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T3_CC1;
/* Daten Rechtsbündig ablegen */
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfConversion = 3; // BUFFERLENGTH;
ADC_Init(ADC1, &ADC_InitStructure);
ADC_InitStructure.ADC_NbrOfConversion = 2; // BUFFERLENGTH;
ADC_Init(ADC3, &ADC_InitStructure);
/* ADC1 regular channel18 (VBAT) & channel16 (TempSensor) configuration *****/
// TODO: 480 Cycles erklären und ggf anpassen
ADC_RegularChannelConfig(ADC1, ADC_Channel_Vbat, 1, ADC_SampleTime_480Cycles);
ADC_RegularChannelConfig(ADC1, ADC_Channel_TempSensor, 2, ADC_SampleTime_480Cycles);
ADC_RegularChannelConfig(ADC1, ADC_Channel_Vrefint, 3, ADC_SampleTime_480Cycles);
ADC_RegularChannelConfig(ADC3, ADC_Channel_7, 1, ADC_SampleTime_480Cycles);
ADC_RegularChannelConfig(ADC3, ADC_Channel_8, 1, ADC_SampleTime_480Cycles);
/* Enable VBAT channel: channel18 */
ADC_VBATCmd(ENABLE);
/* Enable TempSensor and Vrefint channels: channel16 and channel17 */
ADC_TempSensorVrefintCmd(ENABLE);
/* Enable DMA request after last transfer (Single-ADC mode) */
// ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE);
ADC_MultiModeDMARequestAfterLastTransferCmd(ENABLE);
/* Enable STM32_TEMPSENS_ADC_DEVICE EOC interupt. */
//ADC_ITConfig(ADC1, ADC_IT_EOC, ENABLE);
/* Enable ADC1 DMA */
//ADC_DMACmd(ADC1, ENABLE);
//ADC_DMACmd(ADC3, ENABLE);
/* Enable ADC1 */
ADC_Cmd(ADC1, ENABLE);
ADC_Cmd(ADC3, ENABLE);
/* Start ADC1 */
//ADC_SoftwareStartConv(ADC1);
}

Martin #timer #dma #adc1 #adc3
2 REPLIES 2
Posted on October 14, 2013 at 13:29

Not sure how it pairs, but presumably you'd want them balanced symmetrically, otherwise the array would have all kind of sequencing issues.

Why wouldn't you get one ADC unit to do all 5 samples? Or use ADC1 and 3 and two independent DMA streams?
Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
mail2
Associate II
Posted on October 14, 2013 at 16:00

Hi Clive,

The hardware design is fix on ADC3 and the internal sensors are fix on ADC1.

I will try to sample them independently with two DMA streams.

Martin