Giter VIP home page Giter VIP logo

Comments (6)

maxmeli123 avatar maxmeli123 commented on August 17, 2024

Check here at the voice 'Minimize noise', as you can see are exact my advices, use a 100nF to GND and sample more samples, then average the result, possibly add a small delay between any sample acquire will increase accuracy:
https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/adc_calibration.html#minimize-noise

Sorry if I used another message, and sorry if a link is just a text, but my actually pc browser do not allow it, only my phone can do it.

from esp32-adc-calibrate.

techstudio-design avatar techstudio-design commented on August 17, 2024

Thanks for the comment. The idea of using LEDC to generate as a liner voltage reference is certainly an interesting one and I know nothing about it until you mentioned it, I will certainly give it a try when I have time.

To be honest, I haven't touch the ESP32 ADC since 3-year ago when I was doing these testings. Nowadays, I either uses an external 16-bit ADC chip with I2C interface with a separate power rail for serious work (for clients who need precision ADC), or for hobby and quick-and-dirty project, using a much simple 5 sampling points at different voltages, and create an array like adcValues[5]{{1163, 1569, 1657, 1734, 2021} for each voltage measurement. It is much simpler than going through the elaborated way that I was doing several years ago.

from esp32-adc-calibrate.

maxmeli123 avatar maxmeli123 commented on August 17, 2024

Hi, thanks for reply and sorry for delay on my reply,

I managed it a bit to work with a LEDC as precise reference managing 4096 values.
Here a first attemp to do it, note that I used some digital LOW PASS FILTERS to search to remove noise but may these are not necessary.
If you see the code I replaced the internal DAC (8 bit 256 values with LEDC) and setup it to the same resolution to get 4096 values.

To use this I've put an RC to output pin, like a resistor in serie and a small capacitor in parallel to GND.

Anyway it is an high frequency PWM an need to be filtered.

Because I do not know exact values I've put a trimmer and an adjustable capacitor.
I've tried to get a more clean signal as possible but just using a serial monitor to get results is not the right way to do this, need an oscilloscope (and I don't have it).

Note that before this and after I tried your code, I've wrote an ESP32 library based on it, I called it ESP32LinearADC, it works like your code and it is very simple to use, something like that;

#include <ESP32LinearADC>

ESP32LinearADC ADC;

Serial.print ("Initializing ADC ...  ");
if (! ADC.begin()) {   // Begin ADC
      Serial.println ("Error while initialize ADC");
      while (1) delay (1);
}

// Uncomment this line once to calibrate ADC and show ADC LUT on serial monitor, then 
// copy it once to User_Setup.h library header. After this any time you read ADC will return
// linear values.
//ADC.getCalibrationArray();

uint16_t value = ADC.read(35);  // This return our linear raw value (0 to 4095, note that is has a small gap under 50 and highter than 4030 that cannot be fixed)  no need to do anything else, just read values.

float voltage = ADC.read(35,  3.3);  /// Pin, vRef  This return the voltage

This worked well, and use your code to calculate calibration LUT. But now I want to improve it by using LEDC with true 4096 values.
If you want to do a try here some code you can adapt. I do not removed comments, so maybe can be useful for you.... my apologies if I cannot put the code in a code tag, but I'm here with an old PC and my browser refuse to do it.

I hope it is useful for you, at least it will show you how use LEDC to get it working.
If you try it and have success, please reply here your successes.

Many thanks

//#include <Arduino.h>
//#include <driver/dac.h>  // REPLACED WITH LEDC WHERE WE SET 12 BIT RESOLUTION

// Based on original work from Helmut Weber (https://github.com/MacLeod-D/ESP32-ADC)
// that he described at https://esp32.com/viewtopic.php?f=19&t=2881&start=30#p47663
// Modified with bug-fixed by Henry Cheung
//
// Build a ESP32 ADC Lookup table to correct ESP32 ADC linearity issue
// Run this sketch to build your own LUT for each of your ESP32, copy and paste the
// generated LUT to your sketch for using it, see example sketch on how to use it
//
// Version 2.0 - switch to use analogRead() instead of esp-idf function adcStart()
// Version 1.0 - original adoptation and bug fix based on Helmut Weber code

//#define GRAPH      // uncomment this for print on Serial Plotter
//#define FLOAT_LUT     // uncomment this if you need float LUT
#define ADC_PIN 33      // uses any valid Ax pin as you wish

#define LEDC_CHANNEL        0   // Use first channel of 16 channels (started from zero)
#define LEDC_RES           12   // Use 12 bit precision for LEDC timer
#define LEDC_FREQ        5000   // Use 5000 Hz as a LEDC base frequency
#define LED_PIN          25   // Fade LED PIN (replace with LED_BUILTIN constant for built-in LED to test)

#define SAMPLES ((int)(pow(2, LEDC_RES)))
#define AVERAGE_SAMPLES    40

uint16_t TIME_BEFORE_SAMPLE;  // In ms (time required to stabilize before samples are taken)
#define SAMPLING_TIME       100  // In us  100

#define MAX_DUTY_CYCLE ((int)(SAMPLES-1))

int Results[SAMPLES + 1];
//float Res2[ (MAX_DUTY_CYCLE + 1) * 5];
uint32_t Current[SAMPLES];
uint32_t Filtered[SAMPLES];
uint32_t Filtered2[SAMPLES];
uint32_t Filtered3[SAMPLES];
int32_t Diff[SAMPLES];

// LowPass Filter for ADC
float FilterCoef1 = .2;   // decrease to apply more filter, increase (max = FilterMaxCoef) to apply less filter
float FilterCoef2 = .2;
float FilterCoef3 = .2;
float FilterMaxCoef = 1.0;
float F[10], oldF[10];  // Put here max number fo filters

// Arduino like analogWrite value has to be between 0 and valueMax, here we use 4095
void ledcAnalogWrite (uint8_t channel, uint32_t value, uint32_t valueMax = 255) {
   // Calculate duty, 4095 from 2 ^ 12 - 1
   uint32_t duty = (4095 / valueMax) * min (value, valueMax);

   // Write duty to LEDC
   //   Serial.printf ("Duty: %lu\n", (long unsigned int)duty);
   ledcWrite (channel, duty);
}

// Low Pass Filter (LPF)
float Filter (byte index, float nVal, float Coef, float MaxCoef) {
   F[index] = (nVal * Coef) + (oldF[index] * (MaxCoef - Coef));
   oldF[index] = F[index];
   return F[index];
}

void dumpResults (float* arr) {
   Serial.println ("\nDUMP RESULTS:\n");
   for (int i = 0; i < SAMPLES; i++) {
      if (i % 16 == 0) {
         Serial.println();
         Serial.print (i); Serial.print (" - ");
      }
      Serial.print (arr[i], 2); Serial.print (", ");
   }
   Serial.println();
}

void setup() {
   Serial.begin (115200);
   delay (4000);

   //   dac_output_enable (DAC_CHANNEL_1);   // pin 25
   //   dac_output_voltage (DAC_CHANNEL_1, 0);

   Serial.printf ("\n\nInitializing LEDC on pin GPIO%d\n", LED_PIN);
   // Setup timer and attach timer to a pin
   uint32_t freq = ledcSetup ((uint8_t)LEDC_CHANNEL, (uint32_t)LEDC_FREQ, (uint8_t)LEDC_RES);  // Setup LEDC to 12 bit resolution to be the same as ADC. We can use higter resolution but have not much sense   
   ledcAttachPin (LED_PIN, LEDC_CHANNEL);

   ledcAnalogWrite (LEDC_CHANNEL, MAX_DUTY_CYCLE, MAX_DUTY_CYCLE);  // Reset the duty on LEDC channel 0

   Serial.printf ("Done\n\nSetup Frequency: %lu Hz\nReal Frequency: %lu Hz\nMax DutyCycle: %d\n",
                  (long unsigned int)freq, (long unsigned int)ledcReadFreq (LEDC_CHANNEL), MAX_DUTY_CYCLE);

   analogReadResolution (LEDC_RES);  // BY DEFAULT ANALOG READ ALREADY IS SET TO 12 BIT RESOLUTION, BUT THIS WAY WE ENSURE IT IS TRUE AND SET SAME AS LEDC RESOLUTION 

   delay (4000);
}

void loop() {

   Serial.println (F ("\n\nTest Linearity:\n"));

   Current[0] = 0;
   TIME_BEFORE_SAMPLE = 10;

   for (int i = 1; i < SAMPLES; i++) {
      ledcAnalogWrite (LEDC_CHANNEL, i, MAX_DUTY_CYCLE);  // Set the duty on LEDC channel 0
      delay (TIME_BEFORE_SAMPLE); // Wait a bit of milliseconds to stabilize

      for (int n = 0; n < AVERAGE_SAMPLES; n++) {
         delayMicroseconds (SAMPLING_TIME);
         uint32_t analogInput = analogRead (ADC_PIN);
         (analogInput > 0) ? Current[i] += analogInput : Current[i] = 0;
         //   Serial.printf ("Sample %d = %d\n", n, analogInput);
      }

      uint32_t tmp = Current[i];
      if (Current[i] > 0) 
         Current[i] /= AVERAGE_SAMPLES;
          // Apply digital Low Pass Filter to remove noise (uncomment for filtered samples)
          Filtered[i] = Filter (0, Current[i], FilterCoef1, FilterMaxCoef);
          Filtered2[i] = Filter (1, Filtered[i], FilterCoef2, FilterMaxCoef);
          Filtered3[i] = Filter (2, Filtered2[i], FilterCoef3, FilterMaxCoef);
    
          Diff[i] = i - Filtered3[i];
          Results[i] = (i + Diff[i]);

          Serial.printf ("%d AVG:%lu F1:%lu F2:%lu F3:%lu Diff:%d Results:%d\n",
                     i,
                     (long unsigned int)Current[i],
                     (long unsigned int)Filtered[i],
                     (long unsigned int)Filtered2[i],
                     (long unsigned int)Filtered3[i],
                     Diff[i],
                     Results[i]
                    ); 
            }
       delay (5000);

       Serial.println (F ("\nALL IS DONE"));
       for (int i = 0; i < SAMPLES; i += 8) {
         Serial.printf ("idx:%d F3:%lu Diff:%d Results:%d\n",
                     i,
                     (long unsigned int)Filtered3[i],
                     Diff[i],
                     Results[i]
                    );
        delay (10);
     }

     delay (10000);

    #ifdef FLOAT_LUT
       Serial.println ("const float ADC_LUT[4096] = { 0,");
       for (int i = 0; i < MAX_DUTY_CYCLE; i++) {  ///  ERA DA 0 A 4095
          Serial.print (Results[i], 4); Serial.print (",");
          if ((i % 15) == 0) Serial.println();
       }
       Serial.println (Results[MAX_DUTY_CYCLE]);
       Serial.println ("};");
    #else
       Serial.println ("const int ADC_LUT[4096] = { 0,");
       for (int i = 0; i <= MAX_DUTY_CYCLE; i++) { ///  ERA DA 0 A 4095
          Serial.print ((int)Results[i]); Serial.print (",");
          if ((i % 15) == 0) Serial.println();
       }
       Serial.println ((int)Results[MAX_DUTY_CYCLE]);
       Serial.println ("};");
    #endif

    while (1);

}

from esp32-adc-calibrate.

e-tinkers avatar e-tinkers commented on August 17, 2024

Hi, appreciated your effort. Can you clean up your code by removing those unused code, with correct indentation? Code block has nothing to do with how old/new is your PC, github uses markdown language, to put a block of code in a code block, you add three backticks ``` at the beginning and ending of the code.

Since this is not an issue related to my original git repository but a suggestion or an alternative way of achieving the same result. I'm closing this issue for now.

from esp32-adc-calibrate.

maxmeli123 avatar maxmeli123 commented on August 17, 2024

Ok, many thanks tor the tip. 😉
Sorry for my incompetence here, and I've a github repository too 😀 and for my not too good english.

I've fixed the code as your advices. 👍
Hope it's ok now, please if you have some time do a try.

Thanks
Max

from esp32-adc-calibrate.

maxmeli123 avatar maxmeli123 commented on August 17, 2024

Thanks for the comment. The idea of using LEDC to generate as a liner voltage reference is certainly an interesting one and I know nothing about it until you mentioned it, I will certainly give it a try when I have time.

Hi,
there are some develops ?
Did you tried my code ?

Thanks
Max

from esp32-adc-calibrate.

Related Issues (5)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.