1+ #include " led_ctrl.h"
12#include " log.h"
23#include " low_power.h"
34#include " lte.h"
45#include " sequans_controller.h"
56
67#include < Arduino.h>
8+ #include < avr/cpufunc.h>
79#include < avr/io.h>
810#include < avr/sleep.h>
911
5052#define TIMER_LENGTH 11
5153#define TIMER_SLEEP_INDEX 8
5254
53- #define RING_PORT VPORTC
55+ #define RING_PORT VPORTC
56+
57+ #ifdef __AVR_AVR128DB48__ // MINI
58+
59+ #define RING_PIN_bm PIN6_bm
60+
61+ #else
62+
63+ #ifdef __AVR_AVR128DB64__ // Non-Mini
64+
5465#define RING_PIN_bm PIN4_bm
5566
67+ #else
68+ #error "INCOMPATIBLE_DEVICE_SELECTED"
69+ #endif
70+ #endif
71+
5672// Singleton. Defined for use of the rest of the library.
5773LowPowerClass LowPower = LowPowerClass::instance();
5874
@@ -64,6 +80,9 @@ static SleepMode sleep_mode;
6480static bool retrieved_sleep_time = false ;
6581static uint32_t sleep_time = 0 ;
6682
83+ static uint8_t cell_led_state = 0 ;
84+ static uint8_t con_led_state = 0 ;
85+
6786ISR (RTC_PIT_vect) {
6887 RTC.PITINTFLAGS = RTC_PI_bm;
6988 pit_triggered = true ;
@@ -93,7 +112,7 @@ static void uint8ToStringOfBits(const uint8_t value, char *string) {
93112
94113static uint8_t stringOfBitsToUint8 (const char *string) {
95114
96- uint8_t value;
115+ uint8_t value = 0 ;
97116
98117 for (uint8_t i = 0 ; i < 8 ; i++) {
99118 // We assume all other values are zero, so we only shift the ones
@@ -234,32 +253,33 @@ static uint32_t retrieveOperatorSleepTime(void) {
234253
235254static void enablePIT (void ) {
236255
237- // TODO: Fix this, should use external crystal
238- // Setup the clock for RTC. CTRL_SETUP is stored here just for convenience
239- // so that we discard the modifications in the register later
240- //
241- // CLKCTRL.XOSC32KCTRLA |= CLKCTRL_RUNSTBY_bm | CLKCTRL_LPMODE_bm |
242- // CLKCTRL_ENABLE_bm;
256+ uint8_t temp;
243257
244- // Wait for clock to stabilize
245- // while (CLKCTRL.MCLKSTATUS & CLKCTRL_XOSC32KS_bm &&
246- // CLKCTRL.XOSC32KCTRLA & CLKCTRL_SEL_bm) {}
258+ // Disable first and wait for clock to stabilize
259+ temp = CLKCTRL.XOSC32KCTRLA ;
260+ temp &= ~CLKCTRL_ENABLE_bm;
261+ _PROTECTED_WRITE (CLKCTRL.XOSC32KCTRLA , temp);
262+ while (CLKCTRL.MCLKSTATUS & CLKCTRL_XOSC32KS_bm) {}
247263
248- // Now we configure RTC which keeps track of the time during sleep. We do
249- // this here as we yield the RTC afterwards, so a setup every time is just
250- // to safe guard ourselves if other modules use the RTC
251- //
252- // Wait for all registers to be synchronized
264+ // We want the external crystal to run in standby and in low power mode
265+ temp = CLKCTRL.XOSC32KCTRLA ;
266+ temp |= CLKCTRL_RUNSTBY_bm | CLKCTRL_LPMODE_bm;
267+ temp &= ~(CLKCTRL_SEL_bm);
268+ _PROTECTED_WRITE (CLKCTRL.XOSC32KCTRLA , temp);
269+
270+ // Choose to use external crystal on XTAL32K1 and XTAL32K2 pins and enable
271+ // the clock
272+ temp = CLKCTRL.XOSC32KCTRLA ;
273+ temp |= CLKCTRL_ENABLE_bm;
274+ _PROTECTED_WRITE (CLKCTRL.XOSC32KCTRLA , temp);
275+
276+ // Wait for registers to synchronize
253277 while (RTC.PITSTATUS ) {}
254278
255- // TODO: use XOSC32K instead
256- RTC.CLKSEL |= RTC_CLKSEL_INT32K_gc;
279+ RTC.CLKSEL |= RTC_CLKSEL_XOSC32K_gc;
257280 RTC.PITINTCTRL |= RTC_PI_bm;
258281 RTC.PITCTRLA |= RTC_PERIOD_CYC32768_gc | RTC_PITEN_bm;
259282
260- // Now we setup the sleep mode so it is ready.
261- SLPCTRL.CTRLA |= SLPCTRL_SMODE_PDOWN_gc | SLPCTRL_SEN_bm;
262-
263283 // The first PIT intterupt will not necessarily be at the period specified,
264284 // so we just wait until it has triggered and track the reminaing time from
265285 // there
@@ -269,13 +289,37 @@ static void enablePIT(void) {
269289
270290static void disablePIT (void ) {
271291
272- SLPCTRL.CTRLA &= ~SLPCTRL_SEN_bm;
273-
274292 // Disable external clock and turn off RTC PIT
275- CLKCTRL.XOSC32KCTRLA &= (~CLKCTRL_ENABLE_bm);
293+ uint8_t temp;
294+ temp = CLKCTRL.XOSC32KCTRLA ;
295+ temp &= ~(CLKCTRL_ENABLE_bm);
296+ _PROTECTED_WRITE (CLKCTRL.XOSC32KCTRLA , temp);
297+
276298 RTC.PITCTRLA &= ~RTC_PITEN_bm;
277299}
278300
301+ static void powerDownPeripherals (void ) {
302+
303+ cell_led_state = digitalRead (LedCtrl.getLedPin (Led::CELL));
304+ con_led_state = digitalRead (LedCtrl.getLedPin (Led::CON));
305+
306+ LedCtrl.off (Led::CELL, true );
307+ LedCtrl.off (Led::CON, true );
308+ LedCtrl.off (Led::DATA, true );
309+ LedCtrl.off (Led::ERROR, true );
310+ LedCtrl.off (Led::USER, true );
311+ }
312+
313+ static void powerUpPeripherals (void ) {
314+ if (cell_led_state) {
315+ LedCtrl.on (Led::CELL, true );
316+ }
317+
318+ if (con_led_state) {
319+ LedCtrl.on (Led::CON, true );
320+ }
321+ }
322+
279323/* *
280324 * Modem sleeping and CPU deep sleep.
281325 */
@@ -289,6 +333,7 @@ static WakeUpReason regularSleep(void) {
289333 sleep_time = retrieveOperatorSleepTime ();
290334
291335 if (sleep_time == 0 ) {
336+ Log.debugf (" Got invalid sleep time: %d\r\n " , sleep_time);
292337 return WakeUpReason::INVALID_SLEEP_TIME;
293338 } else {
294339 retrieved_sleep_time = true ;
@@ -297,7 +342,8 @@ static WakeUpReason regularSleep(void) {
297342
298343 // The timeout here is arbitrary as we attempt to put the modem in sleep in
299344 // a loop, so we just choose 30 seconds = 30000 ms
300- while (!attemptToEnterPowerSaveModeForModem (30000 )) {}
345+ while (!attemptToEnterPowerSaveModeForModem (30000 ) &&
346+ millis () - start_time_ms < sleep_time * 1000 ) {}
301347
302348 // If we surpassed the sleep time during setting the LTE to sleep, we
303349 // don't have any more time to sleep the CPU, so just return.
@@ -360,17 +406,13 @@ static WakeUpReason deepSleep(void) {
360406 const unsigned long start_time_ms = millis ();
361407
362408 Lte.end ();
363-
364409 enablePIT ();
365410
366411 uint32_t remaining_time_seconds =
367412 sleep_time - (uint32_t )(((millis () - start_time_ms) / 1000 .0f ));
368413
369414 while (remaining_time_seconds > 0 ) {
370415
371- Log.debugf (" Remaining time: %d \r\n " , remaining_time_seconds);
372- delay (10 );
373-
374416 sleep_cpu ();
375417
376418 if (pit_triggered) {
@@ -380,7 +422,6 @@ static WakeUpReason deepSleep(void) {
380422 }
381423
382424 disablePIT ();
383-
384425 Lte.begin ();
385426
386427 return WakeUpReason::OK;
@@ -453,12 +494,19 @@ bool LowPowerClass::begin(const SleepMultiplier sleep_multiplier,
453494}
454495
455496WakeUpReason LowPowerClass::sleep (void ) {
497+
498+ powerDownPeripherals ();
499+ SLPCTRL.CTRLA |= SLPCTRL_SMODE_PDOWN_gc | SLPCTRL_SEN_bm;
500+
456501 switch (sleep_mode) {
457502 case SleepMode::REGULAR:
458503 return regularSleep ();
459504 case SleepMode::DEEP:
460505 return deepSleep ();
461506 }
462507
508+ SLPCTRL.CTRLA &= ~SLPCTRL_SEN_bm;
509+ powerUpPeripherals ();
510+
463511 return WakeUpReason::OK;
464512}
0 commit comments