parent
c071903dd1
commit
333706ccb9
@ -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…
Reference in new issue