OpenRTX/platform/mcu/STM32F4xx/drivers/rtc.c

139 wiersze
4.7 KiB
C

/***************************************************************************
* Copyright (C) 2020 by Federico Amedeo Izzo IU2NUO, *
* Niccolò Izzo IU2KIN *
* Silvano Seva IU2KWO *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, see <http://www.gnu.org/licenses/> *
***************************************************************************/
#include <os.h>
#include "rtc.h"
#include "stm32f4xx.h"
void rtc_init()
{
/* Enable write protection for RTC registers */
RCC->APB1ENR |= RCC_APB1ENR_PWREN;
__DSB();
PWR->CR |= PWR_CR_DBP;
RTC->WPR = 0xCA;
RTC->WPR = 0x53;
RCC->BDCR = RCC_BDCR_RTCEN /* Enable RTC */
| RCC_BDCR_RTCSEL_0 /* Set LSE as clock source */
| RCC_BDCR_LSEON; /* Enable LSE */
/* Wait until external 32kHz crystal stabilises */
while((RCC->BDCR & RCC_BDCR_LSERDY) == 0) ;
}
void rtc_shutdown()
{
RCC->BDCR &= ~ RCC_BDCR_RTCEN | RCC_BDCR_LSEON;
}
void rtc_setTime(curTime_t t)
{
/*
* Convert values to BCD representation placing data in the correct
* positions for both time and date registers.
* Packing is done before updating registers, to minimise time spent with
* RTC in initialisation mode.
*/
uint32_t date = ((t.year / 10) << 20)
| ((t.year % 10) << 16)
| ((t.month / 10) << 12)
| ((t.month % 10) << 8)
| ((t.date / 10) << 4)
| (t.date % 10);
date &= RTC_DR_YT | RTC_DR_YU | RTC_DR_MT | RTC_DR_MU | RTC_DR_DT | RTC_DR_DU;
uint32_t time = ((t.hour / 10) << 20)
| ((t.hour % 10) << 16)
| ((t.minute / 10) << 12)
| ((t.minute % 10) << 8)
| ((t.second / 10) << 4)
| (t.second % 10);
time &= RTC_TR_HT | RTC_TR_HU | RTC_TR_MNT | RTC_TR_MNU | RTC_TR_ST | RTC_TR_SU;
/* Enter initialisation mode and update registers */
// CPU_CRITICAL_ENTER();
RTC->ISR |= RTC_ISR_INIT;
while((RTC->ISR & RTC_ISR_INITF) == 0) ;
RTC->TR = time;
RTC->DR = date;
RTC->ISR &= ~RTC_ISR_INIT;
// CPU_CRITICAL_EXIT();
}
void rtc_setHour(uint8_t hours, uint8_t minutes, uint8_t seconds)
{
curTime_t t = rtc_getTime();
t.hour = hours;
t.minute = minutes;
t.second = seconds;
rtc_setTime(t);
}
void rtc_setDate(uint8_t date, uint8_t month, uint8_t year)
{
curTime_t t = rtc_getTime();
t.date = date;
t.month = month;
t.year = year;
rtc_setTime(t);
}
curTime_t rtc_getTime()
{
curTime_t t;
/*
* Obtain time and date values in BCD format from RTC registers, and fill
* the corresponding fields of the struct to be returned.
*/
uint32_t time = RTC->TR;
t.hour = ((time & RTC_TR_HT) >> 20)*10 + ((time & RTC_TR_HU) >> 16);
t.minute = ((time & RTC_TR_MNT) >> 12)*10 + ((time & RTC_TR_MNU) >> 8);
t.second = ((time & RTC_TR_ST) >> 4)*10 + (time & RTC_TR_SU);
uint32_t date = RTC->DR;
t.year = ((date & RTC_DR_YT) >> 20)*10 + ((date & RTC_DR_YU) >> 16);
t.day = ((date & RTC_DR_WDU) >> 13);
t.month = ((date & RTC_DR_MT) >> 12)*10 + ((date & RTC_DR_MU) >> 8);
t.date = ((date & RTC_DR_DT) >> 4)*10 + (date & RTC_DR_DU);
return t;
}
void rtc_dstSet()
{
/* If BKP bit is set, DST has been already set */
if(RTC->CR & RTC_CR_BCK) return;
// CPU_CRITICAL_ENTER();
RTC->CR |= RTC_CR_BCK | RTC_CR_ADD1H;
// CPU_CRITICAL_EXIT();
}
void rtc_dstClear()
{
/* If BKP bit is cleared, DST has been already removed */
if((RTC->CR & RTC_CR_BCK) == 0) return;
// CPU_CRITICAL_ENTER();
RTC->CR &= ~RTC_CR_BCK;
RTC->CR |= RTC_CR_SUB1H;
// CPU_CRITICAL_EXIT();
}