aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/clock.c62
-rw-r--r--src/gpio.c44
-rw-r--r--src/heap.c38
-rw-r--r--src/initrd.c90
-rw-r--r--src/lcd.c117
-rw-r--r--src/main.c56
-rw-r--r--src/startup_stm32l476xx.s524
-rw-r--r--src/stdlib.c17
-rw-r--r--src/stm32l4xx_it.c34
-rw-r--r--src/system_stm32l4xx.c44
-rw-r--r--src/task.c108
11 files changed, 1134 insertions, 0 deletions
diff --git a/src/clock.c b/src/clock.c
new file mode 100644
index 0000000..ab92386
--- /dev/null
+++ b/src/clock.c
@@ -0,0 +1,62 @@
+#include <clock.h>
+#include <stm32l476xx.h>
+
+#define STK_CTRL *((uint32_t *)0xE000E010)
+#define STK_LOAD *((uint32_t *)0xE000E014)
+#define STK_VAL *((uint32_t *)0xE000E018)
+#define STK_CALIB *((uint32_t *)0xE000E01C)
+
+// ticks since init
+static uint32_t ticks = 0;
+
+void clock_init(void)
+{
+ // turn on HSI (16MHz)
+ RCC->CR |= RCC_CR_HSION;
+ while ((RCC->CR & RCC_CR_HSIRDY) != RCC_CR_HSIRDY);
+
+ // get PLLR to 80MHz (max)
+ // VCO = C * (N/M) -> 16 * (10/1) = 160
+ // SCLK = VCO / R = 160 / 2 = 80 MHz
+ RCC->PLLCFGR &= ~(RCC_PLLCFGR_PLLSRC);
+ RCC->PLLCFGR |= RCC_PLLCFGR_PLLSRC_HSI;
+ RCC->PLLCFGR &= ~(RCC_PLLCFGR_PLLN | RCC_PLLCFGR_PLLM);
+ RCC->PLLCFGR |= 10 << RCC_PLLCFGR_PLLN_Pos;
+ RCC->PLLCFGR &= ~(RCC_PLLCFGR_PLLR); // /2
+ RCC->PLLCFGR |= RCC_PLLCFGR_PLLREN; // PLLR on
+
+ // start PLL
+ RCC->CR |= RCC_CR_PLLON;
+ while ((RCC->CR & RCC_CR_PLLRDY) != RCC_CR_PLLRDY);
+
+ // set system clock to PLL
+ RCC->CFGR &= ~(RCC_CFGR_SW);
+ RCC->CFGR |= RCC_CFGR_SW_PLL;
+ while ((RCC->CFGR & RCC_CFGR_SWS_PLL) != RCC_CFGR_SWS_PLL);
+
+ // SysTick init. 80MHz / 80000 = 1kHz, ms precision
+ STK_LOAD = 80000;
+ STK_CTRL |= 0x07; // no div, interrupt, enable
+}
+
+void delay(uint32_t count)
+{
+ uint32_t target = ticks + count;
+ while (ticks < target);
+}
+
+__attribute__ ((naked))
+void SysTick_Handler(void)
+{
+ uint32_t lr;
+ asm("mov %0, lr" : "=r" (lr));
+
+ // just keep counting
+ ticks++;
+
+ if (!(ticks % 10))
+ SCB->ICSR |= SCB_ICSR_PENDSVSET_Msk;
+
+ asm("mov lr, %0; bx lr" :: "r" (lr));
+}
+
diff --git a/src/gpio.c b/src/gpio.c
new file mode 100644
index 0000000..c2617ee
--- /dev/null
+++ b/src/gpio.c
@@ -0,0 +1,44 @@
+#include <gpio.h>
+
+void gpio_init(void)
+{
+ // enable clocks
+ RCC->AHB2ENR |= 0xFF;
+}
+
+void gpio_pupd(GPIO_TypeDef *port, uint8_t pin, uint8_t pupd)
+{
+ port->PUPDR &= ~(0x03 << (2 * pin));
+ port->PUPDR |= pupd << (2 * pin);
+}
+
+void gpio_speed(GPIO_TypeDef *port, uint8_t pin, uint8_t speed)
+{
+ port->OSPEEDR &= ~(0x03 << (2 * pin));
+ port->OSPEEDR |= speed << (2 * pin);
+}
+
+void gpio_type(GPIO_TypeDef *port, uint8_t pin, uint8_t type)
+{
+ port->OTYPER &= ~(1 << pin);
+ port->OTYPER |= type << pin;
+}
+
+void gpio_mode(GPIO_TypeDef *port, uint8_t pin, uint8_t mode)
+{
+ port->MODER &= ~(0x03 << (2 * pin));
+ port->MODER |= mode << (2 * pin);
+}
+
+void gpio_dout(GPIO_TypeDef *port, uint8_t pin, uint8_t val)
+{
+ if (val)
+ port->BSRR |= (1 << pin);
+ else
+ port->BRR |= (1 << pin);
+}
+
+uint8_t gpio_din(GPIO_TypeDef *port, uint8_t pin)
+{
+ return port->IDR & (1 << pin);
+}
diff --git a/src/heap.c b/src/heap.c
new file mode 100644
index 0000000..1eba901
--- /dev/null
+++ b/src/heap.c
@@ -0,0 +1,38 @@
+#include <heap.h>
+#include <stm32l476xx.h>
+
+#define RAM_END 0x20018000
+
+#define HEAP_SIZE (16 * 1024)
+
+static uint32_t offset = 0;
+
+__attribute__ ((section("._user_heap_stack")))
+uint8_t heap[HEAP_SIZE];
+void *end = heap;
+
+void heap_init(void)
+{
+ // what to do...
+}
+
+uint32_t heap_available(void)
+{
+ return HEAP_SIZE - offset;
+}
+
+void *hmalloc(uint32_t size)
+{
+ void *alloc = end + offset;
+ offset += size;
+ return alloc;
+}
+
+void *hcalloc(uint32_t count, uint32_t size)
+{
+ uint32_t total = count * size;
+ void *alloc = hmalloc(total);
+ for (uint32_t i = 0; i < total; i++)
+ ((uint8_t *)alloc)[i] = 0;
+ return alloc;
+}
diff --git a/src/initrd.c b/src/initrd.c
new file mode 100644
index 0000000..7b68c40
--- /dev/null
+++ b/src/initrd.c
@@ -0,0 +1,90 @@
+#include <initrd.h>
+
+extern uint8_t _binary_initrd_img_start[];
+extern uint8_t _binary_initrd_img_size[];
+
+static const void *initrd_start = (void *)_binary_initrd_img_start;
+static const uint32_t initrd_size = (uint32_t)_binary_initrd_img_size;
+
+static const char *initrd_sig = "!<arch>\n";
+
+uint8_t initrd_validate(void)
+{
+ initrd_header *header = (initrd_header *)initrd_start;
+ for (uint8_t i = 0; i < 8; i++) {
+ if (header->signature[i] != initrd_sig[i])
+ return 0;
+ }
+
+ return 1;
+}
+
+uint8_t initrd_nametest(char *file, const char *want)
+{
+ for (uint8_t i = 0; i < 16; i++) {
+ if (want[i] == '\0')
+ return (file[i] == '/');
+ else if (want[i] != file[i])
+ return 0;
+ }
+
+ return 0;
+}
+
+uint32_t pow10(uint8_t n)
+{
+ uint32_t i = 1;
+ while (n--)
+ i *= 10;
+ return i;
+}
+
+uint32_t initrd_getsize(initrd_file *file)
+{
+ uint32_t size = 0;
+ char *p = file->size + 10;
+ while (*--p == ' ');
+
+ for (int8_t i = p - file->size, j = 0; i >= 0; i--, j++)
+ size += (*p-- - '0') * pow10(j);
+
+ return size;
+}
+
+initrd_file *initrd_getfileptr(const char *name)
+{
+ initrd_file *file = (initrd_file *)(initrd_start + sizeof(initrd_header));
+ uint32_t offset = sizeof(initrd_header);
+
+ while (offset < initrd_size) {
+ if (initrd_nametest(file->name, name))
+ return file;
+ uint32_t size = initrd_getsize(file) + sizeof(initrd_file);
+ offset += size;
+ file += size;
+ }
+
+ return 0;
+}
+
+char *initrd_getfile(const char *name)
+{
+ initrd_file *file = initrd_getfileptr(name);
+ if (file == 0)
+ return 0;
+
+
+ char *ptr = (char *)((void *)file + sizeof(initrd_file));
+ ptr[initrd_getsize(file) - 1] = 0;
+ return ptr;
+}
+
+uint32_t initrd_getfilesize(const char *name)
+{
+ initrd_file *file = initrd_getfileptr(name);
+ if (file == 0)
+ return 0;
+
+ return initrd_getsize(file);
+}
+
diff --git a/src/lcd.c b/src/lcd.c
new file mode 100644
index 0000000..ca1c1a6
--- /dev/null
+++ b/src/lcd.c
@@ -0,0 +1,117 @@
+#include <lcd.h>
+#include <clock.h>
+#include <gpio.h>
+
+#define LCD_D0 GPIO_PORT(A, 0)
+#define LCD_D1 GPIO_PORT(A, 1)
+#define LCD_D2 GPIO_PORT(A, 4)
+#define LCD_D3 GPIO_PORT(B, 0)
+#define LCD_D4 GPIO_PORT(C, 1)
+#define LCD_D5 GPIO_PORT(C, 0)
+#define LCD_D6 GPIO_PORT(C, 2)
+#define LCD_D7 GPIO_PORT(C, 3)
+#define LCD_E GPIO_PORT(C, 12)
+#define LCD_RS GPIO_PORT(C, 10)
+
+#define lcd_data() gpio_dout(LCD_RS, 1)
+
+void lcd_pulse(void)
+{
+ gpio_dout(LCD_E, 1);
+ delay(1);
+ gpio_dout(LCD_E, 0);
+}
+
+void lcd_byte(uint8_t byte)
+{
+ gpio_dout(LCD_D0, byte & 0x01);
+ gpio_dout(LCD_D1, byte & 0x02);
+ gpio_dout(LCD_D2, byte & 0x04);
+ gpio_dout(LCD_D3, byte & 0x08);
+ gpio_dout(LCD_D4, byte & 0x10);
+ gpio_dout(LCD_D5, byte & 0x20);
+ gpio_dout(LCD_D6, byte & 0x40);
+ gpio_dout(LCD_D7, byte & 0x80);
+}
+
+void lcd_cmd(uint8_t cmd)
+{
+ gpio_dout(LCD_RS, 0);
+ lcd_byte(cmd);
+ lcd_pulse();
+}
+
+void lcd_putchar(int c)
+{
+ lcd_data();
+ lcd_byte((uint8_t)c);
+ lcd_pulse();
+}
+
+static int lcd_index = 0;
+void lcd_puts(const char *s)
+{
+ lcd_cmd(0x06);
+ while (*s) {
+ lcd_putchar(*s++);
+ if (++lcd_index == 0x10) {
+ lcd_cmd(0x80 | 0x40);
+ } else if (lcd_index == 0x20) {
+ lcd_cmd(0x80);
+ lcd_index = 0;
+ }
+ }
+}
+
+extern char *itoa(int n, int base);
+void lcd_puti(int i)
+{
+ lcd_puts(itoa(i, 10));
+}
+
+void lcd_puth(int h)
+{
+ lcd_puts(itoa(h, 16));
+}
+
+void lcd_putb(uint8_t b)
+{
+ lcd_puts(itoa(b, 2));
+}
+
+void lcd_clear(void)
+{
+ lcd_cmd(0x01);
+ delay(2);
+ lcd_index = 0;
+}
+
+void lcd_init(void)
+{
+ gpio_mode(LCD_D0, OUTPUT);
+ gpio_mode(LCD_D1, OUTPUT);
+ gpio_mode(LCD_D2, OUTPUT);
+ gpio_mode(LCD_D3, OUTPUT);
+ gpio_mode(LCD_D4, OUTPUT);
+ gpio_mode(LCD_D5, OUTPUT);
+ gpio_mode(LCD_D6, OUTPUT);
+ gpio_mode(LCD_D7, OUTPUT);
+ gpio_mode(LCD_E, OUTPUT);
+ gpio_mode(LCD_RS, OUTPUT);
+ gpio_dout(LCD_D0, 0);
+ gpio_dout(LCD_D1, 0);
+ gpio_dout(LCD_D2, 0);
+ gpio_dout(LCD_D3, 0);
+ gpio_dout(LCD_D4, 0);
+ gpio_dout(LCD_D5, 0);
+ gpio_dout(LCD_D6, 0);
+ gpio_dout(LCD_D7, 0);
+ gpio_dout(LCD_E, 0);
+ gpio_dout(LCD_RS, 0);
+
+ lcd_cmd(0x38);
+ lcd_cmd(0x10);
+ lcd_cmd(0x0D);
+ delay(5);
+ lcd_clear();
+}
diff --git a/src/main.c b/src/main.c
new file mode 100644
index 0000000..e71e712
--- /dev/null
+++ b/src/main.c
@@ -0,0 +1,56 @@
+#include <stm32l476xx.h>
+#include <clock.h>
+#include <heap.h>
+#include <task.h>
+#include <gpio.h>
+#include <lcd.h>
+#include <initrd.h>
+
+/**
+ * Accomplishments:
+ * - GPIO in/out
+ * - got to 80MHz clock
+ * - basic heap
+ * - multitask, can exit
+ * - gpio lib
+ * - lcd support
+ * - initrd support
+ * - lua?
+ */
+
+void pulse(uint8_t byte);
+void kmain(void);
+
+int main(void)
+{
+ asm("cpsid i");
+
+ // prepare flash latency for 40MHz operation
+ FLASH->ACR &= ~(FLASH_ACR_LATENCY);
+ FLASH->ACR |= FLASH_ACR_LATENCY_4WS;
+
+ //MPU->CTRL |= MPU_CTRL_ENABLE_Msk | MPU_CTRL_PRIVDEFENA_Msk;
+ clock_init();
+ gpio_init();
+
+ gpio_mode(GPIOA, 5, OUTPUT);
+
+ task_init(kmain);
+
+ while (1);
+}
+
+void task(void);
+void kmain(void)
+{
+ asm("cpsie i");
+
+ lcd_init();
+
+ char *s = initrd_getfile("test.txt");
+ lcd_puts(s);
+
+ while (1)
+ delay(100);
+}
+
diff --git a/src/startup_stm32l476xx.s b/src/startup_stm32l476xx.s
new file mode 100644
index 0000000..57b11cb
--- /dev/null
+++ b/src/startup_stm32l476xx.s
@@ -0,0 +1,524 @@
+/**
+ ******************************************************************************
+ * @file startup_stm32l476xx.s
+ * @author MCD Application Team
+ * @brief STM32L476xx devices vector table GCC toolchain.
+ * This module performs:
+ * - Set the initial SP
+ * - Set the initial PC == Reset_Handler,
+ * - Set the vector table entries with the exceptions ISR address,
+ * - Configure the clock system
+ * - Branches to main in the C library (which eventually
+ * calls main()).
+ * After Reset the Cortex-M4 processor is in Thread mode,
+ * priority is Privileged, and the Stack is set to Main.
+ ******************************************************************************
+ * @attention
+ *
+ * <h2><center>&copy; COPYRIGHT(c) 2017 STMicroelectronics</center></h2>
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of STMicroelectronics nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ******************************************************************************
+ */
+
+ .syntax unified
+ .cpu cortex-m4
+ .fpu softvfp
+ .thumb
+
+.global g_pfnVectors
+.global Default_Handler
+
+/* start address for the initialization values of the .data section.
+defined in linker script */
+.word _sidata
+/* start address for the .data section. defined in linker script */
+.word _sdata
+/* end address for the .data section. defined in linker script */
+.word _edata
+/* start address for the .bss section. defined in linker script */
+.word _sbss
+/* end address for the .bss section. defined in linker script */
+.word _ebss
+
+//.equ BootRAM, 0xF1E0F85F
+/**
+ * @brief This is the code that gets called when the processor first
+ * starts execution following a reset event. Only the absolutely
+ * necessary set is performed, after which the application
+ * supplied main() routine is called.
+ * @param None
+ * @retval : None
+*/
+
+ .section .text.Reset_Handler
+ .weak Reset_Handler
+ .type Reset_Handler, %function
+Reset_Handler:
+ ldr sp, =_estack /* Atollic update: set stack pointer */
+
+/* Copy the data segment initializers from flash to SRAM */
+ movs r1, #0
+ b LoopCopyDataInit
+
+CopyDataInit:
+ ldr r3, =_sidata
+ ldr r3, [r3, r1]
+ str r3, [r0, r1]
+ adds r1, r1, #4
+
+LoopCopyDataInit:
+ ldr r0, =_sdata
+ ldr r3, =_edata
+ adds r2, r0, r1
+ cmp r2, r3
+ bcc CopyDataInit
+ ldr r2, =_sbss
+ b LoopFillZerobss
+/* Zero fill the bss segment. */
+FillZerobss:
+ movs r3, #0
+ str r3, [r2], #4
+
+LoopFillZerobss:
+ ldr r3, = _ebss
+ cmp r2, r3
+ bcc FillZerobss
+
+/* Call the clock system intitialization function.*/
+ bl SystemInit
+/* Call static constructors */
+ bl __libc_init_array
+/* Call the application's entry point.*/
+ bl main
+
+LoopForever:
+ b LoopForever
+
+.size Reset_Handler, .-Reset_Handler
+
+/**
+ * @brief This is the code that gets called when the processor receives an
+ * unexpected interrupt. This simply enters an infinite loop, preserving
+ * the system state for examination by a debugger.
+ *
+ * @param None
+ * @retval : None
+*/
+ .section .text.Default_Handler,"ax",%progbits
+Default_Handler:
+Infinite_Loop:
+ b Infinite_Loop
+ .size Default_Handler, .-Default_Handler
+/******************************************************************************
+*
+* The minimal vector table for a Cortex-M4. Note that the proper constructs
+* must be placed on this to ensure that it ends up at physical address
+* 0x0000.0000.
+*
+******************************************************************************/
+ .section .isr_vector,"a",%progbits
+ .type g_pfnVectors, %object
+ .size g_pfnVectors, .-g_pfnVectors
+
+
+g_pfnVectors:
+ .word _estack
+ .word Reset_Handler
+ .word NMI_Handler
+ .word HardFault_Handler
+ .word MemManage_Handler
+ .word BusFault_Handler
+ .word UsageFault_Handler
+ .word 0
+ .word 0
+ .word 0
+ .word 0
+ .word SVC_Handler
+ .word DebugMon_Handler
+ .word 0
+ .word PendSV_Handler
+ .word SysTick_Handler
+ .word WWDG_IRQHandler
+ .word PVD_PVM_IRQHandler
+ .word TAMP_STAMP_IRQHandler
+ .word RTC_WKUP_IRQHandler
+ .word FLASH_IRQHandler
+ .word RCC_IRQHandler
+ .word EXTI0_IRQHandler
+ .word EXTI1_IRQHandler
+ .word EXTI2_IRQHandler
+ .word EXTI3_IRQHandler
+ .word EXTI4_IRQHandler
+ .word DMA1_Channel1_IRQHandler
+ .word DMA1_Channel2_IRQHandler
+ .word DMA1_Channel3_IRQHandler
+ .word DMA1_Channel4_IRQHandler
+ .word DMA1_Channel5_IRQHandler
+ .word DMA1_Channel6_IRQHandler
+ .word DMA1_Channel7_IRQHandler
+ .word ADC1_2_IRQHandler
+ .word CAN1_TX_IRQHandler
+ .word CAN1_RX0_IRQHandler
+ .word CAN1_RX1_IRQHandler
+ .word CAN1_SCE_IRQHandler
+ .word EXTI9_5_IRQHandler
+ .word TIM1_BRK_TIM15_IRQHandler
+ .word TIM1_UP_TIM16_IRQHandler
+ .word TIM1_TRG_COM_TIM17_IRQHandler
+ .word TIM1_CC_IRQHandler
+ .word TIM2_IRQHandler
+ .word TIM3_IRQHandler
+ .word TIM4_IRQHandler
+ .word I2C1_EV_IRQHandler
+ .word I2C1_ER_IRQHandler
+ .word I2C2_EV_IRQHandler
+ .word I2C2_ER_IRQHandler
+ .word SPI1_IRQHandler
+ .word SPI2_IRQHandler
+ .word USART1_IRQHandler
+ .word USART2_IRQHandler
+ .word USART3_IRQHandler
+ .word EXTI15_10_IRQHandler
+ .word RTC_Alarm_IRQHandler
+ .word DFSDM1_FLT3_IRQHandler
+ .word TIM8_BRK_IRQHandler
+ .word TIM8_UP_IRQHandler
+ .word TIM8_TRG_COM_IRQHandler
+ .word TIM8_CC_IRQHandler
+ .word ADC3_IRQHandler
+ .word FMC_IRQHandler
+ .word SDMMC1_IRQHandler
+ .word TIM5_IRQHandler
+ .word SPI3_IRQHandler
+ .word UART4_IRQHandler
+ .word UART5_IRQHandler
+ .word TIM6_DAC_IRQHandler
+ .word TIM7_IRQHandler
+ .word DMA2_Channel1_IRQHandler
+ .word DMA2_Channel2_IRQHandler
+ .word DMA2_Channel3_IRQHandler
+ .word DMA2_Channel4_IRQHandler
+ .word DMA2_Channel5_IRQHandler
+ .word DFSDM1_FLT0_IRQHandler
+ .word DFSDM1_FLT1_IRQHandler
+ .word DFSDM1_FLT2_IRQHandler
+ .word COMP_IRQHandler
+ .word LPTIM1_IRQHandler
+ .word LPTIM2_IRQHandler
+ .word OTG_FS_IRQHandler
+ .word DMA2_Channel6_IRQHandler
+ .word DMA2_Channel7_IRQHandler
+ .word LPUART1_IRQHandler
+ .word QUADSPI_IRQHandler
+ .word I2C3_EV_IRQHandler
+ .word I2C3_ER_IRQHandler
+ .word SAI1_IRQHandler
+ .word SAI2_IRQHandler
+ .word SWPMI1_IRQHandler
+ .word TSC_IRQHandler
+ .word LCD_IRQHandler
+ .word 0
+ .word RNG_IRQHandler
+ .word FPU_IRQHandler
+
+
+/*******************************************************************************
+*
+* Provide weak aliases for each Exception handler to the Default_Handler.
+* As they are weak aliases, any function with the same name will override
+* this definition.
+*
+*******************************************************************************/
+
+ .weak NMI_Handler
+ .thumb_set NMI_Handler,Default_Handler
+
+ .weak HardFault_Handler
+ .thumb_set HardFault_Handler,Default_Handler
+
+ .weak MemManage_Handler
+ .thumb_set MemManage_Handler,Default_Handler
+
+ .weak BusFault_Handler
+ .thumb_set BusFault_Handler,Default_Handler
+
+ .weak UsageFault_Handler
+ .thumb_set UsageFault_Handler,Default_Handler
+
+ .weak SVC_Handler
+ .thumb_set SVC_Handler,Default_Handler
+
+ .weak DebugMon_Handler
+ .thumb_set DebugMon_Handler,Default_Handler
+
+ .weak PendSV_Handler
+ .thumb_set PendSV_Handler,Default_Handler
+
+ .weak SysTick_Handler
+ .thumb_set SysTick_Handler,Default_Handler
+
+ .weak WWDG_IRQHandler
+ .thumb_set WWDG_IRQHandler,Default_Handler
+
+ .weak PVD_PVM_IRQHandler
+ .thumb_set PVD_PVM_IRQHandler,Default_Handler
+
+ .weak TAMP_STAMP_IRQHandler
+ .thumb_set TAMP_STAMP_IRQHandler,Default_Handler
+
+ .weak RTC_WKUP_IRQHandler
+ .thumb_set RTC_WKUP_IRQHandler,Default_Handler
+
+ .weak FLASH_IRQHandler
+ .thumb_set FLASH_IRQHandler,Default_Handler
+
+ .weak RCC_IRQHandler
+ .thumb_set RCC_IRQHandler,Default_Handler
+
+ .weak EXTI0_IRQHandler
+ .thumb_set EXTI0_IRQHandler,Default_Handler
+
+ .weak EXTI1_IRQHandler
+ .thumb_set EXTI1_IRQHandler,Default_Handler
+
+ .weak EXTI2_IRQHandler
+ .thumb_set EXTI2_IRQHandler,Default_Handler
+
+ .weak EXTI3_IRQHandler
+ .thumb_set EXTI3_IRQHandler,Default_Handler
+
+ .weak EXTI4_IRQHandler
+ .thumb_set EXTI4_IRQHandler,Default_Handler
+
+ .weak DMA1_Channel1_IRQHandler
+ .thumb_set DMA1_Channel1_IRQHandler,Default_Handler
+
+ .weak DMA1_Channel2_IRQHandler
+ .thumb_set DMA1_Channel2_IRQHandler,Default_Handler
+
+ .weak DMA1_Channel3_IRQHandler
+ .thumb_set DMA1_Channel3_IRQHandler,Default_Handler
+
+ .weak DMA1_Channel4_IRQHandler
+ .thumb_set DMA1_Channel4_IRQHandler,Default_Handler
+
+ .weak DMA1_Channel5_IRQHandler
+ .thumb_set DMA1_Channel5_IRQHandler,Default_Handler
+
+ .weak DMA1_Channel6_IRQHandler
+ .thumb_set DMA1_Channel6_IRQHandler,Default_Handler
+
+ .weak DMA1_Channel7_IRQHandler
+ .thumb_set DMA1_Channel7_IRQHandler,Default_Handler
+
+ .weak ADC1_2_IRQHandler
+ .thumb_set ADC1_2_IRQHandler,Default_Handler
+
+ .weak CAN1_TX_IRQHandler
+ .thumb_set CAN1_TX_IRQHandler,Default_Handler
+
+ .weak CAN1_RX0_IRQHandler
+ .thumb_set CAN1_RX0_IRQHandler,Default_Handler
+
+ .weak CAN1_RX1_IRQHandler
+ .thumb_set CAN1_RX1_IRQHandler,Default_Handler
+
+ .weak CAN1_SCE_IRQHandler
+ .thumb_set CAN1_SCE_IRQHandler,Default_Handler
+
+ .weak EXTI9_5_IRQHandler
+ .thumb_set EXTI9_5_IRQHandler,Default_Handler
+
+ .weak TIM1_BRK_TIM15_IRQHandler
+ .thumb_set TIM1_BRK_TIM15_IRQHandler,Default_Handler
+
+ .weak TIM1_UP_TIM16_IRQHandler
+ .thumb_set TIM1_UP_TIM16_IRQHandler,Default_Handler
+
+ .weak TIM1_TRG_COM_TIM17_IRQHandler
+ .thumb_set TIM1_TRG_COM_TIM17_IRQHandler,Default_Handler
+
+ .weak TIM1_CC_IRQHandler
+ .thumb_set TIM1_CC_IRQHandler,Default_Handler
+
+ .weak TIM2_IRQHandler
+ .thumb_set TIM2_IRQHandler,Default_Handler
+
+ .weak TIM3_IRQHandler
+ .thumb_set TIM3_IRQHandler,Default_Handler
+
+ .weak TIM4_IRQHandler
+ .thumb_set TIM4_IRQHandler,Default_Handler
+
+ .weak I2C1_EV_IRQHandler
+ .thumb_set I2C1_EV_IRQHandler,Default_Handler
+
+ .weak I2C1_ER_IRQHandler
+ .thumb_set I2C1_ER_IRQHandler,Default_Handler
+
+ .weak I2C2_EV_IRQHandler
+ .thumb_set I2C2_EV_IRQHandler,Default_Handler
+
+ .weak I2C2_ER_IRQHandler
+ .thumb_set I2C2_ER_IRQHandler,Default_Handler
+
+ .weak SPI1_IRQHandler
+ .thumb_set SPI1_IRQHandler,Default_Handler
+
+ .weak SPI2_IRQHandler
+ .thumb_set SPI2_IRQHandler,Default_Handler
+
+ .weak USART1_IRQHandler
+ .thumb_set USART1_IRQHandler,Default_Handler
+
+ .weak USART2_IRQHandler
+ .thumb_set USART2_IRQHandler,Default_Handler
+
+ .weak USART3_IRQHandler
+ .thumb_set USART3_IRQHandler,Default_Handler
+
+ .weak EXTI15_10_IRQHandler
+ .thumb_set EXTI15_10_IRQHandler,Default_Handler
+
+ .weak RTC_Alarm_IRQHandler
+ .thumb_set RTC_Alarm_IRQHandler,Default_Handler
+
+ .weak DFSDM1_FLT3_IRQHandler
+ .thumb_set DFSDM1_FLT3_IRQHandler,Default_Handler
+
+ .weak TIM8_BRK_IRQHandler
+ .thumb_set TIM8_BRK_IRQHandler,Default_Handler
+
+ .weak TIM8_UP_IRQHandler
+ .thumb_set TIM8_UP_IRQHandler,Default_Handler
+
+ .weak TIM8_TRG_COM_IRQHandler
+ .thumb_set TIM8_TRG_COM_IRQHandler,Default_Handler
+
+ .weak TIM8_CC_IRQHandler
+ .thumb_set TIM8_CC_IRQHandler,Default_Handler
+
+ .weak ADC3_IRQHandler
+ .thumb_set ADC3_IRQHandler,Default_Handler
+
+ .weak FMC_IRQHandler
+ .thumb_set FMC_IRQHandler,Default_Handler
+
+ .weak SDMMC1_IRQHandler
+ .thumb_set SDMMC1_IRQHandler,Default_Handler
+
+ .weak TIM5_IRQHandler
+ .thumb_set TIM5_IRQHandler,Default_Handler
+
+ .weak SPI3_IRQHandler
+ .thumb_set SPI3_IRQHandler,Default_Handler
+
+ .weak UART4_IRQHandler
+ .thumb_set UART4_IRQHandler,Default_Handler
+
+ .weak UART5_IRQHandler
+ .thumb_set UART5_IRQHandler,Default_Handler
+
+ .weak TIM6_DAC_IRQHandler
+ .thumb_set TIM6_DAC_IRQHandler,Default_Handler
+
+ .weak TIM7_IRQHandler
+ .thumb_set TIM7_IRQHandler,Default_Handler
+
+ .weak DMA2_Channel1_IRQHandler
+ .thumb_set DMA2_Channel1_IRQHandler,Default_Handler
+
+ .weak DMA2_Channel2_IRQHandler
+ .thumb_set DMA2_Channel2_IRQHandler,Default_Handler
+
+ .weak DMA2_Channel3_IRQHandler
+ .thumb_set DMA2_Channel3_IRQHandler,Default_Handler
+
+ .weak DMA2_Channel4_IRQHandler
+ .thumb_set DMA2_Channel4_IRQHandler,Default_Handler
+
+ .weak DMA2_Channel5_IRQHandler
+ .thumb_set DMA2_Channel5_IRQHandler,Default_Handler
+
+ .weak DFSDM1_FLT0_IRQHandler
+ .thumb_set DFSDM1_FLT0_IRQHandler,Default_Handler
+
+ .weak DFSDM1_FLT1_IRQHandler
+ .thumb_set DFSDM1_FLT1_IRQHandler,Default_Handler
+
+ .weak DFSDM1_FLT2_IRQHandler
+ .thumb_set DFSDM1_FLT2_IRQHandler,Default_Handler
+
+ .weak COMP_IRQHandler
+ .thumb_set COMP_IRQHandler,Default_Handler
+
+ .weak LPTIM1_IRQHandler
+ .thumb_set LPTIM1_IRQHandler,Default_Handler
+
+ .weak LPTIM2_IRQHandler
+ .thumb_set LPTIM2_IRQHandler,Default_Handler
+
+ .weak OTG_FS_IRQHandler
+ .thumb_set OTG_FS_IRQHandler,Default_Handler
+
+ .weak DMA2_Channel6_IRQHandler
+ .thumb_set DMA2_Channel6_IRQHandler,Default_Handler
+
+ .weak DMA2_Channel7_IRQHandler
+ .thumb_set DMA2_Channel7_IRQHandler,Default_Handler
+
+ .weak LPUART1_IRQHandler
+ .thumb_set LPUART1_IRQHandler,Default_Handler
+
+ .weak QUADSPI_IRQHandler
+ .thumb_set QUADSPI_IRQHandler,Default_Handler
+
+ .weak I2C3_EV_IRQHandler
+ .thumb_set I2C3_EV_IRQHandler,Default_Handler
+
+ .weak I2C3_ER_IRQHandler
+ .thumb_set I2C3_ER_IRQHandler,Default_Handler
+
+ .weak SAI1_IRQHandler
+ .thumb_set SAI1_IRQHandler,Default_Handler
+
+ .weak SAI2_IRQHandler
+ .thumb_set SAI2_IRQHandler,Default_Handler
+
+ .weak SWPMI1_IRQHandler
+ .thumb_set SWPMI1_IRQHandler,Default_Handler
+
+ .weak TSC_IRQHandler
+ .thumb_set TSC_IRQHandler,Default_Handler
+
+ .weak LCD_IRQHandler
+ .thumb_set LCD_IRQHandler,Default_Handler
+
+ .weak RNG_IRQHandler
+ .thumb_set RNG_IRQHandler,Default_Handler
+
+ .weak FPU_IRQHandler
+ .thumb_set FPU_IRQHandler,Default_Handler
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/src/stdlib.c b/src/stdlib.c
new file mode 100644
index 0000000..e7bf622
--- /dev/null
+++ b/src/stdlib.c
@@ -0,0 +1,17 @@
+#include <stdint.h>
+
+void _exit(int code)
+{
+ (void)code;
+ for (;;);
+}
+
+char *itoa(int n, int base)
+{
+ static char buf[16];
+ char *p = buf + 15;
+ *p = '\0';
+ do *--p = "0123456789ABCDEF"[n % base];
+ while (n /= base);
+ return p;
+}
diff --git a/src/stm32l4xx_it.c b/src/stm32l4xx_it.c
new file mode 100644
index 0000000..2aac023
--- /dev/null
+++ b/src/stm32l4xx_it.c
@@ -0,0 +1,34 @@
+#include <stm32l476xx.h>
+
+void NMI_Handler(void) {}
+
+void HardFault_Handler(void)
+{
+ GPIOA->BSRR |= (1 << 5) | (1 << 6);
+ while (1);
+}
+
+void MemManage_Handler(void)
+{
+ GPIOA->BSRR |= (1 << 5) | (1 << 6);
+ while (1);
+}
+
+void BusFault_Handler(void)
+{
+ GPIOA->BSRR |= (1 << 5) | (1 << 6);
+ while (1);
+}
+
+void UsageFault_Handler(void)
+{
+ GPIOA->BSRR |= (1 << 5) | (1 << 6);
+ while (1);
+}
+
+void SVC_Handler(void) {
+
+}
+
+void DebugMon_Handler(void) {}
+
diff --git a/src/system_stm32l4xx.c b/src/system_stm32l4xx.c
new file mode 100644
index 0000000..4c22bfe
--- /dev/null
+++ b/src/system_stm32l4xx.c
@@ -0,0 +1,44 @@
+#include "stm32l476xx.h"
+
+/************************* Miscellaneous Configuration ************************/
+/*!< Uncomment the following line if you need to relocate your vector Table in
+ Internal SRAM. */
+/* #define VECT_TAB_SRAM */
+#define VECT_TAB_OFFSET 0x00 /*!< Vector Table base offset field.
+ This value must be a multiple of 0x200. */
+/******************************************************************************/
+
+void SystemInit(void)
+{
+ /* FPU settings ------------------------------------------------------------*/
+ #if (__FPU_PRESENT == 1) && (__FPU_USED == 1)
+ SCB->CPACR |= ((3UL << 10*2)|(3UL << 11*2)); /* set CP10 and CP11 Full Access */
+ #endif
+
+ /* Reset the RCC clock configuration to the default reset state ------------*/
+ /* Set MSION bit */
+ RCC->CR |= RCC_CR_MSION;
+
+ /* Reset CFGR register */
+ RCC->CFGR = 0x00000000U;
+
+ /* Reset HSEON, CSSON , HSION, and PLLON bits */
+ RCC->CR &= 0xEAF6FFFFU;
+
+ /* Reset PLLCFGR register */
+ RCC->PLLCFGR = 0x00001000U;
+
+ /* Reset HSEBYP bit */
+ RCC->CR &= 0xFFFBFFFFU;
+
+ /* Disable all interrupts */
+ RCC->CIER = 0x00000000U;
+
+ /* Configure the Vector Table location add offset address ------------------*/
+#ifdef VECT_TAB_SRAM
+ SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM */
+#else
+ SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH */
+#endif
+}
+
diff --git a/src/task.c b/src/task.c
new file mode 100644
index 0000000..a34988a
--- /dev/null
+++ b/src/task.c
@@ -0,0 +1,108 @@
+#include <task.h>
+#include <heap.h>
+#include <stm32l476xx.h>
+
+typedef struct {
+ uint32_t *sp;
+ uint8_t use;
+ uint32_t *stack;
+ void (*code)(void);
+} task_t;
+
+#define MAX_TASKS 4
+
+static task_t tasks[MAX_TASKS];
+static volatile int next_idx = 0;
+
+static uint8_t task_enable = 0;
+
+void task_init(void (*init)(void))
+{
+ for (int i = 0; i < MAX_TASKS; i++)
+ tasks[i].use = 0;
+
+ task_start(init, 1024);
+ asm("\
+ msr psp, %0; \
+ mrs r0, control; \
+ orr r0, r0, #3; \
+ msr control, r0; \
+ isb; \
+ " :: "r" (tasks[0].sp));
+
+ task_enable = 1;
+ init();
+}
+
+extern void _exit(int);
+void task_exit(void)
+{
+ // TODO free stack?
+ asm("cpsid i"); // hope to catch next_idx
+ tasks[next_idx].use = 0;
+ asm("cpsie i");
+ while (1); // bye
+}
+
+void task_start(void (*task)(void), uint16_t stackSize)
+{
+ asm("cpsid i"); // just to be safe
+
+ for (int i = 0; i < MAX_TASKS; i++) {
+ if (tasks[i].use == 0) {
+ tasks[i].stack = hmalloc(stackSize);
+ tasks[i].sp = tasks[i].stack + stackSize - 16;
+ tasks[i].sp[13] = (uint32_t)task_exit;
+ tasks[i].sp[14] = (uint32_t)task;
+ tasks[i].sp[15] = 0x01000000;
+ tasks[i].use = 1;
+ tasks[i].code = task;
+ asm("cpsie i");
+ return;
+ }
+ }
+
+ // TODO handle error
+}
+
+__attribute__ ((naked))
+void PendSV_Handler(void)
+{
+ if (task_enable == 0)
+ asm("bx lr");
+
+ // save state
+ asm("\
+ cpsid i; \
+ isb; \
+ dsb; \
+ mrs r0, psp; \
+ stmdb r0!, {r4-r11}; \
+ mov %0, r0; \
+ " : "=r" (tasks[next_idx].sp));
+
+ // find next task (round-robin style)
+ do {
+ if (++next_idx == MAX_TASKS) {
+ next_idx = 0;
+ break; // task 0 better exist
+ }
+ } while (tasks[next_idx].use == 0);
+
+ // restore
+ asm("\
+ mov r0, %0; \
+ ldmia r0!, {r4-r11}; \
+ msr psp, r0; \
+ isb; \
+ dsb; \
+ " :: "r" (tasks[next_idx].sp));
+
+ // end
+ asm("\
+ mov r0, #0xFFFFFFFD; \
+ cpsie i; \
+ bx r0; \
+ ");
+}
+