From 4bfee77ecbb19ef2143a1cd486cfa92bd3aceef4 Mon Sep 17 00:00:00 2001 From: phfr24 Date: Sun, 12 Jul 2026 17:25:43 -0300 Subject: [PATCH] organize --- Makefile | 3 +- exceptions.c | 53 +++++++++++++++++++++++++++ kentry.c | 27 ++++---------- kernel.c | 100 --------------------------------------------------- led.c | 33 +++++++++++++++++ led.h | 9 +++++ sysclk.c | 25 +++++++++++++ sysclk.h | 6 ++++ uart.c | 80 +++++++++++++++++++++++++++++++++++++++++ uart.h | 9 +++++ 10 files changed, 224 insertions(+), 121 deletions(-) create mode 100644 exceptions.c delete mode 100644 kernel.c create mode 100644 led.c create mode 100644 led.h create mode 100644 sysclk.c create mode 100644 sysclk.h create mode 100644 uart.c create mode 100644 uart.h diff --git a/Makefile b/Makefile index f0ec81f..3c19779 100644 --- a/Makefile +++ b/Makefile @@ -32,6 +32,7 @@ CFLAGS := -march=armv7e-m+fp \ -Wextra \ -Wconversion \ -Wstrict-prototypes \ + -Wmissing-prototypes \ -Wshadow \ -Wundef \ -Wdouble-promotion \ @@ -46,7 +47,7 @@ OCFLAGS := --output-target=binary # --------------------------------------------------------------------------- # -objs := kernel.o kentry.o +objs := $(patsubst %.c, %.o, $(wildcard *.c)) lds := kernel.ld LDFLAGS += -T $(lds) diff --git a/exceptions.c b/exceptions.c new file mode 100644 index 0000000..b3afaaa --- /dev/null +++ b/exceptions.c @@ -0,0 +1,53 @@ +#include "link.h" +#include "led.h" +#include "sysclk.h" +#include "uart.h" + +/* Initialize just enough to be able to handle a fault. */ +__attribute__ ((noinline, used)) static void +sys_init (void) +{ + unsigned int *src, *dst; + + /* Relocate .data section to SRAM */ + src = &_data_lma_start; + dst = &_data_vma_start; + + while (dst < &_data_vma_end) + *(dst++) = *(src++); + + /* Initialize .bss */ + dst = &_bss_vma_start; + + while (dst < &_bss_vma_end) + *(dst++) = 0; + + led_init (); + sysclk_init (); + uart_init (); +} + +/* Startup */ +__attribute__ ((naked, noreturn)) static void +reset_handler (void) +{ + /* Set FAULTMASK */ + asm ("cpsid f"); + + /* This function is the core logic for reset_handler (). We just need it so + * that when we jump to kentry the stack is empty. */ + asm ("bl sys_init"); + + /* Clear FAULTMASK */ + asm ("cpsie f"); + + /* Jump to kernel entry code. When reset_handler () is called we are already + * running on Thread mode (Privileged), so we can just jump directly. */ + asm ("b kentry"); +} + +__attribute__ ((section (".vector_table"), used)) +static unsigned long const vector_table[] = { + (unsigned long) &_sram_end, + (unsigned long) reset_handler, +}; diff --git a/kentry.c b/kentry.c index 33b8295..e9eab94 100644 --- a/kentry.c +++ b/kentry.c @@ -1,4 +1,7 @@ -#include "stm32f411.h" +#include "uart.h" +#include "led.h" + +__attribute__ ((noreturn)) void kentry (void); static const char *text[] = { "hello, friend.\r\n", @@ -15,7 +18,7 @@ static const char *text[] = { void kentry (void) { - unsigned int line, off; + unsigned int line; /* Test UART and LED ---------------------------------------------------- */ @@ -23,24 +26,8 @@ kentry (void) { for (line = 0; line < sizeof text / sizeof *text; ++line) { - /* Print current line */ - off = 0; - while (text[line][off]) - { - /* TXE: Transmit data register empty */ - while (!(*USART1_SR & (1u << 7))); /* 0: Data is not transferred - to the shift register */ - - /* DR[8:0]: Data value */ - *USART1_DR = text[line][off++]; - } - - /* TC: Transmission complete */ - while (!(*USART1_SR & (1u << 6))); /* 0: Transmission is not - complete */ - - /* Blink LED */ - *GPIOC_ODR ^= (1u << 13); + kputs_busytc (text[line]); + led_toggle (); } } } diff --git a/kernel.c b/kernel.c deleted file mode 100644 index 1545c6e..0000000 --- a/kernel.c +++ /dev/null @@ -1,100 +0,0 @@ -#include "link.h" -#include "stm32f411.h" - -__attribute__ ((noreturn)) extern void kentry (void); - -static void -reset_handler (void) -{ - unsigned int *src, *dst; - - /* Set FAULTMASK */ - asm ("cpsid f"); - - /* Initialize .data and .bss in SRAM ------------------------------------ */ - - /* Relocate .data section */ - src = &_data_lma_start; - dst = &_data_vma_start; - - while (dst < &_data_vma_end) - *(dst++) = *(src++); - - /* Initialize .bss */ - dst = &_bss_vma_start; - - while (dst < &_bss_vma_end) - *(dst++) = 0; - - /* LED setup ------------------------------------------------------------ */ - - /* GPIOCEN: IO port C clock enable */ - *RCC_AHB1ENR |= (1u << 2); /* 1: IO port C clock enabled */ - /* MODERy[1:0]: Port x configuration bits (y = 0..15) */ - *GPIOC_MODER &= ~(0b11u << 26); /* Clear PC13 bits */ - *GPIOC_MODER |= (1u << 26); /* 01: General purpose output mode */ - - /* PC13: 0 = LED on - * 1 = LED off */ - - /* SYSCLK setup --------------------------------------------------------- */ - - /* HSEBYP: HSE clock bypass */ - *RCC_CR &= ~(1u << 18); /* 0: HSE oscillator not bypassed */ - /* HSEON: HSE clock enable */ - *RCC_CR |= (1u << 16); /* 1: HSE oscillator ON */ - /* HSERDY: HSE clock ready flag */ - while (!(*RCC_CR & (1u << 17))); /* 0: HSE oscillator not ready */ - /* SW: System clock switch */ - *RCC_CFGR &= ~(0b11u); /* Clear SW bits */ - *RCC_CFGR |= (0b01u); /* 01: HSE oscillator selected as system clock */ - /* SWS: System clock switch status */ - while ((*RCC_CFGR & (0b11u << 2)) != (0b01u << 2)); /* 01: HSE oscillator used - as the system clock */ - /* HSION: Internal high-speed clock enable */ - *RCC_CR &= ~(1u); /* 0: HSI oscillator OFF */ - - /* UART setup ----------------------------------------------------------- */ - - /* GPIOAEN: IO port A clock enable */ - *RCC_AHB1ENR |= (1u); /* 1: IO port A clock enabled */ - /* MODERy[1:0]: Port x configuration bits (y = 0..15) */ - *GPIOA_MODER &= ~(0b1111u << 18); /* Clear PA9 and PA10 bits */ - *GPIOA_MODER |= (0b1010u << 18); /* 10: Alternate function mode */ - /* AFRHy: Alternate function selection for port x bit y (y = 8..15) */ - *GPIOA_AFRH &= ~(0b11111111u << 4); /* Clear PA9 and PA10 bits */ - *GPIOA_AFRH |= (0b01110111u << 4); /* 0111: AF7 */ - - /* PA9: USART1_TX - * PA10: USART1_RX */ - - /* USART1EN: USART1 clock enable */ - *RCC_APB2ENR |= (1u << 4); /* 1: USART1 clock enabled */ - /* UE: USART enable */ - *USART1_CR1 |= (1u << 13); /* 1: USART enable */ - /* M: Word length */ - *USART1_CR1 &= ~(1u << 12); /* 0: 1 Start bit, 8 Data bits, n Stop bit */ - /* PCE: Parity control enable */ - *USART1_CR1 &= ~(1u << 10); /* 0: Parity control disabled */ - /* STOP: STOP bits */ - *USART1_CR2 &= ~(0b11u << 12); /* 00: 1 Stop bit */ - /* Clock frequency: 25MHz - * Desired baud rate: 1.2 KBps - * USARTDIV = 1302.0625 */ - *USART1_BRR = (1302u << 4) | 1u; /* mantissa and fraction (/16) */ - /* TE: Transmitter enable */ - *USART1_CR1 |= (1u << 3); /* 1: Transmitter is enabled */ - - /* Jump to kernel entry code -------------------------------------------- */ - - /* Clear FAULTMASK */ - asm ("cpsie f"); - - kentry (); -} - -__attribute__ ((section (".vector_table"), used)) -static unsigned long const vector_table[] = { - (unsigned long) &_sram_end, - (unsigned long) reset_handler, -}; diff --git a/led.c b/led.c new file mode 100644 index 0000000..6627535 --- /dev/null +++ b/led.c @@ -0,0 +1,33 @@ +#include "led.h" +#include "stm32f411.h" + +void +led_init (void) +{ + /* GPIOCEN: IO port C clock enable */ + *RCC_AHB1ENR |= (1u << 2); /* 1: IO port C clock enabled */ + /* MODERy[1:0]: Port x configuration bits (y = 0..15) */ + *GPIOC_MODER &= ~(0b11u << 26); /* Clear PC13 bits */ + *GPIOC_MODER |= (1u << 26); /* 01: General purpose output mode */ + + /* PC13: 0 = LED on + * 1 = LED off */ +} + +void +led_on (void) +{ + *GPIOC_ODR &= ~(1u << 13); +} + +void +led_off (void) +{ + *GPIOC_ODR |= (1u << 13); +} + +void +led_toggle (void) +{ + *GPIOC_ODR ^= (1u << 13); +} diff --git a/led.h b/led.h new file mode 100644 index 0000000..5f02ce7 --- /dev/null +++ b/led.h @@ -0,0 +1,9 @@ +#ifndef _LED_H_ +#define _LED_H_ + +void led_init (void); +void led_on (void); +void led_off (void); +void led_toggle (void); + +#endif /* _LED_H_ */ diff --git a/sysclk.c b/sysclk.c new file mode 100644 index 0000000..a106774 --- /dev/null +++ b/sysclk.c @@ -0,0 +1,25 @@ +#include "sysclk.h" +#include "stm32f411.h" + +void +sysclk_init (void) +{ + /* HSEBYP: HSE clock bypass */ + *RCC_CR &= ~(1u << 18); /* 0: HSE oscillator not bypassed */ + + /* HSEON: HSE clock enable */ + *RCC_CR |= (1u << 16); /* 1: HSE oscillator ON */ + + /* HSERDY: HSE clock ready flag */ + while (!(*RCC_CR & (1u << 17))); /* 0: HSE oscillator not ready */ + + /* SW: System clock switch */ + *RCC_CFGR &= ~(0b11u); /* Clear SW bits */ + *RCC_CFGR |= (0b01u); /* 01: HSE oscillator selected as system clock */ + + /* SWS: System clock switch status */ + while ((*RCC_CFGR & (0b11u << 2)) != (0b01u << 2)); /* 01: HSE oscillator used + as the system clock */ + /* HSION: Internal high-speed clock enable */ + *RCC_CR &= ~(1u); /* 0: HSI oscillator OFF */ +} diff --git a/sysclk.h b/sysclk.h new file mode 100644 index 0000000..b02ae6a --- /dev/null +++ b/sysclk.h @@ -0,0 +1,6 @@ +#ifndef _SYSCLK_H_ +#define _SYSCLK_H_ + +void sysclk_init (void); + +#endif /* _SYSCLK_H_ */ diff --git a/uart.c b/uart.c new file mode 100644 index 0000000..7174979 --- /dev/null +++ b/uart.c @@ -0,0 +1,80 @@ +#include "uart.h" +#include "stm32f411.h" + +/* Wait for data to be transferred into the shift register. */ +static void +busywait_txe (void) +{ + /* TXE: Transmit data register empty */ + while (!(*USART1_SR & (1u << 7))); /* 0: Data is not transferred to the shift + register */ +} + +/* Wait for transmission of the last frame. */ +static void +busywait_tc (void) +{ + /* TC: Transmission complete */ + while (!(*USART1_SR & (1u << 6))); /* 0: Transmission is not complete */ +} + +static void +tx (char c) +{ + /* DR[8:0]: Data value */ + *USART1_DR = c; +} + +void +uart_init (void) +{ + /* GPIOAEN: IO port A clock enable */ + *RCC_AHB1ENR |= (1u); /* 1: IO port A clock enabled */ + + /* MODERy[1:0]: Port x configuration bits (y = 0..15) */ + *GPIOA_MODER &= ~(0b1111u << 18); /* Clear PA9 and PA10 bits */ + *GPIOA_MODER |= (0b1010u << 18); /* 10: Alternate function mode */ + + /* AFRHy: Alternate function selection for port x bit y (y = 8..15) */ + *GPIOA_AFRH &= ~(0b11111111u << 4); /* Clear PA9 and PA10 bits */ + *GPIOA_AFRH |= (0b01110111u << 4); /* 0111: AF7 */ + + /* PA9: USART1_TX + * PA10: USART1_RX */ + + /* USART1EN: USART1 clock enable */ + *RCC_APB2ENR |= (1u << 4); /* 1: USART1 clock enabled */ + + /* UE: USART enable */ + *USART1_CR1 |= (1u << 13); /* 1: USART enable */ + + /* M: Word length */ + *USART1_CR1 &= ~(1u << 12); /* 0: 1 Start bit, 8 Data bits, n Stop bit */ + + /* PCE: Parity control enable */ + *USART1_CR1 &= ~(1u << 10); /* 0: Parity control disabled */ + + /* STOP: STOP bits */ + *USART1_CR2 &= ~(0b11u << 12); /* 00: 1 Stop bit */ + + /* Clock frequency: 25MHz + * Desired baud rate: 1.2 KBps */ + + /* Mantissa and fraction (/16) */ + *USART1_BRR = (1302u << 4) | 1u; /* USARTDIV = 1302.0625 */ + + /* TE: Transmitter enable */ + *USART1_CR1 |= (1u << 3); /* 1: Transmitter is enabled */ +} + +void +kputs_busytc (const char *str) +{ + while (*str) + { + busywait_txe (); + tx (*(str++)); + } + + busywait_tc (); +} diff --git a/uart.h b/uart.h new file mode 100644 index 0000000..ee16d4c --- /dev/null +++ b/uart.h @@ -0,0 +1,9 @@ +#ifndef _UART_H_ +#define _UART_H_ + +void uart_init (void); + +/* Busy waiting, wait for Transmission Complete (TC). */ +void kputs_busytc (const char *str); + +#endif /* _UART_H_ */ -- 2.54.0