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