2012-11-26 10:39 PM
Hello All,
I am using STM32F2 series of controller. I want to monitor the battery voltage of my device which is connected to GPIO Pin 3 of port A which has alternate function of ADC1. Here is my code void RCC_Configuration(void) { RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); //Enable ADC1 Clock RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); RCC_AHB1PeriphResetCmd(RCC_AHB1Periph_DMA2, ENABLE); } void GPIO_Configuration(void) { GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ; GPIO_Init(GPIOA, &GPIO_InitStructure); }volatile uint16_t ADC1ConveretedValue[64]=0;
volatile uint32_t ADC1ConvertedVoltage=0;void DMA_Configuration(void)
{ DMA_InitTypeDef DMA_InitStructure;/* DMA2_Stream0 channel0 configuration **************************************/
DMA_DeInit(DMA2_Stream0); DMA_InitStructure.DMA_Channel = DMA_Channel_0; DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)ADC1_DR_Address; DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&ADC1ConveretedValue; DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory; DMA_InitStructure.DMA_BufferSize = 64; DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable; 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_Stream0, &DMA_InitStructure); /* DMA2_Stream0 enable */ DMA_Cmd(DMA2_Stream0, ENABLE);ADC_DMACmd(ADC1, ENABLE);
}void AdcInit(void)
{ ADC_InitTypeDef ADC_InitStructure; ADC_CommonInitTypeDef ADC_CommonInitStructure; /* 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);/* ADC1 Init ****************************************************************/
ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b; ADC_InitStructure.ADC_ScanConvMode = DISABLE; ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None; ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1; ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; ADC_InitStructure.ADC_NbrOfConversion = 1; ADC_Init(ADC1, &ADC_InitStructure);ADC_RegularChannelConfig(ADC1,ADC_Channel_1,1,ADC_SampleTime_3Cycles);
ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE);
ADC_DMACmd(ADC1, ENABLE);
}
int8_t ReadADC1(void)
{ uint8_t TimeOut=2000; ADC_RegularChannelConfig(ADC1, ADC_Channel_3, 1, ADC_SampleTime_3Cycles); ADC_SoftwareStartConv(ADC1); // Wait until conversion completion if(TimeOut>0) { while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET); //Check End of Concersion Flag return ADC_GetConversionValue(ADC1); // Get the conversion value TimeOut--; } else return ADC_TIMEOUT_ERROR; }int main(void)
{ ADC_InitTypeDef ADC_InitStructure; DMA_InitTypeDef DMA_InitStructure; TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_OCInitTypeDef TIM_OCInitStructure; ADC_CommonInitTypeDef ADC_CommonInitStructure;/* System clocks configuration ---------------------------------------------*/ RCC_Configuration(); /* GPIO configuration ------------------------------------------------------*/ GPIO_Configuration(); DisplayInit();
DMA_Configuration();
AdcInit();
while(1) { uint8_t ConvertedValue; ConvertedValue=ReadBatteryVoltage(); DisplaySetPos(0,0); DisplayWriteData(ConvertedValue); Delay_M(200); DisplayWriteCmd(DISPLAY_CMD_CLR); delay(20); } /* does not exit - kind of important */ return 0; }int8_t ReadVoltage()
{ uint8_t ConvertedValue; ConvertedValue=ReadADC1(); return ConvertedValue; } I cannot see any output from ADC.Could anyone pls let me know if anything is missed out or something wrong #vbat-monitoring #adc #stm322012-11-27 07:07 AM
3 Cycles is probably too quick to get a stable measurement.
Decide if you're using DMA or polling, DMA will copy values into the buffer defined for it, read the values in the buffer and convert the 12-bit value by scaling against VDDA (VREF). The ADC will not be able to measure voltages that exceed VDDA The ADC has a VBAT channel for the battery supply pin of the device. Don't use 8-bit variables to pass 12/16-bit content.2012-11-27 08:45 PM
Thanks Clive
I have changed sampling time to ADC_SampleTime_15Cycles. I have decided to use DMA.DMA will copy values into the buffer defined for it, read the values in the buffer The buffer i have defined is ADC1ConveretedValue DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&ADC1ConveretedValue;So i have to read this. Please let me know if i am correct. Could u pls tell me more about converting 12 bit value by scaling against VDDA. Thanks2012-11-27 09:28 PM
Well it's reading constantly into an array, you'd probably want
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&ADC1ConveretedValue[0]; // For a 3.3V reference/supply something like float voltage; voltage = ((float)(ADC1ConvertedValue[0] & 0xFFF) * 3.3) / 4096.0; int millivolts; millivolts = ((int)(ADC1ConvertedValue[0] & 0xFFF) * 3300) >> 12;2012-11-28 02:20 AM
Hi,
In the STM32F2 StdPeriph_Lib package, there is a similar example (VBAT_Measurement). It takes into account that the VBAT pin is internally connected to a bridge divider by 2 to avoid exceeding VDDA (VBAT/2 connected to ADC1_IN18). Cheers, STOne-32