cancel
Showing results for 
Search instead for 
Did you mean: 

Non linearity in ADC Measurement using STM32F051R4T6TR IC

Amal Babu
Associate III

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.

28 REPLIES 28
Amal Babu
Associate III

> This sounds like your DMA configuration, i.e. number of elements, is not right.

> DMA is a "dumb" unit that transfers the configured number of elements of configured size.

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

Amal Babu
Associate III

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
Lead

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

what rate do you need the data ?

Amal Babu
Associate III

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

T J
Lead

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
Lead

> 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
Associate III

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
Lead

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
Lead

copy and paste doesn't work...

attaching now.