aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJosh Rahm <joshuarahm@gmail.com>2020-11-24 00:38:09 -0700
committerJosh Rahm <joshuarahm@gmail.com>2020-11-24 00:53:28 -0700
commit2478a549b9f64c50310da41c861b8f86fdea2861 (patch)
tree3a62960f83453f354cbf309ac0722ed2ea6c27c7
parent9dab2bf91ed3e6af7c7b07590ccc8c3b211a763a (diff)
downloadstm32l4-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.h2
-rw-r--r--02-usart/include/arch/stm32l4xxx/peripherals/usart.h3
-rw-r--r--02-usart/include/kern/init.h67
-rw-r--r--02-usart/include/kern/log.h12
-rw-r--r--02-usart/linker/linker_script.ld19
-rw-r--r--02-usart/src/arch/stm32l4xxx/peripherals/clock.c11
-rw-r--r--02-usart/src/arch/stm32l4xxx/peripherals/usart.c13
-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.c55
-rw-r--r--02-usart/src/kern/main.c109
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