How to wake up the M SoM from HIBERNATE?

I am in the process of switching from the B SoM to M SoM for several products. I'm trying to figure out how to get the M SoM to wake up from hibernation using a GPIO pin like I have with the B SoM. Based on my reading of the docs, it should be possible using the same approach.

I have a digital line (A7) that I am using to put the device into hibernate and wake it (essentially, it's watching for mains power). Currently, the device goes into hibernation just fine using the code below, but the only way I can get it to wake up is to manually press "RESET".

System.sleep(
          SystemSleepConfiguration().mode(SystemSleepMode::HIBERNATE).gpio(PIN_MAINS_ACTIVE, RISING)
        );

Any thoughts/guidance would be appreciated. Also, can someone create new tags for the new product lineup?

It looks like that should work. A7 is the only pin that can wake from hibernate.

Are you using your own board, or one of the breakouts? Which one?

Is the pin driven with a push-pull or does it have a pull resistor? External or relying on the MCU pull?

Hi @rickkas7 - thanks for the quick response.

It is my own board and using a similar design used for the past few years successfully. The pin is set as INPUT_PULLDOWN, so using the MCU's internal pulldown.

I am reading from a voltage divider that converts the 12V mains power to a 0-~3.3V signal. I've checked the voltages and everything appears to work as expected as far as that goes, but it's not triggering he wake up of the MCU.

It appears that I can reproduce this problem but I don't know why it's happening or have a workaround. It's a mystery to me.

  • Tested with both 5.9.0 and 6.2.0 on M-SoM.
  • Tested RISING and FALLING.
  • Tested with pull and without pull.
  • Tried adding a duration.
#include "Particle.h"

SYSTEM_MODE(SEMI_AUTOMATIC);

SYSTEM_THREAD(ENABLED);

SerialLogHandler logHandler(LOG_LEVEL_INFO);

const pin_t PIN_MAINS_ACTIVE = A7;

void setup() {
    // pinMode(PIN_MAINS_ACTIVE, INPUT_PULLDOWN);
}

void loop() {
    delay(5000);

    SystemSleepConfiguration config;
    config
        .mode(SystemSleepMode::HIBERNATE)
        .gpio(PIN_MAINS_ACTIVE, RISING);

    System.sleep(config);
}

Thanks for the update @rickkas7 - I'm glad it's not just me! I'll keep working on it and post any updates here and will check back to see if Particle learns anything as well.

const int POWER_BUTTON_PIN = A7;
pinMode(POWER_BUTTON_PIN, INPUT_PULLUP);
attachInterrupt(POWER_BUTTON_PIN, POWER_BUTTON_INTERRUPT, FALLING);
void POWER_BUTTON_INTERRUPT();
bool POWER_BUTTON_FLAG = false;
....
  // Configure hibernation mode
  SystemSleepConfiguration config;
  config.mode(SystemSleepMode::HIBERNATE).gpio(POWER_BUTTON_PIN, FALLING);
  System.sleep(config);
.....
void POWER_BUTTON_INTERRUPT() {
    POWER_BUTTON_FLAG = true;
}

I just tested it with my code and 6.2.0 on the Muon. It worked normally. The one difference is I have an interrupt on the A7 pin.

Hey @rickkas7 - I was wondering if there were any updates from Particle on this?

Hi @hagandh , I built exactly the same code that @rickkas7 posted above for MSoM that is installed on M.2 SoM Breakout board against DVOS@5.9.0 and it appeared to be working as expected, no matter whether pinMode(PIN_MAINS_ACTIVE, INPUT_PULLDOWN); is called or not. Just make sure that the A7 is not used by other peripherals, for example, if the MSoM is ever configured for Particle Muon , the A7 is then used by DVOS as PMIC interrupt, see device-os/user/applications/tinker/src/board_config.cpp at develop · particle-iot/device-os · GitHub

@rickkas7 BTW, this is out of date:

A7 is the only pin that can wake from hibernate.

Since v5.5.0, the following listed pins are capable of waking up from hibernate mode: device-os/hal/src/rtl872x/sleep_hal.cpp at v5.5.0 · particle-iot/device-os · GitHub. Basically, there are four pipes can be configured as wakeup source simultaneously and each pipe can only choose one of the three pins as the wakeup pin.

u8 aon_wakepin[4][3] = {
    {    /* wakepin 0 */
        _PA_12, /* PINMUX_S0 */
        _PA_16, /* PINMUX_S1 */
        _PA_20, /* PINMUX_S2 */
    },
    {    /* wakepin 1 */
        _PA_13, /* PINMUX_S0 */
        _PA_17, /* PINMUX_S1 */
        _PA_21, /* PINMUX_S2 */
    },
    {    /* wakepin 2 */
        _PA_14, /* PINMUX_S0 */
        _PA_18, /* PINMUX_S1 */
        _PA_25, /* PINMUX_S2 */
    },
    {    /* wakepin 3 */
        _PA_15, /* PINMUX_S0 */
        _PA_19, /* PINMUX_S1 */
        _PA_26  /* PINMUX_S2 */
    },
};

Hi @ielec thanks for your response. Did you test against an M404 or M524?

I was using M524. There shouldn’t be any difference regarding the pinmap between M404 and M524.

@ielec My understanding from the Particle team is that there is something going on where this works on the M524 but not the M404.

Just tried with a M404 and it worked as expected well.

As it turns out, there is an important difference between engineering samples of the M-SoM and the production version.

On the production M-SoM, pin A7/D28/WKP is on M.2 pin 47 and MCU pin PA[20]. This is what is documented in the datasheet.

On engineering samples, which is what I had used to test as well, M.2 pin 47 is VBAT_MEAS and PA[20] is on M.2 pin 57, SOM17 on the M.2 breakout board.

A production M-SoM works correctly using A7 to wake on the breakout board pin A7 (M.2 pin 47).

On an EVT sample, if you move the wake source to SOM17 (M.2 pin 57) it behaves as if it was A7.

Can confirm I was using an engineering sample previously. I have switched to a non-engineering sample, but do still have issues, though likely due to implementation.

I'm trying to read a 12-16V mains power signal and shut down when mains is turned off and back on when it's turned on. Simple enough. I have a voltage divider set up to drop it down to ~2.7V when on and 0 when off with a 22 µF cap as well per the suggestions in the datasheet for dealing with the impedance issues on A7.

However, when the device goes to sleep, there is additional resistance on A7 that drops the voltage divider such that it doesn't get about ~1.3V when mains is back on so it won't wake up. As soon as the reset button is pressed, this additional resistance goes away and it's all good.

Is there a known way around this? Or do I just need to switch to a small regulator to drop the 12-16V down to 3.3V and that should drive enough current to make A7 happy?

If you use RISING or FALLING for your interrupt, an internal pull is set on the pin before sleep.

If the wake is on CHANGE it does not apply pull, since it's unclear which direction to pull it. It's not exactly the same because it will behave differently if the pin is already in the interrupt state when going to sleep, but sometimes this can be a workaround.

But yes, a voltage regulator is a good option. We use the AP2204K for this purpose as it's inexpensive, tiny, and does not require an external inductor.

1 Like

Thanks! That's the exact one I have on the bench to test as well, so that's convinient.