334 lines
7.8 KiB
C
334 lines
7.8 KiB
C
/* USER CODE BEGIN Header */
|
|
/**
|
|
******************************************************************************
|
|
* @file rtc.c
|
|
* @brief This file provides code for the configuration
|
|
* of the RTC instances.
|
|
******************************************************************************
|
|
* @attention
|
|
*
|
|
* Copyright (c) 2025 STMicroelectronics.
|
|
* All rights reserved.
|
|
*
|
|
* This software is licensed under terms that can be found in the LICENSE file
|
|
* in the root directory of this software component.
|
|
* If no LICENSE file comes with this software, it is provided AS-IS.
|
|
*
|
|
******************************************************************************
|
|
*/
|
|
/* USER CODE END Header */
|
|
/* Includes ------------------------------------------------------------------*/
|
|
#include "rtc.h"
|
|
|
|
/* USER CODE BEGIN 0 */
|
|
#define RTC_BKP_CONFIGURED_MARKER 0x32A5U
|
|
#define RTC_BKP_MARKER_REG RTC_BKP_DR1
|
|
#define RTC_BKP_YEAR_MONTH_REG RTC_BKP_DR2
|
|
#define RTC_BKP_DATE_WEEKDAY_REG RTC_BKP_DR3
|
|
|
|
static uint8_t RTC_NormalizeYear(uint16_t year, uint8_t *normalized_year)
|
|
{
|
|
if (year <= 99U)
|
|
{
|
|
*normalized_year = (uint8_t)year;
|
|
return 1U;
|
|
}
|
|
|
|
if ((year >= 2000U) && (year <= 2099U))
|
|
{
|
|
*normalized_year = (uint8_t)(year - 2000U);
|
|
return 1U;
|
|
}
|
|
|
|
return 0U;
|
|
}
|
|
|
|
static uint8_t RTC_IsLeapYearFull(uint16_t year)
|
|
{
|
|
return (uint8_t)(((year % 4U) == 0U) && (((year % 100U) != 0U) || ((year % 400U) == 0U)));
|
|
}
|
|
|
|
static uint8_t RTC_DaysInMonth(uint16_t year, uint8_t month)
|
|
{
|
|
static const uint8_t days_in_month[] = { 31U, 28U, 31U, 30U, 31U, 30U, 31U, 31U, 30U, 31U, 30U, 31U };
|
|
|
|
if ((month == 0U) || (month > 12U))
|
|
{
|
|
return 0U;
|
|
}
|
|
|
|
if ((month == 2U) && RTC_IsLeapYearFull(year))
|
|
{
|
|
return 29U;
|
|
}
|
|
|
|
return days_in_month[month - 1U];
|
|
}
|
|
|
|
static uint8_t RTC_IsDateValid(uint16_t year, uint8_t month, uint8_t date)
|
|
{
|
|
uint8_t normalized_year = 0U;
|
|
uint16_t full_year = year;
|
|
uint8_t max_day = 0U;
|
|
|
|
if (RTC_NormalizeYear(year, &normalized_year) == 0U)
|
|
{
|
|
return 0U;
|
|
}
|
|
|
|
if (year <= 99U)
|
|
{
|
|
full_year = 2000U + year;
|
|
}
|
|
|
|
max_day = RTC_DaysInMonth(full_year, month);
|
|
return (uint8_t)((date >= 1U) && (date <= max_day));
|
|
}
|
|
|
|
static void RTC_SaveDateToBackup(const RTC_DateTypeDef *date)
|
|
{
|
|
uint32_t year_month = (((uint32_t)date->Year) << 8U) | date->Month;
|
|
uint32_t date_weekday = (((uint32_t)date->Date) << 8U) | date->WeekDay;
|
|
|
|
if ((HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_YEAR_MONTH_REG) != year_month) ||
|
|
(HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_DATE_WEEKDAY_REG) != date_weekday))
|
|
{
|
|
HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_YEAR_MONTH_REG, year_month);
|
|
HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_DATE_WEEKDAY_REG, date_weekday);
|
|
}
|
|
|
|
if (HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_MARKER_REG) != RTC_BKP_CONFIGURED_MARKER)
|
|
{
|
|
HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_MARKER_REG, RTC_BKP_CONFIGURED_MARKER);
|
|
}
|
|
}
|
|
|
|
static uint8_t RTC_RestoreDateFromBackup(void)
|
|
{
|
|
RTC_DateTypeDef restored_date = {0};
|
|
uint32_t year_month = 0U;
|
|
uint32_t date_weekday = 0U;
|
|
|
|
if (HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_MARKER_REG) != RTC_BKP_CONFIGURED_MARKER)
|
|
{
|
|
return 0U;
|
|
}
|
|
|
|
year_month = HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_YEAR_MONTH_REG);
|
|
date_weekday = HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_DATE_WEEKDAY_REG);
|
|
|
|
restored_date.Year = (uint8_t)((year_month >> 8U) & 0xFFU);
|
|
restored_date.Month = (uint8_t)(year_month & 0xFFU);
|
|
restored_date.Date = (uint8_t)((date_weekday >> 8U) & 0xFFU);
|
|
restored_date.WeekDay = (uint8_t)(date_weekday & 0xFFU);
|
|
|
|
if (RTC_IsDateValid(restored_date.Year, restored_date.Month, restored_date.Date) == 0U)
|
|
{
|
|
return 0U;
|
|
}
|
|
|
|
if (restored_date.WeekDay > RTC_WEEKDAY_SATURDAY)
|
|
{
|
|
restored_date.WeekDay = RTC_WEEKDAY_MONDAY;
|
|
}
|
|
|
|
hrtc.DateToUpdate = restored_date;
|
|
return 1U;
|
|
}
|
|
|
|
/* USER CODE END 0 */
|
|
|
|
RTC_HandleTypeDef hrtc;
|
|
|
|
/* RTC init function */
|
|
void MX_RTC_Init(void)
|
|
{
|
|
|
|
/* USER CODE BEGIN RTC_Init 0 */
|
|
|
|
/* USER CODE END RTC_Init 0 */
|
|
|
|
RTC_TimeTypeDef sTime = {0};
|
|
RTC_DateTypeDef DateToUpdate = {0};
|
|
|
|
/* USER CODE BEGIN RTC_Init 1 */
|
|
uint8_t rtc_backup_ready = 0U;
|
|
|
|
/* USER CODE END RTC_Init 1 */
|
|
|
|
/** Initialize RTC Only
|
|
*/
|
|
hrtc.Instance = RTC;
|
|
hrtc.Init.AsynchPrediv = RTC_AUTO_1_SECOND;
|
|
hrtc.Init.OutPut = RTC_OUTPUTSOURCE_SECOND;
|
|
if (HAL_RTC_Init(&hrtc) != HAL_OK)
|
|
{
|
|
Error_Handler();
|
|
}
|
|
|
|
/* USER CODE BEGIN Check_RTC_BKUP */
|
|
rtc_backup_ready = RTC_RestoreDateFromBackup();
|
|
|
|
/* USER CODE END Check_RTC_BKUP */
|
|
|
|
/** Initialize RTC and set the Time and Date
|
|
*/
|
|
if (rtc_backup_ready == 0U)
|
|
{
|
|
sTime.Hours = 0U;
|
|
sTime.Minutes = 0U;
|
|
sTime.Seconds = 0U;
|
|
|
|
if (HAL_RTC_SetTime(&hrtc, &sTime, RTC_FORMAT_BIN) != HAL_OK)
|
|
{
|
|
Error_Handler();
|
|
}
|
|
DateToUpdate.WeekDay = RTC_WEEKDAY_MONDAY;
|
|
DateToUpdate.Month = RTC_MONTH_JANUARY;
|
|
DateToUpdate.Date = 1U;
|
|
DateToUpdate.Year = 0U;
|
|
|
|
if (HAL_RTC_SetDate(&hrtc, &DateToUpdate, RTC_FORMAT_BIN) != HAL_OK)
|
|
{
|
|
Error_Handler();
|
|
}
|
|
|
|
RTC_SaveDateToBackup(&DateToUpdate);
|
|
}
|
|
/* USER CODE BEGIN RTC_Init 2 */
|
|
|
|
/* USER CODE END RTC_Init 2 */
|
|
|
|
}
|
|
|
|
void HAL_RTC_MspInit(RTC_HandleTypeDef* rtcHandle)
|
|
{
|
|
|
|
if(rtcHandle->Instance==RTC)
|
|
{
|
|
/* USER CODE BEGIN RTC_MspInit 0 */
|
|
|
|
/* USER CODE END RTC_MspInit 0 */
|
|
HAL_PWR_EnableBkUpAccess();
|
|
/* Enable BKP CLK enable for backup registers */
|
|
__HAL_RCC_BKP_CLK_ENABLE();
|
|
/* RTC clock enable */
|
|
__HAL_RCC_RTC_ENABLE();
|
|
|
|
/* RTC interrupt Init */
|
|
HAL_NVIC_SetPriority(RTC_IRQn, 0, 0);
|
|
HAL_NVIC_EnableIRQ(RTC_IRQn);
|
|
/* USER CODE BEGIN RTC_MspInit 1 */
|
|
|
|
/* USER CODE END RTC_MspInit 1 */
|
|
}
|
|
}
|
|
|
|
void HAL_RTC_MspDeInit(RTC_HandleTypeDef* rtcHandle)
|
|
{
|
|
|
|
if(rtcHandle->Instance==RTC)
|
|
{
|
|
/* USER CODE BEGIN RTC_MspDeInit 0 */
|
|
|
|
/* USER CODE END RTC_MspDeInit 0 */
|
|
/* Peripheral clock disable */
|
|
__HAL_RCC_RTC_DISABLE();
|
|
|
|
/* RTC interrupt Deinit */
|
|
HAL_NVIC_DisableIRQ(RTC_IRQn);
|
|
/* USER CODE BEGIN RTC_MspDeInit 1 */
|
|
|
|
/* USER CODE END RTC_MspDeInit 1 */
|
|
}
|
|
}
|
|
|
|
/* USER CODE BEGIN 1 */
|
|
uint8_t RTC_CalendarIsValid(const RTC_CalendarTypeDef *calendar)
|
|
{
|
|
if (calendar == NULL)
|
|
{
|
|
return 0U;
|
|
}
|
|
|
|
return (uint8_t)((calendar->hours <= 23U) &&
|
|
(calendar->minutes <= 59U) &&
|
|
(calendar->seconds <= 59U) &&
|
|
RTC_IsDateValid(calendar->year, calendar->month, calendar->date));
|
|
}
|
|
|
|
HAL_StatusTypeDef RTC_CalendarGet(RTC_CalendarTypeDef *calendar)
|
|
{
|
|
RTC_TimeTypeDef time = {0};
|
|
RTC_DateTypeDef date = {0};
|
|
|
|
if (calendar == NULL)
|
|
{
|
|
return HAL_ERROR;
|
|
}
|
|
|
|
if (HAL_RTC_GetDate(&hrtc, &date, RTC_FORMAT_BIN) != HAL_OK)
|
|
{
|
|
return HAL_ERROR;
|
|
}
|
|
|
|
if (HAL_RTC_GetTime(&hrtc, &time, RTC_FORMAT_BIN) != HAL_OK)
|
|
{
|
|
return HAL_ERROR;
|
|
}
|
|
|
|
RTC_SaveDateToBackup(&date);
|
|
|
|
calendar->hours = time.Hours;
|
|
calendar->minutes = time.Minutes;
|
|
calendar->seconds = time.Seconds;
|
|
calendar->date = date.Date;
|
|
calendar->month = date.Month;
|
|
calendar->year = 2000U + date.Year;
|
|
calendar->weekday = date.WeekDay;
|
|
|
|
return HAL_OK;
|
|
}
|
|
|
|
HAL_StatusTypeDef RTC_CalendarSet(const RTC_CalendarTypeDef *calendar)
|
|
{
|
|
RTC_TimeTypeDef time = {0};
|
|
RTC_DateTypeDef date = {0};
|
|
uint8_t normalized_year = 0U;
|
|
|
|
if ((calendar == NULL) || (RTC_CalendarIsValid(calendar) == 0U))
|
|
{
|
|
return HAL_ERROR;
|
|
}
|
|
|
|
if (RTC_NormalizeYear(calendar->year, &normalized_year) == 0U)
|
|
{
|
|
return HAL_ERROR;
|
|
}
|
|
|
|
time.Hours = (uint8_t)calendar->hours;
|
|
time.Minutes = (uint8_t)calendar->minutes;
|
|
time.Seconds = (uint8_t)calendar->seconds;
|
|
|
|
date.Year = normalized_year;
|
|
date.Month = (uint8_t)calendar->month;
|
|
date.Date = (uint8_t)calendar->date;
|
|
date.WeekDay = RTC_WEEKDAY_MONDAY;
|
|
|
|
if (HAL_RTC_SetTime(&hrtc, &time, RTC_FORMAT_BIN) != HAL_OK)
|
|
{
|
|
return HAL_ERROR;
|
|
}
|
|
|
|
if (HAL_RTC_SetDate(&hrtc, &date, RTC_FORMAT_BIN) != HAL_OK)
|
|
{
|
|
return HAL_ERROR;
|
|
}
|
|
|
|
RTC_SaveDateToBackup(&date);
|
|
|
|
return HAL_OK;
|
|
}
|
|
|
|
/* USER CODE END 1 */
|