November 19, 2025, 03:55:08 PM

Recent posts

#51
ESP32 / Re: ESP32-H2-DevKit-Lipo - Bat...
Last post by LubOlimex - October 22, 2025, 10:42:00 AM
Yes, it is good and simple way to calibrate but you have to store to non volatile memory or it won't persist after restart (e.g. you have to calibrate every time). More advanced way would be using the espressif guide here:

https://docs.espressif.com/projects/esp-idf/en/stable/esp32h2/api-reference/peripherals/adc_calibration.html

Here is better Arduino IDE code that can be used to calibrate, store to nvm:

// ==========================================================
// ESP32-H2-DevKit-LiPo Battery and Power Sense Demo
// ----------------------------------------------------------
// External Power Sense: GPIO25
// Battery Measurement:  GPIO2
// User Button (BUT1):   GPIO9
// LED:                  GPIO8
//
// Resistor divider coefficient = (R5 + R1) / R5 = 5.7
// Maximum battery voltage = 4.2V
//
// ➤ Press BUT1 for 2–6 seconds → enter ADC calibration mode
// ➤ Press BUT1 for >6 seconds → reset stored calibration factor
// ➤ Measure the battery with a multimeter *while still connected*
//    (at battery contacts on the bottom of the board)
// ➤ LED blinks fast in calibration mode and flashes 3× on success
// ➤ LED flashes 5× quickly on calibration reset
// ==========================================================

#include <Preferences.h>

#define POWER_SENSE_PIN   25
#define BATTERY_PIN       2
#define BUTTON_PIN        9
#define LED_PIN           8

// Divider ratio (R5+R1)/R5 = 5.7
float resistorCoeff = 5.7;

// ADC calibration coefficient (stored in flash)
Preferences prefs;
float calibrationFactor = 1.0;

// LED control
unsigned long lastBlink = 0;
bool ledState = false;

// Calibration mode flag
bool calibrating = false;

// Button press tracking
unsigned long buttonPressStart = 0;
bool buttonPressed = false;

// ----------------------------------------------------------
// Setup
// ----------------------------------------------------------
void setup() {
  Serial.begin(115200);
  pinMode(POWER_SENSE_PIN, INPUT);
  pinMode(BATTERY_PIN, INPUT);
  pinMode(BUTTON_PIN, INPUT_PULLUP);
  pinMode(LED_PIN, OUTPUT);

  prefs.begin("adc-calib", false);
  calibrationFactor = prefs.getFloat("factor", 1.0);

  Serial.println("\nESP32-H2-DevKit-LiPo Power & Battery Sense");
  Serial.println("------------------------------------------------");
  Serial.print("Resistor divider coefficient: ");
  Serial.println(resistorCoeff);
  Serial.print("Calibration factor: ");
  Serial.print(calibrationFactor);
  if (prefs.isKey("factor"))
    Serial.println("  (loaded from flash)");
  else
    Serial.println("  (using default)");
  Serial.println("------------------------------------------------\n");
}

// ----------------------------------------------------------
// Main loop
// ----------------------------------------------------------
void loop() {
  unsigned long now = millis();

  // LED blinking pattern
  unsigned long interval = calibrating ? 150 : 800;
  if (now - lastBlink > interval) {
    ledState = !ledState;
    digitalWrite(LED_PIN, ledState);
    lastBlink = now;
  }

  // Button press detection
  if (digitalRead(BUTTON_PIN) == LOW) {
    if (!buttonPressed) {
      buttonPressStart = now;
      buttonPressed = true;
    }
  } else {
    if (buttonPressed) {
      unsigned long pressDuration = now - buttonPressStart;

      if (pressDuration >= 2000 && pressDuration < 6000) {
        // Enter calibration mode
        startCalibration();
      } else if (pressDuration >= 6000) {
        // Reset calibration
        calibrationFactor = 1.0;
        prefs.clear();
        Serial.println("\n*** Calibration data reset! Using default = 1.0 ***");

        // Flash LED 5× to confirm reset
        for (int i = 0; i < 5; i++) {
          digitalWrite(LED_PIN, HIGH);
          delay(150);
          digitalWrite(LED_PIN, LOW);
          delay(150);
        }
      }

      buttonPressed = false;
    }
  }

  // Regular measurement mode
  if (!calibrating) {
    Serial.print("External Power Sense: ");
    Serial.println(digitalRead(POWER_SENSE_PIN));

    int mv = analogReadMilliVolts(BATTERY_PIN);
    float actualMv = mv * resistorCoeff * calibrationFactor;

    Serial.print("Battery Voltage: ");
    Serial.print(actualMv);
    Serial.println(" mV\n");
    delay(500);
  }
}

// ----------------------------------------------------------
// Calibration mode
// ----------------------------------------------------------
void startCalibration() {
  calibrating = true;
  Serial.println("\n=== ADC Calibration Mode ===");
  Serial.println("Measure the battery with a multimeter (while connected).");
  Serial.println("Enter the measured voltage in millivolts (e.g., 4120):");

  while (true) {
    if (Serial.available()) {
      String input = Serial.readStringUntil('\n');
      input.trim();
      float measuredMv = input.toFloat();

      if (measuredMv > 0) {
        int rawMv = analogReadMilliVolts(BATTERY_PIN) * resistorCoeff;
        calibrationFactor = measuredMv / rawMv;

        prefs.putFloat("factor", calibrationFactor);
        Serial.print("Calibration complete! Factor saved: ");
        Serial.println(calibrationFactor);

        // Flash LED 3× to confirm success
        for (int i = 0; i < 3; i++) {
          digitalWrite(LED_PIN, HIGH);
          delay(150);
          digitalWrite(LED_PIN, LOW);
          delay(150);
        }

        calibrating = false;
        Serial.println("Exiting calibration mode.\n");
        break;
      } else {
        Serial.println("Invalid input. Please enter numeric millivolts (e.g., 4120):");
      }
    }
  }
}



Open the serial console, then press and hold button BUT1 for 3 seconds and release to enter calibration mode. If you hold it for 6 seconds or more and release default calibration value of 1.0 will be loaded. Important!!! Measure battery while still connected to the board (at the contacts at the bottom). If you measure the battery while it is disconnected from the board there would be huge discrepancy!!!
#52
ESP32 / Re: ESP32-H2-DevKit-Lipo - Bat...
Last post by lmerckx - October 21, 2025, 08:12:34 PM
Indeed, I think the problem is due to the ADC reliability.
I persisted in charging the battery and finally it was full after several hours.

What I didn't understand is that the voltage returned by the ADC is not linear.
It grows fast until a plateau. Then, the ADC returns the same value for a very long period, then it grows again fast until another plateau, etc.
For my battery, these plateau's are around 667 (+/- 3800 mV), 683 (+/- 3890 mV) and 699 (+/- 3990 mV).
When my battery was finally charged and the LED turned off, the value returned by the ADC was 716 (4081.20 mV). But when I checked with the multimeter, the real value was indeed 4,19 V.

So, perhaps I was simply not patient enough and the ADC behavior perturbed me.

Just a last question: to correct the value returned by the ADC and approximately match the real voltage of the battery, can I multiply by 5.87 instead of 5.7. Or is there a better solution for that ?

Thanks again.
#53
ESP32 / Re: ESP32-H2-DevKit-Lipo - Bat...
Last post by LubOlimex - October 20, 2025, 03:36:32 PM
It is not perfect here either. The battery seems to be fully charged, the yellow LED turned off (this is indication it is no longer charging) and I get 4143.90 mV ~ 4.14V from the software.

If I measure just the battery it is 4.21V. So the ADC is definitely not perfect.
#54
ESP32 / Re: ESP32-H2-DevKit-Lipo - Bat...
Last post by lmerckx - October 20, 2025, 01:43:56 PM
Hello LubOlimex,

Thank you again for your help.

My code is exactly the same for getting the voltage of the battery. Except that now, I also compute an average of 100 values to get a stable value.
Here is a sample of trace:
Voltage: avg = 3804.69 mV - min = 3801.90 mV - max = 3807.60 mV
Voltage: avg = 3804.81 mV - min = 3801.90 mV - max = 3807.60 mV
Voltage: avg = 3804.75 mV - min = 3801.90 mV - max = 3807.60 mV
Voltage: avg = 3805.03 mV - min = 3801.90 mV - max = 3807.60 mV
Voltage: avg = 3804.64 mV - min = 3801.90 mV - max = 3807.60 mV
We can see that minimum and maximum measures are very closed.

The interesting point of your proposal is the results I got with my multimeter.
Measure from the Olimex card: 3804 mV (with or without the USB cable); measure from my multimeter: 3,95 V
I tried to charge the battery for one hour more and made a new measure after:
Measure from the Olimex card: 3804 mV (with or without the USB cable); measure from my multimeter: 3,97 V

It makes me think of a peak reached in the measure that cannot be exceeded.
Can it be a problem with the card ? Or a calibration to do ?
#55
ESP32 / Re: ESP32-H2-DevKit-Lipo - Bat...
Last post by LubOlimex - October 20, 2025, 09:47:09 AM
Yes, just set in voltage measurement mode and measure between + and - of battery to see what is the real voltage of the battery and if there is huge difference between the software report.

Meanwhile I also got one board to test here. This is my Arduino code:

#define POWER_SENSE 25
#define BATTERY 2

void setup()
{
  Serial.begin (115200);
  pinMode (POWER_SENSE, INPUT);
  pinMode (BATTERY, INPUT);
}

void loop()
{
  Serial.print ("External power sense: ");
  Serial.println (digitalRead (POWER_SENSE));

  Serial.print ("Battery measurement: ");
  Serial.print (analogReadMilliVolts (BATTERY)*5.7);
  Serial.println (" mV");

  Serial.println ();

  delay (2000);
}

So far the software shows that my battery is 4058.40 mV and the measurement via voltage meter is pretty close at 4060. The charge current is around 75mA, this is expected since after 3.7V DC the charger charges with lower current than the maximum allowed (which is 100mA).
#56
ESP32 / Re: ESP32-H2-DevKit-Lipo - Bat...
Last post by lmerckx - October 20, 2025, 09:22:16 AM
No. I suppose I can test it with a simple multimeter between the red and black wires ?
I will try.

Thanks.
#57
ESP32 / Re: ESP32-H2-DevKit-Lipo - Bat...
Last post by LubOlimex - October 20, 2025, 09:00:31 AM
Did you measure the voltage of the battery with external tool to compare with the software readings?
#58
ESP32 / Re: ESP32-H2-DevKit-Lipo - Bat...
Last post by lmerckx - October 19, 2025, 11:34:18 AM
Hello,

I tested further like this:
- longer charge of the battery
- use 100 measures of the battery voltage (each 10 ms) and use the average as final value

And indeed, the battery voltage increased slowly as expected until a peak.
But now that this peak is reached, analogReadMilliVolts always returns 667 or 668. So, 3801.90 or 3807.60 mV (after multiplying by 5.7). I expected (like you above) to reach +/- 4200 mV for my battery.
My code for one measurement is simply: analogReadMilliVolts(BATTERY_VOLTAGE_PIN) * 5.7f
as explained in the documentation.
Have you an idea ?

About your last comment, is it possible that the influence of the charger on battery measurement only happens when battery is low ?
Because I noticed it at the beginning but no more now.
Now, I measure the same voltage if the battery and USB are both connected or if it is only the battery.

Sorry for all these questions. And thanks for your support.
#59
New Product Ideas / Re: could you provide a random...
Last post by LubOlimex - October 17, 2025, 10:27:13 AM
MOD-MP3-X-LITE can not work in stand-alone mode. It lacks a main microcontroller.

MOD-MP3-X can work in stand-alone mode since it has STM32F103 on-board. The firmware of STM32F103 can be modified via ARM JTAG tool. The random function can be added if you modify the firmware, and specifically mp3PlayerTask.c and if you add a command to switch between random mode and regular mode, you'd also have to add it in uartUserInterface.c and uartUserInterface.h.

#60
NXP / Re: RTC for iMX8MP-SOM-EVB-IND
Last post by LubOlimex - October 17, 2025, 09:59:44 AM
I can see we that we use PCA9450 which one of the recommended by NXP power management chips. It has own quartz, so as long as the PCA9450 is powered it should keep the RTC alive. Also all connection are proper even the lowest power mode is properly connected (SNVS mode). PCA9450 has seven different operating modes (controlled by the input voltage on the VSYS pin and an external control signal (I2C that I inspected is connected between the main chip, the PMU, and the EEPROM).

The PCA9450 doesn't operate on battery tho. It requires 5V DC and from those it makes LDO1 and LDO2. And then if you seek lower power mode, configure the PMU for SNVS mode via the I2C. Refer to these documents:

https://www.nxp.com/docs/en/application-note/AN14246.pdf
https://www.nxp.com/docs/en/data-sheet/PCA9450.pdf

Notice that you can also check what the official NXP forums say since the board uses iMX8 and NXP PMU PCA9450C which is a recommended combo and NXP staff can also provide some insight.