cancel
Showing results for 
Search instead for 
Did you mean: 

ADC and DAC Issues with STM32F4VGT6

k2399
Associate
Posted on September 11, 2014 at 17:30

Hi,

I am using trying to use the ADCs on the STM32f4vgt6 with the DMA Controller in continuous conversion mode. I have this chip mounted on a custom board and I am using 8 ADC channels. Below is my initialization code:

uint16_t ADC_Values[1];
void adc_init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
ADC_InitTypeDef ADC_InitStructure;
ADC_CommonInitTypeDef ADC_CommonInitStructure;
DMA_InitTypeDef DMA_InitStructure;
GPIO_StructInit(&GPIO_InitStructure);
ADC_StructInit(&ADC_InitStructure);
ADC_CommonStructInit(&ADC_CommonInitStructure);
DMA_StructInit(&DMA_InitStructure);
// Setup Peripheral Clocks
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2,ENABLE);
// GPIO Pin Configuration in Analog Mode
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
GPIO_Init(GPIOC, &GPIO_InitStructure);
//Configure DMA2, Stream4 on Channel 0
DMA_DeInit(DMA2_Stream4); 
DMA_InitStructure.DMA_Channel = DMA_Channel_0;
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR;
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&ADC_Values[0];
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
DMA_InitStructure.DMA_BufferSize = 1;
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_Disable;
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_Init(DMA2_Stream4, &DMA_InitStructure);
DMA_Cmd(DMA2_Stream4, ENABLE);
ADC_DeInit();
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConvEdge_None;
ADC_InitStructure.ADC_NbrOfConversion = 1;
ADC_InitStructure.ADC_ScanConvMode = ENABLE;
ADC_Init(ADC1,&ADC_InitStructure);
ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;
ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2;
//ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles; // Dont need this in Independant ADC Mode
ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;
ADC_CommonInit(&ADC_CommonInitStructure);
ADC_RegularChannelConfig(ADC1,ADC_Channel_10,1,ADC_SampleTime_480Cycles);
ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE); // Causing ADC to read 0xFFF if Continuous Conversion mode is enabled
ADC_DMACmd(ADC1, ENABLE);
ADC_Cmd(ADC1, ENABLE); 
ADC_SoftwareStartConv(ADC1); // Start ADC1 conversion
}

Keep in mind that I want to actually convert on 8 channels but in the code above I am only converting on one channel to make debugging easier. However, using the code above I have some unusual behaviour. Whenever the ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE); command is present, the ADC would output 0xFFF, all the time. If commented out, the ADC would convert the value correctly but only on the first attempt after flashing the chip. And after resetting the chip, the ADC conversion value is close to the real value but never the same and never as close as the first time after flashing. Therefore after every instance that I flash the chip, I can get the correct ADC reading but not in any other scenario. Another interesting thing is that I turned off the Continuous conversion mode and uncommented ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE);. This gave the same result whereby the ADC result would only be correct after flashing the chip. I really don't know why this code wouldn't work. My discovery board has stopped working otherwise I would try the code on there. I have tried other ADC Channels as well with the same result. I don't know what to do anymore and any help would be appreciated. I also have a problem with the DAC where the output value is much lower than expected. And setting the DAC register to low values will cause the output to oscillate. Below is my DAC Code:

void DAC_init(void)
{
DAC_InitTypeDef DAC_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure ;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
GPIO_StructInit(&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
GPIO_Init(GPIOA, &GPIO_InitStructure);
DAC_InitStructure.DAC_Trigger = DAC_Trigger_None;
DAC_InitStructure.DAC_WaveGeneration = DAC_WaveGeneration_None;
DAC_InitStructure.DAC_OutputBuffer = DAC_OutputBuffer_Enable;
DAC_Init(DAC_Channel_1, &DAC_InitStructure);
DAC_Cmd(DAC_Channel_1, ENABLE);
}

Thanks #adc #dac #stm32 #dma
3 REPLIES 3
Posted on September 11, 2014 at 18:01

What tool chain?

I'd perhaps be using a volatile buffer, with a deeper array. I've typically used a different DMA configuration.

What's attached to the DAC pin? There's not much load driving capability.

How's +VREF attached?

How do some my examples [DEAD LINK /public/STe2ecommunities/mcu/Lists/cortex_mx_stm32/Flat.aspx?RootFolder=/public/STe2ecommunities/mcu/Lists/cortex_mx_stm32/Help%20with%20simple%20ADC%20on%20STM32F4&FolderCTID=0x01200200770978C69A1141439FE559EB459D7580009C4E14902C3CDE46A77F0FFD06506F5B&currentviews=5702]posted here work?
Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
k2399
Associate
Posted on September 11, 2014 at 19:33 Thanks for responding. The tool chain is Keil MDK-ARMv5 The VREF+ pin is attached to 3.3V using a ferrite bead and a low pass filter. It is connected exactly how it is on the discovery board schematic. The DAC pin is connected into an opamp buffer so not really driving any load from the DAC pin directly. I have tried using the code below from your examples. It seemed to me that it is the simplest and should work.

void RCC_Configuration(void)
{
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
}
/**************************************************************************************/
void GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/* ADC Channel 11 -> PC1 */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
GPIO_Init(GPIOC, &GPIO_InitStructure);
}
/**************************************************************************************/
void ADC_Configuration(void)
{
ADC_CommonInitTypeDef ADC_CommonInitStructure;
ADC_InitTypeDef ADC_InitStructure;
/* ADC Common Init */
ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;
ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2;
ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;
ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;
ADC_CommonInit(&ADC_CommonInitStructure);
ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
ADC_InitStructure.ADC_ScanConvMode = DISABLE; // 1 Channel
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; // Conversions Triggered
ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None; // Manual
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T2_TRGO;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfConversion = 1;
ADC_Init(ADC1, &ADC_InitStructure);
/* ADC1 regular channel 11 configuration */
ADC_RegularChannelConfig(ADC1, ADC_Channel_11, 1, ADC_SampleTime_144Cycles); // PC1
/* Enable ADC1 */
ADC_Cmd(ADC1, ENABLE);
}
/**************************************************************************************/
#define BUFFERSIZE 128
uint16_t ADCConvertedValues[BUFFERSIZE];
int main(void)
{
int i;
RCC_Configuration();
GPIO_Configuration();
ADC_Configuration();
STM_EVAL_LEDInit(LED3); /* Configure LEDs to monitor program status */
STM_EVAL_LEDOn(LED3); /* Turn LED3 on */
i = 0;
while(1) // Don't want to exit
{
/* Start ADC1 Software Conversion */
ADC_SoftwareStartConv(ADC1);
while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);
ADCConvertedValues[i++] = ADC_GetConversionValue(ADC1);
i %= BUFFERSIZE;
}
}

I am printing out the ADCConvertedValue[i] onto the serial port and I see something unusual whereby the converted value is 0 for the first 128 cycles of the while loop and then the value is 4095 continuously. I am starting to believe that there is a fault in my microcontroller and may need to solder a new one onto my board.
frankmeyer9
Associate II
Posted on September 12, 2014 at 09:25

The DAC pin is connected into an opamp buffer so not really driving any load from the DAC pin directly. 

 

That depends on the circuitry, and the opamp.

Without the output buffer enabled, the DAC has an output impedance of 1 Megaohm. This is easy to overload with certain opamps and feedback circuitry.

With output buffer enabled, this reduces to 15 kOhm, but at the expense of (up to) 200mV offset at each rail. Just read the DAC section of the datasheet carefully.