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
main.cpp@4:91a322a2ec86, 2016-02-29 (annotated)
- Committer:
- mfiore
- Date:
- Mon Feb 29 19:28:01 2016 +0000
- Revision:
- 4:91a322a2ec86
- Parent:
- 3:90cf39b6ed0d
- Child:
- 5:e493656a4a1a
update some comments, bail out if the radio doesn't shut down
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
mfiore | 3:90cf39b6ed0d | 1 | /** Dragonfly Cellular Low Power Example |
mfiore | 3:90cf39b6ed0d | 2 | * This program will run forever doing the following |
mfiore | 3:90cf39b6ed0d | 3 | * bring up the cellular link |
mfiore | 3:90cf39b6ed0d | 4 | * ping Google's DNS server |
mfiore | 3:90cf39b6ed0d | 5 | * properly power off the radio |
mfiore | 3:90cf39b6ed0d | 6 | * go to sleep |
mfiore | 3:90cf39b6ed0d | 7 | * |
mfiore | 3:90cf39b6ed0d | 8 | * There are two methods for properly powering off the cellular radio |
mfiore | 3:90cf39b6ed0d | 9 | * 1) Software shutdown |
mfiore | 4:91a322a2ec86 | 10 | * - use Cellular::sendBasicCommand() to issue AT#SHDN to the radio and make sure it is successful |
mfiore | 4:91a322a2ec86 | 11 | * - poll vdd1_8_mon - when the radio powers off this line will go to 0 (at least 10s after AT#SHDN) |
mfiore | 3:90cf39b6ed0d | 12 | * - drop the radio_reset line to 0 (pin PC_13) so the radio control chip doesn't attempt to restart the radio |
mfiore | 3:90cf39b6ed0d | 13 | * - (optional) drop the radio_pwr line to 0 |
mfiore | 3:90cf39b6ed0d | 14 | * + this eliminates all current draw from the radio when it is powered off but increases the time it takes to reconnect to the network |
mfiore | 3:90cf39b6ed0d | 15 | * 2) Hardware shutdown |
mfiore | 3:90cf39b6ed0d | 16 | * - drop the radio_reset line to 0 (pin PC_13) so the radio control chip doesn't attempt to restart the radio |
mfiore | 3:90cf39b6ed0d | 17 | * - poll vdd1_8_mon - when the radio powers off this line will go to 0 (at least 10s after radio_reset was dropped) |
mfiore | 3:90cf39b6ed0d | 18 | * - (optional) drop the radio_pwr line to 0 |
mfiore | 3:90cf39b6ed0d | 19 | * + this eliminates all current draw from the radio when it is powered off but increases the time it takes to reconnect to the network |
mfiore | 0:da114ae7c596 | 20 | * |
mfiore | 0:da114ae7c596 | 21 | * NOTE: This example changes the baud rate of the debug port to 115200 baud! |
mfiore | 4:91a322a2ec86 | 22 | * NOTE: A SIM card is required for GSM radios to connect to the network! |
mfiore | 4:91a322a2ec86 | 23 | * NOTE: CDMA cellular radios need to be provisioned before use! |
mfiore | 0:da114ae7c596 | 24 | */ |
mfiore | 0:da114ae7c596 | 25 | |
mfiore | 0:da114ae7c596 | 26 | #include "mbed.h" |
mfiore | 0:da114ae7c596 | 27 | #include "mtsas.h" |
mfiore | 3:90cf39b6ed0d | 28 | #include "WakeUp.h" |
mfiore | 0:da114ae7c596 | 29 | |
mfiore | 2:0288328818cb | 30 | // This line controls the regulator's battery charger. |
mfiore | 2:0288328818cb | 31 | // BC_NCE = 0 enables the battery charger |
mfiore | 2:0288328818cb | 32 | // BC_NCE = 1 disables the battery charger |
mfiore | 2:0288328818cb | 33 | DigitalOut bc_nce(PB_2); |
mfiore | 2:0288328818cb | 34 | |
mfiore | 3:90cf39b6ed0d | 35 | // These lines are used to control the maximum current draw of the regulator |
mfiore | 3:90cf39b6ed0d | 36 | // | 100mA mode | 500mA mode| 1A mode | |
mfiore | 3:90cf39b6ed0d | 37 | // -------------------------------------------- |
mfiore | 3:90cf39b6ed0d | 38 | // BC_EN1 | 0 | 1 | 0 | |
mfiore | 3:90cf39b6ed0d | 39 | // BC_EN2 | 0 | 0 | 1 | |
mfiore | 3:90cf39b6ed0d | 40 | // -------------------------------------------- |
mfiore | 3:90cf39b6ed0d | 41 | // Default is 1A mode |
mfiore | 3:90cf39b6ed0d | 42 | DigitalOut bc_en1(PC_14, 0); |
mfiore | 3:90cf39b6ed0d | 43 | DigitalOut bc_en2(PC_15, 1); |
mfiore | 3:90cf39b6ed0d | 44 | |
mfiore | 3:90cf39b6ed0d | 45 | // This line is used to reset or perform a HW shutdown the radio |
mfiore | 3:90cf39b6ed0d | 46 | // Set it low and keep it low to perform a HW shutdown |
mfiore | 3:90cf39b6ed0d | 47 | // Toggle it low and then high again to reset the radio |
mfiore | 3:90cf39b6ed0d | 48 | DigitalOut radio_reset(PC_13, 1); |
mfiore | 3:90cf39b6ed0d | 49 | |
mfiore | 3:90cf39b6ed0d | 50 | // This line controls power to the radio |
mfiore | 3:90cf39b6ed0d | 51 | // 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 |
mfiore | 3:90cf39b6ed0d | 52 | DigitalOut radio_pwr(PC_3, 1); |
mfiore | 3:90cf39b6ed0d | 53 | |
mfiore | 3:90cf39b6ed0d | 54 | // This line is 1 when the radio has sufficient power |
mfiore | 3:90cf39b6ed0d | 55 | // It goes to 0 after the radio has successfully shut down |
mfiore | 3:90cf39b6ed0d | 56 | DigitalIn vdd1_8_mon(PC_5); |
mfiore | 3:90cf39b6ed0d | 57 | |
mfiore | 0:da114ae7c596 | 58 | bool init_mtsas(); |
mfiore | 3:90cf39b6ed0d | 59 | void enterStopMode(const uint32_t interval); |
mfiore | 0:da114ae7c596 | 60 | |
mfiore | 1:1411b4274907 | 61 | // The MTSSerialFlowControl object represents the physical serial link between the processor and the cellular radio. |
mfiore | 0:da114ae7c596 | 62 | mts::MTSSerialFlowControl* io; |
mfiore | 1:1411b4274907 | 63 | // The Cellular object represents the cellular radio. |
mfiore | 0:da114ae7c596 | 64 | mts::Cellular* radio; |
mfiore | 0:da114ae7c596 | 65 | |
mfiore | 1:1411b4274907 | 66 | // An APN is required for GSM radios. |
mfiore | 0:da114ae7c596 | 67 | static const char apn[] = ""; |
mfiore | 0:da114ae7c596 | 68 | |
mfiore | 0:da114ae7c596 | 69 | bool radio_ok = false; |
mfiore | 0:da114ae7c596 | 70 | |
mfiore | 0:da114ae7c596 | 71 | int main() { |
mfiore | 2:0288328818cb | 72 | // Disable the battery charger unless a battery is attached. |
mfiore | 2:0288328818cb | 73 | bc_nce = 1; |
mfiore | 2:0288328818cb | 74 | |
mfiore | 3:90cf39b6ed0d | 75 | uint32_t sleep_time = 10; |
mfiore | 3:90cf39b6ed0d | 76 | Timer tmr; |
mfiore | 3:90cf39b6ed0d | 77 | |
mfiore | 1:1411b4274907 | 78 | // Change the baud rate of the debug port from the default 9600 to 115200. |
mfiore | 0:da114ae7c596 | 79 | Serial debug(USBTX, USBRX); |
mfiore | 0:da114ae7c596 | 80 | debug.baud(115200); |
mfiore | 0:da114ae7c596 | 81 | |
mfiore | 0:da114ae7c596 | 82 | //Sets the log level to INFO, higher log levels produce more log output. |
mfiore | 0:da114ae7c596 | 83 | //Possible levels: NONE, FATAL, ERROR, WARNING, INFO, DEBUG, TRACE |
mfiore | 0:da114ae7c596 | 84 | mts::MTSLog::setLogLevel(mts::MTSLog::INFO_LEVEL); |
mfiore | 0:da114ae7c596 | 85 | radio_ok = init_mtsas(); |
mfiore | 0:da114ae7c596 | 86 | if (! radio_ok) { |
mfiore | 0:da114ae7c596 | 87 | while (true) { |
mfiore | 0:da114ae7c596 | 88 | logError("failed to initialize cellular radio"); |
mfiore | 0:da114ae7c596 | 89 | wait(1); |
mfiore | 0:da114ae7c596 | 90 | } |
mfiore | 0:da114ae7c596 | 91 | } |
mfiore | 0:da114ae7c596 | 92 | |
mfiore | 3:90cf39b6ed0d | 93 | while (true) { |
mfiore | 3:90cf39b6ed0d | 94 | logInfo("changing regulator to 1A mode"); |
mfiore | 3:90cf39b6ed0d | 95 | bc_en1 = 0; |
mfiore | 3:90cf39b6ed0d | 96 | bc_en2 = 1; |
mfiore | 3:90cf39b6ed0d | 97 | logInfo("powering on radio"); |
mfiore | 3:90cf39b6ed0d | 98 | radio_pwr = 1; |
mfiore | 3:90cf39b6ed0d | 99 | radio_reset = 1; |
mfiore | 3:90cf39b6ed0d | 100 | int tries = 0; |
mfiore | 3:90cf39b6ed0d | 101 | |
mfiore | 3:90cf39b6ed0d | 102 | while (radio->sendBasicCommand("AT", 1000) != MTS_SUCCESS) { |
mfiore | 4:91a322a2ec86 | 103 | wait(1); |
mfiore | 3:90cf39b6ed0d | 104 | tries++; |
mfiore | 3:90cf39b6ed0d | 105 | if (tries % 25 == 0) { |
mfiore | 3:90cf39b6ed0d | 106 | logWarning("no response from radio after 25 tries (total tries %d) - resetting radio", tries); |
mfiore | 3:90cf39b6ed0d | 107 | radio_reset = 0; |
mfiore | 3:90cf39b6ed0d | 108 | wait_ms(10); |
mfiore | 3:90cf39b6ed0d | 109 | radio_reset = 1; |
mfiore | 3:90cf39b6ed0d | 110 | } |
mfiore | 4:91a322a2ec86 | 111 | printf("."); |
mfiore | 3:90cf39b6ed0d | 112 | } |
mfiore | 4:91a322a2ec86 | 113 | printf("\r\n"); |
mfiore | 0:da114ae7c596 | 114 | |
mfiore | 3:90cf39b6ed0d | 115 | logInfo("setting APN"); |
mfiore | 3:90cf39b6ed0d | 116 | if (radio->setApn(apn) != MTS_SUCCESS) |
mfiore | 3:90cf39b6ed0d | 117 | logError("failed to set APN to \"%s\"", apn); |
mfiore | 3:90cf39b6ed0d | 118 | logInfo("bringing up the link"); |
mfiore | 3:90cf39b6ed0d | 119 | if (! radio->connect()) { |
mfiore | 3:90cf39b6ed0d | 120 | logError("failed to bring up the link"); |
mfiore | 3:90cf39b6ed0d | 121 | } else { |
mfiore | 3:90cf39b6ed0d | 122 | for (int i = 0; i < 10; i++) { |
mfiore | 3:90cf39b6ed0d | 123 | logInfo("pinging"); |
mfiore | 3:90cf39b6ed0d | 124 | if (! radio->ping("www.google.com")) |
mfiore | 3:90cf39b6ed0d | 125 | logError("failed to ping"); |
mfiore | 3:90cf39b6ed0d | 126 | else |
mfiore | 3:90cf39b6ed0d | 127 | logInfo("ping succeeded"); |
mfiore | 3:90cf39b6ed0d | 128 | } |
mfiore | 3:90cf39b6ed0d | 129 | logInfo("finished - bringing down link"); |
mfiore | 3:90cf39b6ed0d | 130 | radio->disconnect(); |
mfiore | 0:da114ae7c596 | 131 | } |
mfiore | 3:90cf39b6ed0d | 132 | |
mfiore | 3:90cf39b6ed0d | 133 | // power down the radio |
mfiore | 3:90cf39b6ed0d | 134 | logInfo("powering down radio"); |
mfiore | 3:90cf39b6ed0d | 135 | radio_reset = 0; |
mfiore | 4:91a322a2ec86 | 136 | logInfo("waiting up to 30s for vdd1_8_mon to go low"); |
mfiore | 3:90cf39b6ed0d | 137 | tmr.reset(); |
mfiore | 3:90cf39b6ed0d | 138 | tmr.start(); |
mfiore | 3:90cf39b6ed0d | 139 | // wait up to 30s for the radio to shut down |
mfiore | 4:91a322a2ec86 | 140 | while (vdd1_8_mon != 0 && tmr.read() < 30) { |
mfiore | 4:91a322a2ec86 | 141 | wait(1); |
mfiore | 4:91a322a2ec86 | 142 | printf("."); |
mfiore | 4:91a322a2ec86 | 143 | } |
mfiore | 3:90cf39b6ed0d | 144 | tmr.stop(); |
mfiore | 4:91a322a2ec86 | 145 | printf("\r\n"); |
mfiore | 4:91a322a2ec86 | 146 | if (vdd1_8_mon != 0 && tmr.read() >= 30) { |
mfiore | 4:91a322a2ec86 | 147 | logError("radio did not shut down! aborting iteration"); |
mfiore | 4:91a322a2ec86 | 148 | continue; |
mfiore | 4:91a322a2ec86 | 149 | } |
mfiore | 4:91a322a2ec86 | 150 | |
mfiore | 3:90cf39b6ed0d | 151 | logInfo("radio powered off after %fs", tmr.read()); |
mfiore | 3:90cf39b6ed0d | 152 | radio_pwr = 0; |
mfiore | 3:90cf39b6ed0d | 153 | logInfo("putting regulator in 100mA mode"); |
mfiore | 3:90cf39b6ed0d | 154 | bc_en1 = 0; |
mfiore | 3:90cf39b6ed0d | 155 | bc_en2 = 0; |
mfiore | 3:90cf39b6ed0d | 156 | |
mfiore | 3:90cf39b6ed0d | 157 | logInfo("going to sleep for %lu seconds", sleep_time); |
mfiore | 3:90cf39b6ed0d | 158 | enterStopMode(sleep_time); |
mfiore | 0:da114ae7c596 | 159 | } |
mfiore | 0:da114ae7c596 | 160 | |
mfiore | 0:da114ae7c596 | 161 | return 0; |
mfiore | 0:da114ae7c596 | 162 | } |
mfiore | 0:da114ae7c596 | 163 | |
mfiore | 0:da114ae7c596 | 164 | bool init_mtsas() { |
mfiore | 0:da114ae7c596 | 165 | io = new mts::MTSSerialFlowControl(RADIO_TX, RADIO_RX, RADIO_RTS, RADIO_CTS); |
mfiore | 0:da114ae7c596 | 166 | if (! io) |
mfiore | 0:da114ae7c596 | 167 | return false; |
mfiore | 0:da114ae7c596 | 168 | |
mfiore | 0:da114ae7c596 | 169 | // radio default baud rate is 115200 |
mfiore | 0:da114ae7c596 | 170 | io->baud(115200); |
mfiore | 0:da114ae7c596 | 171 | radio = mts::CellularFactory::create(io); |
mfiore | 0:da114ae7c596 | 172 | if (! radio) |
mfiore | 0:da114ae7c596 | 173 | return false; |
mfiore | 0:da114ae7c596 | 174 | |
mfiore | 0:da114ae7c596 | 175 | // Transport must be set properly before any TCPSocketConnection or UDPSocket objects are created |
mfiore | 0:da114ae7c596 | 176 | Transport::setTransport(radio); |
mfiore | 0:da114ae7c596 | 177 | |
mfiore | 0:da114ae7c596 | 178 | return true; |
mfiore | 0:da114ae7c596 | 179 | } |
mfiore | 3:90cf39b6ed0d | 180 | |
mfiore | 3:90cf39b6ed0d | 181 | #define RTC_ALARMA_DISABLE() do { \ |
mfiore | 3:90cf39b6ed0d | 182 | RTC->ISR &= ~RTC_ISR_ALRAF; \ |
mfiore | 3:90cf39b6ed0d | 183 | RTC->WPR = 0xCA; \ |
mfiore | 3:90cf39b6ed0d | 184 | RTC->WPR = 0x53; \ |
mfiore | 3:90cf39b6ed0d | 185 | RTC->CR &= ~(RTC_CR_ALRAE | RTC_CR_ALRAIE); \ |
mfiore | 3:90cf39b6ed0d | 186 | RTC->WPR = 0xFF; \ |
mfiore | 3:90cf39b6ed0d | 187 | } while (0) |
mfiore | 3:90cf39b6ed0d | 188 | |
mfiore | 3:90cf39b6ed0d | 189 | void enterStopMode(const uint32_t interval) { |
mfiore | 3:90cf39b6ed0d | 190 | // disable ADC - it can consume power in stop mode |
mfiore | 3:90cf39b6ed0d | 191 | ADC1->CR2 &= ~ADC_CR2_ADON; |
mfiore | 3:90cf39b6ed0d | 192 | |
mfiore | 3:90cf39b6ed0d | 193 | // enable debugging during stop mode |
mfiore | 3:90cf39b6ed0d | 194 | HAL_EnableDBGStopMode(); |
mfiore | 3:90cf39b6ed0d | 195 | |
mfiore | 3:90cf39b6ed0d | 196 | // put regulators into low-power mode |
mfiore | 3:90cf39b6ed0d | 197 | HAL_PWREx_EnableMainRegulatorLowVoltage(); |
mfiore | 3:90cf39b6ed0d | 198 | HAL_PWREx_EnableLowRegulatorLowVoltage(); |
mfiore | 3:90cf39b6ed0d | 199 | |
mfiore | 3:90cf39b6ed0d | 200 | // power down flash |
mfiore | 3:90cf39b6ed0d | 201 | HAL_PWREx_EnableFlashPowerDown(); |
mfiore | 3:90cf39b6ed0d | 202 | |
mfiore | 3:90cf39b6ed0d | 203 | // configure RTC Alarm A to wake the device up |
mfiore | 3:90cf39b6ed0d | 204 | WakeUp::set(interval); |
mfiore | 3:90cf39b6ed0d | 205 | |
mfiore | 3:90cf39b6ed0d | 206 | // make sure wakeup flag is cleared |
mfiore | 3:90cf39b6ed0d | 207 | PWR->CR |= PWR_CR_CWUF; |
mfiore | 3:90cf39b6ed0d | 208 | |
mfiore | 3:90cf39b6ed0d | 209 | logInfo("entering stop mode %08x", RTC->ISR); |
mfiore | 3:90cf39b6ed0d | 210 | fflush(stdout); |
mfiore | 3:90cf39b6ed0d | 211 | |
mfiore | 3:90cf39b6ed0d | 212 | // enter stop mode - don't execute past here until woken up |
mfiore | 3:90cf39b6ed0d | 213 | HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI); |
mfiore | 3:90cf39b6ed0d | 214 | |
mfiore | 3:90cf39b6ed0d | 215 | // HSI (High Speed Internal) oscillator is selected when coming out of stop mode - set up clocking |
mfiore | 3:90cf39b6ed0d | 216 | SetSysClock(); |
mfiore | 3:90cf39b6ed0d | 217 | |
mfiore | 3:90cf39b6ed0d | 218 | // disable RTC alarm A and RTC alarm A interrupt |
mfiore | 3:90cf39b6ed0d | 219 | RTC_ALARMA_DISABLE(); |
mfiore | 3:90cf39b6ed0d | 220 | |
mfiore | 3:90cf39b6ed0d | 221 | // clear wakeup flag in power control register |
mfiore | 3:90cf39b6ed0d | 222 | PWR->CR |= PWR_CR_CWUF; |
mfiore | 3:90cf39b6ed0d | 223 | |
mfiore | 3:90cf39b6ed0d | 224 | // put regulators back into to full-power mode |
mfiore | 3:90cf39b6ed0d | 225 | HAL_PWREx_DisableMainRegulatorLowVoltage(); |
mfiore | 3:90cf39b6ed0d | 226 | HAL_PWREx_DisableLowRegulatorLowVoltage(); |
mfiore | 3:90cf39b6ed0d | 227 | |
mfiore | 3:90cf39b6ed0d | 228 | // turn the flash back on |
mfiore | 3:90cf39b6ed0d | 229 | HAL_PWREx_DisableFlashPowerDown(); |
mfiore | 3:90cf39b6ed0d | 230 | |
mfiore | 3:90cf39b6ed0d | 231 | // enable the ADC |
mfiore | 3:90cf39b6ed0d | 232 | ADC1->CR2 |= ADC_CR2_ADON; |
mfiore | 3:90cf39b6ed0d | 233 | |
mfiore | 3:90cf39b6ed0d | 234 | // disable debugging during stop mode |
mfiore | 3:90cf39b6ed0d | 235 | HAL_DisableDBGStopMode(); |
mfiore | 3:90cf39b6ed0d | 236 | } |