This is the code used on my video series "Hybrid Supercapacitor Car Battery" for my own hardware monitoring system. THe videos can be found on madelectronengineering.com

Dependencies:   BurstSPI Fonts INA219 mbed LPC1114_WakeInterruptIn

Fork of SharpMemoryLCD by Paul Staron

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers WakeUp_STM32_others.cpp Source File

WakeUp_STM32_others.cpp

00001 // Created new file only for STM32/Nucleo boards which I have own it
00002 //  by JH1PJL       2017-9-21
00003 
00004 #if defined(TARGET_NUCLEO_F446RE) || defined(TARGET_NUCLEO_F411RE)\
00005  || defined(TARGET_NUCLEO_F401RE)\
00006  || defined(TARGET_NUCLEO_L152RE) || defined(TARGET_NUCLEO_L073RZ)\
00007  || defined(TARGET_NUCLEO_L053R8)
00008 
00009 #include "WakeUp.h"
00010 #include "rtc_api.h"
00011 
00012 //#define DEBUG
00013 
00014 extern Serial pc;
00015 
00016 #if 0
00017 #define DBG(...)   pc.printf(__VA_ARGS__)
00018 #else
00019 #define DBG(...)   {;}
00020 #endif
00021 
00022 #if 0
00023 #define DBGP(...)   pc.printf(__VA_ARGS__)
00024 #else
00025 #define DBGP(...)   {;}
00026 #endif
00027 
00028 #define BYTE2BCD(byte)  ((byte % 10) | ((byte / 10) << 4))
00029 
00030 //Most things are pretty similar between the different STM targets.
00031 //Only the IRQ number the alarm is connected to differs. Any errors
00032 //with RTC_IRQn/RTC_Alarm_IRQn in them are related to this
00033 #if defined(TARGET_M4) || defined(TARGET_M3)
00034 #define RTC_IRQ     RTC_Alarm_IRQn               
00035 #else
00036 #define RTC_IRQ     RTC_IRQn
00037 #endif
00038 
00039 // Some things to handle Disco L476VG (and similar ones)
00040 #if defined(TARGET_STM32L4)
00041 #define IMR     IMR1
00042 #define EMR     EMR1
00043 #define RTSR    RTSR1
00044 #define FTSR    FTSR2
00045 #define PR      PR1
00046 #endif
00047 
00048 Callback<void()> WakeUp::callback;
00049 bool WakeUp::use_reset = false;
00050 
00051 
00052 void WakeUp::set_ms(uint32_t ms)
00053 {
00054     if (ms == 0) {              //Just disable alarm
00055         return;
00056     }
00057     
00058     if (!rtc_isenabled()) {     //Make sure RTC is running
00059         rtc_init();
00060         wait_us(250);           //The f401 seems to want a delay after init
00061     }
00062 
00063     PWR->CR |= PWR_CR_DBP;      //Enable power domain
00064     RTC->WPR = 0xCA;            //Disable RTC write protection
00065     RTC->WPR = 0x53;
00066 
00067     //Alarm must be disabled to change anything
00068     RTC->CR &= ~RTC_CR_ALRAE;
00069     RTC->CR &= 0x00ff00ff;
00070     while(!(RTC->ISR & RTC_ISR_ALRAWF));
00071 
00072     DBG("Step(%u)\r\n", __LINE__);
00073 
00074     //RTC prescaler + calculate how many sub-seconds should be added
00075     uint32_t prescaler = (RTC->PRER & 0x7FFF) + 1;
00076     uint32_t subsecsadd = ((ms % 1000) * prescaler) / 1000;
00077 
00078     if ((ms < 1000) && (subsecsadd < 2))
00079         subsecsadd = 2;//At least 5 subsecs delay to be sure interrupt is called
00080 
00081     __disable_irq();   //At this point we don't want IRQs anymore
00082 
00083     //Get current time
00084     uint32_t subsecs = RTC->SSR;
00085     time_t secs = rtc_read(); 
00086     DBG("Step(%u),secs:%d,subsecs:%d\r\n", __LINE__, secs, subsecs);
00087 
00088     //Calculate alarm values
00089     //Subseconds is countdown,
00090     //    so substract the 'added' sub-seconds and prevent underflow
00091     if (subsecs < subsecsadd) {
00092         subsecs += prescaler;
00093         secs++;
00094     }
00095     subsecs -= subsecsadd;
00096 
00097     //Set seconds correctly
00098     secs += ms / 1000;
00099     struct tm *timeinfo = localtime(&secs);
00100     DBG("Step(%u),secs:%d\r\n", __LINE__, secs);
00101  
00102     //Enable rising edge EXTI interrupt of the RTC
00103     EXTI->IMR |= RTC_EXTI_LINE_ALARM_EVENT;     // enable it
00104     EXTI->EMR &= ~RTC_EXTI_LINE_ALARM_EVENT;    // disable event
00105     EXTI->RTSR |= RTC_EXTI_LINE_ALARM_EVENT;    // enable rising edge
00106     EXTI->FTSR &= ~RTC_EXTI_LINE_ALARM_EVENT;   // disable falling edge
00107 
00108     //Calculate alarm register values
00109     uint32_t alarmreg = 0;
00110     alarmreg |= BYTE2BCD(timeinfo->tm_sec)  << 0;
00111     alarmreg |= BYTE2BCD(timeinfo->tm_min)  << 8;
00112     alarmreg |= BYTE2BCD(timeinfo->tm_hour) << 16;
00113     alarmreg |= BYTE2BCD(timeinfo->tm_mday) << 24;
00114     alarmreg &= 0x3f3f7f7f; // All MSKx & WDSEL = 0
00115 
00116     //Enable RTC interrupt (use Alarm-A)
00117     DBG("Step(%u),alarmreg:0x%08x\r\n", __LINE__, alarmreg);
00118     DBG("Step(%u),RTC->ISR:0x%08x\r\n", __LINE__, RTC->ISR); 
00119     RTC->ALRMAR = alarmreg;
00120     RTC->ALRMASSR = subsecs | RTC_ALRMASSR_MASKSS;      //Mask no subseconds
00121     DBG("Step(%u),alarmreg(reg):0x%08x\r\n", __LINE__, RTC->ALRMAR);
00122     RTC->CR |= RTC_CR_ALRAE | RTC_CR_ALRAIE;            //Enable Alarm-A  
00123     DBG("Step(%u),RTC->CR:0x%08x\r\n", __LINE__, RTC->CR); 
00124 
00125     RTC->WPR = 0xFF;        //Enable RTC write protection
00126     PWR->CR &= ~PWR_CR_DBP; //Disable power domain
00127 
00128     __enable_irq();         //Alarm is set, so irqs can be enabled again
00129 
00130     //Enable everything else
00131     NVIC_SetVector(RTC_IRQ, (uint32_t)WakeUp::irq_handler);
00132     NVIC_EnableIRQ(RTC_IRQ);
00133     use_reset = false;
00134     //---- Only for Debug purpose
00135     DBGP("PWR->CR     0x%08x:0x%08x\r\n",&PWR->CR, PWR->CR);
00136     DBGP("PWR->CSR    0x%08x:0x%08x\r\n",&PWR->CSR, PWR->CSR);
00137     DBGP("SCB->SCR    0x%08x:0x%08x\r\n",&SCB->SCR, SCB->SCR);
00138     DBGP("SCB->AIRCR  0x%08x:0x%08x\r\n",&SCB->AIRCR, SCB->AIRCR);
00139     DBGP("EXTI->IMR   0x%08x:0x%08x\r\n",&EXTI->IMR, EXTI->IMR);
00140     DBGP("EXTI->EMR   0x%08x:0x%08x\r\n",&EXTI->EMR, EXTI->EMR);
00141     DBGP("EXTI->RTSR  0x%08x:0x%08x\r\n",&EXTI->RTSR, EXTI->RTSR);
00142     DBGP("EXTI->FTSR  0x%08x:0x%08x\r\n",&EXTI->FTSR, EXTI->FTSR);
00143     DBGP("RTC->TR     0x%08x:0x%08x\r\n",&RTC->TR,RTC->TR);
00144     DBGP("RTC->DR     0x%08x:0x%08x\r\n",&RTC->DR,RTC->DR);
00145     DBGP("RTC->CR     0x%08x:0x%08x\r\n",&RTC->CR,RTC->CR);
00146     DBGP("RTC->ISR    0x%08x:0x%08x\r\n",&RTC->ISR,RTC->ISR);
00147     DBGP("RTC->ALRMAR 0x%08x:0x%08x\r\n",&RTC->ALRMAR,RTC->ALRMAR);
00148 }
00149 
00150 void WakeUp::standby_then_reset(uint32_t ms)
00151 {
00152     DBG("Step(%u),ms:%d\r\n", __LINE__, ms);
00153     if (ms == 0){   // just go to Reset
00154         __NVIC_SystemReset();
00155     } 
00156     set_ms(ms);
00157     use_reset = true;
00158     PWR->CR |= PWR_CR_CWUF;
00159     HAL_PWR_EnterSTANDBYMode();
00160 }
00161 
00162 void WakeUp::irq_handler(void)
00163 {
00164     //Clear RTC + EXTI interrupt flags
00165     PWR->CR |= PWR_CR_DBP;      // Enable power domain
00166     RTC->ISR &= ~RTC_ISR_ALRAF;
00167     RTC->CR &= 0x00ff00ff;      // just in case
00168     RTC->WPR = 0xCA;            // Disable RTC write protection
00169     RTC->WPR = 0x53;
00170     RTC->CR &= ~(RTC_CR_ALRAE | RTC_CR_ALRAIE); //DisEnable Alarm-A  
00171     RTC->WPR = 0xFF;            // Enable RTC write protection
00172     EXTI->PR = RTC_EXTI_LINE_ALARM_EVENT;  
00173     PWR->CR &= ~PWR_CR_DBP;     // Disable power domain
00174     if (use_reset == true){
00175         NVIC_SystemReset();
00176     } else {
00177         if (callback){
00178             callback.call();
00179         }
00180     }
00181 }
00182 
00183 void WakeUp::calibrate(void)
00184 {
00185     //RTC, we assume it is accurate enough without calibration
00186 }
00187 
00188 #endif