Skip to content

Commit

Permalink
Added test of sleep mode
Browse files Browse the repository at this point in the history
  • Loading branch information
Ebiroll committed Feb 12, 2018
1 parent 8ad2347 commit 7e790e4
Show file tree
Hide file tree
Showing 5 changed files with 246 additions and 3 deletions.
2 changes: 2 additions & 0 deletions .vscode/c_cpp_properties.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
{
"name": "Win32",
"includePath": [
"d:/msys2/home/Olof/rak/RAK811_BreakBoard/lib/wakeup",
"d:/msys2/home/Olof/rak/RAK811_BreakBoard/lib/crypto",
"d:/msys2/home/Olof/rak/RAK811_BreakBoard/lib/radio",
"d:/msys2/home/Olof/rak/RAK811_BreakBoard/lib/radio/sx1276",
Expand Down Expand Up @@ -51,6 +52,7 @@
"limitSymbolsToIncludedHeaders": true,
"databaseFilename": "",
"path": [
"d:/msys2/home/Olof/rak/RAK811_BreakBoard/lib/wakeup",
"d:/msys2/home/Olof/rak/RAK811_BreakBoard/lib/crypto",
"d:/msys2/home/Olof/rak/RAK811_BreakBoard/lib/radio",
"d:/msys2/home/Olof/rak/RAK811_BreakBoard/lib/radio/sx1276",
Expand Down
102 changes: 102 additions & 0 deletions lib/wakeup/WakeUp.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
//#include "mbed.h"
#include <stdint.h>

/**
* Class to make wake up a microcontroller from deepsleep using a low-power timer.
*
* @code
* // Depending on the LED connections either the LED is off the 2 seconds
* // the target spends in deepsleep(), and on for the other second. Or it is inverted
*
* #include "mbed.h"
* #include "WakeUp.h"
*
* DigitalOut myled(LED1);
*
* int main() {
* wait(5);
*
* //The low-power oscillator can be quite inaccurate on some targets
* //this function calibrates it against the main clock
* WakeUp::calibrate();
*
* while(1) {
* //Set LED to zero
* myled = 0;
*
* //Set wakeup time for 2 seconds
* WakeUp::set_ms(2000);
*
* //Enter deepsleep, the program won't go beyond this point until it is woken up
* deepsleep();
*
* //Set LED for 1 second to one
* myled = 1;
* wait(1);
* }
* }
* @endcode
*/

class WakeUp
{
public:
/**
* Set the timeout
*
* @param s required time in seconds
*/
static void set(uint32_t s) {
set_ms(1000 * s);
}

/**
* Set the timeout
*
* @param ms required time in milliseconds
*/
static void set_ms(uint32_t ms);

/**
* Attach a function to be called after timeout
*
* This is optional, if you just want to wake up you
* do not need to attach a function.
*
* Important: Many targets will run the wake-up routine
* at reduced clock speed, afterwards clock speed is restored.
* This means that clock speed dependent functions, such as printf
* might end up distorted.
*
* @code
* // Attaching regular function
* WakeUp::attach(&yourFunc);
* // Attaching member function inside another library
* WakeUp::attach(callback(this, &YourLib::yourLibFunction));
* @endcode
*
* It uses the new Callback system to attach functions.
*
* @param *function function to call
*/
//static void attach(Callback<void()> function) {
// callback = function;
//}

/**
* Calibrate the timer
*
* Some of the low-power timers have very bad accuracy.
* This function calibrates it against the main timer.
*
* Warning: Blocks for 100ms!
*/
static void calibrate(void);


private:
//static Callback<void()> callback;
static void irq_handler(void);
static float cycles_per_ms;
};

127 changes: 127 additions & 0 deletions lib/wakeup/WakeUp_STM_RTC.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
#ifdef TARGET_STM

#include "WakeUp.h"
//#include "rtc_api.h"
#include "stm32l1xx_hal_rtc.h"

#define BYTE2BCD(byte) ((byte % 10) | ((byte / 10) << 4))

//Most things are pretty similar between the different STM targets.
//Only the IRQ number the alarm is connected to differs. Any errors
//with RTC_IRQn/RTC_Alarm_IRQn in them are related to this
#if defined(TARGET_M4) || defined(TARGET_M3)
#define RTC_IRQ RTC_Alarm_IRQn
#else
#define RTC_IRQ RTC_IRQn
#endif

// Some things to handle Disco L476VG (and similar ones)
#if defined(TARGET_STM32L4)
#define IMR IMR1
#define EMR EMR1
#define RTSR RTSR1
#define FTSR FTSR2
#define PR PR1
#endif

//Disabling the Backup Powerdomain does not seem to work nicely anymore if you want to use other RTC functions afterwards.
//For now I have disabled it in code, if you find WakeUp increases your powerconsumption, try enabling it again (code is still there, just commented)

//Callback<void()> WakeUp::callback;

void WakeUp::set_ms(uint32_t ms)
{
if (!rtc_isenabled()) { //Make sure RTC is running
HAL_RTC_Init();
HAL_Delay(1/*250*/); //The f401 seems to want a delay after init
}

//PWR->CR |= PWR_CR_DBP; //Enable power domain
RTC->WPR = 0xCA; //Disable RTC write protection
RTC->WPR = 0x53;

//Alarm must be disabled to change anything
RTC->CR &= ~RTC_CR_ALRAE;
while(!(RTC->ISR & RTC_ISR_ALRAWF));

if (ms == 0) { //Just disable alarm
//PWR->CR &= ~PWR_CR_DBP; //Disable power domain
RTC->WPR = 0xFF; //Enable RTC write protection
return;
}

//RTC prescaler + calculate how many sub-seconds should be added
uint32_t prescaler = (RTC->PRER & 0x7FFF) + 1;
uint32_t subsecsadd = ((ms % 1000) * prescaler) / 1000;

if ((ms < 1000) && (subsecsadd < 2))
subsecsadd = 2; //At least 2 subsecs delay to be sure interrupt is called

__disable_irq(); //At this point we don't want IRQs anymore

//Get current time
uint32_t subsecs = RTC->SSR;
time_t secs = rtc_read();

//Calculate alarm values
//Subseconds is countdown, so substract the 'added' sub-seconds and prevent underflow
if (subsecs < subsecsadd) {
subsecs += prescaler;
secs++;
}
subsecs -= subsecsadd;

//Set seconds correctly
secs += ms / 1000;
struct tm *timeinfo = localtime(&secs);

//Enable rising edge EXTI interrupt of the RTC
EXTI->IMR |= RTC_EXTI_LINE_ALARM_EVENT;
EXTI->EMR &= ~RTC_EXTI_LINE_ALARM_EVENT;
EXTI->RTSR |= RTC_EXTI_LINE_ALARM_EVENT;
EXTI->FTSR &= ~RTC_EXTI_LINE_ALARM_EVENT;

//Calculate alarm register values
uint32_t alarmreg = 0;
alarmreg |= BYTE2BCD(timeinfo->tm_sec) << 0;
alarmreg |= BYTE2BCD(timeinfo->tm_min) << 8;
alarmreg |= BYTE2BCD(timeinfo->tm_hour) << 16;
alarmreg |= BYTE2BCD(timeinfo->tm_mday) << 24;

//Enable RTC interrupt
RTC->ALRMAR = alarmreg;
RTC->ALRMASSR = subsecs | RTC_ALRMASSR_MASKSS; //Mask no subseconds
RTC->CR |= RTC_CR_ALRAE | RTC_CR_ALRAIE; //Enable Alarm

RTC->WPR = 0xFF; //Enable RTC write protection
//PWR->CR &= ~PWR_CR_DBP; //Disable power domain

__enable_irq(); //Alarm is set, so irqs can be enabled again

//Enable everything else
NVIC_SetVector(RTC_IRQ, (uint32_t)WakeUp::irq_handler);
NVIC_EnableIRQ(RTC_IRQ);
}


void WakeUp::irq_handler(void)
{
//Clear RTC + EXTI interrupt flags
//PWR->CR |= PWR_CR_DBP; //Enable power domain
RTC->ISR &= ~RTC_ISR_ALRAF;
RTC->WPR = 0xCA; //Disable RTC write protection
RTC->WPR = 0x53;
RTC->CR &= ~RTC_CR_ALRAE;
RTC->WPR = 0xFF; //Enable RTC write protection
EXTI->PR = RTC_EXTI_LINE_ALARM_EVENT;
//PWR->CR &= ~PWR_CR_DBP; //Disable power domain
//callback.call();
}

void WakeUp::calibrate(void)
{
//RTC, we assume it is accurate enough without calibration
}


#endif
6 changes: 3 additions & 3 deletions platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@
[env:rak811]
lib_dir = lib
src_dir = src, src/RAK811BreakBoard/
lib_extra_dirs = crypto , radio/sx1276
lib_deps = system_utils, Retarget_printf
lib_extra_dirs = crypto , radio/sx1276 , wakeup
lib_deps = system_utils, obme280, wakeup
platform = ststm32
board = rak811
framework=cmsis
build_flags = -fno-builtin -D STM32L151xB -D STM32L151CBU6 -D REGION_EU868 -std=gnu99 -I lib/crypto -I lib/radio -I lib/radio/sx1276 -I src/mac -I src/usb/dfu/inc -I src/mac/region -I lib/system_utils/crypto -I src/boards/mcu/stm32/STM32_USB_Device_Library/Class/DFU/Inc/ -I src/boards/mcu/stm32/STM32_USB_Device_Library/Class/CDC/Inc/ -I src/usb/cdc/inc -I src/boards/mcu/stm32/STM32_USB_Device_Library/Core/Inc/ -I src/boards/mcu/stm32/STM32L0xx_HAL_Driver/Inc/ -I src/peripherals/ -I src/boards/mcu/stm32/ -I src/boards/mcu/stm32/STM32L1xx_HAL_Driver/Inc -I src/RAK811BreakBoard/cmsis/ -I src/RAK811BreakBoard/ -IRAK811_BreakBoard/src -I lib/system_utils -I RAK811_BreakBoard/src/boards/RAK811BreakBoard -I RAK811_BreakBoard/src/boards/RAK811BreakBoard/cmsis -I .piolibdeps/mbed-dev_ID2491/targets/TARGET_STM/TARGET_STM32L1/TARGET_MOTE_L152RC/device/ -I RAK811_BreakBoard/src/boards/mcu/stm32/cmsis/ -I RAK811_BreakBoard/src/boards/mcu/stm32/STM32L1xx_HAL_Driver/Inc -I RAK811_BreakBoard/src/boards/mcu/stm32 -I RAK811_BreakBoard/src/system/ -I RAK811_BreakBoard/src/radio -I RAK811_BreakBoard/src/peripherals/ -I RAK811_BreakBoard/src/mac -I RAK811_BreakBoard/src/mac/region/
build_flags = -fno-builtin -D STM32L151xB -D STM32L151CBU6 -D REGION_EU868 -std=gnu99 -I lib/wakeup -I lib/crypto -I lib/radio -I lib/radio/sx1276 -I src/mac -I src/usb/dfu/inc -I src/mac/region -I lib/system_utils/crypto -I src/boards/mcu/stm32/STM32_USB_Device_Library/Class/DFU/Inc/ -I src/boards/mcu/stm32/STM32_USB_Device_Library/Class/CDC/Inc/ -I src/usb/cdc/inc -I src/boards/mcu/stm32/STM32_USB_Device_Library/Core/Inc/ -I src/boards/mcu/stm32/STM32L0xx_HAL_Driver/Inc/ -I src/peripherals/ -I src/boards/mcu/stm32/ -I src/boards/mcu/stm32/STM32L1xx_HAL_Driver/Inc -I src/RAK811BreakBoard/cmsis/ -I src/RAK811BreakBoard/ -IRAK811_BreakBoard/src -I lib/system_utils -I RAK811_BreakBoard/src/boards/RAK811BreakBoard -I RAK811_BreakBoard/src/boards/RAK811BreakBoard/cmsis -I .piolibdeps/mbed-dev_ID2491/targets/TARGET_STM/TARGET_STM32L1/TARGET_MOTE_L152RC/device/ -I RAK811_BreakBoard/src/boards/mcu/stm32/cmsis/ -I RAK811_BreakBoard/src/boards/mcu/stm32/STM32L1xx_HAL_Driver/Inc -I RAK811_BreakBoard/src/boards/mcu/stm32 -I RAK811_BreakBoard/src/system/ -I RAK811_BreakBoard/src/radio -I RAK811_BreakBoard/src/peripherals/ -I RAK811_BreakBoard/src/mac -I RAK811_BreakBoard/src/mac/region/
12 changes: 12 additions & 0 deletions src/test_wakeup.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#include "WakeUp.h"
#include "stm32l1xx_ll_pwr.h"

extern "C" void test_wakeup() {
//Set wakeup time for 2 seconds
WakeUp::set_ms(2000);

//Enter deepsleep, the program won't go beyond this point until it is woken up
//HAL_PWR_EnterSLEEPMode(PWR_LOWPOWERREGULATOR_ON, PWR_SLEEPENTRY_WFx);
LL_PWR_SetPowerMode(LL_PWR_MODE_STANDBY);
//deepsleep();
}

0 comments on commit 7e790e4

Please sign in to comment.