Skip to content

Commit

Permalink
RTC for stm32f1
Browse files Browse the repository at this point in the history
  • Loading branch information
Former committed Mar 25, 2019
1 parent 1859d03 commit 96c3431
Show file tree
Hide file tree
Showing 3 changed files with 263 additions and 1 deletion.
1 change: 1 addition & 0 deletions boards/bluepill/doc.txt
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ flash][Flashsize].
| USB | no |
| Timer | yes |
| CAN | no |
| RTC | yes |


## Flashing
Expand Down
1 change: 1 addition & 0 deletions boards/common/stm32f103c8/Makefile.features
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
FEATURES_PROVIDED += periph_adc
FEATURES_PROVIDED += periph_i2c
FEATURES_PROVIDED += periph_pwm
FEATURES_PROVIDED += periph_rtc
FEATURES_PROVIDED += periph_spi
FEATURES_PROVIDED += periph_timer
FEATURES_PROVIDED += periph_uart
Expand Down
262 changes: 261 additions & 1 deletion cpu/stm32_common/periph/rtc.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
* 2016 Laksh Bhatia
* 2016-2017 OTA keys S.A.
* 2017 Freie Universität Berlin
* 2019 Alexei Bezborodov
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
Expand All @@ -19,6 +20,7 @@
* @author Laksh Bhatia <bhatialaksh3@gmail.com>
* @author Vincent Dupont <vincent@otakeys.com>
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
* @author Alexei Bezborodov <alexeibv+riot@narod.ru>
* @}
*/

Expand All @@ -27,7 +29,12 @@
#include "stmclk.h"
#include "periph/rtc.h"

/* this implementation does not work for the stm32f1 */
#define ENABLE_DEBUG (0)
#include "debug.h"

/** Print out a message that function is not yet implementd */
#define NOT_YET_IMPLEMENTED() DEBUG("%s not yet implemented\n", __func__)

#if !defined(CPU_FAM_STM32F1)

/* map some CPU specific register names */
Expand Down Expand Up @@ -322,4 +329,257 @@ void ISR_NAME(void)
cortexm_isr_end();
}

#elif defined(CPU_FAM_STM32F1)

void rtc_init(void)
{
DEBUG("[RTC rtc_init]\n");

// Enable APB1 clocks
RCC->APB1ENR |= RCC_APB1ENR_PWREN | RCC_APB1ENR_BKPEN;

// Disable backup domain write protection
PWR->CR |= PWR_CR_DBP;

if ((RCC->BDCR & RCC_BDCR_RTCEN) != RCC_BDCR_RTCEN) // if RTC clock disabled
{
DEBUG("[RTC initialize]\n");

// Resets the entire Backup domain
RCC->BDCR |= RCC_BDCR_BDRST;
// Reset not activated
RCC->BDCR &= ~RCC_BDCR_BDRST;

//RTC clock enabled
//LSE oscillator clock used as RTC clock10: LSI oscillator clock used as RTC clock
RCC->BDCR |= RCC_BDCR_RTCEN | RCC_BDCR_RTCSEL_LSE;

// Second interrupt is enabled.
RTC->CRH |= RTC_CRH_SECIE;

// Enter configuration mode.
RTC->CRL |= RTC_CRL_CNF;

//If the input clock frequency (fRTCCLK) is 32.768 kHz, write 7FFFh in this register to get a signal period of 1 second.
RTC->PRLH = 0;
RTC->PRLL = 0x8000; //тактирование от внешнего кварца

// Calibration clock output disable (for enable in pin PC13 "AFIO->EVCR = 0xAD" and "BKP->RTCCR | = BKP_RTCCR_CCO | BKP_RTCCR_ASOS | BKP_RTCCR_ASOE;")
AFIO->EVCR = 0;
BKP->RTCCR = 0;

// Exit configuration mode (start update of RTC registers).
RTC->CRL &= ~RTC_CRL_CNF;

RCC->BDCR |= RCC_BDCR_LSEON;
while ((RCC->BDCR & RCC_BDCR_LSEON) != RCC_BDCR_LSEON){}

// Wait registers synchronize flag
RTC->CRL &= (uint16_t)~RTC_CRL_RSF;
while((RTC->CRL & RTC_CRL_RSF) != RTC_CRL_RSF){}
}
}

static void _rtc_enter_config_mode(void)
{
// Wait until the RTOFF bit is 1 (no RTC register writes ongoing).
while ((RTC->CRL & RTC_CRL_RTOFF) == 0);

// Enter configuration mode.
RTC->CRL |= RTC_CRL_CNF;
}

static void _rtc_exit_config_mode(void)
{
// Exit configuration mode.
RTC->CRL &= ~RTC_CRL_CNF;

// Wait until the RTOFF bit is 1 (our RTC register write finished).
while ((RTC->CRL & RTC_CRL_RTOFF) == 0);
}

static void _rtc_set_alarm_time(uint32_t alarm_time)
{
_rtc_enter_config_mode();
RTC->ALRL = (alarm_time & 0x0000ffff);
RTC->ALRH = (alarm_time & 0xffff0000) >> 16;
_rtc_exit_config_mode();
}

static void _rtc_enable_alarm(void)
{
_rtc_enter_config_mode();
RTC->CRH |= RTC_CRH_ALRIE;
_rtc_exit_config_mode();
}

static void _rtc_disable_alarm(void)
{
_rtc_enter_config_mode();
RTC->CRH &= ~RTC_CRH_ALRIE;
_rtc_exit_config_mode();
}

static uint32_t rtc_get_counter_val(void)
{
return (RTC->CNTH << 16) | RTC->CNTL;
}

static uint32_t rtc_get_alarm_val(void)
{
return (RTC->ALRH << 16) | RTC->ALRL;
}

static void _rtc_set_counter_val(uint32_t counter_val)
{
_rtc_enter_config_mode();
RTC->CNTH = (counter_val & 0xffff0000) >> 16; // CNT[31:16]
RTC->CNTL = counter_val & 0x0000ffff; // CNT[15:0]
_rtc_exit_config_mode();
}

// (UnixTime = 00:00:00 01.01.1970 = JD0 = 2440588)
#define JULIAN_DATE_BASE 2440588

// Julian day number calculation - https://en.wikipedia.org/wiki/Julian_day
static void _rtc_get_time_from_count(const uint32_t rtc_counter, struct tm *time)
{
unsigned long t;
unsigned long t1, a, b, c, d, e, m;
int year = 0;
int mon = 0;
int wday = 0;
int mday = 0;
int hour = 0;
int min = 0;
int sec = 0;
uint64_t jd = 0;;
uint64_t jdn = 0;

jd = ((rtc_counter + 43200) / (86400 >> 1)) + (2440587 <<1 ) + 1;
jdn = jd >> 1;

t = rtc_counter;
t1 = t / 60;
sec = t - t1 * 60;

t = t1;
t1 = t / 60;
min = t - t1 * 60;

t = t1;
t1 = t / 24;
hour = t - t1 * 24;

wday = jdn % 7;

a = jdn + 32044;
b = (4 * a + 3) / 146097;
c = a - (146097 * b) / 4;
d = (4 * c + 3) / 1461;
e = c - (1461 * d) / 4;
m = (5 * e + 2) / 153;
mday = e - (153 * m + 2) / 5 + 1;
mon = m + 3 - 12 * (m / 10);
year = 100 * b + d - 4800 + (m / 10);

time->tm_year = year - 1900;
time->tm_mon = mon;
time->tm_mday = mday;
time->tm_hour = hour;
time->tm_min = min;
time->tm_sec = sec;
time->tm_wday = wday;

DEBUG("[RTC time_from_count] c=%lu; %04i-%02i-%02i %02i:%02i:%02i\n", rtc_counter,
time->tm_year + 1900, time->tm_mon + 1, time->tm_mday,
time->tm_hour, time->tm_min, time->tm_sec);
}

// Julian day number calculation - https://en.wikipedia.org/wiki/Julian_day
uint32_t _rtc_get_count_from_time(struct tm *time)
{
uint8_t a;
uint16_t y;
uint8_t m;
uint32_t result_count;

a = (14 - time->tm_mon) / 12;
y = (time->tm_year + 1900) + 4800 - a;
m = time->tm_mon + (12 * a) - 3;

result_count = time->tm_mday;
result_count += (153 * m + 2) / 5;
result_count += 365 * y;
result_count += y / 4;
result_count += -y / 100;
result_count += y / 400;
result_count = result_count - 32045;
result_count = result_count - JULIAN_DATE_BASE;
result_count *= 86400;
result_count += (time->tm_hour * 3600);
result_count += (time->tm_min * 60);
result_count += (time->tm_sec);

DEBUG("[RTC count_from_time] c=%lu; %04i-%02i-%02i %02i:%02i:%02i\n", result_count,
time->tm_year + 1900, time->tm_mon + 1, time->tm_mday,
time->tm_hour, time->tm_min, time->tm_sec);

return result_count;
}

int rtc_set_time(struct tm *time)
{
_rtc_set_counter_val(_rtc_get_count_from_time(time));
return 0;
}

int rtc_get_time(struct tm *time)
{
uint32_t time_count_val = rtc_get_counter_val();
_rtc_get_time_from_count(time_count_val, time);
return 0;
}

int rtc_set_alarm(struct tm *time, rtc_alarm_cb_t cb, void *arg)
{
(void)cb;
(void)arg;
if (cb != NULL) {
DEBUG("[RTC rtc_set_alarm: warning callback not used]\n");
}

uint32_t time_count_val = _rtc_get_count_from_time(time);
_rtc_disable_alarm();
_rtc_set_alarm_time(time_count_val);
_rtc_enable_alarm();

return 0;
}

int rtc_get_alarm(struct tm *time)
{
uint32_t time_count_val = rtc_get_alarm_val();
_rtc_get_time_from_count(time_count_val, time);
return 0;
}

void rtc_clear_alarm(void)
{
_rtc_disable_alarm();
_rtc_set_alarm_time(0);
}

void rtc_poweron(void)
{
/* TODO implement */
NOT_YET_IMPLEMENTED();
}

void rtc_poweroff(void)
{
/* TODO implement */
NOT_YET_IMPLEMENTED();
}

#endif /* !CPU_FAM_STM32F1 */

0 comments on commit 96c3431

Please sign in to comment.