dbuezas / lgt8fx

Board Package for Logic Green LGT8F328P LGT8F328D and LGT8F88D
359 stars 90 forks source link

understanding analogRead(VCCM) #228

Closed holgerlembke closed 1 year ago

holgerlembke commented 1 year ago

Moin.

I try to understand how measuring the supply voltage works. I have a LGT8F328, the 1.0.7 and use the following code.

void setup() {
  Serial.begin(115200);
  while (!Serial) {
    delay(100);
  }
  Serial.println(F("\n\nVcc Tester"));

  analogReference(DEFAULT);

  // Mux-settle read, needed?
  analogRead(VCCM);
  delay(1);

  // Default 10 bits
  {
    int adc = analogRead(VCCM);

    float vcc = 5.0 / ((1 << 10)-1) * adc;

    Serial.print(F("Vcc: "));
    Serial.print(vcc, 4);
    Serial.println(F(" V"));
  }

  analogReadResolution(12);
  {
    int adc = analogRead(VCCM);

    float vcc = 5.0 / ((1 << 12)-1) * adc;

    Serial.print(F("Vcc: "));
    Serial.print(vcc, 4);
    Serial.println(F(" V"));
  }

  // Reference: A0 is connected to 3.29 V
  analogReadResolution(12);
  {
    analogRead(A0);
    delay(1);
    int adc = analogRead(A0);

    float vcc = 5.0 / ((1 << 12)-1) * adc;

    Serial.print(F("A0: "));
    Serial.print(vcc, 4);
    Serial.println(F(" V"));

    float realvcc = 3.29 * ((1 << 12)-1) / adc;

    Serial.print(F("Vcc/A0: "));
    Serial.print(realvcc, 4);
    Serial.println(F(" V"));
  }
}
void loop() {}

Result is:

Vcc Tester
Vcc: 0.9912 V
Vcc: 0.9961 V
A0: 3.5645 V
Vcc/A0: 4.6150 V

So the 1 V is a little bit wrong. Did I do something wrong? Did I miss something? What?

// me confused.

holgerlembke commented 1 year ago

Small fix that changes not much: (1 << 10) is wrong, should be ((1 << 10)-1) and same for 12 bits.

holgerlembke commented 1 year ago

So the data sheet says something about "Internal support 1/5 Divider input (VDO)" and that would match my results. In which "Match" is a little stretch.

Vcc: 4.9853 V
Vcc: 4.9817 V
A0: 3.5568 V
Vcc/A0: 4.6250 V

(4.625 V is verified. I could add more digits.)

0.3 V off? I seem to make something wrong.

// me confused.

LaZsolt commented 1 year ago

Hi!

The default values after reset:

analogReference(DEFAULT) == 1.024V analogResolution == 1024 VCCM internal voltage is 1/5 VCC So if the VCC level is 5V then this internal input level is 1V.

After your first measure you get this value form analogRead(VCCM): 1000 This value need to multiplied by 5 to get the MCU's VCC in mV.

0.3 V off?

On the green board there is a 'power selector' diode. If you powered your board by USB this diode will drop the VCC by 0.3 - 0.5 V.

holgerlembke commented 1 year ago

That is very confusing.

Vcc at LGT8F328 pin 4 is 4.62 V.

My 3.3V=A0 is measured correctly and scaled by 5V reference voltage value.

The Vcc diode stuff is confusing. If the LGT8F328 sees the voltage after the diode, it should be lower...

I found no schematic of the green board I have and can't really trace out mine, because it is fix soldered into a different pcb.

LaZsolt commented 1 year ago

I am confused too.

You selected the DEFAULT internal reference voltage, which is 1.024V You applied 3.3V on pin A0. If you measure it with ADC you always get 1023 or 4095 because 3.3V greater than the 1.024V reference voltage.

But if you use VCC for reference voltage when measuring 3.3V then your reference was 4.62V.

LaZsolt commented 1 year ago

Anyway this calculation is not correct float vcc = 5.0 / ((1 << 12)-1) * adc;

The ADC will get the maximum (4095) value when it's input is is reach or exceeds the 1.024V reference voltage.

So the correct calculation is: float vcc = 5.12 / ((1 << 12)-1) * adc;

LaZsolt commented 1 year ago

I made a test with my board. VCC measured by multimeter: 4.96V VCC measured by MCU: 5.11V Difference is 3% which is acceptable.

holgerlembke commented 1 year ago

Please show what the above code produces.

1======================================= I'm reading throu wiring_analog.c.

What is https://github.com/LaZsolt/lgt8fx/blob/master/lgt8f/cores/lgt8f/wiring_analog.c#L161 doing?

#if defined(ADCSRA) && defined(ADCL)
    #if defined(__LGT8FX8P__)
    sbi(ADCSRC, SPN);
    nVal = adcRead();
    cbi(ADCSRC, SPN);
    #endif

    pVal = adcRead();

    #if defined(__LGT8FX8P__)
    pVal = (pVal + nVal) >> 1;
    #endif
#else

Looks like averaging two measurements? Why?

2======================================= As far as I understand the code, it simply ignores that with setting https://github.com/LaZsolt/lgt8fx/blob/master/lgt8f/cores/lgt8f/wiring_analog.c#L114 it has to adjust the answer by 5 because it gets vcc/5.

LaZsolt commented 1 year ago

2=================== The 1/5 of VCC is 1V (at 5V VCC) so ADC measure 1 V against 1.024V reference. The ADC reach its maximum value when 1.024V measured against 1.024V

1===================

What is https://github.com/LaZsolt/lgt8fx/blob/master/lgt8f/cores/lgt8f/wiring_analog.c#L161 doing?

The algorithm of the measurement came from LGT8F328P databook:

Dynamic detuning compensation algorithm procedures: 1. As per application demand to initialize ADC conversion parameter 2. Setting SPN=1, start ADC sampling, record ADC sampling result as VADC1 3. Setting SPN=0, start ADC sampling, record ADC sampling result as VADC2 4. If (VADC1 + VADC2) >> 1, then it is this ADC conversion result In actual application, to acheive much better result by combination of above algorithm and sampling average method.

You may learm more from the databook, page: 258 https://raw.githubusercontent.com/dbuezas/lgt8fx/master/docs/LGT8FX8P_databook_v1.0.5-English.pdf

holgerlembke commented 1 year ago

Thanks.

Currently I clean up the code of __analogRead from all the defines. It is was difficult to read with all the unused atmega stuff.

I found that ADC-stuff in that pdf already. They seam simply measure from top to bottom and bottom to top and average that. It gives some bits difference. One could use only one read, result is valid, too. It is just whether two times the processing time might not be wanted. Or precision.

I might need to sleep a night over that all. To me it still looks like the error is simply missing the 1/5 vcc factor correction.

Oh, I just noticed: it might be a misunderstanding what to expect from analogRead(). I expect it to behave in accordance to analagReference() and hide the 1/5 internal factoring with vccm.

holgerlembke commented 1 year ago

Ok, I think I would like to implement this solution (I will submit a pull after the pending pulls are pulled...):

This would make it easy for a starting user and provides a clear interface,

All this should be documented in the wiki. I will happily do that.

holgerlembke commented 1 year ago

Sooo. It is alive. https://github.com/holgerlembke/lgt8fx/blob/master/lgt8f/cores/lgt8f/wiring_analog.c#L169

Results seem to be spot on, ähm, 3,5% difference.

Vcc/A0: 4.6297 V analogReadVccmV: 4643 mV

dbuezas commented 1 year ago

Results seem to be spot on, ähm, 3,5% difference.

That's 3‰ , not 3%!