diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/clock.c | 62 | ||||
-rw-r--r-- | src/gpio.c | 44 | ||||
-rw-r--r-- | src/heap.c | 38 | ||||
-rw-r--r-- | src/initrd.c | 90 | ||||
-rw-r--r-- | src/lcd.c | 117 | ||||
-rw-r--r-- | src/main.c | 56 | ||||
-rw-r--r-- | src/startup_stm32l476xx.s | 524 | ||||
-rw-r--r-- | src/stdlib.c | 17 | ||||
-rw-r--r-- | src/stm32l4xx_it.c | 34 | ||||
-rw-r--r-- | src/system_stm32l4xx.c | 44 | ||||
-rw-r--r-- | src/task.c | 108 |
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>© 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; \ + "); +} + |