-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
246 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
}; | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(); | ||
} |