Skip to main content
Amal Babu
Associate III
October 2, 2018
Question

Non linearity in ADC Measurement using STM32F051R4T6TR IC

  • October 2, 2018
  • 28 replies
  • 5997 views

Hai,

i have been into designing a solar inverter using STMF051R4 series IC for past few years. Presently we are working

on ADC Measurement with DC voltage.The problem we are facing now is we not able to get a linearity in measurement of the dc voltage at the adc pins of the STM32 ic.We are getting different ratio for the different voltage ranges when we linearly increase the voltage with a constant difference .Can you please suggest me what kind of problem am i facing with the measurement of the voltages.Specifically can someone help me with the error i am facing right now.

I have also tried using low pass filter but couldnt find much difference in reading the values at the adc pins of the ic.

    This topic has been closed for replies.

    28 replies

    Amal Babu
    Amal BabuAuthor
    Associate III
    October 3, 2018

    Check out my code shown below:

    This is the way i am reading the converted adc values 'max' variable

    int main()

     {

       Start_HSE();

       PORTA_CLK_EN;   

       PORTB_CLK_EN;

       PORTC_CLK_EN;

           adc_configuration();

       DMA_config();

       while(1)

        {

          max = ADC_array[0];                  

        }

     }

    void DMA_config()

    {

       RCC->AHBENR |= RCC_AHBENR_DMA1EN;

       DMA1_Channel1->CPAR = (uint32_t) (&(ADC1->DR));

       DMA1_Channel1->CMAR = (uint32_t)(ADC_array);

       DMA1_Channel1->CNDTR = 1;

       DMA1_Channel1->CCR |= DMA_CCR_MINC | DMA_CCR_MSIZE_0 | DMA_CCR_PSIZE_0 | DMA_CCR_TEIE | DMA_CCR_CIRC | DMA_CCR_PL_0;

       DMA1_Channel1->CCR |= DMA_CCR_EN;

    }

    void adc_configuration()

    {

       GPIOC->MODER |= BIT(9) | BIT(8);                                                      // Analog mode

       GPIOA->MODER |= BIT(7)| BIT(6);

          ADC1->CR &= ~ADC_CR_ADEN;

       RCC->APB2ENR |= RCC_APB2ENR_ADCEN;                                                              //Select a clock source for the ADC

       ADC1->CFGR2 |= ADC_CFGR2_CKMODE_0;    

       ADC1->SMPR |= 0X00000007;

       ADC1->CFGR1 |= ADC_CFGR1_CONT | ADC_CFGR1_DMACFG | ADC_CFGR1_DMAEN | ADC_CFGR1_RES_0| ADC_CFGR1_SCANDIR;

       ADC1->CFGR1 &= ~(ADC_CFGR1_ALIGN | ADC_CFGR1_SCANDIR);                                 // Right alignment, Upward scan

           ADC1->SMPR   &= ~ADC_SMPR_SMP;                                                          // 1.5 ADC clock cycles

       ADC1->CHSELR |= ADC_CHSELR_CHSEL4 ;                   // Input Channel-0 is selected for conversion

       //ADC Enable

       ADC1->CR |= ADC_CR_ADEN;

       while(!(ADC1->ISR & ADC_ISR_ADRDY));

       ADC1->CR |= ADC_CR_ADSTART;

    }

    T J
    Senior III
    October 3, 2018

    You could configure a timer interrupt to do a single channel conversion, without DMA

    what rate do you need the data ?

    Amal Babu
    Amal BabuAuthor
    Associate III
    October 3, 2018

    Actually i am using my timers for SPWM generation and need DMA for managing my adc measurement.

    T J
    Senior III
    October 3, 2018

    did you do the calibration ?

    which reading is correct ?

    Suggest that you check your Vdda reading and do the calculations to prove its correct.

    AvaTar
    Senior III
    October 3, 2018

    > Can you Please throw some light on these statements...can you please make it more clear

    In your case, you will need to transfer 4 half-words (16 bit) for 4 channels. The DMA unit doesn't mind if you configure anything else, only the data would be a mess.

    In other words, you must take care yourself that DMA source (ADC channels), transfer size and target area (memory buffer size and alignment) match, else you get runtime issues.

    Use the DMA TC interrupt to pick up the array of ADC values, and move them out for processing. Else they are overwritten in the next conversion cycle.

    I would suggest to first get the ADC setup right by its own. Just present a reasonable voltage (0V ... 3.0V) directly to the inputs, and check that the value and the memory location is correct.

    Only then start to include your divider network / opamp circuitry.

    Amal Babu
    Amal BabuAuthor
    Associate III
    October 3, 2018

    The shown below is the ISR for DMA

    void DMA1_Channel1_IRQHandler(void)

    {

    min = ADC_array[0];

    DMA1->IFCR = DMA_IFCR_CTCIF1 ;

    }

    The probkem is that, when i use this ISR to read the value , the program loops within this ISR.And no other statements written after this , are not being executed.

    T J
    Senior III
    October 4, 2018

    I know you are looking in the reference manual,

    on this line,

    DMA1->IFCR = DMA_IFCR_CTCIF1

    can you check the other interrupt flags and clear them too ?

    T J
    Senior III
    October 4, 2018

    copy and paste doesn't work...

    attaching now.