From fd13d29f0c5ccc8a357df167b89b454650231adc Mon Sep 17 00:00:00 2001 From: Renaud Fivet Date: Sat, 5 Dec 2020 08:13:29 +0800 Subject: [PATCH] uptime -- tells how long the system has been running --- Makefile | 3 +- printf.c | 77 +++++++++++++++++++++++++++++++++ putchar.c | 12 ++++++ system.h | 12 ++++++ uplow.2.c | 124 +++++++++++++++++++++++++++++++++++++++++++++++++++++ uptime.1.c | 2 +- uptime.c | 47 ++++++++++++++++++++ 7 files changed, 275 insertions(+), 2 deletions(-) create mode 100644 printf.c create mode 100644 putchar.c create mode 100644 system.h create mode 100644 uplow.2.c create mode 100644 uptime.c diff --git a/Makefile b/Makefile index 06e895d..5fccdca 100644 --- a/Makefile +++ b/Makefile @@ -30,7 +30,8 @@ PROJECT = f030f4 #SRCS = startup.c init.c success.c #SRCS = startup.c board.c success.c #SRCS = startup.c usart1tx.c hello.c -SRCS = startup.c uplow.1.c uptime.1.c +#SRCS = startup.c uplow.1.c uptime.1.c +SRCS = startup.c uplow.2.c uptime.c printf.c putchar.c OBJS = $(SRCS:.c=.o) CPU = -mthumb -mcpu=cortex-m0 CFLAGS = $(CPU) -g -Wall -Wextra -Os diff --git a/printf.c b/printf.c new file mode 100644 index 0000000..bd42702 --- /dev/null +++ b/printf.c @@ -0,0 +1,77 @@ +/* printf.c -- format and print data */ +/* Copyright (c) 2020 Renaud Fivet */ + +#include +#include +#include "system.h" /* kputc(), kputs() */ + +static int kputu( unsigned u, unsigned d) { + char s[ 12] ; /* room for 11 octal digit + EOS */ + char *p = &s[ sizeof s - 1] ; /* point to last byte */ + + *p = 0 ; /* null terminated string */ + do { + unsigned r = u % d ; + u /= d ; + *--p = "0123456789ABCDEF"[ r] ; + } while( u) ; + + return kputs( p) ; +} + +static int kputi( int i) { + int flag = i < 0 ; + if( flag) { + i = -i ; + kputc( '-') ; + } + + return flag + kputu( i, 10) ; +} + +int printf( const char *fmt, ...) { + va_list ap ; + int cnt = 0 ; + int c ; /* current char in format string */ + + va_start( ap, fmt) ; + while( ( c = *fmt++) != 0) + if( c != '%') { + cnt += 1 ; kputc( c) ; + } else if( ( c = *fmt++) == 0) { + cnt += 1 ; kputc( '%') ; + break ; + } else + switch( c) { + case 'c': + cnt += 1 ; kputc( va_arg( ap, int /* char */)) ; + break ; + case 'o': + cnt += kputu( va_arg( ap, unsigned), 8) ; + break ; + case 'u': + cnt += kputu( va_arg( ap, unsigned), 10) ; + break ; + case 'x': + case 'X': + cnt += kputu( va_arg( ap, unsigned), 16) ; + break ; + case 'i': + case 'd': + cnt += kputi( va_arg( ap, int)) ; + break ; + case 's': + cnt += kputs( va_arg( ap, char *)) ; + break ; + default: + cnt += 1 ; kputc( '%') ; + /* fallthrough */ + case '%': + cnt += 1 ; kputc( c) ; + } + + va_end( ap) ; + return cnt ; +} + +/* end of printf.c */ diff --git a/putchar.c b/putchar.c new file mode 100644 index 0000000..7e1d598 --- /dev/null +++ b/putchar.c @@ -0,0 +1,12 @@ +/* putchar.c -- write a character to stdout */ +/* Copyright (c) 2020 Renaud Fivet */ + +#include +#include "system.h" /* kputc() */ + +int putchar( int c) { + kputc( c) ; + return c ; +} + +/* end of putchar.c */ diff --git a/system.h b/system.h new file mode 100644 index 0000000..8aa1ecf --- /dev/null +++ b/system.h @@ -0,0 +1,12 @@ +/* system.h -- system services */ +/* Copyright (c) 2020 Renaud Fivet */ + +extern volatile unsigned uptime ; /* seconds elapsed since boot */ + +int init( void) ; /* System initialization, called once at startup */ + +void kputc( unsigned char c) ; /* character output */ +int kputs( const char s[]) ; /* string output */ +void yield( void) ; /* give way */ + +/* end of system.h */ diff --git a/uplow.2.c b/uplow.2.c new file mode 100644 index 0000000..85578f2 --- /dev/null +++ b/uplow.2.c @@ -0,0 +1,124 @@ +/* uplow.2.c -- uptime lower layer +** Copyright (c) 2020 Renaud Fivet +** +** implements system.h interface +** uptime = seconds elapsed since boot +** SysClck 8MHz HSI based, baudrate 9600, Busy wait transmission +** user LED toggled every second +** SysTick interrupt every second +*/ + +#include "system.h" /* implements system.h */ + +#define SYSTICK ((volatile long *) 0xE000E010) +#define SYSTICK_CSR SYSTICK[ 0] +#define SYSTICK_RVR SYSTICK[ 1] +#define SYSTICK_CVR SYSTICK[ 2] + +#define CAT( a, b) a##b +#define HEXA( a) CAT( 0x, a) +#define RCC ((volatile long *) 0x40021000) +#define RCC_AHBENR RCC[ 5] +#define RCC_AHBENR_IOP( h) (1 << (17 + HEXA( h) - 0xA)) +#define RCC_APB2ENR RCC[ 6] +#define RCC_APB2ENR_USART1EN 0x00004000 /* 14: USART1 clock enable */ + +#define GPIOA ((volatile long *) 0x48000000) +#define GPIOB ((volatile long *) 0x48000400) +#define GPIO( x) CAT( GPIO, x) +#define MODER 0 +#define ODR 5 +#define AFRH 9 + +#define USART1 ((volatile long *) 0x40013800) +#define CR1 0 /* Config */ +#define BRR 3 /* Baudrate */ +#define ISR 7 /* Interrupt and Status */ +#define TDR 10 /* Transmit Data */ +#define USART_CR1_TE 8 /* 3: Transmit Enable */ +#define USART_CR1_RE 4 /* 2: Receive Enable */ +#define USART_CR1_UE 1 /* 0: USART Enable */ +#define USART_ISR_TXE (1 << 7) /* 7: Transmit Data Register Empty */ + +/* user LED ON when PA4 is high */ +#define LED_IOP A +#define LED_PIN 4 +#define LED_ON 1 + +void kputc( unsigned char c) { /* character output */ + static unsigned char lastc ; + + if( c == '\n' && lastc != '\r') + kputc( '\r') ; + +/* Active wait while transmit register is full */ + while( (USART1[ ISR] & USART_ISR_TXE) == 0) ; + + USART1[ TDR] = c ; + lastc = c ; +} + +int kputs( const char s[]) { /* string output */ + int cnt = 0 ; + int c ; + + while( (c = *s++) != 0) { + kputc( c) ; + cnt += 1 ; + } + + return cnt ; +} + +void yield( void) { /* give way */ + __asm( "WFI") ; /* Wait for System Tick Interrupt */ +} + +volatile unsigned uptime ; /* seconds elapsed since boot */ + +#ifdef LED_ON +static void userLEDtoggle( void) { + GPIO( LED_IOP)[ ODR] ^= 1 << LED_PIN ; /* Toggle User LED */ +} +#endif + +void SysTick_Handler( void) { + uptime += 1 ; +#ifdef LED_ON + userLEDtoggle() ; +#endif +} + +int init( void) { +/* By default SYSCLK == HSI [8MHZ] */ + +/* SYSTICK */ + SYSTICK_RVR = 1000000 - 1 ; /* HBA / 8 */ + SYSTICK_CVR = 0 ; + SYSTICK_CSR = 3 ; /* HBA / 8, Interrupt ON, Enable */ + /* SysTick_Handler will execute every 1s from now on */ + +#ifdef LED_ON +/* User LED ON */ + RCC_AHBENR |= RCC_AHBENR_IOP( LED_IOP) ; /* Enable IOPx periph */ + GPIO( LED_IOP)[ MODER] |= 1 << (LED_PIN * 2) ; /* LED_IO Output [01], + ** over default 00 */ + /* OTYPER Push-Pull by default */ + /* Pxn output default LOW at reset */ +# if LED_ON + userLEDtoggle() ; +# endif +#endif + +/* USART1 9600 8N1 */ + RCC_AHBENR |= RCC_AHBENR_IOP( A) ; /* Enable GPIOA periph */ + GPIOA[ MODER] |= 0x0A << (9 * 2) ; /* PA9-10 ALT 10, over default 00 */ + GPIOA[ AFRH] |= 0x110 ; /* PA9-10 AF1 0001, over default 0000 */ + RCC_APB2ENR |= RCC_APB2ENR_USART1EN ; + USART1[ BRR] = 8000000 / 9600 ; /* PCLK [8MHz] */ + USART1[ CR1] |= USART_CR1_UE | USART_CR1_TE ; /* Enable USART & Tx */ + + return 0 ; +} + +/* end of uplow.2.c */ diff --git a/uptime.1.c b/uptime.1.c index 5165693..1b351c2 100644 --- a/uptime.1.c +++ b/uptime.1.c @@ -1,4 +1,4 @@ -/* uptime.1.c --tells how long the system has been running +/* uptime.1.c -- tells how long the system has been running ** Copyright (c) 2020 Renaud Fivet ** ** v1 displays the number of seconds elapsed since boot diff --git a/uptime.c b/uptime.c new file mode 100644 index 0000000..1b8e8fe --- /dev/null +++ b/uptime.c @@ -0,0 +1,47 @@ +/* uptime.c -- tells how long the system has been running */ +/* Copyright (c) 2020 Renaud Fivet */ + +#include +#include "system.h" /* uptime, yield() */ + +static void display( unsigned u, const char *s) { + if( u) + printf( " %d %s%s", u, s, &"s"[ u <= 1]) ; +} + +int main( void) { + static unsigned last ; + + for( ;;) + if( last != uptime) { + unsigned w, d, h, m ,s ; + + last = uptime ; + d = h = m = 0 ; + s = last % 60 ; + w = last / 60 ; + if( w) { + m = w % 60 ; + w /= 60 ; + if( w) { + h = w % 24 ; + w /= 24 ; + if( w) { + d = w % 7 ; + w /= 7 ; + } + } + } + + printf( "up") ; + display( w, "week") ; + display( d, "day") ; + display( h, "hour") ; + display( m, "minute") ; + display( s, "second") ; + printf( "\n") ; + } else + yield() ; /* Wait for System Tick Interrupt */ +} + +/* end of uptime.c */