Skip to content

Instantly share code, notes, and snippets.

@goog
Created May 17, 2019 09:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save goog/10950e57bfaf5489a3572ce87a971fe9 to your computer and use it in GitHub Desktop.
Save goog/10950e57bfaf5489a3572ce87a971fe9 to your computer and use it in GitHub Desktop.
/**
* @file
*
* @ingroup arm
*
* @brief RTC driver for STM32F4 SoC.
*
*/
/*
* Copyright (c) 2019 Jay Cheng<googcheng@gmail.com>.
*
* 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