Skip to content
This repository has been archived by the owner on Nov 16, 2023. It is now read-only.

How to avoid the simcom module turning on at boot #8

Closed
gasagna opened this issue Oct 18, 2022 · 10 comments
Closed

How to avoid the simcom module turning on at boot #8

gasagna opened this issue Oct 18, 2022 · 10 comments

Comments

@gasagna
Copy link

gasagna commented Oct 18, 2022

Hi,

the simcom module is set to turn on automatically when the board wakes up from deep sleep. This is inconvenient, since I do not need the modem to turn on every time the board wakes up from sleep, as I only need the network every 10 or so cycles.

How can I make sure the simcom module remains off? Currently, I am shutting down the module manually in setup() using this code

// A7608 Power off - see simcom-A7608 hardware design document
void modem_hw_poweroff() {
    pinMode(PWR_PIN, OUTPUT);    
    digitalWrite(PWR_PIN, LOW);  delay(3000); // this is Toff
    digitalWrite(PWR_PIN, HIGH);
}

but the 3 second delay is too long and the modules turns on before going off.

I wonder if keeping the PWR_PIN to LOW all the time would achieve what I am after.

Thanks

@gasagna
Copy link
Author

gasagna commented Oct 18, 2022

Some update on this issue. I am basically unable to turn the module off by pulling down the power pin. I have looked at the power off procedure for the a7608 here, and here is some code to demonstrate how the procedure fails

#define PWR_PIN 4

// A7608 Power off
// see simcom-A7608 hardware design document
void modem_hw_poweroff() {
    pinMode(PWR_PIN, OUTPUT);
    digitalWrite(PWR_PIN, LOW);  delay(3000); // this is Toff 
    digitalWrite(PWR_PIN, HIGH); 
}

void setup() {
    // setup ports
    Serial.begin(9600); delay(1000);

    Serial.println("start");
    delay(15000); // module will power on automatically at boot during this delay

    // initiate power off
    Serial.println("try poweroff");
    modem_hw_poweroff(); // this does not work

    Serial.println("done?"); // here module should be off, but it's not
    delay(50000);
}

I have tried keeping the power pin low for different times, but I am basically unable to turn the module off via the power pin. Using the AT+CPOF command via the modem works, but that requires the module to be reachable to AT commands.

Basically what I am asking is how can I shutdown the module, or prevent it from starting at boot.

@LilyGO
Copy link
Contributor

LilyGO commented Oct 20, 2022

You can declare a variable (RTC_DATA_ATTR int num ). Judgment to the tenth time then execute start A7608

@gasagna
Copy link
Author

gasagna commented Oct 23, 2022

Hi @LilyGO, I see what you mean, but that is not sufficient. For some reason the module wakes up automatically at boot. It would be nice to understand why.

Anyway, I found this issue which uses the functions gpio_hold_en and gpio_deep_sleep_hold_en to keep the power pin low all the time.

Also, given how the GPIO 4 is connected to the POWER KEY of the simcom module (see schematic) a HIGH pulse is needed. Here is now my power off function. This avoids the module turning on when it wakes up from deep sleep.

void modem_hw_poweroff() {
    pinMode(PWR_PIN, OUTPUT);
    digitalWrite(PWR_PIN, HIGH);  delay(3000); // this is Toff
    digitalWrite(PWR_PIN, LOW);   delay(2000);

    // avoid modem starting when waking up from sleep
    gpio_deep_sleep_hold_en();
    gpio_hold_en(GPIO_NUM_4);
}

This can be closed.

EDIT: the code above works but hold the pin state during sleep makes it impossible to reach low currents (i get about 1.5 mA). See comment below for the correct implementation.

@gasagna gasagna closed this as completed Oct 23, 2022
@gasagna
Copy link
Author

gasagna commented Oct 29, 2022

Some updates on this issue in case people have similar issues. I have finally discovered what is the purpose of the BAT_EN pin. Basically, it can be used to enable or disable the simcom module while on battery power. This pin also has a role in ensuring the module does not wake up automatically when waking up from sleep, which is the behaviour that made me open this github issue. The sketch below demonstrates how to properly use BAT_EN to control the simcom module.

// pins
#define BAT_EN  12
#define PWR_PIN 4
#define RESET   5

// enable modem on battery power
void enable_battery_functions() {
    pinMode(BAT_EN, OUTPUT);
    digitalWrite(BAT_EN, HIGH);
}

// disable modem on battery power (not a power off, just avoid it waking up by itself)
void disable_battery_functions() {
    pinMode(BAT_EN, OUTPUT);
    digitalWrite(BAT_EN, LOW);
}

// A7608 Power off
// see simcom-A7608 hardware design document
void modem_hw_poweroff() {
    pinMode(PWR_PIN, OUTPUT);
    digitalWrite(PWR_PIN, LOW);   delay(100);
    digitalWrite(PWR_PIN, HIGH);  delay(3000); // this is Toff
    digitalWrite(PWR_PIN, LOW);
}

// A7608 Power on
// see simcom-A7608 hardware design document
void modem_hw_poweron() {
    pinMode(PWR_PIN, OUTPUT);
    digitalWrite(PWR_PIN, LOW);  delay(100);
    digitalWrite(PWR_PIN, HIGH); delay(1000); // this is Ton
    digitalWrite(PWR_PIN, LOW);  delay(20000); // wait for module to start
}

// persistent variable after sleep
RTC_DATA_ATTR int bootCount = 0;

// microseconds to seconds
int us_to_s_factor = 1000000;

void setup() {
    // start serial
    Serial.begin(9600); delay(100);

    // update
    bootCount++;
    Serial.print("bootCount = "); Serial.println(bootCount);

    // turn on every five boots (useful to send data every N sampling periods)
    if (bootCount == 1 || bootCount == 5) {
        // battery enable
        // withouth this, the simcom module cannot turn on while on battery power
        Serial.print("enabling battery ...");
        enable_battery_functions();
        Serial.println("done");

        // power on
        Serial.print("modem power on ...");
        modem_hw_poweron();
        Serial.println("done");

       // do stuff with the network ...

        // battery disable
        // withouth this, modem wakes up autonomously during deep sleep
        Serial.print("disabling battery ...");
        disable_battery_functions();
        Serial.println("done");
        
        // reset bootCount
        bootCount = 1;
    }

    // some task, e.g. sample a sensor, etc..
    delay(15000);

    // shutdown
    if (bootCount == 1) {
        Serial.print("modem power off ...");
        modem_hw_poweroff();
        Serial.println("done");
        // modem does not wake up after this if
        // disable_battery_functions has been called 
    }

    // go to sleep
    Serial.print("going to sleep");
    esp_sleep_enable_timer_wakeup(5 * us_to_s_factor); delay(100);
    esp_deep_sleep_start();
}


void loop() {}

The simcom module is powered on when bootCount=1 then is powered off and the dev board goes to sleep. The board then wakes up 4 times, at which point bootCount=5 and the module starts again. As shown in the comments, not enabling the battery prevents the simcom module from turning on, and not disabling the battery makes it wake up by itself during sleep. The esp32 is not affected by this and functionality is independent from whether BAT_EN is low or high. I have attached the board to my multimeter to see what the board was doing based on the current it was sucking.

Note that all of this only works when on battery power. If the board is attached to usb, the enable_/disable_battery_functions do not seem to have any influence.
This might help people discussing the role of BAT_EN here.

@gasagna
Copy link
Author

gasagna commented Nov 5, 2022

Reopening this issue, as I have not been able to find a solution for my use case.

Here is a minimal working example of what I am trying to do. The board should periodically wake up from sleep to take a measurement from a sensor and every N boot cycles (3 in the example below), it should turn on the modem and send data over the network. The example below does not include the measurement and data transfer as it is not necessary to demonstrate the problem.

I have flashed this code on the three boards I purchased and none of them works. The modem never wakes up. I have plugged a multimeter in series with the battery to measure the current use to debug what is going on and here are my conclusions. All is good until bootCount == 3. The code enters the if branch and enables the battery by pulling high the BAT_EN pin. Shortly thereafter, there is an increase in the current, so I believe the simcom module is trying to start but then I believe the esp32 crashes or restarts. In fact, the 15 seconds delay after modem_hw_reset is never reached, nor the modem wakes up. This also resets the RTC_DATA_ATTR variable bootCount to zero and the cycle restart. The same code work when on USB power, but of course the simcom module wakes up at every boot probably for the same issue described here.

I wonder if this might have to do with the board design, but I would appreciate some help on this. Perhaps there is a software solution this this problem. Thanks.

#define TINY_GSM_MODEM_SIM7600
#include <TinyGsmClient.h>
TinyGsm modem(Serial1);

// pins
#define BAT_EN  12
#define PWR_PIN 4
#define RESET   5
#define PIN_TX  26
#define PIN_RX  27

const char apn[]      = "em";
const char gprsUser[] = "";
const char gprsPass[] = "";

// enable battery
void enable_battery_functions() {
    pinMode(BAT_EN, OUTPUT);
    digitalWrite(BAT_EN, HIGH);
}

// disable battery
void disable_battery_functions() {
    pinMode(BAT_EN, OUTPUT);
    digitalWrite(BAT_EN, LOW); delay(100);
}

// A7608 Reset
// see simcom-A7608 hardware design document
void modem_hw_reset() {
    pinMode(RESET, OUTPUT);
    digitalWrite(RESET, HIGH); delay(1000);
    digitalWrite(RESET, LOW);  delay(100);
}

// A7608 Power on
// see simcom-A7608 hardware design document
void modem_hw_poweron() {
    pinMode(PWR_PIN, OUTPUT);
    digitalWrite(PWR_PIN, HIGH); delay(1000); // this is Ton
    digitalWrite(PWR_PIN, LOW);  delay(15000);
}

RTC_DATA_ATTR int bootCount = 0;
int s_to_us_factor = 1000000;

void setup() {
    // some delay to see current draw on multimeter
    delay(3000);

    // start main serial port
    Serial.begin(115200); 
    while (!Serial) {}

    // bootcount keeps increasing on usb power
    Serial.print("bootcount: ");
    bootCount++;
    Serial.println(bootCount);

    // start modem every three boots
    if (bootCount % 3 == 0) {
        Serial.println("Enabling battery ...");
        enable_battery_functions();

        // wait modem to start. Does not happen. I think esp just restarts
        Serial.println("Resetting modem ...");
        modem_hw_reset();
        delay(15000); 

        // start serial communication with simcom module?
        Serial1.begin(115200, SERIAL_8N1, PIN_RX, PIN_TX);
        while (!Serial1) {}
        
        Serial.print("Initializing modem ...");
        if (modem.init()) {
            Serial.println(" done");
        } else {
            Serial.println(" failed");
        }

        Serial.print("Waiting for network ...");
        if (modem.waitForNetwork()) {
            Serial.println(" done");
        } else {
            Serial.println(" failed");
        }

        Serial.print("Connecting to access point ...");
        if (modem.gprsConnect(apn, gprsUser, gprsPass)) {
            Serial.println(" done");
        } else {
            Serial.println(" failed");
        }

        Serial.println("Disconnecting GPRS ...");
        modem.gprsDisconnect();

        Serial.println("Powering off modem ...");
        modem.poweroff();

        // on usb power modem wakes up anyway during sleep, but on battery
        // power this allows the modem to remain off 
        Serial.println("Disabling battery functions");
        disable_battery_functions();
    }

    Serial.print("Going to sleep");
    esp_sleep_enable_timer_wakeup(15 * s_to_us_factor); delay(200);
    esp_deep_sleep_start();
}

void loop() {
}

@LilyGO
Copy link
Contributor

LilyGO commented Nov 7, 2022

  1. Start-up of the reference example
    //A7608 Reset
    pinMode(RESET, OUTPUT);
    digitalWrite(PWR_PIN, LOW);
    delay(100);
    digitalWrite(RESET, HIGH);
    delay(1000);
    digitalWrite(RESET, LOW);

//A7608 Power on
pinMode(PWR_PIN, OUTPUT);
digitalWrite(PWR_PIN, LOW);
delay(100);
digitalWrite(PWR_PIN, HIGH);
delay(1000);
digitalWrite(PWR_PIN, LOW);

  1. without entering an if statement. Your BAT_EN status also needs to be handled.

@gasagna
Copy link
Author

gasagna commented Nov 7, 2022

Hi @LilyGO, thanks, but I am not sure I understand what you mean – i hope you can clarify.

The reset and power on should only be executed once every $N$ times – i do not want the simcom module to power on every time i take a measurement. They need to be in an if statement.

Secondly, what do you mean by "handling" the BAT_EN status?

Thanks.

@gasagna
Copy link
Author

gasagna commented Nov 7, 2022

Also @LilyGO , I do not think the reset and power on are so important. Here is an even simpler sketch that demonstrates that enabling the battery in the if statement resets the board. Put an LED on, for example, pin 32 to debug the sketch and see what it is doing.

// pins
#define BAT_EN  12
#define PWR_PIN 4
#define RESET   5
#define PIN_TX  26
#define PIN_RX  27

// put an LED on pin 32
#define LED_PIN 32

// enable battery
void enable_battery_functions() {
    pinMode(BAT_EN, OUTPUT);
    digitalWrite(BAT_EN, HIGH);
}

// disable battery
void disable_battery_functions() {
    pinMode(BAT_EN, OUTPUT);
    digitalWrite(BAT_EN, LOW);
}

RTC_DATA_ATTR int bootCount = 0;
int s_to_us_factor = 1000000;

void setup() {
    // some delay
    delay(3000);

    // enable pin
    pinMode(LED_PIN, OUTPUT);

    // bootcount keeps increasing on usb power
    bootCount++;

    // flash the LED slowly, as many times as bootCount
    for (int i=0; i<bootCount; i++) {
        digitalWrite(LED_PIN, HIGH); delay(500);
        digitalWrite(LED_PIN, LOW);  delay(500);
    }

    // start modem every three boots
    if (bootCount % 3 == 0) {
        enable_battery_functions();

        // some delay
        delay(1000);

        // this stuff never gets executed: you will never see the LED flashing quickly.
        // Instead, after three flashes, you'll see one flash, because the esp
        // has restarted, bootCount has been reset to zero and the code has produced 
        // one flash as instructed few lines above here
        for (int i=0; i<10; i++) {
            digitalWrite(LED_PIN, HIGH); delay(100);
            digitalWrite(LED_PIN, LOW);  delay(100);
        }

        // this also never gets executed
        disable_battery_functions();
    }

    esp_sleep_enable_timer_wakeup(5 * s_to_us_factor); delay(200);
    esp_deep_sleep_start();
}

void loop() {}

You will never see four or more flashes - the board gets reset by enable_battery_functions(). For some reason, enabling the battery with BAT_EN in the middle of the sketch messes up the board, forces a restart and the RTC memory gets wiped.

@LilyGO
Copy link
Contributor

LilyGO commented Nov 8, 2022

Use battery power only. Everything goes according to plan

#define uS_TO_S_FACTOR 1000000ULL /* Conversion factor for micro seconds to seconds /
#define TIME_TO_SLEEP 8 /
Time ESP32 will go to sleep (in seconds) */

RTC_DATA_ATTR int bootCount = 0;

#include "soc/soc.h"
#include "soc/rtc_cntl_reg.h"
void setup()
{
// Set console baud rate
SerialMon.begin(115200);
delay(10);
SerialAT.begin(UART_BAUD, SERIAL_8N1, PIN_RX, PIN_TX);
WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0); //Power off detection
SerialMon.println("setup...");

pinMode(BAT_EN, OUTPUT);
digitalWrite(BAT_EN, LOW);
delay(1000);


SerialMon.print("bootCount ");
SerialMon.println(bootCount);
if (bootCount % 3 == 0) {
    SerialMon.println("A7608 EN");
    // BAT EN
    digitalWrite(BAT_EN, HIGH);
    delay(1000);
    //A7608 Reset
    pinMode(RESET, OUTPUT);
    digitalWrite(PWR_PIN, LOW);
    delay(100);
    digitalWrite(RESET, HIGH);
    delay(1000);
    digitalWrite(RESET, LOW);

    //A7608 Power on
    pinMode(PWR_PIN, OUTPUT);
    digitalWrite(PWR_PIN, LOW);
    delay(100);
    digitalWrite(PWR_PIN, HIGH);
    delay(1000);
    digitalWrite(PWR_PIN, LOW);


    int i = 10;
    Serial.println("\nTesting Modem Response...\n");
    Serial.println("****");
    while (i) {
        SerialAT.println("AT");
        delay(500);
        if (SerialAT.available()) {
            String r = SerialAT.readString();
            Serial.println(r);
            if ( r.indexOf("OK") >= 0 ) {
                break;;
            }
        }
        delay(500);
        i--;
    }
    SerialMon.println("A7608 EN done");
}


++bootCount;

delay(5000);

#if TINY_GSM_POWERDOWN
// Try to power-off (modem may decide to restart automatically)
// To turn off modem completely, please use Reset/Enable pins
DBG("Poweroff.");
modem.poweroff();

#endif
SerialMon.println("Poweroff...............");

// pinMode(BAT_EN, INPUT_PULLUP);
// Test is complete Set it to sleep mode
esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR);
delay(200);
esp_deep_sleep_start();

// Do nothing forevermore
while (true) {
    modem.maintain();
}

}
void loop()
{

}

@gasagna
Copy link
Author

gasagna commented Nov 17, 2022

OK, some updates. Thanks @LilyGO for suggesting to turn off the brownout detector with WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0). This worked well. The difficulty was that the issue was arising only on battery power, where obviously I did not get a serial monitor to debug the code. For reference, in case people have funny battery-power-related issues, I connected a second board through a serial interface, to see what the first board was doing.

Here is the final version of my example code, in case people need a similar application

#define TINY_GSM_MODEM_SIM7600
#include <TinyGsmClient.h>
TinyGsm modem(Serial1);

#include "soc/soc.h"
#include "soc/rtc_cntl_reg.h"

// pins
#define BAT_EN  12
#define PWR_PIN 4
#define RESET   5
#define PIN_TX  26
#define PIN_RX  27

// access point - change to your sim operator
const char apn[]      = "em";
const char gprsUser[] = "";
const char gprsPass[] = "";

// enable reading battery voltage and using battery power
void enable_battery_functions() {
    pinMode(BAT_EN, OUTPUT);
    digitalWrite(BAT_EN, HIGH);
}

// disable battery
void disable_battery_functions() {
    pinMode(BAT_EN, OUTPUT);
    digitalWrite(BAT_EN, LOW);
}

// A7608 Reset
// see simcom-A7608 hardware design document
void modem_hw_reset() {
    pinMode(RESET, OUTPUT);
    digitalWrite(RESET, LOW);  delay(100);
    digitalWrite(RESET, HIGH); delay(1000);
    digitalWrite(RESET, LOW);
}

// A7608 Power on
// see simcom-A7608 hardware design document
void modem_hw_poweron() {
    pinMode(PWR_PIN, OUTPUT);
    digitalWrite(PWR_PIN, LOW);  delay(100);
    digitalWrite(PWR_PIN, HIGH); delay(1000);  // this is Ton
    digitalWrite(PWR_PIN, LOW);  delay(15000); // wait for power on
}

RTC_DATA_ATTR int bootCount = 0;
int s_to_us_factor = 1000000;

void setup() {
    // serial port - connect a second board to GPIO 3 and 1 to read output when on battery power
    Serial2.begin(115200, SERIAL_8N1, GPIO_NUM_3, GPIO_NUM_1);
    while (!Serial2) {}

    // disable brownout detector
    Serial2.println("Disabling detector ... ");
    WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0); 

    // some delay
    delay(15000);

    // bootcount
    bootCount++;
    Serial2.print("bootCount = "); Serial2.println(bootCount);

    // start modem every three boots
    if (bootCount % 3 == 0) {
        // enable battery
        Serial2.print("Enabling battery ... ");
        enable_battery_functions();

        // reset and power on modem
        Serial2.println("Resetting modem ... ");
        modem_hw_reset();

        Serial2.println("Powering on modem ... ");
        modem_hw_poweron();

        // start serial communication with simcom module
        Serial1.begin(115200, SERIAL_8N1, PIN_RX, PIN_TX);
        while (!Serial1) {}

        Serial2.print("Initializing modem ...");
        if (modem.init()) {
            Serial2.println(" done");
        } else {
            Serial2.println(" failed");
        }

        Serial2.print("Waiting for network ...");
        if (modem.waitForNetwork()) {
            Serial2.println(" done");
        } else {
            Serial2.println(" failed");
        }

        Serial2.print("Connecting to access point ...");
        if (modem.gprsConnect(apn, gprsUser, gprsPass)) {
            Serial2.println(" done");
        } else {
            Serial2.println(" failed");
        }

        delay(2000);

        Serial2.println("Disconnecting GPRS ...");
        modem.gprsDisconnect();

        Serial2.println("Powering off modem ...");
        modem.poweroff();

        Serial2.println("Disable battery functions ... ");
        disable_battery_functions();
    }

    Serial2.println("Going to sleep ... ");
    esp_sleep_enable_timer_wakeup(5 * s_to_us_factor); delay(200);
    esp_deep_sleep_start();
}

void loop() {}

@gasagna gasagna closed this as completed Nov 17, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants
@gasagna @LilyGO and others