/*************************************************************************** * 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 * ***************************************************************************/ #include #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(); }