ARMmbed / mbed-os

Arm Mbed OS is a platform operating system designed for the internet of things
https://mbed.com
Other
4.64k stars 2.97k forks source link

RAK3172 ADC pins don't work when deep sleep is enabled #15391

Open goshawk22 opened 1 year ago

goshawk22 commented 1 year ago

Description of defect

ADC pins on the RAK3172 stops working correctly after deep sleep. Using the below code to measure the voltage:

#include "mbed.h"
AnalogIn voltage(PB_3);

int main()
{
    //sleep_manager_lock_deep_sleep();
    while (true) {
        float raw_adc;
        float calc_voltage;
        raw_adc = voltage.read();
        calc_voltage = ((3.3f*raw_adc*(5.0f))/(3.0f))*(1.3f);
        printf("\r\nRaw ADC: %f\r\n", raw_adc);
        printf("\r\n Calc Voltage: %f\r\n", calc_voltage);
        ThisThread::sleep_for(5s);
    }
}

When deep sleep is locked, the code works correctly and consistently reports around 3.3v as expected. When deep sleep is unlocked, it reports around 2.77v the first time and then seems to hang, not reporting anything else.

Target(s) affected by this defect ?

RAK3172 (STM32WL)

Toolchain(s) (name and version) displaying this defect ?

What version of Mbed-os are you using (tag or sha) ?

mbed-os-6.17.0

What version(s) of tools are you using. List all that apply (E.g. mbed-cli)

mbed studio 1.4.4

How is this defect reproduced ?

Use the above code on a RAK3172 with the adc pin connected to a voltage divider. Build in develop or release mode to enable deep sleep.

mbedmain commented 1 year ago

@goshawk22 thank you for raising this issue.Please take a look at the following comments:

Could you add some more detail to the description? A good description should be at least 25 words. What toolchain(s) are you using? What Mbed OS version are you using? How can we reproduce your issue?

NOTE: If there are fields which are not applicable then please just add 'n/a' or 'None'. This indicates to us that at least all the fields have been considered. Please update the issue header with the missing information.

goshawk22 commented 1 year ago

The apparent hang after the first reading seems to have been caused by #15331. After fixing this, when deep sleep is enabled, analogin reports near zero values around 0.09.

jeromecoutant commented 1 year ago

From STM32WL ref manual, seems that ADC configuration is not retained with Stop2 (deep sleep) power mode. So idea could be:

goshawk22 commented 1 year ago

With regards to point 1 and 2, if I put AnalogIn voltage(PB_3) inside a function so that it is called each time I want to read the adc pin, I get wrong values. It returns roughly 2.7 instead of the expected 3.3.

hallard commented 1 year ago

@goshawk22 interesting answer from @jeromecoutant to rewrite hal_deepsleep() for this one (and also for the serial) but I'm far from ST HAL guru, so if anyone have an example on how to reset 115200 on serial console after deep sleep, I take it. Anyway I don't have the ADC issue mentioned here.

What I'm doing after deep sleep is to call read_sensors() this as follow

bool read_sensors() 
{
  vdda = get_vdda();
  vbat = get_vbat();
  info("Vdda %dmV  Vbat %dmV  ", vdda, vbat);
}

and functions used are


// Defined globally
DigitalOut baten(BAT_EN, 0); // Digital Pin to enable R divider to read battery voltage
AnalogIn adc_vbat(BAT_MON);
uint16_t vdda = 0; // VDD Average in mV (calculated by internal ADC)
uint16_t vbat = 0; // Vbat in mV calculated with Resistor Divider

uint16_t get_vdd() 
{
  uint16_t vref_cal = *((const uint16_t*)VREFINT_CAL_ADDR);
  return ((float)VREFINT_CAL_VREF * vref_cal / (AnalogIn(ADC_VREF).read() * 4095.0));
}

uint16_t get_vdda() 
{
  uint32_t sum = 0;
  // Average 8 measures
  for (int i=0; i<8 ; i++) {
    sum += get_vdd();
  }
  vdda = sum >> 3 ;
  return vdda;
}

uint16_t get_vbat()
{
  float sum = 0;
  baten = 1; // Enable reading analog R/R divider
  adc_vbat.set_reference_voltage((float) vdda / 1000.0f);
  ThisThread::sleep_for(5ms); // voltage to settle
  // Average 8 measures
  for (int i=0; i<8 ; i++) {
    sum += adc_vbat.read_voltage() * 1.27 * 1000.0;
  }
  vbat = (uint16_t) (sum / 8.0f) ;
  baten = 0; // Disable reading analog R/R divider (save R/R power)
  return vbat;
}