Created
May 17, 2019 09:48
-
-
Save goog/10950e57bfaf5489a3572ce87a971fe9 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* @file | |
* | |
* @ingroup arm | |
* | |
* @brief RTC driver for STM32F4 SoC. | |
* | |
*/ | |
/* | |
* Copyright (c) 2019 Jay Cheng<[email protected]>. | |
* | |
* The license and distribution terms for this file may be | |
* found in the file LICENSE in this distribution or at | |
* http://www.rtems.com/license/LICENSE. | |
*/ | |
#if 1//IS_STM32F4 | |
#include <rtems.h> | |
#include <bsp.h> | |
#include <time.h> | |
#include <libchip/rtc.h> | |
#define STM32F4_RTC_BASE 0x40002800 | |
#define STM32F4_RTC_WPR (*(volatile uint32_t *)(STM32F4_RTC_BASE+0x24)) | |
#define STM32F4_RTC_CR (*(volatile uint32_t *)(STM32F4_RTC_BASE+0x08)) | |
#define STM32F4_RTC_TR (*(volatile uint32_t *)(STM32F4_RTC_BASE)) | |
#define STM32F4_RTC_DR (*(volatile uint32_t *)(STM32F4_RTC_BASE+0x04)) | |
#define STM32F4_RTC_ISR (*(volatile uint32_t *)(STM32F4_RTC_BASE+0x0C)) | |
#define STM32F4_RTC_PRER (*(volatile uint32_t *)(STM32F4_RTC_BASE+0x10)) | |
#define STM32F4_RTC_WUTR (*(volatile uint32_t *)(STM32F4_RTC_BASE+0x14)) | |
#define STM32F4_RTC_SSR (*(volatile uint32_t *)(STM32F4_RTC_BASE+0x28)) | |
#define STM32F4_RTC_ISR_INITF (1<<6) | |
#define STM32F4_PWR_CR_DBP (1<<8) | |
#define STM32F4_RTC_CR_WUTE (1<<10) | |
#define STM32F4_RTC_ISR_WUTWF (1<<2) | |
#define STM32F4_RTC_ISR_WUTF (1<<10) | |
#define STM32F4_RTC_CR_WUTIE (1<<14) | |
#define RTC_INIT_TIMEOUT ((uint32_t)0x00002000) | |
#define PWR_CR (*(volatile uint32_t *)0x40007000) | |
#define RCC_APB1ENR (*(volatile uint32_t *)0x40023840) | |
#define RCC_BDCR (*(volatile uint32_t *)0x40023870) | |
#define dec(a) ((a & 0x0f)+ (((a & 0xf0) >> 4 )*10)) | |
#define bcd(a) (((a / 10) << 4) | (a % 10)) | |
rtems_device_minor_number RTC_Minor; | |
size_t RTC_Count = 1; | |
static void rtc_write_enable(void); | |
static void rtc_write_disable(void); | |
void rtc_init(int minor); | |
uint8_t rtc_wait_sync(void); | |
int stm32f4_rtc_gettime(int minor,rtems_time_of_day *t); | |
int stm32f4_rtc_settime(int minor, const rtems_time_of_day *t); | |
/* | |
* probe for a rtc. we always claim to have one. | |
*/ | |
static bool stm32f4_rtc_probe(int minor) | |
{ | |
return true; | |
} | |
static void rtc_write_enable(void) | |
{ | |
STM32F4_RTC_WPR = 0xCA; | |
STM32F4_RTC_WPR = 0x53; | |
} | |
static void rtc_write_disable(void) | |
{ | |
//Write some random value other than key to disable | |
STM32F4_RTC_WPR = 0xff; | |
} | |
static void rtc_set_dbp() | |
{ | |
//volatile uint32_t *PWR_CR = 0x40007000; | |
PWR_CR |= STM32F4_PWR_CR_DBP; // set DBP | |
} | |
static void rtc_clear_dbp() | |
{ | |
//volatile uint32_t *PWR_CR = 0x40007000; | |
PWR_CR &= ~STM32F4_PWR_CR_DBP; // clear DBP | |
} | |
uint8_t rtc_enter_init_mode() | |
{ | |
uint32_t retry = 0X10000; | |
if(STM32F4_RTC_ISR & STM32F4_RTC_ISR_INITF) return 0; // Initialization flag | |
STM32F4_RTC_ISR |= 1<<7; // set Initialization mode | |
while(retry && ((STM32F4_RTC_ISR & STM32F4_RTC_ISR_INITF)==0x00)) | |
{ | |
retry--; | |
} | |
if(STM32F4_RTC_ISR & STM32F4_RTC_ISR_INITF) | |
return 0; | |
else | |
return 1; | |
} | |
void rtc_write_bkr(uint32_t BKRx,uint32_t data) | |
{ | |
uint32_t temp=0; | |
temp=STM32F4_RTC_BASE+0x50+BKRx*4; | |
(*(uint32_t *)temp) = data; | |
} | |
uint32_t rtc_read_bkr(uint32_t BKRx) | |
{ | |
uint32_t *p = NULL; | |
p = STM32F4_RTC_BASE + 0x50 + BKRx*4; | |
return (*p); | |
} | |
void rtc_wakeup_setup() | |
{ | |
rtc_write_enable(); | |
// set wakeup clock | |
// Disable the wake-up counter | |
//printk("wakeup block begin\n"); | |
STM32F4_RTC_CR &= ~STM32F4_RTC_CR_WUTE; | |
// Wait for the RTC WUTWF flag is set or timeout | |
int wait = RTC_INIT_TIMEOUT; | |
while (!(STM32F4_RTC_ISR & STM32F4_RTC_ISR_WUTWF) && --wait); | |
if(!(STM32F4_RTC_ISR & STM32F4_RTC_ISR_WUTWF)) | |
{ | |
rtc_write_disable(); | |
rtc_clear_dbp(); | |
return 1; | |
} | |
printk("will sett wutr\n"); | |
STM32F4_RTC_WUTR = 2; | |
//STM32F4_RTC_WUTR = 30; | |
printk("before set CR %08X\n", STM32F4_RTC_CR); | |
// disable alarm a | |
STM32F4_RTC_CR &= ~(1<<8); | |
STM32F4_RTC_CR &= (uint32_t)~(7); // clear lowest 3bits | |
STM32F4_RTC_CR |= 0x00000005; | |
printk("after clear alarma WUCKSEL CR value %08X\n", STM32F4_RTC_CR); | |
printk("WUTR %08X\n", STM32F4_RTC_WUTR); | |
STM32F4_RTC_ISR &= ~STM32F4_RTC_ISR_WUTF; // clear Wakeup timer flag | |
STM32F4_RTC_CR |= STM32F4_RTC_CR_WUTIE; | |
STM32F4_RTC_CR |= STM32F4_RTC_CR_WUTE; // enable wakeup timer | |
STM32F4_RTC_CR &= ~(1<<12); | |
printk("**CR %08X \n", STM32F4_RTC_CR); | |
//STM32F4_RTC_ISR &= ~(1<<7); // exit init mode | |
printk("isr value %08x \n", STM32F4_RTC_ISR); | |
volatile uint32_t EXIT_PR = *(volatile uint32_t *)0x40013C14; | |
EXIT_PR = (uint32_t)1<<22; | |
printk("clear line 22 exit flag \n"); | |
(*(volatile uint32_t*)0x40013C00) |= (1<<22); | |
(*(volatile uint32_t*)0x40013C08) |= (1<<22); | |
(*(uint32_t*)0xE000ED0C) = 0x05FA0000 | 0x400; | |
(*(uint8_t*)0xE000E403) = 0xe0; | |
// nvic enable interrupter number | |
// 0xE000E100 | |
(*(volatile uint32_t*)0xE000E100) |= (1<<3); | |
rtc_write_disable(); | |
} | |
void rtc_init(int minor) | |
{ | |
//printk("rtc \n"); | |
//volatile uint32_t *RCC_APB1ENR = 0x40023840; | |
uint16_t retry = 0X1FFF; | |
RCC_APB1ENR |= 1<<28; // Power interface clock enable | |
rtc_set_dbp(); | |
if(rtc_read_bkr(0) != 0x5050) | |
{ | |
RCC_BDCR |= 1<<0; //LSE enable | |
while(retry && ((RCC_BDCR & 0x02) == 0)) // External low-speed oscillator ready | |
{ | |
retry--; | |
//delay_ms(5); | |
usleep(5000); | |
} | |
//printk("after while BDCR %08x\n", *RCC_BDCR); | |
if(retry == 0) | |
{ | |
return 1; | |
} | |
RCC_BDCR |=1<<8; //LSE as rtc clock | |
RCC_BDCR |=1<<15; // RTC clock enable | |
//printk("BDCR %08x\n", RCC_BDCR); | |
// access write | |
rtc_write_enable(); | |
//printk("after rtc_write_enable\n"); | |
if(rtc_enter_init_mode()) return 2; // rtc into init mode | |
//printk("enter init mode\n"); | |
//STM32F4_RTC_PRER = 0xff; | |
STM32F4_RTC_PRER = 0xff; | |
STM32F4_RTC_PRER |= 0x007F<<16; | |
//printk("prer %08x\n", STM32F4_RTC_PRER); | |
STM32F4_RTC_CR &= ~(1<<6); // 24h Hour format | |
STM32F4_RTC_ISR &= ~(1<<7); // exit init mode | |
rtc_write_disable(); | |
rtems_time_of_day time_set_t = {0}; | |
rtems_time_of_day r = {0}; | |
time_set_t.second = 6; | |
time_set_t.minute = 6; | |
time_set_t.hour = 23; | |
time_set_t.day = 19; | |
time_set_t.month = 4; | |
time_set_t.year = 2019; | |
stm32f4_rtc_settime(0, &time_set_t); | |
#if 0 | |
stm32f4_rtc_gettime(0, &r); | |
printk("Secs %d",r.second); | |
printk("Mins %d",r.minute); | |
printk("Hours %d",r.hour); | |
printk("Days %d",r.day); | |
printk("Months %d",r.month); | |
printk("Years %d\n", r.year); | |
printk("ss %u\n", r.ticks); | |
#endif | |
rtc_write_bkr(0, 0x5050); | |
} | |
//rtc_clear_dbp(); | |
return 0; | |
} | |
uint8_t rtc_wait_sync(void) | |
{ | |
uint32_t retry = 0XFFFFF; | |
rtc_write_enable(); | |
STM32F4_RTC_ISR &=~(1<<5); | |
while(retry&&((STM32F4_RTC_ISR & (1<<5))==0x00)) | |
{ | |
retry--; | |
} | |
if(retry == 0) return 1; | |
rtc_write_disable(); | |
return 0; | |
} | |
int stm32f4_rtc_gettime(int minor, rtems_time_of_day *t) | |
{ | |
if(minor != 0) | |
return RTEMS_INVALID_NUMBER; | |
uint32_t temp = 0; | |
while(rtc_wait_sync()); | |
temp = STM32F4_RTC_TR; | |
t->hour= dec((temp>>16)&0X3F); | |
t->minute = dec((temp>>8)&0X7F); | |
t->second = dec(temp&0X7F); | |
temp = STM32F4_RTC_DR; | |
t->year = dec((temp>>16)&0XFF) + 2000; | |
t->month = dec((temp>>8)&0X1F); | |
t->day = dec(temp&0X3F); | |
t->ticks = STM32F4_RTC_SSR & 0xffff; | |
//printk("BYPSHAD %u\n", STM32F4_RTC_CR & 1<<5 ); | |
//volatile uint32_t tt = 0; | |
(void)STM32F4_RTC_DR; | |
return RTEMS_SUCCESSFUL; | |
} | |
int stm32f4_rtc_settime(int minor,const rtems_time_of_day *t) | |
{ | |
int rv; | |
if(minor != 0) | |
return RTEMS_INVALID_NUMBER; | |
uint32_t temp = 0; | |
uint8_t year, month, date, week; | |
week = 0; | |
year = t->year%100; // xx 2019 19 | |
month = t->month; | |
date = t->day; | |
rtc_write_enable(); | |
if(rtc_enter_init_mode()) return 1; | |
//temp=(((uint32_t)week&0X07)<<13)|((uint32_t)bcd(year)<<16)|((uint32_t)bcd(month)<<8)|(bcd(date)); | |
temp = ((uint32_t)bcd(year)<<16) | ((uint32_t)bcd(month)<<8) | (bcd(date)); | |
STM32F4_RTC_DR = temp; | |
//STM32F4_RTC_ISR &= ~(1<<7); | |
uint8_t hour, min, sec; | |
temp = 0; | |
hour = t->hour; | |
min = t->minute; | |
sec = t->second; | |
temp= ((uint32_t)bcd(hour)<<16)|((uint32_t)bcd(min)<<8)|(bcd(sec)); | |
STM32F4_RTC_TR = temp; | |
STM32F4_RTC_ISR &= ~(1<<7); | |
rtc_write_disable(); | |
return 0; | |
} | |
/* | |
* driver function table. | |
*/ | |
rtc_fns STM32F4_rtc_fns = { | |
rtc_init, | |
stm32f4_rtc_gettime, | |
stm32f4_rtc_settime | |
}; | |
/* | |
* the following table configures the RTC drivers used in this BSP | |
*/ | |
rtc_tbl RTC_Table[] = { | |
{ | |
"/dev/rtc", /* sDeviceName */ | |
RTC_CUSTOM, /* deviceType */ | |
&STM32F4_rtc_fns, /* pDeviceFns */ | |
stm32f4_rtc_probe, /* deviceProbe */ | |
NULL, /* pDeviceParams */ | |
0, /* ulCtrlPort1 */ | |
0, /* ulDataPort */ | |
NULL, /* getRegister */ | |
NULL /* setRegister */ | |
} | |
}; | |
#endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment