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

Committer:
madelectroneng
Date:
Tue Dec 26 21:30:09 2017 +0000
Revision:
2:0c49a8f32f6e
Inital setup

Who changed what in which revision?

UserRevisionLine numberNew contents of line
madelectroneng 2:0c49a8f32f6e 1 // Created new file only for STM32/Nucleo boards which I have own it
madelectroneng 2:0c49a8f32f6e 2 // by JH1PJL 2017-9-21
madelectroneng 2:0c49a8f32f6e 3
madelectroneng 2:0c49a8f32f6e 4 #if defined(TARGET_NUCLEO_F446RE) || defined(TARGET_NUCLEO_F411RE)\
madelectroneng 2:0c49a8f32f6e 5 || defined(TARGET_NUCLEO_F401RE)\
madelectroneng 2:0c49a8f32f6e 6 || defined(TARGET_NUCLEO_L152RE) || defined(TARGET_NUCLEO_L073RZ)\
madelectroneng 2:0c49a8f32f6e 7 || defined(TARGET_NUCLEO_L053R8)
madelectroneng 2:0c49a8f32f6e 8
madelectroneng 2:0c49a8f32f6e 9 #include "WakeUp.h"
madelectroneng 2:0c49a8f32f6e 10 #include "rtc_api.h"
madelectroneng 2:0c49a8f32f6e 11
madelectroneng 2:0c49a8f32f6e 12 //#define DEBUG
madelectroneng 2:0c49a8f32f6e 13
madelectroneng 2:0c49a8f32f6e 14 extern Serial pc;
madelectroneng 2:0c49a8f32f6e 15
madelectroneng 2:0c49a8f32f6e 16 #if 0
madelectroneng 2:0c49a8f32f6e 17 #define DBG(...) pc.printf(__VA_ARGS__)
madelectroneng 2:0c49a8f32f6e 18 #else
madelectroneng 2:0c49a8f32f6e 19 #define DBG(...) {;}
madelectroneng 2:0c49a8f32f6e 20 #endif
madelectroneng 2:0c49a8f32f6e 21
madelectroneng 2:0c49a8f32f6e 22 #if 0
madelectroneng 2:0c49a8f32f6e 23 #define DBGP(...) pc.printf(__VA_ARGS__)
madelectroneng 2:0c49a8f32f6e 24 #else
madelectroneng 2:0c49a8f32f6e 25 #define DBGP(...) {;}
madelectroneng 2:0c49a8f32f6e 26 #endif
madelectroneng 2:0c49a8f32f6e 27
madelectroneng 2:0c49a8f32f6e 28 #define BYTE2BCD(byte) ((byte % 10) | ((byte / 10) << 4))
madelectroneng 2:0c49a8f32f6e 29
madelectroneng 2:0c49a8f32f6e 30 //Most things are pretty similar between the different STM targets.
madelectroneng 2:0c49a8f32f6e 31 //Only the IRQ number the alarm is connected to differs. Any errors
madelectroneng 2:0c49a8f32f6e 32 //with RTC_IRQn/RTC_Alarm_IRQn in them are related to this
madelectroneng 2:0c49a8f32f6e 33 #if defined(TARGET_M4) || defined(TARGET_M3)
madelectroneng 2:0c49a8f32f6e 34 #define RTC_IRQ RTC_Alarm_IRQn
madelectroneng 2:0c49a8f32f6e 35 #else
madelectroneng 2:0c49a8f32f6e 36 #define RTC_IRQ RTC_IRQn
madelectroneng 2:0c49a8f32f6e 37 #endif
madelectroneng 2:0c49a8f32f6e 38
madelectroneng 2:0c49a8f32f6e 39 // Some things to handle Disco L476VG (and similar ones)
madelectroneng 2:0c49a8f32f6e 40 #if defined(TARGET_STM32L4)
madelectroneng 2:0c49a8f32f6e 41 #define IMR IMR1
madelectroneng 2:0c49a8f32f6e 42 #define EMR EMR1
madelectroneng 2:0c49a8f32f6e 43 #define RTSR RTSR1
madelectroneng 2:0c49a8f32f6e 44 #define FTSR FTSR2
madelectroneng 2:0c49a8f32f6e 45 #define PR PR1
madelectroneng 2:0c49a8f32f6e 46 #endif
madelectroneng 2:0c49a8f32f6e 47
madelectroneng 2:0c49a8f32f6e 48 Callback<void()> WakeUp::callback;
madelectroneng 2:0c49a8f32f6e 49 bool WakeUp::use_reset = false;
madelectroneng 2:0c49a8f32f6e 50
madelectroneng 2:0c49a8f32f6e 51
madelectroneng 2:0c49a8f32f6e 52 void WakeUp::set_ms(uint32_t ms)
madelectroneng 2:0c49a8f32f6e 53 {
madelectroneng 2:0c49a8f32f6e 54 if (ms == 0) { //Just disable alarm
madelectroneng 2:0c49a8f32f6e 55 return;
madelectroneng 2:0c49a8f32f6e 56 }
madelectroneng 2:0c49a8f32f6e 57
madelectroneng 2:0c49a8f32f6e 58 if (!rtc_isenabled()) { //Make sure RTC is running
madelectroneng 2:0c49a8f32f6e 59 rtc_init();
madelectroneng 2:0c49a8f32f6e 60 wait_us(250); //The f401 seems to want a delay after init
madelectroneng 2:0c49a8f32f6e 61 }
madelectroneng 2:0c49a8f32f6e 62
madelectroneng 2:0c49a8f32f6e 63 PWR->CR |= PWR_CR_DBP; //Enable power domain
madelectroneng 2:0c49a8f32f6e 64 RTC->WPR = 0xCA; //Disable RTC write protection
madelectroneng 2:0c49a8f32f6e 65 RTC->WPR = 0x53;
madelectroneng 2:0c49a8f32f6e 66
madelectroneng 2:0c49a8f32f6e 67 //Alarm must be disabled to change anything
madelectroneng 2:0c49a8f32f6e 68 RTC->CR &= ~RTC_CR_ALRAE;
madelectroneng 2:0c49a8f32f6e 69 RTC->CR &= 0x00ff00ff;
madelectroneng 2:0c49a8f32f6e 70 while(!(RTC->ISR & RTC_ISR_ALRAWF));
madelectroneng 2:0c49a8f32f6e 71
madelectroneng 2:0c49a8f32f6e 72 DBG("Step(%u)\r\n", __LINE__);
madelectroneng 2:0c49a8f32f6e 73
madelectroneng 2:0c49a8f32f6e 74 //RTC prescaler + calculate how many sub-seconds should be added
madelectroneng 2:0c49a8f32f6e 75 uint32_t prescaler = (RTC->PRER & 0x7FFF) + 1;
madelectroneng 2:0c49a8f32f6e 76 uint32_t subsecsadd = ((ms % 1000) * prescaler) / 1000;
madelectroneng 2:0c49a8f32f6e 77
madelectroneng 2:0c49a8f32f6e 78 if ((ms < 1000) && (subsecsadd < 2))
madelectroneng 2:0c49a8f32f6e 79 subsecsadd = 2;//At least 5 subsecs delay to be sure interrupt is called
madelectroneng 2:0c49a8f32f6e 80
madelectroneng 2:0c49a8f32f6e 81 __disable_irq(); //At this point we don't want IRQs anymore
madelectroneng 2:0c49a8f32f6e 82
madelectroneng 2:0c49a8f32f6e 83 //Get current time
madelectroneng 2:0c49a8f32f6e 84 uint32_t subsecs = RTC->SSR;
madelectroneng 2:0c49a8f32f6e 85 time_t secs = rtc_read();
madelectroneng 2:0c49a8f32f6e 86 DBG("Step(%u),secs:%d,subsecs:%d\r\n", __LINE__, secs, subsecs);
madelectroneng 2:0c49a8f32f6e 87
madelectroneng 2:0c49a8f32f6e 88 //Calculate alarm values
madelectroneng 2:0c49a8f32f6e 89 //Subseconds is countdown,
madelectroneng 2:0c49a8f32f6e 90 // so substract the 'added' sub-seconds and prevent underflow
madelectroneng 2:0c49a8f32f6e 91 if (subsecs < subsecsadd) {
madelectroneng 2:0c49a8f32f6e 92 subsecs += prescaler;
madelectroneng 2:0c49a8f32f6e 93 secs++;
madelectroneng 2:0c49a8f32f6e 94 }
madelectroneng 2:0c49a8f32f6e 95 subsecs -= subsecsadd;
madelectroneng 2:0c49a8f32f6e 96
madelectroneng 2:0c49a8f32f6e 97 //Set seconds correctly
madelectroneng 2:0c49a8f32f6e 98 secs += ms / 1000;
madelectroneng 2:0c49a8f32f6e 99 struct tm *timeinfo = localtime(&secs);
madelectroneng 2:0c49a8f32f6e 100 DBG("Step(%u),secs:%d\r\n", __LINE__, secs);
madelectroneng 2:0c49a8f32f6e 101
madelectroneng 2:0c49a8f32f6e 102 //Enable rising edge EXTI interrupt of the RTC
madelectroneng 2:0c49a8f32f6e 103 EXTI->IMR |= RTC_EXTI_LINE_ALARM_EVENT; // enable it
madelectroneng 2:0c49a8f32f6e 104 EXTI->EMR &= ~RTC_EXTI_LINE_ALARM_EVENT; // disable event
madelectroneng 2:0c49a8f32f6e 105 EXTI->RTSR |= RTC_EXTI_LINE_ALARM_EVENT; // enable rising edge
madelectroneng 2:0c49a8f32f6e 106 EXTI->FTSR &= ~RTC_EXTI_LINE_ALARM_EVENT; // disable falling edge
madelectroneng 2:0c49a8f32f6e 107
madelectroneng 2:0c49a8f32f6e 108 //Calculate alarm register values
madelectroneng 2:0c49a8f32f6e 109 uint32_t alarmreg = 0;
madelectroneng 2:0c49a8f32f6e 110 alarmreg |= BYTE2BCD(timeinfo->tm_sec) << 0;
madelectroneng 2:0c49a8f32f6e 111 alarmreg |= BYTE2BCD(timeinfo->tm_min) << 8;
madelectroneng 2:0c49a8f32f6e 112 alarmreg |= BYTE2BCD(timeinfo->tm_hour) << 16;
madelectroneng 2:0c49a8f32f6e 113 alarmreg |= BYTE2BCD(timeinfo->tm_mday) << 24;
madelectroneng 2:0c49a8f32f6e 114 alarmreg &= 0x3f3f7f7f; // All MSKx & WDSEL = 0
madelectroneng 2:0c49a8f32f6e 115
madelectroneng 2:0c49a8f32f6e 116 //Enable RTC interrupt (use Alarm-A)
madelectroneng 2:0c49a8f32f6e 117 DBG("Step(%u),alarmreg:0x%08x\r\n", __LINE__, alarmreg);
madelectroneng 2:0c49a8f32f6e 118 DBG("Step(%u),RTC->ISR:0x%08x\r\n", __LINE__, RTC->ISR);
madelectroneng 2:0c49a8f32f6e 119 RTC->ALRMAR = alarmreg;
madelectroneng 2:0c49a8f32f6e 120 RTC->ALRMASSR = subsecs | RTC_ALRMASSR_MASKSS; //Mask no subseconds
madelectroneng 2:0c49a8f32f6e 121 DBG("Step(%u),alarmreg(reg):0x%08x\r\n", __LINE__, RTC->ALRMAR);
madelectroneng 2:0c49a8f32f6e 122 RTC->CR |= RTC_CR_ALRAE | RTC_CR_ALRAIE; //Enable Alarm-A
madelectroneng 2:0c49a8f32f6e 123 DBG("Step(%u),RTC->CR:0x%08x\r\n", __LINE__, RTC->CR);
madelectroneng 2:0c49a8f32f6e 124
madelectroneng 2:0c49a8f32f6e 125 RTC->WPR = 0xFF; //Enable RTC write protection
madelectroneng 2:0c49a8f32f6e 126 PWR->CR &= ~PWR_CR_DBP; //Disable power domain
madelectroneng 2:0c49a8f32f6e 127
madelectroneng 2:0c49a8f32f6e 128 __enable_irq(); //Alarm is set, so irqs can be enabled again
madelectroneng 2:0c49a8f32f6e 129
madelectroneng 2:0c49a8f32f6e 130 //Enable everything else
madelectroneng 2:0c49a8f32f6e 131 NVIC_SetVector(RTC_IRQ, (uint32_t)WakeUp::irq_handler);
madelectroneng 2:0c49a8f32f6e 132 NVIC_EnableIRQ(RTC_IRQ);
madelectroneng 2:0c49a8f32f6e 133 use_reset = false;
madelectroneng 2:0c49a8f32f6e 134 //---- Only for Debug purpose
madelectroneng 2:0c49a8f32f6e 135 DBGP("PWR->CR 0x%08x:0x%08x\r\n",&PWR->CR, PWR->CR);
madelectroneng 2:0c49a8f32f6e 136 DBGP("PWR->CSR 0x%08x:0x%08x\r\n",&PWR->CSR, PWR->CSR);
madelectroneng 2:0c49a8f32f6e 137 DBGP("SCB->SCR 0x%08x:0x%08x\r\n",&SCB->SCR, SCB->SCR);
madelectroneng 2:0c49a8f32f6e 138 DBGP("SCB->AIRCR 0x%08x:0x%08x\r\n",&SCB->AIRCR, SCB->AIRCR);
madelectroneng 2:0c49a8f32f6e 139 DBGP("EXTI->IMR 0x%08x:0x%08x\r\n",&EXTI->IMR, EXTI->IMR);
madelectroneng 2:0c49a8f32f6e 140 DBGP("EXTI->EMR 0x%08x:0x%08x\r\n",&EXTI->EMR, EXTI->EMR);
madelectroneng 2:0c49a8f32f6e 141 DBGP("EXTI->RTSR 0x%08x:0x%08x\r\n",&EXTI->RTSR, EXTI->RTSR);
madelectroneng 2:0c49a8f32f6e 142 DBGP("EXTI->FTSR 0x%08x:0x%08x\r\n",&EXTI->FTSR, EXTI->FTSR);
madelectroneng 2:0c49a8f32f6e 143 DBGP("RTC->TR 0x%08x:0x%08x\r\n",&RTC->TR,RTC->TR);
madelectroneng 2:0c49a8f32f6e 144 DBGP("RTC->DR 0x%08x:0x%08x\r\n",&RTC->DR,RTC->DR);
madelectroneng 2:0c49a8f32f6e 145 DBGP("RTC->CR 0x%08x:0x%08x\r\n",&RTC->CR,RTC->CR);
madelectroneng 2:0c49a8f32f6e 146 DBGP("RTC->ISR 0x%08x:0x%08x\r\n",&RTC->ISR,RTC->ISR);
madelectroneng 2:0c49a8f32f6e 147 DBGP("RTC->ALRMAR 0x%08x:0x%08x\r\n",&RTC->ALRMAR,RTC->ALRMAR);
madelectroneng 2:0c49a8f32f6e 148 }
madelectroneng 2:0c49a8f32f6e 149
madelectroneng 2:0c49a8f32f6e 150 void WakeUp::standby_then_reset(uint32_t ms)
madelectroneng 2:0c49a8f32f6e 151 {
madelectroneng 2:0c49a8f32f6e 152 DBG("Step(%u),ms:%d\r\n", __LINE__, ms);
madelectroneng 2:0c49a8f32f6e 153 if (ms == 0){ // just go to Reset
madelectroneng 2:0c49a8f32f6e 154 __NVIC_SystemReset();
madelectroneng 2:0c49a8f32f6e 155 }
madelectroneng 2:0c49a8f32f6e 156 set_ms(ms);
madelectroneng 2:0c49a8f32f6e 157 use_reset = true;
madelectroneng 2:0c49a8f32f6e 158 PWR->CR |= PWR_CR_CWUF;
madelectroneng 2:0c49a8f32f6e 159 HAL_PWR_EnterSTANDBYMode();
madelectroneng 2:0c49a8f32f6e 160 }
madelectroneng 2:0c49a8f32f6e 161
madelectroneng 2:0c49a8f32f6e 162 void WakeUp::irq_handler(void)
madelectroneng 2:0c49a8f32f6e 163 {
madelectroneng 2:0c49a8f32f6e 164 //Clear RTC + EXTI interrupt flags
madelectroneng 2:0c49a8f32f6e 165 PWR->CR |= PWR_CR_DBP; // Enable power domain
madelectroneng 2:0c49a8f32f6e 166 RTC->ISR &= ~RTC_ISR_ALRAF;
madelectroneng 2:0c49a8f32f6e 167 RTC->CR &= 0x00ff00ff; // just in case
madelectroneng 2:0c49a8f32f6e 168 RTC->WPR = 0xCA; // Disable RTC write protection
madelectroneng 2:0c49a8f32f6e 169 RTC->WPR = 0x53;
madelectroneng 2:0c49a8f32f6e 170 RTC->CR &= ~(RTC_CR_ALRAE | RTC_CR_ALRAIE); //DisEnable Alarm-A
madelectroneng 2:0c49a8f32f6e 171 RTC->WPR = 0xFF; // Enable RTC write protection
madelectroneng 2:0c49a8f32f6e 172 EXTI->PR = RTC_EXTI_LINE_ALARM_EVENT;
madelectroneng 2:0c49a8f32f6e 173 PWR->CR &= ~PWR_CR_DBP; // Disable power domain
madelectroneng 2:0c49a8f32f6e 174 if (use_reset == true){
madelectroneng 2:0c49a8f32f6e 175 NVIC_SystemReset();
madelectroneng 2:0c49a8f32f6e 176 } else {
madelectroneng 2:0c49a8f32f6e 177 if (callback){
madelectroneng 2:0c49a8f32f6e 178 callback.call();
madelectroneng 2:0c49a8f32f6e 179 }
madelectroneng 2:0c49a8f32f6e 180 }
madelectroneng 2:0c49a8f32f6e 181 }
madelectroneng 2:0c49a8f32f6e 182
madelectroneng 2:0c49a8f32f6e 183 void WakeUp::calibrate(void)
madelectroneng 2:0c49a8f32f6e 184 {
madelectroneng 2:0c49a8f32f6e 185 //RTC, we assume it is accurate enough without calibration
madelectroneng 2:0c49a8f32f6e 186 }
madelectroneng 2:0c49a8f32f6e 187
madelectroneng 2:0c49a8f32f6e 188 #endif