From 6e00544afe1ae83fcf51f262cfa744953dc8d023 Mon Sep 17 00:00:00 2001
From: Robin Krens <robin@robinkrens.nl>
Date: Thu, 1 Aug 2019 23:32:49 +0800
Subject: [PATCH] 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.
---
 Makefile             |  2 +-
 clock.c              | 26 ----------------
 drivers/uart.c       | 39 ++++++++++--------------
 include/sys/mmap.h   | 19 ++++++++++--
 include/sys/robsys.h |  7 +++--
 main.c               |  9 +++++-
 rtc.c                | 85 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 term.c               | 21 +++++++++----
 8 files changed, 147 insertions(+), 61 deletions(-)
 create mode 100644 rtc.c

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 <drivers/uart.h>
 
-#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 <drivers/led.h>
 #include <drivers/tm1637.h>
 
+//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 <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#include <sys/robsys.h>
+#include <sys/mmap.h>
+
+#include <lib/regfunc.h>
+#include <lib/stdio.h>
+
+
+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");
  
-- 
2.7.4