From: Robin Krens Date: Thu, 1 Aug 2019 15:32:49 +0000 (+0800) Subject: rtc implementation X-Git-Url: https://robinkrens.nl/gitweb/?p=cortex-from-scratch;a=commitdiff_plain;h=6e00544afe1ae83fcf51f262cfa744953dc8d023 rtc implementation Basic rtc implementation. LSE oscillator is used as clock source (32kHz). Second (periodic) interrupt is enabled to trigger a interrupt every second. RTC is not calibrated with tamper pin (so could be off with a few second each month). Added small uptime cmd. --- diff --git a/Makefile b/Makefile index edff16a..5cc5791 100644 --- a/Makefile +++ b/Makefile @@ -20,7 +20,7 @@ INCLUDE+= -Iinclude BIN = bin ODIR = obj -_OBJ = ivt.o systick.o sysinfo.o term.o main.o clock.o +_OBJ = ivt.o systick.o sysinfo.o term.o main.o clock.o rtc.o OBJ = $(patsubst %, $(ODIR)/%,$(_OBJ)) DDIR = obj/drivers diff --git a/clock.c b/clock.c index 2bcca11..02a26ab 100644 --- a/clock.c +++ b/clock.c @@ -13,9 +13,6 @@ * Some buses might not support the maximum speed and * should be prescaled (i.e. low speed APB) * - * 2. Routines to setup a real time clock (RTC). A external - * low speed oscillator (LSE) is used. - * * $USAGE * Check external crystals on board and maximum speed * for buses. In this example, a 8 Mhz external crystal @@ -48,34 +45,11 @@ static void setup_hse() { while(!rchkbit(RCC_CFGR, 3)); /* Wait for the clock switch to complete */ } -static void setup_rtc() { - -// TODO: long time to get stable? -// /* Enable PWREN and BKPEN */ -// rsetbit(RCC_APB1ENR, 28); -// rsetbit(RCC_APB1ENR, 27); -// -// /* Enable access to backup registers and RTC */ -// rsetbit(PWR_CR, 8); -// -// rsetbit(RCC_BDCR, 0); /* LSE enable */ -// while(!rchkbit(RCC_BDCR, 1)); /* wait for LSE to come up */ -// -// rsetbitsfrom(RCC_BDCR, 8, 0x1); /* use LSE as RTC source */ -// rsetbit(RCC_BDCR, 15); /* enable RTC */ -// - -} - void clock_init() { #ifdef ENABLE_HSE setup_hse(); #endif -#ifdef ENABLE_RTC -setup_rtc(); -#endif - } diff --git a/drivers/uart.c b/drivers/uart.c index b370294..05f0406 100644 --- a/drivers/uart.c +++ b/drivers/uart.c @@ -10,7 +10,6 @@ #include -#define RXNE ((*USART1_SR >> 5) & 0x1) #define UARTBUF 256 #define ECHO 1 @@ -24,16 +23,12 @@ void set_baudrate(); void * uart_handler() { - //uart_puts("echo: "); - while (RXNE) { + while (rchkbit(USART1_SR, 5)) { char echochar = *USART1_DR; -// uart_putc(echochar); linefeed.buf[linefeed.wpos++] = echochar; if (linefeed.wpos == UARTBUF) linefeed.wpos = 0; - //regw_u32(USART1_DR, echochar, 0, O_WRITE); } - //uart_putc('\n'); } @@ -43,45 +38,43 @@ void uart_init() { linefeed.wpos = 0; //memset(&linefeed, 0, (sizeof(struct linefeed) )); - regw_u32(RCC_APB2ENR, 0x4005, 0, SETBIT);// enable clock to UART1, AFIO and GPIOA + //regw_u32(RCC_APB2ENR, 0x4005, 0, SETBIT);// enable clock to UART1, AFIO and GPIOA + rsetbitsfrom(RCC_APB2ENR, 0, 0x4005); /* (after enable GPIOA), on PA9&PA10 and set mode * to alternative output */ - regw_u32(GPIOA_CRH, 0x444444D4, 0, OWRITE); - regw_u8(AFIO_EVCR, 0x89, 0, OWRITE);// set event control register, output on PA, Pin 9 TODO: check + //regw_u32(GPIOA_CRH, 0x444444D4, 0, OWRITE); + rwrite(GPIOA_CRH, 0x444444D4); + //regw_u8(AFIO_EVCR, 0x89, 0, OWRITE);// set event control register, output on PA, Pin 9 TODO: check + rsetbitsfrom(AFIO_EVCR, 0, 0x89); //disable temporarily to set values - regw_u8(USART1_CR1, 0x0, 13, SETBIT); + //regw_u8(USART1_CR1, 0x0, 13, SETBIT); + rclrbit(USART1_CR1, 13); set_baudrate(); - regw_u32(USART1_CR2, 0x0000, 0, OWRITE); //set stop bit, default is 1 stop bit 0x00 + //regw_u32(USART1_CR2, 0x0000, 0, OWRITE); //set stop bit, default is 1 stop bit 0x00 + rwrite(USART1_CR2, 0x0000); /* parity = 8 bit, UART1 enabled, * TX and RX enabled, interrupts enabled */ - //regw_u32(USART1_CR1, 0x000030AC, 0, O_WRITE); - regw_u32(USART1_CR1, 0x0000302C, 0, OWRITE); + //regw_u32(USART1_CR1, 0x0000302C, 0, OWRITE); + rwrite(USART1_CR1, 0x0000302C); ivt_set_gate(53, uart_handler, 0); - *NVIC_ISER1 = (1 << 5); // Enable UART interrupt at NVIC -} - -static void wait() { - for (int i = 0; i < 400; i++); + rsetbit(NVIC_ISER1, 5); } void uart_putc(unsigned char ch) { if (ch == '\n') { - while (*USART1_SR & 0x0C) { } // transmit data register empty and complete + while(!rchkbit(USART1_SR, 6)); regw_u8(USART1_DR, 0x0D, 0, OWRITE); // return line } - - while (*USART1_SR & 0x0C) {} + while(!rchkbit(USART1_SR, 6)); regw_u8(USART1_DR, ch, 0, OWRITE); - - wait(); } char uart_getc(void) { diff --git a/include/sys/mmap.h b/include/sys/mmap.h index 71ecbd5..6dda221 100644 --- a/include/sys/mmap.h +++ b/include/sys/mmap.h @@ -51,7 +51,7 @@ #define STK_RELOAD MEM_ADDR(0xE000E014) #define STK_CALIB MEM_ADDR(0xE000E01C) -/* CLOCK REGISTER */ +/* RESET AND CLOCK REGISTER */ #define RCC_CR MEM_ADDR(0x40021000) #define RCC_CFGR MEM_ADDR(0x40021004) #define RCC_BDCR MEM_ADDR(0x40021020) @@ -68,8 +68,11 @@ #define GPIOA_CRH MEM_ADDR(0x40010804) // for USART1 #define GPIOB_CRL MEM_ADDR(0x40010C00) // low register (!) for I2C1 -#define GPIOC_CRL MEM_ADDR(0x40011000) // for led -#define GPIOC_ODR MEM_ADDR(0x4001100C) // +#define GPIOC_CRL MEM_ADDR(0x40011000) // led +#define GPIOC_ODR MEM_ADDR(0x4001100C) + +//#define GPIOD_CRL MEM_ADDR(0x40011400) +//#define GPIOD_ODR MEM_ADDR(0x4001140C) #define AFIO_EVCR MEM_ADDR(0x40010000) @@ -94,3 +97,13 @@ #define USART1_CR1 MEM_ADDR(0x4001380C) #define USART1_CR2 MEM_ADDR(0x40013810) #define USART1_CR3 MEM_ADDR(0x40013814) + +/* REAL TIME CLOCK REGISTERS */ +#define RTC_CRH MEM_ADDR(0x40002800) // interrupts +#define RTC_CRL MEM_ADDR(0x40002804) +#define RTC_PRLL MEM_ADDR(0x4000280C) +#define RTC_CNTH MEM_ADDR(0x40002818) +#define RTC_CNTL MEM_ADDR(0x4000281C) + +/* BACKUP (CALIBR) REGISTERS */ +#define BKP_RTCCR MEM_ADDR(0x40006C2C) // RTC Calibration diff --git a/include/sys/robsys.h b/include/sys/robsys.h index 162dafc..78aedef 100644 --- a/include/sys/robsys.h +++ b/include/sys/robsys.h @@ -9,13 +9,16 @@ * rates etc. */ #define ENABLE_HSE -#define ENABLE_RTC //efine CRYSTAL_MHZ 8 //efine CLKSPEED_MHZ 72 extern void clock_init(); -extern int clock_test(); +// extern int clock_test(); // extern void clock_reset(); +/* RTC.C */ +#define ENABLE_RTC +extern void rtc_init(); + /* IVT.C */ extern void ivt_init(); extern void ivt_set_gate(unsigned char, void *(), short); diff --git a/main.c b/main.c index 4240f0c..ccf6015 100644 --- a/main.c +++ b/main.c @@ -24,6 +24,12 @@ #include #include +//void sleep() { +// +// __asm__ __volatile__("wfe"); +// +//} + void main() { clock_init(); @@ -32,6 +38,7 @@ void main() // cputs("ROBSYS LOADING...\n"); systick_init(); led_init(); + rtc_init(); // SPEED_TEST /* cputs("START TEST (8MHz) \n"); @@ -50,9 +57,9 @@ void main() a + 2; } cputs("END TEST\n"); */ - sysinfo(); + // tm1637_init(); // tm1637_start(); diff --git a/rtc.c b/rtc.c new file mode 100644 index 0000000..9ffffc7 --- /dev/null +++ b/rtc.c @@ -0,0 +1,85 @@ +/* (CC-BY-NC-SA) ROBIN KRENS - ROBIN @ ROBINKRENS.NL + * + * $LOG$ + * 2019/7/30 - ROBIN KRENS + * Initial version + * + * $DESCRIPTION$ + * + * */ + +#include +#include +#include + +#include +#include + +#include +#include + + +static void periodic_intr() { + + while(!rchkbit(RTC_CRL, 5)); // Check last write is terminated + rsetbit(RTC_CRL, 4); + + rsetbit(RTC_CRH, 0); // enable periodic (second) interrupt + + while(!rchkbit(RTC_CRL, 5)); + + rwrite(RTC_PRLL, 0x7FFF); // 1 second + rclrbit(RTC_CRL, 4); + while(!rchkbit(RTC_CRL, 5)); // Check last write is terminated +} + +static void calibrate_rtc() { + + +// rsetbit(BKP_RTCCR, 7); // enable CC0, +// while(!rchkbit(RTC_CRL, 5)); // Check last write is terminated +// rsetbit(RTC_CRL, 4); + + // Set up and check tamper pin + +// rclrbit(RTC_CRL, 4); +// while(!rchkbit(RTC_CRL, 5)); // Check last write is terminated +} + +void * rtc_handler() { + + //cputs("TICKING IN REAL TIME\n"); + rclrbit(RTC_CRL, 0); +} + +static void setup_rtc() { + +// TODO: long time to get stable? + /* Enable PWREN and BKPEN */ + rsetbit(RCC_APB1ENR, 28); + rsetbit(RCC_APB1ENR, 27); + + /* Enable access to backup registers and RTC */ + rsetbit(PWR_CR, 8); + + rsetbit(RCC_BDCR, 0); /* LSE enable */ + while(!rchkbit(RCC_BDCR, 1)); /* wait for LSE to come up */ + + rsetbitsfrom(RCC_BDCR, 8, 0x1); /* use LSE as RTC source */ + rsetbit(RCC_BDCR, 15); /* enable RTC */ + + ivt_set_gate(19, rtc_handler, 0); /* setup interrupt handler */ + +// calibrate_rtc(); TODO: TAMPER PIN? + + periodic_intr();// setup periodic interrupt + +} + +void rtc_init() { + +#ifdef ENABLE_RTC + setup_rtc(); +#endif + +} diff --git a/term.c b/term.c index 51eb9cf..dba355b 100644 --- a/term.c +++ b/term.c @@ -15,14 +15,15 @@ #define BUFSIZE 200 #define MAXARGS 5 #define WHITESPACE "\t\r\n " -#define BUILTINCMDS 3 +#define BUILTINCMDS 4 int help(int, char**); /* * Built in commands * info -- shows basic info of system - * reset -- software reset + * uptime -- uptime; read from the RTC register + * reset -- software reset TODO * show [ADDRESS-ADDRESS] -- shows SRAM range * switchmode -- switch to unprivileged mode * */ @@ -37,11 +38,17 @@ struct cmd { struct cmd builtincmds[4]; -int help(int argc, char ** argsv) { +int info(int argc, char ** argsv) { sysinfo(); return 0; } +int uptime(int arg, char ** argsv) { + cputs("CURRENT UPTIME: "); + cputs(regtohex(*RTC_CNTL)); + cputchar('\n'); +} + int led(int argc, char ** argsv) { @@ -116,8 +123,8 @@ int exec_cmd(char * buf) { void terminal() { - builtincmds[0].name = "help"; - builtincmds[0].function = help; + builtincmds[0].name = "info"; + builtincmds[0].function = info; builtincmds[1].name = "led"; builtincmds[1].function = led; @@ -125,6 +132,10 @@ void terminal() { builtincmds[2].name = "show"; builtincmds[2].function = show; + builtincmds[3].name = "uptime"; + builtincmds[3].function = uptime; + + char *buf; cputs("WELCOME TO ROBSYS!\n");