Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Redesigned algorithm for VPP measurement #54

Open
hubertushirsch opened this issue Feb 14, 2024 · 4 comments
Open

Redesigned algorithm for VPP measurement #54

hubertushirsch opened this issue Feb 14, 2024 · 4 comments

Comments

@hubertushirsch
Copy link
Contributor

hubertushirsch commented Feb 14, 2024

I propose a simplified form of voltage measurement in the Afterburner.
This affects the varVppMeasureVpp() function in aftb_vpp.h and some definitions.
The mathematical basics:

ADC = return value of analogRead()
Vin = voltage at the analog input
res = resolution - 2^10 = 1024 (10 bit resolution)
Vpp = programming voltage VPP
Vref = reference voltage of the A/D converter at pin AREF

Based on the basic formula

(1) ADC = Vin * res / Vref

After converting formula (1) we get

(2) Vin = ADC * Vref / res

Vin results from the voltage divider R5/R6

Vpp ---+
       |
       -
      | | R5
      | |
       -
       |
       o---- Vin to analog input
       |
       -
      | | R6
      | |
       -
       |
      ___ GND
      
(3) Vpp / (R5 + R6) = Vin / R6

Switched to Vpp

(4) Vpp = Vin * (R5 + R6) / R6

Vin substituted by (2):

(5) Vpp = (ADC * Vref * (R5 + R6)) / (R6 * res)

If you calculate with floating point, you can measure the Vref of your specific afterburner with a good multimeter and specify it precisely, e.g.

#define VREF (3.28)      // Vref in Volts as float

This also applies to the resistors R5 and R6, which can be measured beforehand.

#define ADC_R5 (99.96)   // R5 in kOhm as float
#define ADC_R6 (20.01)   // R6 in kOhm as float

I put the definitions of the parameters in a separate header file aftb_adcparms.h, which is included in aftb_vpp.h.
This makes it easy to adapt to your own hardware without having to spend a long time searching between the lines of code.
The varVppMeasureVpp() function has been completely rewritten.

Measuring using this method provides a significantly better agreement between the displayed VPP values compared to a multimeter.
The difference between the Arduino measurement and the multimeter was a maximum of 0.02V (Arduino NANO, Vref = internal 1.1V, R5 = 20k, R6 = 1.3k).

@fredcwbr
Copy link

I'm following this with great interest., ..

@hubertushirsch
Copy link
Contributor Author

I'm following this with great interest., ..

I would be very grateful if you could test the suggested code change.
See pull request #55

@fredcwbr
Copy link

fredcwbr commented Feb 15, 2024

I'll look into it closely, at the time i can get my hands in a 4131..

While waiting, did try another approach with a a handmade DAC R2R , and it worked,
so i opened a discussion to share my thoughts ...

@Emile666
Copy link

Emile666 commented Sep 23, 2024

So I built an afterburner and started by checking Vpp voltages. The voltage readings were a bit inaccurate: A Vpp of 16.50 Volt (multimeter) resulted in an reported voltage of 16.08 Volts. I observed the following:

  • The AREF pin is not decoupled

  • There is a series resistor (R7) of 3K3 from the +3V3 to AREF. The AREF pin has a current draw of around 94 uA (measurement and confirmed by graph in datasheet). This results in a VREF of 3.03 Volts instead of 3.30 Volts.

  • Pot R9 doesn't decrease the inaccuracy between the voltmeter readings and the values on screen.

  • The Vpp reading is read in 14 times and then divided by 8 (no comment why it is done this way). A VPP of 16.50 then results in a code of (16.5 / 6) * (14/8) * 1023 / 3.04 = 1619, which is pretty much the voltage reported on screen. So this is by design and you need the offsets to compensate for this. But the conversion itself is the problem and should be adjusted.

  • So there are a couple of hardware improvements to make: decouple the AREF pin with (at least) 100 nF and either remove R7 completely or make the value a lot smaller.

  • The Full-Scale for the ADC is 1980 E-2 V (this is 6 * 330 E-2 V, the 6 is the R6/R5 voltage divider). Therefore, the ADC value is multiplied with this number and divided by n * 1023, n being the number of times the ADC value is read. I would suggest the following code (already tested in my local repository):

#define ADC_R5      (100.0)      /* R5 in kOhm as float */
#define ADC_R6      (20.0)       /* R6 in kOhm as float */
#define VREF        (3.03)       /* Vref in Volts as float */ 
#define ADCRES      (10)         /* Analog Read Resolution in bits as integer */

//-----------------------------------------------------------------------
// MCOUNT is the number of ADC-reads summed together for VPP
// VDIV is the voltage divider of R5 and R6 on the afterburner PCB
// ADC_MUL_VAL is the constant to multiply with to get to Vpp [E-2 V]
//-----------------------------------------------------------------------
#define MCOUNT      (14)                    /* Number of added measurements as integer */
#define VDIV        (1.0 + (ADC_R5/ADC_R6)) /* Voltage divider on afterburner PCB */
#define ADC_MUL_VAL ((100.0 * VDIV * VREF) / (MCOUNT * float((1<<ADCRES)-1)))

If you then multiply (not divide, too computation intensive!) the 14-times summed ADC value with ADC_MUL_VAL, you end up with the proper value in E-2 V. Note that by using these defines, calculation is transparent and the values are easy to change. And you have only 1 multiplication instead of various multiply/divide operations. The VarVppMeasureVpp() now looks like:

static int16_t varVppMeasureVpp(int8_t printValue) {
    int adcsum = 0;     // Sum MCOUNT measurements here
    int loops = 0;      // Counter for measure loop
    float vpp;          // Vpp result as float

    // Measure MCOUNT times and add results
    do {
        adcsum += analogRead(VPP);      // Sum MCOUNT measurements here
    } while (++loops < MCOUNT);
    // Now calculate the VPP
    vpp  = float(adcsum) * ADC_MUL_VAL; // vpp now in [E-2 V]
    vpp += float(calOffset);            // calOffset in [E-2 V]
    if (printValue) {
        Serial.println(vpp,1);
    }
    return int16_t(vpp + 0.5);
} 
  • I would support the software changes suggested by hubertushirsch, since that is basically what I am describing here. I changed his new file aftb_adcparams.h to reflect the changes described here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants