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
Diff: main.cpp
- Revision:
- 3:90cf39b6ed0d
- Parent:
- 2:0288328818cb
- Child:
- 4:91a322a2ec86
--- a/main.cpp Fri Feb 26 16:47:54 2016 +0000 +++ b/main.cpp Mon Feb 29 14:53:33 2016 +0000 @@ -1,18 +1,60 @@ -/** Dragonfly Cellular Ping Example - * Configures the cellular radio, brings up the cellular link, and pings Google. +/** 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; @@ -28,6 +70,9 @@ // 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); @@ -35,8 +80,6 @@ //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); - - logInfo("initializing cellular radio"); radio_ok = init_mtsas(); if (! radio_ok) { while (true) { @@ -45,26 +88,64 @@ } } - logInfo("setting APN"); - if (radio->setApn(apn) != MTS_SUCCESS) - logError("failed to set APN to \"%s\"", apn); + 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("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("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); } - logInfo("finished - bringing down link"); - radio->disconnect(); - return 0; } @@ -84,3 +165,60 @@ 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(); +}