diff options
author | Josh Rahm <joshuarahm@gmail.com> | 2020-11-24 00:38:09 -0700 |
---|---|---|
committer | Josh Rahm <joshuarahm@gmail.com> | 2020-11-24 00:53:28 -0700 |
commit | 2478a549b9f64c50310da41c861b8f86fdea2861 (patch) | |
tree | 3a62960f83453f354cbf309ac0722ed2ea6c27c7 | |
parent | 9dab2bf91ed3e6af7c7b07590ccc8c3b211a763a (diff) | |
download | stm32l4-2478a549b9f64c50310da41c861b8f86fdea2861.tar.gz stm32l4-2478a549b9f64c50310da41c861b8f86fdea2861.tar.bz2 stm32l4-2478a549b9f64c50310da41c861b8f86fdea2861.zip |
Add new system for startup.
Now instead of init() and main() being responsible for all
initialization, individual modules can link in their own
initialization routines.
There are 7 levels for these initializiation routines.
So far these are how the levels are defined
level 0 - Here the world is dark. Nothing is initialized.
This level is responsible for initializing the
system clock.
level 1 - The system clock has been configured, but nothing else. Not
even global variables. This level is responsible for loading
the data sections from flash and clearing the .bss section.
level 2 - USART2 is enabled and set to be the main kernel logging
vehicle. From this point on klogf(...) can be used.
level 3 - The NVIC is reset to point to the flash. From this point
on interrupts can be received. I expect this is where
most core initialization routines will take place
levels 4 to 7 - User initializiation levels.
main - main() is called after all 8 initialization levels have executed,
so in a sense main() is like a 9th initialization level, except
that there is can be only one main() routine whereas there can be
multiple initalization routines per level.
-rw-r--r-- | 02-usart/include/arch/stm32l4xxx/peripherals/clock.h | 2 | ||||
-rw-r--r-- | 02-usart/include/arch/stm32l4xxx/peripherals/usart.h | 3 | ||||
-rw-r--r-- | 02-usart/include/kern/init.h | 67 | ||||
-rw-r--r-- | 02-usart/include/kern/log.h | 12 | ||||
-rw-r--r-- | 02-usart/linker/linker_script.ld | 19 | ||||
-rw-r--r-- | 02-usart/src/arch/stm32l4xxx/peripherals/clock.c | 11 | ||||
-rw-r--r-- | 02-usart/src/arch/stm32l4xxx/peripherals/usart.c | 13 | ||||
-rw-r--r-- | 02-usart/src/kern/init.c (renamed from 02-usart/src/arch/stm32l4xxx/peripherals/init.c) | 45 | ||||
-rw-r--r-- | 02-usart/src/kern/log.c | 55 | ||||
-rw-r--r-- | 02-usart/src/kern/main.c | 109 |
10 files changed, 224 insertions, 112 deletions
diff --git a/02-usart/include/arch/stm32l4xxx/peripherals/clock.h b/02-usart/include/arch/stm32l4xxx/peripherals/clock.h index 6e461de..6f628fd 100644 --- a/02-usart/include/arch/stm32l4xxx/peripherals/clock.h +++ b/02-usart/include/arch/stm32l4xxx/peripherals/clock.h @@ -123,4 +123,6 @@ int configure_pll( pllm_divisor_t pllm, /* PLL denominator. */ pll_src_t pllsrc /* PLL source */); +uint8_t get_clock_mhz(); + #endif /* CORE_CLOCK_H__ */ diff --git a/02-usart/include/arch/stm32l4xxx/peripherals/usart.h b/02-usart/include/arch/stm32l4xxx/peripherals/usart.h index e42e31e..a1542f4 100644 --- a/02-usart/include/arch/stm32l4xxx/peripherals/usart.h +++ b/02-usart/include/arch/stm32l4xxx/peripherals/usart.h @@ -3,6 +3,7 @@ #include <arch.h> #include <stdint.h> +#include <stdarg.h> #include "kern/common.h" #include "arch/stm32l4xxx/peripherals/rcc.h" @@ -197,5 +198,7 @@ void usart_transmit_str_sync(__IO usart_t* usart, const char* str); void usart_printf(__IO usart_t* usart, const char* fmt, ...); +void usart_vprintf(__IO usart_t* usart, const char* fmt, va_list l); + #endif /* H__USART_ */ diff --git a/02-usart/include/kern/init.h b/02-usart/include/kern/init.h new file mode 100644 index 0000000..737b85f --- /dev/null +++ b/02-usart/include/kern/init.h @@ -0,0 +1,67 @@ +#ifndef INIT_H_ +#define INIT_H_ + +/** Globals annotated with _no_init will not be set during init1 bootup + * where the data segement is loaded from flash and the bss segment is + * cleared. + * + * This is useful for routines that run in the init0 boot procedure + * that need persistent globals. + * + * Note that initializing a global annotated with _no_init will have + * no effect as the variable will remain uninitialized until explicitly + * set by by the program. + */ +#define _no_init \ + __attribute((__section__(".noinit"))) + +#define init0 \ + static void init0fn(); \ + static __attribute((__section__(".init0"))) \ + __attribute((__used__)) \ + void(*init0_ptr)() = init0fn; \ + static void init0fn +#define init1 \ + static void init1fn(); \ + static __attribute((__section__(".init1"))) \ + __attribute((__used__)) \ + void(*init1_ptr)() = init1fn; \ + static void init1fn +#define init2 \ + static void init2fn(); \ + static __attribute((__section__(".init2"))) \ + __attribute((__used__)) \ + void(*init2_ptr)() = init2fn; \ + static void init2fn +#define init3 \ + static void init3fn(); \ + static __attribute((__section__(".init3"))) \ + __attribute((__used__)) \ + void(*init3_ptr)() = init3fn; \ + static void init3fn +#define init4 \ + static void init4fn(); \ + static __attribute((__section__(".init4"))) \ + __attribute((__used__)) \ + void(*init4_ptr)() = init4fn; \ + static void init4fn +#define init5 \ + static void init5fn(); \ + static __attribute((__section__(".init5"))) \ + __attribute((__used__)) \ + void(*init5_ptr)() = init5fn; \ + static void init5fn +#define init6 \ + static void init6fn(); \ + static __attribute((__section__(".init6"))) \ + __attribute((__used__)) \ + void(*init6_ptr)() = init6fn; \ + static void init6fn +#define init7 \ + static void init7fn(); \ + static __attribute((__section__(".init7"))) \ + __attribute((__used__)) \ + void(*init7_ptr)() = init7fn; \ + static void init7fn + +#endif /* INIT_H_ */ diff --git a/02-usart/include/kern/log.h b/02-usart/include/kern/log.h new file mode 100644 index 0000000..5e49def --- /dev/null +++ b/02-usart/include/kern/log.h @@ -0,0 +1,12 @@ +#ifndef LOG_H_ +#define LOG_H_ + +/* + * Defines logging capabilities. This logging unit will enable logging on + * the systems main USART output. + */ + +/** Similar to fprintf, but with a stripped-down format-string DSL. */ +void klogf(const char* fmt, ...); + +#endif diff --git a/02-usart/linker/linker_script.ld b/02-usart/linker/linker_script.ld index 348d03b..9a9f5b3 100644 --- a/02-usart/linker/linker_script.ld +++ b/02-usart/linker/linker_script.ld @@ -23,8 +23,27 @@ SECTIONS *(.data); DATA_SEGMENT_STOP = .; + INIT_ROUTINES_FLASH_START = + LOADADDR(.data) + (DATA_SEGMENT_STOP - DATA_SEGMENT_START); + + INITS_START = .; + *(.init0); + *(.init1); + *(.init2); + *(.init3); + *(.init4); + *(.init5); + *(.init6); + *(.init7); + INITS_END = .; + + INIT_ROUTINES_FLASH_STOP = + LOADADDR(.data) + (INITS_END - DATA_SEGMENT_START); + /* Align by 4 so we can optimize the copier to use uint32's. */ . = ALIGN(0x04); + + *(.noinit); } >sram1 AT>flash BSS_START = .; diff --git a/02-usart/src/arch/stm32l4xxx/peripherals/clock.c b/02-usart/src/arch/stm32l4xxx/peripherals/clock.c index 1029d39..9051572 100644 --- a/02-usart/src/arch/stm32l4xxx/peripherals/clock.c +++ b/02-usart/src/arch/stm32l4xxx/peripherals/clock.c @@ -5,10 +5,13 @@ #include "arch/stm32l4xxx/peripherals/clock.h" #include "arch/stm32l4xxx/peripherals/flash.h" +#include "kern/init.h" + #include <stdint.h> #define TIMEOUT 10000 + int pll_off() { uint32_t c; @@ -66,8 +69,16 @@ int configure_pll( return 0; } +static _no_init uint8_t clock_mHz; +uint8_t get_clock_mhz() +{ + return clock_mHz; +} + int set_system_clock_MHz(uint8_t mhz) { + clock_mHz = mhz; + /* Set the source of the system colck to MSI temporarily. */ set_system_clock_src(SYSTEM_CLOCK_SRC_MSI); diff --git a/02-usart/src/arch/stm32l4xxx/peripherals/usart.c b/02-usart/src/arch/stm32l4xxx/peripherals/usart.c index d37eee2..7309b48 100644 --- a/02-usart/src/arch/stm32l4xxx/peripherals/usart.c +++ b/02-usart/src/arch/stm32l4xxx/peripherals/usart.c @@ -97,9 +97,8 @@ void usart_enable_dma(__IO usart_t* usart, usart_enable_t enabled) }; } -void usart_printf(__IO usart_t* usart, const char* fmt, ...) +void usart_vprintf(__IO usart_t* usart, const char* fmt, va_list l) { - va_list l; union { void* ptr; char* str; @@ -107,8 +106,6 @@ void usart_printf(__IO usart_t* usart, const char* fmt, ...) } b; char buf[128]; - va_start(l, fmt); - while (*fmt != 0) { if (*fmt == '%') { switch (*(++fmt)) { @@ -145,3 +142,11 @@ void usart_printf(__IO usart_t* usart, const char* fmt, ...) end: va_end(l); } + +void usart_printf(__IO usart_t* usart, const char* fmt, ...) +{ + va_list l; + va_start(l, fmt); + + usart_vprintf(usart, fmt, l); +} diff --git a/02-usart/src/arch/stm32l4xxx/peripherals/init.c b/02-usart/src/kern/init.c index 47bfaa5..2531ca9 100644 --- a/02-usart/src/arch/stm32l4xxx/peripherals/init.c +++ b/02-usart/src/kern/init.c @@ -1,8 +1,13 @@ +#include "kern/init.h" + #include "arch.h" #include "arch/stm32l4xxx/peripherals/system.h" +#include "arch/stm32l4xxx/peripherals/clock.h" + +#include "kern/log.h" /* Forward-declare the main function. This is implemented in main.c. */ -void main(); +int main(); /* These are defined in the linker script. */ @@ -13,12 +18,19 @@ extern uint32_t DATA_SEGMENT_STOP; extern uint32_t BSS_START; extern uint32_t BSS_END; -/* - * Runs before main. Initializes the data and bss segments by loading them - * into memory. - */ -_Noreturn void on_reset() +extern void(*INIT_ROUTINES_FLASH_START)(); +extern void(*INIT_ROUTINES_FLASH_STOP)(); + +init0() +{ + /* Enable a higher clock speed. This is the first thing we do + * beacuse it will boost the boot up time. */ + set_system_clock_MHz(80); +} + +init1() { + /* Next, we'll copy the data sections from flash to ram. */ uint32_t* src; uint32_t* dest; @@ -35,10 +47,31 @@ _Noreturn void on_reset() while (dest != &BSS_END) { *(dest++) = 0; } +} + +init3() +{ + klogf("--- System Restart ---\n"); + klogf("Setting the vector offset table to point to the start of flash.\n"); /* Set the vector offset table to be at the start * of FLASH memory. */ SCB.vto_r = 0x08000000; +} + +/* + * Runs before main. Initializes the data and bss segments by loading them + * into memory. + */ +_Noreturn void on_reset() +{ + void (**initfn)(); + for(initfn = &INIT_ROUTINES_FLASH_START; + initfn < &INIT_ROUTINES_FLASH_STOP; + ++ initfn) { + + (*initfn)(); + } /* Jump to main. */ main(); diff --git a/02-usart/src/kern/log.c b/02-usart/src/kern/log.c new file mode 100644 index 0000000..a217183 --- /dev/null +++ b/02-usart/src/kern/log.c @@ -0,0 +1,55 @@ +#include "arch/stm32l4xxx/peripherals/usart.h" +#include "arch/stm32l4xxx/peripherals/clock.h" + +#include "kern/log.h" +#include "kern/init.h" +#include "kern/gpio/gpio_manager.h" + +#include "kern/common.h" + +void setup_usart2(uint32_t baud_rate); + +/** This module requires an initialization routine. This is a level2 routine, + * so anything running at level3 or lower is guaranteed to have access + * to the klong. */ +init2() +{ + setup_usart2(115200); + regset(USART2.c_r1, usart_txeie, 1); + regset(USART2.c_r1, usart_rxneie, 1); + usart_set_enabled(&USART2, USART_ENABLE_TX | USART_ENABLE_RX); + + klogf("klog() enabled on USART2\n"); +} + +void klogf(const char* fmt, ...) +{ + va_list l; + va_start(l, fmt); + + usart_vprintf(&USART2, fmt, l); +} + +void setup_usart2(uint32_t baud_rate) +{ + enable_hsi(&RCC, true); + + int ec = 0; + gpio_enable_alternate_function( + GPIO_ALTERNATE_FUNCTION_USART2_TX, GPIO_PIN_PA2, &ec); + + gpio_enable_alternate_function( + GPIO_ALTERNATE_FUNCTION_USART2_RX, GPIO_PIN_PA15, &ec); + + set_usart2_clock_src(&RCC, USART_CLK_SRC_HSI16); + set_usart2_clock_enabled(&RCC, USART_CLK_SRC_HSI16); + + /* De-assert reset of USART2 */ + regset(RCC.apb1rst1_r, rcc_usart2rst, 0); + + USART2.c_r1 = 0; + USART2.c_r2 = 0; + USART2.c_r3 = 0; + + usart_set_divisor(&USART2, 16000000 / baud_rate); +} diff --git a/02-usart/src/kern/main.c b/02-usart/src/kern/main.c index 32166bc..ebb2164 100644 --- a/02-usart/src/kern/main.c +++ b/02-usart/src/kern/main.c @@ -1,67 +1,12 @@ - #include "arch.h" +#include "kern/log.h" -#include "arch/stm32l4xxx/peripherals/clock.h" -#include "arch/stm32l4xxx/peripherals/dma.h" -#include "arch/stm32l4xxx/peripherals/gpio.h" #include "arch/stm32l4xxx/peripherals/system.h" -#include "arch/stm32l4xxx/peripherals/usart.h" -#include "arch/stm32l4xxx/peripherals/nvic.h" -#include "arch/stm32l4xxx/peripherals/irq.h" - -#include "kern/dma/dma_manager.h" -#include "kern/gpio/gpio_manager.h" -#include "kern/gpio/sysled.h" - -#include "kern/delay.h" -#include "kern/mem.h" -#include "kern/string.h" - -/** Overrides the default systick irq handler. */ -void on_systick() -{ - static int is_on = 0; - gpio_reserved_pin_t sysled = get_sysled(); - - if (is_on) { - set_gpio_pin_low(sysled); - } else { - set_gpio_pin_high(sysled); - } - - is_on = ! is_on; -} +#include "arch/stm32l4xxx/peripherals/clock.h" -void setup_usart2(uint32_t baud_rate) +void on_systick() /* Overrides weak-symbol on_systick. */ { - enable_hsi(&RCC, true); - - int ec = 0; - gpio_enable_alternate_function( - GPIO_ALTERNATE_FUNCTION_USART2_TX, GPIO_PIN_PA2, &ec); - - if (ec) { - unhandled_isr(ec & 0xff); - } - - gpio_enable_alternate_function( - GPIO_ALTERNATE_FUNCTION_USART2_RX, GPIO_PIN_PA15, &ec); - - if (ec) { - unhandled_isr(ec & 0xff); - } - - set_usart2_clock_src(&RCC, USART_CLK_SRC_HSI16); - set_usart2_clock_enabled(&RCC, USART_CLK_SRC_HSI16); - - /* De-assert reset of USART2 */ - regset(RCC.apb1rst1_r, rcc_usart2rst, 0); - - USART2.c_r1 = 0; - USART2.c_r2 = 0; - USART2.c_r3 = 0; - - usart_set_divisor(&USART2, 16000000 / baud_rate); + klogf("Systick\n"); } #ifdef ARCH_STM32L4 @@ -69,56 +14,16 @@ void setup_usart2(uint32_t baud_rate) /* Main function. This gets executed from the interrupt vector defined above. */ int main() { - /* Enable a higher clock frequency. */ - set_system_clock_MHz(80); - - setup_usart2(115200); - regset(USART2.c_r1, usart_txeie, 1); - regset(USART2.c_r1, usart_rxneie, 1); - usart_enable_dma(&USART2, USART_ENABLE_TX); - usart_set_enabled(&USART2, USART_ENABLE_TX | USART_ENABLE_RX); - - - dma_opts_t opts = DEFAULT_DMA_OPTS; - opts.transfer_complete_interrupt_enable = 1; - int ec = 0; - dma_mem2p_channel_t dma_chan = - select_dma_channel_mem2p(DMA1_PERIPH_USART2_TX, &opts, &ec); - enable_interrupt(dma_channel_get_interrupt(dma_chan.c_)); + klogf("Hello, World! Clock Mhz: %d\n", (uint32_t) get_clock_mhz()); - if (ec) { - usart_printf(&USART2, "Select DMA channel failed :( %d\n", ec); - for (;;); - } - - // const char* thing = "Good Thing This Works!"; - - char* str = halloc(128); - kstrcpy(str, "Hello, Heap!"); - - usart_printf(&USART2, "DATA_SEGMENT_START %p\n", &DATA_SEGMENT_START); - usart_printf(&USART2, "DATA_SEGMENT_STOP: %p\n", &DATA_SEGMENT_STOP); - usart_printf(&USART2, "str at: %p\n", str); - usart_printf(&USART2, "str: %s\n", str); - // usart_printf(&USART2, "%s\n", thing); - // regset(USART2.ic_r, usart_tccf, 1); - // dma_mem2p_initiate_transfer(dma_chan, thing, strlen(thing)); - - gpio_reserved_pin_t sysled = get_sysled(); - set_gpio_pin_high(sysled); - - // usart_printf(&USART2, "Start Configuring Countdown!\n"); - - /* Set the countdown to start from 1,000,0000. */ - SCB.strv_r = 1000000; + /* Set the countdown to start from 10,000,0000. */ + SCB.strv_r = 10000000; /* Enable interrupts. */ regset(SCB.stcs_r, scb_tickint, 1); /* Start the systick. */ regset(SCB.stcs_r, scb_enable, 1); - - // usart_printf(&USART2, "Start Countdown Started!\n"); } #endif |