cancel
Showing results for 
Search instead for 
Did you mean: 

ADC fluctuations problem

Maciej Skrzypczak
Associate II
Posted on February 26, 2018 at 14:50

Hi,

I am having a problem with ADC read. The values I get from conversion are 100% random. They get from 0 to max range without any pattern. Example codes from MXCube work fine and the value is stable. My own code generated in cube is not fixing the issue. I tried to compare the example and my own code, but didnt find any difference besides CPUcache beeing enabled in example (that I ignored). Every other function in ADC works for me. Can anyone please tell me what am I doing wrong? Thanks in advance!

I am using KeiluVision 5.0 with STM32F767ZI on nucleo board. Here is my code 

.

int main()

{

   ADC_init();

   ADC_port_init();

}

.

void ADC_port_init(void)

{

   /////////// AHB for GPIOA

   RCC -> AHB1ENR |= RCC_AHB1ENR_GPIOAEN;

.

   /////////// Pin A1 analog

   GPIOA -> MODER |= GPIO_MODER_MODER1_0 | GPIO_MODER_MODER1_1;

.

   /////////// Pin A1 very high speed

   GPIOA -> OSPEEDR |= GPIO_OSPEEDER_OSPEEDR1_0 | GPIO_OSPEEDER_OSPEEDR1_1;

}

.

void ADC_init (void)

{

   /////////// Conwerter ON

   ADC1 -> CR2 |= ADC_CR2_ADON;

.

   /////////// APB for ADC init

   RCC->APB2ENR |= RCC_APB2ENR_ADC1EN;

.

   /////////// Interrupt when EOC

   ADC1 -> CR1 |= ADC_CR1_EOCIE;

.

   /////////// 12 bit resolution (11)

   ADC1 -> CR1 &= ~ADC_CR1_RES_0 & ~ADC_CR1_RES_0;

.

   /////////// Single conversion

   ADC1 -> CR2 &= ~ADC_CR2_CONT;

.

   /////////// EOC after regular group

   ADC1 ->CR2 &= ~ADC_CR2_EOCS;

.

   /////////// Sample time 480 cycles (010)

   ADC1 ->SMPR2 |= ADC_SMPR2_SMP1_0 | ADC_SMPR2_SMP1_1 | ADC_SMPR2_SMP1_2;

.

   /////////// 1 measurement in regular group (0000)

   ADC1 -> SQR1 &= ~ADC_SQR1_L_0 & ~ADC_SQR1_L_1 & ~ADC_SQR1_L_2 & ~ADC_SQR1_L_3;

.

   /////////// First measurement on PA1 (0001)

   ADC1 -> SQR3 &= ~ADC_SQR3_SQ1_0 | ADC_SQR3_SQ1_1 & ~ADC_SQR3_SQ1_2 & ~ADC_SQR3_SQ1_3;

.

   /////////// Start regular conversion

   ADC1 -> CR2 |= ADC_CR2_SWSTART;

}

#problem #adc #fluctuations #stm32f767zi
10 REPLIES 10
AvaTar
Lead
Posted on February 26, 2018 at 15:15

I don't cube.

But what seems to stick out:

   /////////// Conwerter ON

   ADC1 -> CR2 |= ADC_CR2_ADON;

   /////////// APB for ADC init

   RCC->APB2ENR |= RCC_APB2ENR_ADC1EN;

Always enable the peripheral first (RCC) before you write to any of it's registers.

Posted on February 26, 2018 at 16:12

ADC1 -> SQR3 &= ~ADC_SQR3_SQ1_0 | ADC_SQR3_SQ1_1 & ~ADC_SQR3_SQ1_2 & ~ADC_SQR3_SQ1_3;

What?

JW

Posted on February 26, 2018 at 17:50

Thank You for Your reply. I realised now that the code contains some mistakes(not too big). Your solution ended up changing the behavior of ADC, but not solved that. Now instead of getting a value in full range of 12 bits I get it in first 25% that is from 0 to about 1000. I would like to ask You if there is any register for the ADC control that I should include. I saw that in older versions of the device people calibrated their ADCs but i didnt find that is datasheet.

Posted on February 26, 2018 at 17:51

Ye, that was bad... After changing the code ADC still not operating well. Have You got any ideas?

Posted on February 26, 2018 at 18:18

Maciej Skrzypczak wrote:

ADC still not operating well. 

What, exactly, does that mean?

Be specific.

Give numbers.

Also, have you looked at the ADC input on an oscilloscope? If it's noisy, then you will obviously get noisy results!

You need to use 

an oscilloscope - a meter reading is useless here.

Posted on February 26, 2018 at 18:28

I didnt measure the signal on the oscilloscope but the example project in cube worked with almost no fluctuations. My hand made code returns values that are even 50% off from the expecte value. For example, when I set the potentiometer to the half range i get sometimes 0 and sometimes 4095. The outputs are randomly oscliating and I cant control them. I assume the signal cant be too bad because I use the nucleo board that has built in LC filter. I expect some error but not randomness.

Posted on February 26, 2018 at 19:08

Initialization of peripherals is usually a onetime thing - efficiency is not real important.

So I used to take an example (SPL at this times) copied and modified it.

You could try a Cube or LL example, see if it works, and copy the init code.

Now instead of getting a value in full range of 12 bits I get it in first 25% that is from 0 to about 1000.

This sounds like a different problem.

As JW commented to your

ADC1 -> SQR3 &= ~ADC_SQR3_SQ1_0 | ADC_SQR3_SQ1_1 & ~ADC_SQR3_SQ1_2 & ~ADC_SQR3_SQ1_3;

line:

Have you checked that it actually does what you think it should ?

Posted on February 26, 2018 at 23:28

Ye, I checked and it wasnt the way I expected. After correction the code behaves still the same way (almost full range fluctuatiions). This register was responsible for selecting a channel to measure. I was so desperate that i connected all inputs of ADC to 1 signal that I wanted to measure so it didnt impact my results.

In the meantime the results returned to the same spot as before (almost full range fluctuations). Probably I wrote the last reply too early and not everything was set up. 

Can You please tell me what LL is?

As I wrote, I tied to compare a Cube example but I cant really see the difference besides 'cache_enable' command and some clocks speeds.

My init code for ADC now looks like that: 

/////////// APB for ADC init

RCC->APB2ENR |= RCC_APB2ENR_ADC1EN;

.

/////////// Converter ON

ADC1 -> CR2 |= ADC_CR2_ADON;

.

/////////// Interrupt when EOC

ADC1 -> CR1 |= ADC_CR1_EOCIE;

.

/////////// 12 bit resolution (00)

ADC1 -> CR1 &= ~ADC_CR1_RES_0 & ~ADC_CR1_RES_0;

.

/////////// Single conversion

ADC1 -> CR2 &= ~ADC_CR2_CONT;

.

/////////// EOC after regular group

ADC1 ->CR2 &= ~ADC_CR2_EOCS;

.

/////////// Sample time 28 cycles (010)

ADC1 ->SMPR2 |= ADC_SMPR2_SMP1_1;

.

/////////// 1 measurement in regular group (0000)

ADC1 -> SQR1 &= ~ADC_SQR1_L_0 & ~ADC_SQR1_L_1 & ~ADC_SQR1_L_2 & ~ADC_SQR1_L_3;

.

/////////// First measurement on PA1 (0001)

ADC1 -> SQR3 |= ADC_SQR3_SQ1_0;

.

/////////// Start regular conversion

ADC1 -> CR2 |= ADC_CR2_SWSTART;
Posted on February 27, 2018 at 07:19

Can You please tell me what LL is?

ST's LowLevel - API, a subset of the monstrous Cube.

The modules belonging to this API have a '_ll' in the file name.

I was so desperate that i connected all inputs of ADC to 1 signal that I wanted to measure so it didnt impact my results.

I would connect one ADC input to a fixed voltage, and the others to GND, both with relatively low impedance connections.

Are you sure about the proper input terminals (pins) ?

Anything else on the pin(s) ?