2013-09-28 12:19 PM
Hi all
This task is absolutely simple and I'm really wondering why i'm having a problem with it. I'm supposed to read the battery level via the ADC on stm32f100c8. What i'm doing is completely and utterly basic, nothing big! Take a look at this:void ADC_Config(void)
{
/* Enables the High Speed APB (APB2) peripheral clock, ADC1 */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
/**
* Steps to switch the ADC ON
* Initialize ADC1 with the parameters
* Assign the channels
* Enable the interrupts
* Enable ADC DMA transfer
* Enable the ADC
* Calibrate the ADC
* Start conversion
*/
/* Initialize the ADC1 according to the ADC_InitStructure members */
ADC_InitTypeDef ADC_InitStructure;
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
ADC_InitStructure.ADC_ScanConvMode = DISABLE;
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfChannel = 1;
ADC_Init(ADC1, &ADC_InitStructure);
/* Configures ADC1 Channel0 */
ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_239Cycles5);
/* Enable ADC1 EOC interrupt */
ADC_ITConfig(ADC1, ADC_IT_EOC, ENABLE);
/* Enable ADC1 */
ADC_Cmd(ADC1, ENABLE);
/* Reset the ADC1 Calibration registers */
ADC_ResetCalibration(ADC1);
/* Check the end of ADC1 reset calibration register */
while(ADC_GetResetCalibrationStatus(ADC1));
/* It is recommended to start calibration for the ADC after each power up */
/* Start the ADC1 Calibration */
ADC_StartCalibration(ADC1);
/* Get the ADC1 calibration status */
while(ADC_GetCalibrationStatus(ADC1));
/* Start by software the ADC1 Conversion */
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
}
/* ADC ISR */
void __attribute__ ((interrupt)) __cs3_isr_adc1_2 (void)
{
static uint8 counter = 0;
static uint16 ConvertedValue = 0;
if(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC))
{
ADC_ClearFlag(ADC1, ADC_FLAG_EOC);
/* Clear the ADC1 EOC interrupt pending bit */
ADC_ClearITPendingBit(ADC1, ADC_IT_EOC);
if(ConversionIsComplete == 0)
{
counter++;
ConvertedValue += ADC_GetConversionValue(ADC1);
if(counter == 10) /* Collect 10 values and take the average */
{
BatteryADCValue = ConvertedValue/(uint16)(counter);
ConvertedValue = 0;
counter = 0;
ConversionIsComplete = 1; /* Raise a flag to check on in main */
}
}
}
}
int main(void)
{
/* System Clocks Configurations */
RCC_Config();
/* IOs Configurations */
Port_Config();
/* ISR Configurations */
NVIC_Config();
/* ADCs Configurations */
ADC_Config();
while(1)
{
if(ConversionIsComplete)
{
CheckBatteryLevel();
ConversionIsComplete = 0; /* Reset the Flag */
}
}
}
Forget about any unmentioned functions, the problem is that I receive different value than what I actually read from the pin via the avometer.
The conversion value when using a source of 3.2volts is around 28 When applying this value to this equation: Vin = Vdigital*Vref/2^12, Vin = 2.2volts which might have been sensible only if the avometer reads the same, but it doesn't, it reads 1.87volts.
Another nonsense arises when I change the sampling rate, like if I used 5 cycles instead of 5, the digital output decreases to around 2 The battery level doesn't have that much of fluctuations to differ from one sampling rate to another!
#adc
2013-09-29 07:06 AM
You missed a clue - the 239.5 sampling time results in the expected converted value.
There is nothing wrong with the code. The problem is that the battery has a limited current drive ability to charge up the ADC multiplexor sample and hold capacitor. The longer sample time is needed to get the capacitor fully charged. Cheers, Hal2013-09-29 08:18 AM
That sounds reasonable but it only resolves the second part of the problem.
2013-09-30 05:06 AM
Check for other possible other problem sources:
The ADC pin not initialized in AN mode. The ADC pin is also connected to something else (a common problem on Discovery kits). Incorrect ADC clock speed. Cheers, Hal