Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: Lab04_Check_StandBy_os2 Lab04_wakeup_STM32
WakeUp_STM32.cpp
- Committer:
- cspista
- Date:
- 2021-11-12
- Revision:
- 3:aa8fb11c30d2
- Parent:
- 2:502051beeb95
File content as of revision 3:aa8fb11c30d2:
/*
Original idea & program
https://os.mbed.com/users/Sissors/code/WakeUp/
by Erik
modified version
https://os.mbed.com/users/kenjiArai/code/WakeUp/
*/
/*
* Modified only for STM CPU
* by Kenji Arai / JH1PJL
*
* http://www7b.biglobe.ne.jp/~kenjia/
* http://mbed.org/users/kenjiArai/
* Created: September 21st, 2017
* Revised: March 12th, 2020
*/
#if \
defined(TARGET_NUCLEO_F334R8)
# error Not support yet
#elif \
defined(TARGET_NUCLEO_F401RE)\
|| defined(TARGET_NUCLEO_F411RE)\
|| defined(TARGET_NUCLEO_F446RE)\
|| defined(TARGET_NUCLEO_L053R8)\
|| defined(TARGET_NUCLEO_L073RZ)\
|| defined(TARGET_NUCLEO_L152RE)
#include "WakeUp_STM32.h"
#include "rtc_api.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
void WakeUp::set_ms(uint32_t ms)
{
if (ms == 0) { //Just disable alarm
return;
}
if (!rtc_isenabled()) { //Make sure RTC is running
rtc_init();
wait_us(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;
RTC->CR &= 0x00ff00ff;
while(!(RTC->ISR & RTC_ISR_ALRAWF));
//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 5 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; // enable it
EXTI->EMR &= ~RTC_EXTI_LINE_ALARM_EVENT; // disable event
EXTI->RTSR |= RTC_EXTI_LINE_ALARM_EVENT; // enable rising edge
EXTI->FTSR &= ~RTC_EXTI_LINE_ALARM_EVENT; // disable falling edge
//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;
alarmreg &= 0x3f3f7f7f; // All MSKx & WDSEL = 0
//Enable RTC interrupt (use Alarm-A)
RTC->ALRMAR = alarmreg;
RTC->ALRMASSR = subsecs | RTC_ALRMASSR_MASKSS; //Mask no subseconds
RTC->CR |= RTC_CR_ALRAE | RTC_CR_ALRAIE; //Enable Alarm-A
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::standby_then_reset(uint32_t ms)
{
if (ms == 0){ // just go to Reset
system_reset();
}
set_ms(ms);
PWR->CR |= PWR_CR_CWUF;
HAL_PWR_EnterSTANDBYMode();
}
void WakeUp::irq_handler(void)
{
//Clear RTC + EXTI interrupt flags
PWR->CR |= PWR_CR_DBP; // Enable power domain
RTC->ISR &= ~RTC_ISR_ALRAF;
RTC->CR &= 0x00ff00ff; // just in case
RTC->WPR = 0xCA; // Disable RTC write protection
RTC->WPR = 0x53;
RTC->CR &= ~(RTC_CR_ALRAE | RTC_CR_ALRAIE); //DisEnable Alarm-A
RTC->WPR = 0xFF; // Enable RTC write protection
EXTI->PR = RTC_EXTI_LINE_ALARM_EVENT;
PWR->CR &= ~PWR_CR_DBP; // Disable power domain
system_reset();
}
#endif