// // RTC: configure real-time clock // #include "stm32f0xx_hal.h" #include "rtc.h" #include "gpio.h" static RTC_HandleTypeDef hrtc; static volatile uint32_t seconds_ctr = 0; void rtc_incseconds(void) { //HAL_GPIO_TogglePin(LED_BLUE); seconds_ctr += 1; } static void Error_Handler(void) { volatile uint8_t crap = 1; for(uint16_t i=0; i<300; i++) { HAL_GPIO_TogglePin(LED_BLUE); HAL_Delay(100); } } // Initialize RTC void rtc_init(void) { __HAL_RCC_RTC_ENABLE(); RTC_TimeTypeDef sTime; RTC_DateTypeDef sDate; RTC_AlarmTypeDef sAlarm; HAL_PWR_EnableBkUpAccess(); hrtc.Instance = RTC; hrtc.Init.HourFormat = RTC_HOURFORMAT_24; hrtc.Init.AsynchPrediv = 127; // Note that both these dividers actually divide by their value + 1 hrtc.Init.SynchPrediv = 311; // About 1Hz with 40kHz LSI hrtc.Init.OutPut = RTC_OUTPUT_DISABLE; hrtc.Init.OutPutPolarity = RTC_OUTPUT_POLARITY_HIGH; hrtc.Init.OutPutType = RTC_OUTPUT_TYPE_OPENDRAIN; if (HAL_RTC_Init(&hrtc) != HAL_OK) { Error_Handler(); } sTime.Hours = 0x0; sTime.Minutes = 0x0; sTime.Seconds = 0x0; sTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE; sTime.StoreOperation = RTC_STOREOPERATION_RESET; if (HAL_RTC_SetTime(&hrtc, &sTime, RTC_FORMAT_BCD) != HAL_OK) { Error_Handler(); } sDate.WeekDay = RTC_WEEKDAY_MONDAY; sDate.Month = RTC_MONTH_JANUARY; sDate.Date = 0x01; sDate.Year = 0x19; if (HAL_RTC_SetDate(&hrtc, &sDate, RTC_FORMAT_BCD) != HAL_OK) { Error_Handler(); } /**Enable the Alarm A */ sAlarm.AlarmTime.Hours = 0x0; sAlarm.AlarmTime.Minutes = 0x0; sAlarm.AlarmTime.Seconds = 0x0; sAlarm.AlarmTime.SubSeconds = 0x0; sAlarm.AlarmTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE; sAlarm.AlarmTime.StoreOperation = RTC_STOREOPERATION_RESET; // Alarm will trigger on the Xth second of every minute sAlarm.AlarmMask = RTC_ALARMMASK_ALL; // Trigger every second for now sAlarm.AlarmSubSecondMask = RTC_ALARMSUBSECONDMASK_SS14; //RTC_ALARMSUBSECONDMASK_ALL; sAlarm.AlarmDateWeekDaySel = RTC_ALARMDATEWEEKDAYSEL_DATE; sAlarm.AlarmDateWeekDay = RTC_WEEKDAY_MONDAY; sAlarm.Alarm = RTC_ALARM_A; if (HAL_RTC_SetAlarm_IT(&hrtc, &sAlarm, RTC_FORMAT_BCD) != HAL_OK) { Error_Handler(); } HAL_NVIC_SetPriority(RTC_IRQn, 0, 0); HAL_NVIC_EnableIRQ(RTC_IRQn); HAL_RTC_WaitForSynchro(&hrtc); } static RTC_TimeTypeDef time_last = {0}; // Get the time from the RTC RTC_TimeTypeDef* rtc_time(void) { HAL_RTC_GetTime(&hrtc, &time_last, RTC_FORMAT_BCD); return &time_last; } // Calculate value in milliseconds from subseconds of the RTC uint16_t __rtc_millis(uint32_t sub_seconds) { // Subsecond counter counts down from SynchPrediv value to zero return (hrtc.Init.SynchPrediv - sub_seconds) * 999 / hrtc.Init.SynchPrediv; // 0 - 999 mS } #define JULIAN_DATE_BASE 2440588 // Unix epoch time in Julian calendar (UnixTime = 00:00:00 01.01.1970 => JDN = 2440588) // Calculate timestamp in milliseconds since Unix epoch uint64_t rtc_timestamp(void) { RTC_TimeTypeDef time = {0}; RTC_DateTypeDef date = {0}; HAL_RTC_GetTime(&hrtc, &time, RTC_FORMAT_BCD); HAL_RTC_GetDate(&hrtc, &date, RTC_FORMAT_BCD); // Thanks to LonelyWolf: https://github.com/LonelyWolf/stm32/blob/master/stm32l-dosfs/RTC.c // Convert Date/Time structures to epoch time uint8_t a; uint16_t y; uint8_t m; uint64_t JDN; // These hardcore math's are taken from http://en.wikipedia.org/wiki/Julian_day // Calculate some coefficients a = (14 - date.Month) / 12; y = (date.Year + 2000) + 4800 - a; // years since 1 March, 4801 BC m = date.Month + (12 * a) - 3; // since 1 March, 4801 BC // Gregorian calendar date compute JDN = date.Date; JDN += (153 * m + 2) / 5; JDN += 365 * y; JDN += y / 4; JDN += -y / 100; JDN += y / 400; JDN = JDN - 32045; JDN = JDN - JULIAN_DATE_BASE; // Calculate from base date JDN *= 86400; // Days to seconds JDN += time.Hours * 3600; // ... and today seconds JDN += time.Minutes * 60; JDN += time.Seconds; JDN *= 1000; // Prepare to add ms JDN += __rtc_millis(time.SubSeconds); return JDN; } uint32_t rtc_timestamp_seconds(void) { return seconds_ctr; } // Calibrate the RTC somehow void rtc_cal(void) { // Do something with hrtc.Instance->CALR; // this has a plus and minus component, see refman } // RTC accessor RTC_HandleTypeDef* rtc_gethandle(void) { return &hrtc; }