stm32f0: rtc: set up the real-time clock and implement functions to get and set the time

tags/0.1.0
S.J.R. van Schaik 7 years ago
parent c071903dd1
commit 333706ccb9
  1. 7
      include/rtc.h
  2. 1
      source/platform/stm32f0/Makefile
  3. 146
      source/platform/stm32f0/rtc.c

@ -0,0 +1,7 @@
#pragma once
#include <time.h>
int rtc_init(struct tm *time);
int rtc_get_time(struct tm *time);
time_t rtc_time(void);

@ -1,2 +1,3 @@
obj-y += source/platform/stm32f0/gpio.o
obj-y += source/platform/stm32f0/rcc.o
obj-y += source/platform/stm32f0/rtc.o

@ -0,0 +1,146 @@
#include <libopencm3/stm32/pwr.h>
#include <libopencm3/stm32/rcc.h>
#include <libopencm3/stm32/rtc.h>
#include <macros.h>
#include <rtc.h>
static void rtc_set_clock_source(enum rcc_osc clock_source)
{
uint32_t reg;
switch (clock_source) {
case RCC_LSE:
/* Turn on the LSE and wait until it stabilised. */
RCC_BDCR |= RCC_BDCR_LSEON;
while ((reg = (RCC_BDCR & RCC_BDCR_LSERDY)) == 0);
/* Choose LSE as the RTC clock source. */
RCC_BDCR &= ~BITS(8, 9);
RCC_BDCR |= BIT(8);
break;
case RCC_LSI:
/* Turn on the LSI and wait until it stabilised. */
RCC_CSR |= RCC_CSR_LSION;
while ((reg = (RCC_CSR & RCC_CSR_LSIRDY)) == 0);
/* Choose LSI as the RTC clock source. */
RCC_BDCR &= ~BITS(8, 9);
RCC_BDCR |= BIT(9);
break;
case RCC_HSE:
/* Turn on the HSE and wait until it stabilised. */
RCC_CR |= RCC_CR_HSEON;
while ((reg = (RCC_CR & RCC_CR_HSERDY)) == 0);
/* Choose HSE as the RTC clock source. */
RCC_BDCR &= ~BITS(8, 9);
RCC_BDCR |= BITS(8, 9);
break;
default:
/* Unusable clock sources. Turn off the clock source for RTC. */
RCC_BDCR &= ~BITS(8, 9);
break;
}
}
int rtc_get_time(struct tm *time)
{
uint32_t rtc_tr, rtc_dr;
rtc_tr = RTC_TR;
rtc_dr = RTC_DR;
time->tm_sec = (unsigned char)(rtc_tr & 0xF);
time->tm_sec += (unsigned char)(((rtc_tr >> 4) & 0xF) * 10);
time->tm_min = (unsigned char)((rtc_tr >> 8) & 0xF);
time->tm_min += (unsigned char)(((rtc_tr >> 12) & 0xF) * 10);
time->tm_hour = (unsigned char)((rtc_tr >> 16) & 0xF);
time->tm_hour += (unsigned char)(((rtc_tr >> 20) & 0xF) * 10);
time->tm_mday = (unsigned char)(rtc_dr & 0xF);
time->tm_mday += (unsigned char)(((rtc_dr >> 4) & 0x3) * 10);
time->tm_mon = (unsigned char)((rtc_dr >> 8) & 0xF);
time->tm_mon += (unsigned char)(((rtc_dr >> 12) & 0x1) * 10);
time->tm_year = (unsigned char)((rtc_dr >> 16) & 0xF);
time->tm_year += (unsigned char)(((rtc_dr >> 20) & 0xF) * 10);
time->tm_year += 100;
return 0;
}
static int rtc_set_time(struct tm *time)
{
uint32_t rtc_tr, rtc_dr;
uint32_t year;
if (!time)
return -1;
year = time->tm_year - 100;
rtc_tr = (time->tm_sec % 10);
rtc_tr |= (time->tm_sec / 10) << 4;
rtc_tr |= (time->tm_min % 10) << 8;
rtc_tr |= (time->tm_min / 10) << 12;
rtc_tr |= (time->tm_hour % 10) << 16;
rtc_tr |= (time->tm_hour / 10) << 20;
rtc_dr = (time->tm_mday % 10);
rtc_dr |= (time->tm_mday / 10) << 4;
rtc_dr |= (time->tm_mon % 10) << 8;
rtc_dr |= (time->tm_mon / 10) << 12;
rtc_dr |= (year % 10) << 16;
rtc_dr |= (year / 10) << 20;
RTC_TR = rtc_tr;
RTC_DR = rtc_dr;
return 0;
}
int rtc_init(struct tm *time)
{
/* Turn on power block to enable unlocking. */
rcc_periph_clock_enable(RCC_PWR);
pwr_disable_backup_domain_write_protect();
/* Reset the RTC. */
RCC_BDCR |= RCC_BDCR_BDRST;
RCC_BDCR &= ~RCC_BDCR_BDRST;
/* Enable the LSI and set it as the clock source for RTC. */
rcc_osc_on(RCC_LSI);
rcc_wait_for_osc_ready(RCC_LSI);
rtc_set_clock_source(RCC_LSI);
/* Enable the RTC clock */
rcc_periph_clock_enable(RCC_RTC);
/* Unlock the registers in the RTC domain. */
rtc_unlock();
/* Enter init mode. */
RTC_ISR |= RTC_ISR_INIT;
while ((RTC_ISR & RTC_ISR_INITF) == 0);
/* Configure the RTC. */
rtc_set_prescaler(0x1ff, 0x7f);
rtc_set_time(time);
/* Exit init mode. */
RTC_ISR &= ~(RTC_ISR_INIT);
/* Lock the registers. */
rtc_lock();
pwr_enable_backup_domain_write_protect();
/* Wait for the synchronisation. */
rtc_wait_for_synchro();
return 0;
}
Loading…
Cancel
Save