165 lines
3.3 KiB
C
165 lines
3.3 KiB
C
/*
|
|
* rtc.c
|
|
*
|
|
* Created on: Oct 16, 2024
|
|
* Author: true
|
|
*/
|
|
|
|
|
|
#include <ch32v20x.h>
|
|
#include <stdint.h>
|
|
|
|
#include "periph/rtc.h"
|
|
|
|
|
|
|
|
#define RTC_INIT_PATTERN 0x1337
|
|
|
|
|
|
|
|
static const uint8_t days_per_mon[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
|
|
|
|
|
|
|
|
uint8_t rtc_state;
|
|
|
|
|
|
|
|
void rtc_set_state(uint16_t state)
|
|
{
|
|
rtc_state = state;
|
|
}
|
|
|
|
/*
|
|
* @fn rtc_is_leapyear
|
|
* @brief Returns true if year is a leap year.
|
|
*
|
|
* @param year
|
|
*
|
|
* @return 1 - Yes
|
|
* 0 - No
|
|
*/
|
|
uint8_t rtc_is_leapyear(u16 year)
|
|
{
|
|
if (year % 4 == 0) {
|
|
if (year % 100 == 0) {
|
|
if (year % 400 == 0) {
|
|
return 1;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
else return 1;
|
|
}
|
|
else return 0;
|
|
}
|
|
|
|
/*
|
|
* @fn rtc_set_clock
|
|
* @brief Set Time.
|
|
*
|
|
* @param Struct of RTClock
|
|
*
|
|
* @return 1 - error
|
|
* 0 - success
|
|
*/
|
|
int8_t rtc_set_clock(struct RTClock *c)
|
|
{
|
|
uint16_t x;
|
|
uint8_t m;
|
|
uint32_t count = 0;
|
|
|
|
if(c->year < 1970 || c->year > 2099)
|
|
return -1;
|
|
|
|
for(x = 1970; x < c->year; x++) {
|
|
if (rtc_is_leapyear(x))
|
|
count += 31622400;
|
|
else
|
|
count += 31536000;
|
|
}
|
|
|
|
m = c->mon - 1;
|
|
for(x = 0; x < m; x++){
|
|
count += (u32)days_per_mon[x] * 86400;
|
|
if(rtc_is_leapyear(c->year) && x == 1)
|
|
count += 86400;
|
|
}
|
|
|
|
count += (u32)(c->day - 1) * 86400;
|
|
count += (u32)c->h * 3600;
|
|
count += (u32)c->m * 60;
|
|
count += c->s;
|
|
|
|
PWR_BackupAccessCmd(ENABLE);
|
|
RTC_SetCounter(count);
|
|
RTC_WaitForLastTask();
|
|
|
|
return 0;
|
|
}
|
|
|
|
int8_t rtc_init()
|
|
{
|
|
uint32_t timeout;
|
|
static const struct RTClock clock = {
|
|
.year = 2024,
|
|
.mon = 11,
|
|
.day = 1,
|
|
.h = 8,
|
|
.m = 0,
|
|
.s = 0
|
|
};
|
|
|
|
// enable access to RTC registers
|
|
PWR_BackupAccessCmd(ENABLE);
|
|
|
|
// get RTC state
|
|
// if things aren't configured it'll be initialized in a moment
|
|
rtc_state = BKP_ReadBackupRegister(RTC_STATE_DR);
|
|
RTC_WaitForLastTask();
|
|
|
|
// is RTC already configured?
|
|
if (BKP_ReadBackupRegister(RTC_INIT_DR) != RTC_INIT_PATTERN) {
|
|
// must not be. initialize rtc
|
|
BKP_DeInit();
|
|
|
|
RCC_LSEConfig(RCC_LSE_ON);
|
|
|
|
timeout = SystemCoreClock / 2;
|
|
while(RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET && timeout--);
|
|
|
|
// if crystal didn't start in time, let the application know
|
|
if (!timeout) return -1;
|
|
|
|
// use crystal for RTC and enable it
|
|
RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);
|
|
RCC_RTCCLKCmd(ENABLE);
|
|
RTC_WaitForLastTask();
|
|
RTC_WaitForSynchro();
|
|
// RTC_ITConfig(RTC_IT_ALR, ENABLE);
|
|
// RTC_ITConfig(RTC_IT_SEC, ENABLE);
|
|
// RTC_WaitForLastTask();
|
|
|
|
RTC_EnterConfigMode();
|
|
RTC_SetPrescaler(32767);
|
|
RTC_WaitForLastTask();
|
|
|
|
// set an initial time
|
|
|
|
rtc_set_clock((struct RTClock *)&clock);
|
|
RTC_ExitConfigMode();
|
|
|
|
rtc_state = RTC_STATE_CLOCK_NOT_SET;
|
|
BKP_WriteBackupRegister(RTC_STATE_DR, rtc_state);
|
|
RTC_WaitForLastTask();
|
|
BKP_WriteBackupRegister(RTC_INIT_DR, RTC_INIT_PATTERN);
|
|
|
|
// RTC_NVIC_Config();
|
|
// RTC_Get();
|
|
}
|
|
|
|
RTC_WaitForLastTask();
|
|
|
|
return 0;
|
|
}
|