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
Device/WakeUp_STM_RTC.cpp@2:0c49a8f32f6e, 2017-12-26 (annotated)
- Committer:
- madelectroneng
- Date:
- Tue Dec 26 21:30:09 2017 +0000
- Revision:
- 2:0c49a8f32f6e
Inital setup
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
madelectroneng | 2:0c49a8f32f6e | 1 | #ifdef TARGET_STM |
madelectroneng | 2:0c49a8f32f6e | 2 | // added by JH1PJL 2017-9-21 |
madelectroneng | 2:0c49a8f32f6e | 3 | #if defined(TARGET_NUCLEO_F446RE) || defined(TARGET_NUCLEO_F411RE)\ |
madelectroneng | 2:0c49a8f32f6e | 4 | || defined(TARGET_NUCLEO_F401RE)\ |
madelectroneng | 2:0c49a8f32f6e | 5 | || defined(TARGET_NUCLEO_L152RE) || defined(TARGET_NUCLEO_L073RZ)\ |
madelectroneng | 2:0c49a8f32f6e | 6 | || defined(TARGET_NUCLEO_L053R8) |
madelectroneng | 2:0c49a8f32f6e | 7 | // use WakeUp_STM32_others.cpp |
madelectroneng | 2:0c49a8f32f6e | 8 | #else |
madelectroneng | 2:0c49a8f32f6e | 9 | |
madelectroneng | 2:0c49a8f32f6e | 10 | #include "WakeUp.h" |
madelectroneng | 2:0c49a8f32f6e | 11 | #include "rtc_api.h" |
madelectroneng | 2:0c49a8f32f6e | 12 | |
madelectroneng | 2:0c49a8f32f6e | 13 | #define BYTE2BCD(byte) ((byte % 10) | ((byte / 10) << 4)) |
madelectroneng | 2:0c49a8f32f6e | 14 | |
madelectroneng | 2:0c49a8f32f6e | 15 | //Most things are pretty similar between the different STM targets. |
madelectroneng | 2:0c49a8f32f6e | 16 | //Only the IRQ number the alarm is connected to differs. Any errors |
madelectroneng | 2:0c49a8f32f6e | 17 | //with RTC_IRQn/RTC_Alarm_IRQn in them are related to this |
madelectroneng | 2:0c49a8f32f6e | 18 | #if defined(TARGET_M4) || defined(TARGET_M3) |
madelectroneng | 2:0c49a8f32f6e | 19 | #define RTC_IRQ RTC_Alarm_IRQn |
madelectroneng | 2:0c49a8f32f6e | 20 | #else |
madelectroneng | 2:0c49a8f32f6e | 21 | #define RTC_IRQ RTC_IRQn |
madelectroneng | 2:0c49a8f32f6e | 22 | #endif |
madelectroneng | 2:0c49a8f32f6e | 23 | |
madelectroneng | 2:0c49a8f32f6e | 24 | // Some things to handle Disco L476VG (and similar ones) |
madelectroneng | 2:0c49a8f32f6e | 25 | #if defined(TARGET_STM32L4) |
madelectroneng | 2:0c49a8f32f6e | 26 | #define IMR IMR1 |
madelectroneng | 2:0c49a8f32f6e | 27 | #define EMR EMR1 |
madelectroneng | 2:0c49a8f32f6e | 28 | #define RTSR RTSR1 |
madelectroneng | 2:0c49a8f32f6e | 29 | #define FTSR FTSR2 |
madelectroneng | 2:0c49a8f32f6e | 30 | #define PR PR1 |
madelectroneng | 2:0c49a8f32f6e | 31 | #endif |
madelectroneng | 2:0c49a8f32f6e | 32 | |
madelectroneng | 2:0c49a8f32f6e | 33 | //Disabling the Backup Powerdomain does not seem to work nicely anymore if you want to use other RTC functions afterwards. |
madelectroneng | 2:0c49a8f32f6e | 34 | //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) |
madelectroneng | 2:0c49a8f32f6e | 35 | |
madelectroneng | 2:0c49a8f32f6e | 36 | Callback<void()> WakeUp::callback; |
madelectroneng | 2:0c49a8f32f6e | 37 | |
madelectroneng | 2:0c49a8f32f6e | 38 | void WakeUp::set_ms(uint32_t ms) |
madelectroneng | 2:0c49a8f32f6e | 39 | { |
madelectroneng | 2:0c49a8f32f6e | 40 | if (!rtc_isenabled()) { //Make sure RTC is running |
madelectroneng | 2:0c49a8f32f6e | 41 | rtc_init(); |
madelectroneng | 2:0c49a8f32f6e | 42 | wait_us(250); //The f401 seems to want a delay after init |
madelectroneng | 2:0c49a8f32f6e | 43 | } |
madelectroneng | 2:0c49a8f32f6e | 44 | |
madelectroneng | 2:0c49a8f32f6e | 45 | //PWR->CR |= PWR_CR_DBP; //Enable power domain |
madelectroneng | 2:0c49a8f32f6e | 46 | RTC->WPR = 0xCA; //Disable RTC write protection |
madelectroneng | 2:0c49a8f32f6e | 47 | RTC->WPR = 0x53; |
madelectroneng | 2:0c49a8f32f6e | 48 | |
madelectroneng | 2:0c49a8f32f6e | 49 | //Alarm must be disabled to change anything |
madelectroneng | 2:0c49a8f32f6e | 50 | RTC->CR &= ~RTC_CR_ALRAE; |
madelectroneng | 2:0c49a8f32f6e | 51 | while(!(RTC->ISR & RTC_ISR_ALRAWF)); |
madelectroneng | 2:0c49a8f32f6e | 52 | |
madelectroneng | 2:0c49a8f32f6e | 53 | if (ms == 0) { //Just disable alarm |
madelectroneng | 2:0c49a8f32f6e | 54 | //PWR->CR &= ~PWR_CR_DBP; //Disable power domain |
madelectroneng | 2:0c49a8f32f6e | 55 | RTC->WPR = 0xFF; //Enable RTC write protection |
madelectroneng | 2:0c49a8f32f6e | 56 | return; |
madelectroneng | 2:0c49a8f32f6e | 57 | } |
madelectroneng | 2:0c49a8f32f6e | 58 | |
madelectroneng | 2:0c49a8f32f6e | 59 | //RTC prescaler + calculate how many sub-seconds should be added |
madelectroneng | 2:0c49a8f32f6e | 60 | uint32_t prescaler = (RTC->PRER & 0x7FFF) + 1; |
madelectroneng | 2:0c49a8f32f6e | 61 | uint32_t subsecsadd = ((ms % 1000) * prescaler) / 1000; |
madelectroneng | 2:0c49a8f32f6e | 62 | |
madelectroneng | 2:0c49a8f32f6e | 63 | if ((ms < 1000) && (subsecsadd < 2)) |
madelectroneng | 2:0c49a8f32f6e | 64 | subsecsadd = 2; //At least 2 subsecs delay to be sure interrupt is called |
madelectroneng | 2:0c49a8f32f6e | 65 | |
madelectroneng | 2:0c49a8f32f6e | 66 | __disable_irq(); //At this point we don't want IRQs anymore |
madelectroneng | 2:0c49a8f32f6e | 67 | |
madelectroneng | 2:0c49a8f32f6e | 68 | //Get current time |
madelectroneng | 2:0c49a8f32f6e | 69 | uint32_t subsecs = RTC->SSR; |
madelectroneng | 2:0c49a8f32f6e | 70 | time_t secs = rtc_read(); |
madelectroneng | 2:0c49a8f32f6e | 71 | |
madelectroneng | 2:0c49a8f32f6e | 72 | //Calculate alarm values |
madelectroneng | 2:0c49a8f32f6e | 73 | //Subseconds is countdown, so substract the 'added' sub-seconds and prevent underflow |
madelectroneng | 2:0c49a8f32f6e | 74 | if (subsecs < subsecsadd) { |
madelectroneng | 2:0c49a8f32f6e | 75 | subsecs += prescaler; |
madelectroneng | 2:0c49a8f32f6e | 76 | secs++; |
madelectroneng | 2:0c49a8f32f6e | 77 | } |
madelectroneng | 2:0c49a8f32f6e | 78 | subsecs -= subsecsadd; |
madelectroneng | 2:0c49a8f32f6e | 79 | |
madelectroneng | 2:0c49a8f32f6e | 80 | //Set seconds correctly |
madelectroneng | 2:0c49a8f32f6e | 81 | secs += ms / 1000; |
madelectroneng | 2:0c49a8f32f6e | 82 | struct tm *timeinfo = localtime(&secs); |
madelectroneng | 2:0c49a8f32f6e | 83 | |
madelectroneng | 2:0c49a8f32f6e | 84 | //Enable rising edge EXTI interrupt of the RTC |
madelectroneng | 2:0c49a8f32f6e | 85 | EXTI->IMR |= RTC_EXTI_LINE_ALARM_EVENT; |
madelectroneng | 2:0c49a8f32f6e | 86 | EXTI->EMR &= ~RTC_EXTI_LINE_ALARM_EVENT; |
madelectroneng | 2:0c49a8f32f6e | 87 | EXTI->RTSR |= RTC_EXTI_LINE_ALARM_EVENT; |
madelectroneng | 2:0c49a8f32f6e | 88 | EXTI->FTSR &= ~RTC_EXTI_LINE_ALARM_EVENT; |
madelectroneng | 2:0c49a8f32f6e | 89 | |
madelectroneng | 2:0c49a8f32f6e | 90 | //Calculate alarm register values |
madelectroneng | 2:0c49a8f32f6e | 91 | uint32_t alarmreg = 0; |
madelectroneng | 2:0c49a8f32f6e | 92 | alarmreg |= BYTE2BCD(timeinfo->tm_sec) << 0; |
madelectroneng | 2:0c49a8f32f6e | 93 | alarmreg |= BYTE2BCD(timeinfo->tm_min) << 8; |
madelectroneng | 2:0c49a8f32f6e | 94 | alarmreg |= BYTE2BCD(timeinfo->tm_hour) << 16; |
madelectroneng | 2:0c49a8f32f6e | 95 | alarmreg |= BYTE2BCD(timeinfo->tm_mday) << 24; |
madelectroneng | 2:0c49a8f32f6e | 96 | |
madelectroneng | 2:0c49a8f32f6e | 97 | //Enable RTC interrupt |
madelectroneng | 2:0c49a8f32f6e | 98 | RTC->ALRMAR = alarmreg; |
madelectroneng | 2:0c49a8f32f6e | 99 | RTC->ALRMASSR = subsecs | RTC_ALRMASSR_MASKSS; //Mask no subseconds |
madelectroneng | 2:0c49a8f32f6e | 100 | RTC->CR |= RTC_CR_ALRAE | RTC_CR_ALRAIE; //Enable Alarm |
madelectroneng | 2:0c49a8f32f6e | 101 | |
madelectroneng | 2:0c49a8f32f6e | 102 | RTC->WPR = 0xFF; //Enable RTC write protection |
madelectroneng | 2:0c49a8f32f6e | 103 | //PWR->CR &= ~PWR_CR_DBP; //Disable power domain |
madelectroneng | 2:0c49a8f32f6e | 104 | |
madelectroneng | 2:0c49a8f32f6e | 105 | __enable_irq(); //Alarm is set, so irqs can be enabled again |
madelectroneng | 2:0c49a8f32f6e | 106 | |
madelectroneng | 2:0c49a8f32f6e | 107 | //Enable everything else |
madelectroneng | 2:0c49a8f32f6e | 108 | NVIC_SetVector(RTC_IRQ, (uint32_t)WakeUp::irq_handler); |
madelectroneng | 2:0c49a8f32f6e | 109 | NVIC_EnableIRQ(RTC_IRQ); |
madelectroneng | 2:0c49a8f32f6e | 110 | } |
madelectroneng | 2:0c49a8f32f6e | 111 | |
madelectroneng | 2:0c49a8f32f6e | 112 | |
madelectroneng | 2:0c49a8f32f6e | 113 | void WakeUp::irq_handler(void) |
madelectroneng | 2:0c49a8f32f6e | 114 | { |
madelectroneng | 2:0c49a8f32f6e | 115 | //Clear RTC + EXTI interrupt flags |
madelectroneng | 2:0c49a8f32f6e | 116 | //PWR->CR |= PWR_CR_DBP; //Enable power domain |
madelectroneng | 2:0c49a8f32f6e | 117 | RTC->ISR &= ~RTC_ISR_ALRAF; |
madelectroneng | 2:0c49a8f32f6e | 118 | RTC->WPR = 0xCA; //Disable RTC write protection |
madelectroneng | 2:0c49a8f32f6e | 119 | RTC->WPR = 0x53; |
madelectroneng | 2:0c49a8f32f6e | 120 | RTC->CR &= ~RTC_CR_ALRAE; |
madelectroneng | 2:0c49a8f32f6e | 121 | RTC->WPR = 0xFF; //Enable RTC write protection |
madelectroneng | 2:0c49a8f32f6e | 122 | EXTI->PR = RTC_EXTI_LINE_ALARM_EVENT; |
madelectroneng | 2:0c49a8f32f6e | 123 | //PWR->CR &= ~PWR_CR_DBP; //Disable power domain |
madelectroneng | 2:0c49a8f32f6e | 124 | callback.call(); |
madelectroneng | 2:0c49a8f32f6e | 125 | } |
madelectroneng | 2:0c49a8f32f6e | 126 | |
madelectroneng | 2:0c49a8f32f6e | 127 | void WakeUp::calibrate(void) |
madelectroneng | 2:0c49a8f32f6e | 128 | { |
madelectroneng | 2:0c49a8f32f6e | 129 | //RTC, we assume it is accurate enough without calibration |
madelectroneng | 2:0c49a8f32f6e | 130 | } |
madelectroneng | 2:0c49a8f32f6e | 131 | |
madelectroneng | 2:0c49a8f32f6e | 132 | #endif // TARGET_NUCLEO_F446RE (added by JH1PJL 2017-9-21) |
madelectroneng | 2:0c49a8f32f6e | 133 | #endif |