AnsweredAssumed Answered

ADC reading problem

Question asked by amer.sherif.001 on Sep 28, 2013
Latest reply on Sep 30, 2013 by baird.hal.001
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 2810. 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 71.5 cycles instead of 239.5, the digital output decreases to around 2360. The battery level doesn't have that much of fluctuations to differ from one sampling rate to another!

Outcomes