rogerclarkmelbourne / Arduino_STM32

Arduino STM32. Hardware files to support STM32 boards, on Arduino IDE 1.8.x including LeafLabs Maple and other generic STM32F103 boards
Other
2.53k stars 1.26k forks source link

Non zero values on ADC in DMA mode #612

Closed fa1ke5 closed 5 years ago

fa1ke5 commented 5 years ago

Hi all! im testing DMA mode of one channel ADC and take non zero samles on it. im using example code MultiChannelContinuousConversion. and i only correcting multichannel to one channel. i have 20nF and correct voltage divider, but take this in terminal

begin sample[0] = 134 sample[1] = 133 sample[2] = 134 sample[3] = 135 sample[4] = 133 sample[5] = 134 sample[6] = 136 sample[7] = 134

If im change myADC.setSampleRate(ADC_SMPR_1_5); to ADC_SMPR_7_5 level is lower and i take this output

begin sample[0] = 97 sample[1] = 97 sample[2] = 95 sample[3] = 97 sample[4] = 96 sample[5] = 95 sample[6] = 97

e.t.c In this case, i can read external voltage on ADC input, but measurement is non linear.

If im use direct reading by STM32ADC::getData() function all Ok, linear and zero level is perfect.

stevstrong commented 5 years ago

In scan mode you are not allowed (at least is not recommended) to convert the same input as multiple channels simultaneously.

fa1ke5 commented 5 years ago

I dont using scan mode

`//calibrate ADC myADC.calibrate();

// Set up our analog pin(s) // for (unsigned int j = 0; j <8; j++) pinMode(pins[0], INPUT_ANALOG);

myADC.setSampleRate(ADC_SMPR_1_5);//set the Sample Rate // myADC.setScanMode(); //set the ADC in Scan mode. myADC.setPins(pins, 1); //set how many and which pins to convert. myADC.setContinuous(); //set the ADC in continuous mode.

//set the DMA transfer for the ADC. //in this case we want to increment the memory side and run it in circular mode //By doing this, we can read the last value sampled from the channels by reading the dataPoints array myADC.setDMA(dataPoints, 8, (DMA_MINC_MODE | DMA_CIRC_MODE), NULL);

//start the conversion. //because the ADC is set as continuous mode and in circular fashion, this can be done //on setup().
myADC.startConversion();
`

fa1ke5 commented 5 years ago

any solutions???

stevstrong commented 5 years ago

Please post the complete example. Which is your target board? 20nF capacitor is too small, try higher values, ~1µF.

fa1ke5 commented 5 years ago

`/* This example shows how to use the ADC library to continuously sample several channels/pins. The acquisition of the channels is done using DMA in circular mode.

*/

include

STM32ADC myADC(ADC1);

define BOARD_LED D33 //this is for Maple Mini

//Channels to be acquired. uint8 pins[] = {PB0};

const int maxSamples = 8; // 8 channels

// Array for the ADC data uint16_t dataPoints[maxSamples];

void setup() { Serial.begin(19200); pinMode(BOARD_LED, OUTPUT); pinMode(D32, INPUT); //startup blink... good idea from Pig-O-Scope digitalWrite(BOARD_LED, HIGH); delay(1000); digitalWrite(BOARD_LED, LOW); delay(1000);

//calibrate ADC myADC.calibrate();

// Set up our analog pin(s) // for (unsigned int j = 0; j <8; j++) pinMode(pins[0], INPUT_ANALOG);

myADC.setSampleRate(ADC_SMPR_1_5);//set the Sample Rate // myADC.setScanMode(); //set the ADC in Scan mode. myADC.setPins(pins, 1); //set how many and which pins to convert. myADC.setContinuous(); //set the ADC in continuous mode.

//set the DMA transfer for the ADC. //in this case we want to increment the memory side and run it in circular mode //By doing this, we can read the last value sampled from the channels by reading the dataPoints array myADC.setDMA(dataPoints, 8, (DMA_MINC_MODE | DMA_CIRC_MODE), NULL);

//start the conversion. //because the ADC is set as continuous mode and in circular fashion, this can be done //on setup().
myADC.startConversion();

}

void loop(){ //send the latest data acquired when the button is pushed.

  Serial.println("begin");
  // Take our samples

  for(unsigned int i = 0; i < maxSamples; i ++) {
    Serial.print("sample[");
    Serial.print(i);
    Serial.print("] = ");
    Serial.println(dataPoints[i]);
    }

}`

Capacitor dont change anything, im using voltage divider 12k x 160k (1/13) for measuring up to 48V input. if im use ADC_SMPR_1_5 i take nonzero level

begin sample[0] = 134 sample[1] = 137 sample[2] = 136 sample[3] = 136 sample[4] = 134 sample[5] = 136 sample[6] = 137 sample[7] = 136

if i use ADC_SMPR_239_5 i take about 5-6 nonzero values in shorten divider

begin sample[0] = 6 sample[1] = 6 sample[2] = 8 sample[3] = 6 sample[4] = 5 sample[5] = 5 sample[6] = 7 sample[7] = 5

But if i using direct reading ADC data by getData() funcrion, i take nice zerolevel, 0 in terminal and good linearty. And more....if i connect divider to negative voltage source " - 1 " V, i take good zero on terminal. I think in DMA mode ADC registers have a wrong setting. PS Im using blue pill board without modding.... PPS Sorry for my poor englesh, nice day!

fa1ke5 commented 5 years ago

Voltage divider is equal this https://www.stm32duino.com/viewtopic.php?t=3233#p41495 and this code nice working

//Shorten 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 //1.6V in 0.437 0.461 0.468 0.464 0.468 0.468 0.468 0.468 0.471 0.464 0.464 0.464 0.464 0.471 0.464 0.468 0.464 0.464

fa1ke5 commented 5 years ago

???

stevstrong commented 5 years ago

If you think that ADC registers have wrong settings, then you are welcome to correct them. I would suggest to use a higher capacitor and lower resistance, because ~10kOhm impedance is too high for high speed AD conversion.

fa1ke5 commented 5 years ago

10kOm work great, im testing it above in one sample mode and code work nice, but if im using DMA its data is corrupt. https://leoniv.livejournal.com/194681.html capacitor dont may be must greater then 10-100 nF and dont use it is good idea.....

fa1ke5 commented 5 years ago

i testing another resistors and capacitors, it does not solve the problem

fa1ke5 commented 5 years ago

may be possible solution is described here https://blog.kiltum.tech/2017/08/16/stm32-adc-multiple-channels-hal/ https://github.com/kiltum/stm32adc

fa1ke5 commented 5 years ago

Hi all! I successfully solved the ADC problem! as discribed here https://leoniv.livejournal.com/194681.html lage capasitor in filter is violates the correct operation of the ADC. In my case im down capacitive of input filter on 4 nF and take good ADC samples in ADC_SMPR_41_5 sample rate.

chechobertotti commented 4 years ago

hi,

in my experience, your problem is about signal source output impedance.

if its low, you will not have problem, but with higer values you will start to see this kind of errors.

i suggest carefull reading of st appnotes, especially a "Workaround for extra high impedance sources" item starting on page 40

https://www.st.com/resource/en/application_note/cd00211314-how-to-get-the-best-adc-accuracy-in-stm32-microcontrollers-stmicroelectronics.pdf

you must increase the sample time, and time between samples. there you can see how to calculate both

stm32 dont have a buffer amp hardware in every analog input, then your circuit will be connected directly to the internal sample capacitor, and this is why output impedance must be low

read this too. https://www.analog.com/media/en/analog-dialogue/volume-46/number-4/articles/front-end-amp-and-rc-filter-design.pdf