Example program demonstrating proper powering down of Telit radio and putting the processor into STOP mode.

Dependencies:   WakeUp mbed mtsas SpiFlash25

Fork of Dragonfly_Cellular_Ping_Example by MultiTech

main.cpp

Committer:
mfiore
Date:
2016-02-29
Revision:
3:90cf39b6ed0d
Parent:
2:0288328818cb
Child:
4:91a322a2ec86

File content as of revision 3:90cf39b6ed0d:

/** Dragonfly Cellular Low Power Example
 * This program will run forever doing the following
 *      bring up the cellular link
 *      ping Google's DNS server
 *      properly power off the radio
 *      go to sleep
 *
 * There are two methods for properly powering off the cellular radio
 *  1) Software shutdown
 *      - use Cellular::sendBasicCommand() to issue AT#SH to the radio and make sure it is successful
 *      - poll vdd1_8_mon - when the radio powers off this line will go to 0 (at least 10s after AT#SH)
 *      - drop the radio_reset line to 0 (pin PC_13) so the radio control chip doesn't attempt to restart the radio
 *      - (optional) drop the radio_pwr line to 0
 *          + this eliminates all current draw from the radio when it is powered off but increases the time it takes to reconnect to the network
 *  2) Hardware shutdown
 *      - drop the radio_reset line to 0 (pin PC_13) so the radio control chip doesn't attempt to restart the radio
 *      - poll vdd1_8_mon - when the radio powers off this line will go to 0 (at least 10s after radio_reset was dropped)
 *      - (optional) drop the radio_pwr line to 0
 *          + this eliminates all current draw from the radio when it is powered off but increases the time it takes to reconnect to the network
 *
 * NOTE: This example changes the baud rate of the debug port to 115200 baud!
 */

#include "mbed.h"
#include "mtsas.h"
#include "WakeUp.h"

// This line controls the regulator's battery charger.
// BC_NCE = 0 enables the battery charger
// BC_NCE = 1 disables the battery charger
DigitalOut bc_nce(PB_2);

// These lines are used to control the maximum current draw of the regulator
//        | 100mA mode | 500mA mode| 1A mode  |
// --------------------------------------------
// BC_EN1 |      0     |     1     |    0     |
// BC_EN2 |      0     |     0     |    1     |
// --------------------------------------------
// Default is 1A mode
DigitalOut bc_en1(PC_14, 0);
DigitalOut bc_en2(PC_15, 1);

// This line is used to reset or perform a HW shutdown the radio
// Set it low and keep it low to perform a HW shutdown
// Toggle it low and then high again to reset the radio
DigitalOut radio_reset(PC_13, 1);

// This line controls power to the radio
// It should only be dropped after the radio has been powered off via the radio_reset line or AT#SHDN command to reduce all current consumption from the radio
DigitalOut radio_pwr(PC_3, 1);

// This line is 1 when the radio has sufficient power
// It goes to 0 after the radio has successfully shut down
DigitalIn vdd1_8_mon(PC_5);

bool init_mtsas();
void enterStopMode(const uint32_t interval);

// The MTSSerialFlowControl object represents the physical serial link between the processor and the cellular radio.
mts::MTSSerialFlowControl* io;
// The Cellular object represents the cellular radio.
mts::Cellular* radio;

// An APN is required for GSM radios.
static const char apn[] = "";

bool radio_ok = false;

int main() {
    // Disable the battery charger unless a battery is attached.
    bc_nce = 1;
    
    uint32_t sleep_time = 10;
    Timer tmr;
    
    // Change the baud rate of the debug port from the default 9600 to 115200.
    Serial debug(USBTX, USBRX);
    debug.baud(115200);
    
    //Sets the log level to INFO, higher log levels produce more log output.
    //Possible levels: NONE, FATAL, ERROR, WARNING, INFO, DEBUG, TRACE
    mts::MTSLog::setLogLevel(mts::MTSLog::INFO_LEVEL);
    radio_ok = init_mtsas();
    if (! radio_ok) {
        while (true) {
            logError("failed to initialize cellular radio");
            wait(1);
        }
    }
    
    while (true) {
        logInfo("changing regulator to 1A mode");
        bc_en1 = 0;
        bc_en2 = 1;
        logInfo("powering on radio");
        radio_pwr = 1;
        radio_reset = 1;
        int tries = 0;
        
        while (radio->sendBasicCommand("AT", 1000) != MTS_SUCCESS) {
            tries++;
            if (tries % 25 == 0) {
                logWarning("no response from radio after 25 tries (total tries %d) - resetting radio", tries);
                radio_reset = 0;
                wait_ms(10);
                radio_reset = 1;
            }
            wait(1);
        }
        
        logInfo("setting APN");
        if (radio->setApn(apn) != MTS_SUCCESS)
            logError("failed to set APN to \"%s\"", apn);
        logInfo("bringing up the link");
        if (! radio->connect()) {
            logError("failed to bring up the link");
        } else {
            for (int i = 0; i < 10; i++) {
                logInfo("pinging");
                if (! radio->ping("www.google.com"))
                    logError("failed to ping");
                else
                    logInfo("ping succeeded");
            }
            logInfo("finished - bringing down link");
            radio->disconnect();
        }
        
        // power down the radio
        logInfo("powering down radio");
        radio_reset = 0;
        logInfo("waiting for vdd1_8_mon to go low");
        tmr.reset();
        tmr.start();
        // wait up to 30s for the radio to shut down
        while (vdd1_8_mon != 0 && tmr.read() < 30)
            wait_ms(500);
        tmr.stop();
        logInfo("radio powered off after %fs", tmr.read());
        radio_pwr = 0;
        logInfo("putting regulator in 100mA mode");
        bc_en1 = 0;
        bc_en2 = 0;
        
        logInfo("going to sleep for %lu seconds", sleep_time);
        enterStopMode(sleep_time);
    }
    
    return 0;
}

bool init_mtsas() {
    io = new mts::MTSSerialFlowControl(RADIO_TX, RADIO_RX, RADIO_RTS, RADIO_CTS);
    if (! io)
        return false;
        
    // radio default baud rate is 115200
    io->baud(115200);
    radio = mts::CellularFactory::create(io);
    if (! radio)
        return false;
        
    // Transport must be set properly before any TCPSocketConnection or UDPSocket objects are created
    Transport::setTransport(radio);
    
    return true;
}

#define RTC_ALARMA_DISABLE() do { \
    RTC->ISR &= ~RTC_ISR_ALRAF; \
    RTC->WPR = 0xCA; \
    RTC->WPR = 0x53; \
    RTC->CR &= ~(RTC_CR_ALRAE | RTC_CR_ALRAIE); \
    RTC->WPR = 0xFF; \
} while (0)

void enterStopMode(const uint32_t interval) {
    // disable ADC - it can consume power in stop mode
    ADC1->CR2 &= ~ADC_CR2_ADON;

    // enable debugging during stop mode
    HAL_EnableDBGStopMode();

    // put regulators into low-power mode
    HAL_PWREx_EnableMainRegulatorLowVoltage();
    HAL_PWREx_EnableLowRegulatorLowVoltage();

    // power down flash
    HAL_PWREx_EnableFlashPowerDown();
    
    // configure RTC Alarm A to wake the device up
    WakeUp::set(interval);

    // make sure wakeup flag is cleared
    PWR->CR |= PWR_CR_CWUF;

    logInfo("entering stop mode %08x", RTC->ISR);
    fflush(stdout);

    // enter stop mode - don't execute past here until woken up
    HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI);

    // HSI (High Speed Internal) oscillator is selected when coming out of stop mode - set up clocking
    SetSysClock();

    // disable RTC alarm A and RTC alarm A interrupt
    RTC_ALARMA_DISABLE();

    // clear wakeup flag in power control register
    PWR->CR |= PWR_CR_CWUF;

    // put regulators back into to full-power mode
    HAL_PWREx_DisableMainRegulatorLowVoltage();
    HAL_PWREx_DisableLowRegulatorLowVoltage();

    // turn the flash back on
    HAL_PWREx_DisableFlashPowerDown();

    // enable the ADC
    ADC1->CR2 |= ADC_CR2_ADON;

    // disable debugging during stop mode
    HAL_DisableDBGStopMode();
}