BeRTOS
rtc_stm32.c
Go to the documentation of this file.
00001 
00038 #include "clock_stm32.h"
00039 
00040 #include <cfg/compiler.h>
00041 #include <cfg/module.h>
00042 #include <cfg/debug.h>
00043 
00044 #include <io/stm32.h>
00045 #include <io/stm32_pwr.h>
00046 
00047 #include <cpu/power.h> // cpu_relax()
00048 
00049 #include <drv/rtc.h>
00050 
00051 /* PWR registers base */
00052 static struct PWR *PWR = (struct PWR *)PWR_BASE;
00053 
00054 /* RTC clock source: LSE */
00055 #define RTC_CLKSRC  0x00000100
00056 /* RTC clock: 32768 Hz */
00057 #define RTC_CLOCK   32768
00058 /* RTC clock period (in ms) */
00059 #define RTC_PERIOD      1000
00060 
00061 /* RTC control register */
00062 #define RTC_CRH     (*(reg16_t *)(RTC_BASE + 0x00))
00063 #define RTC_CRL     (*(reg16_t *)(RTC_BASE + 0x04))
00064 
00065 #define RTC_CRL_SECIE         BV(0)
00066 #define RTC_CRL_ALRIE         BV(1)
00067 #define RTC_CRL_OWIE          BV(2)
00068 
00069 #define RTC_CRL_SECF          BV(0)
00070 #define RTC_CRL_ALRF          BV(1)
00071 #define RTC_CRL_OWF           BV(2)
00072 #define RTC_CRL_RSF           BV(3)
00073 #define RTC_CRL_CNF           BV(4)
00074 #define RTC_CRL_RTOFF         BV(5)
00075 
00076 /* RTC prescaler load register */
00077 #define RTC_PRLH    (*(reg16_t *)(RTC_BASE + 0x08))
00078 #define RTC_PRLL    (*(reg16_t *)(RTC_BASE + 0x0c))
00079 
00080 /* RTC prescaler divider register */
00081 #define RTC_DIVH    (*(reg16_t *)(RTC_BASE + 0x10))
00082 #define RTC_DIVL    (*(reg16_t *)(RTC_BASE + 0x14))
00083 
00084 /* RTC counter register */
00085 #define RTC_CNTH    (*(reg16_t *)(RTC_BASE + 0x18))
00086 #define RTC_CNTL    (*(reg16_t *)(RTC_BASE + 0x1c))
00087 
00088 /* RTC alarm register */
00089 #define RTC_ALRH    (*(reg16_t *)(RTC_BASE + 0x20))
00090 #define RTC_ALRL    (*(reg16_t *)(RTC_BASE + 0x24))
00091 
00092 static void rtc_enterConfig(void)
00093 {
00094     /* Enter configuration mode */
00095     RTC_CRL |= RTC_CRL_CNF;
00096 }
00097 
00098 static void rtc_exitConfig(void)
00099 {
00100     /* Exit from configuration mode */
00101     RTC_CRL &= ~RTC_CRL_CNF;
00102     while (!(RTC_CRL & RTC_CRL_RTOFF))
00103         cpu_relax();
00104 }
00105 
00106 uint32_t rtc_time(void)
00107 {
00108     return (RTC_CNTH << 16) | RTC_CNTL;
00109 }
00110 
00111 void rtc_setTime(uint32_t val)
00112 {
00113     rtc_enterConfig();
00114     RTC_CNTH = (val >> 16) & 0xffff;
00115     RTC_CNTL = val & 0xffff;
00116     rtc_exitConfig();
00117 }
00118 
00119 /* Initialize the RTC clock */
00120 int rtc_init(void)
00121 {
00122 #if CONFIG_KERN
00123     MOD_CHECK(proc);
00124 #endif
00125     /* Enable clock for Power interface */
00126     RCC->APB1ENR |= RCC_APB1_PWR;
00127 
00128     /* Enable access to RTC registers */
00129     PWR->CR |= PWR_CR_DBP;
00130 
00131     /* Enable LSE */
00132     RCC->BDCR |= RCC_BDCR_LSEON;
00133     /* Wait for LSE ready */
00134     while (!(RCC->BDCR & RCC_BDCR_LSERDY))
00135         cpu_relax();
00136 
00137     /* Set clock source and enable RTC peripheral */
00138     RCC->BDCR |= RTC_CLKSRC | RCC_BDCR_RTCEN;
00139 
00140     rtc_enterConfig();
00141 
00142     /* Set prescaler */
00143     RTC_PRLH = ((RTC_PERIOD * RTC_CLOCK / 1000 - 1) >> 16) & 0xff;
00144     RTC_PRLL = ((RTC_PERIOD * RTC_CLOCK / 1000 - 1)) & 0xffff;
00145 
00146     rtc_exitConfig();
00147 
00148     /* Disable access to the RTC registers */
00149     PWR->CR &= ~PWR_CR_DBP;
00150 
00151     return 0;
00152 }