From 7bc4391185be34dbef225017ebb34be8f614df8a Mon Sep 17 00:00:00 2001 From: jaseg Date: Sun, 27 Jun 2021 13:44:21 +0200 Subject: [PATCH] Initial commit, demo works --- .gitmodules | 19 + demo/fw/.gitignore | 2 + demo/fw/Makefile | 172 +++++++ demo/fw/openocd.cfg | 16 + demo/fw/src/con_usart.c | 54 +++ demo/fw/src/con_usart.h | 38 ++ demo/fw/src/dma_util.c | 46 ++ demo/fw/src/dma_util.h | 10 + demo/fw/src/gpio_helpers.c | 46 ++ demo/fw/src/gpio_helpers.h | 14 + demo/fw/src/jl_global.h | 35 ++ demo/fw/src/main.c | 282 ++++++++++++ demo/fw/src/serial.c | 207 +++++++++ demo/fw/src/serial.h | 84 ++++ demo/fw/src/spi.c | 97 ++++ demo/fw/src/spi.h | 22 + demo/fw/src/startup_stm32f407xx.s | 521 +++++++++++++++++++++ demo/fw/src/stm32f4_isr.h | 98 ++++ demo/fw/src/system_stm32f4xx.c | 742 ++++++++++++++++++++++++++++++ demo/fw/stm32f407.ld | 148 ++++++ demo/fw/tinyprintf | 1 + demo/fw/tools/ldparser.py | 126 +++++ demo/fw/tools/linkmem.py | 276 +++++++++++ demo/fw/tools/linksize.py | 62 +++ demo/fw/tools/linktracer.py | 118 +++++ demo/fw/tools/mapparse.py | 129 ++++++ upstream/CMSIS_5 | 1 + upstream/PyCortexMDebug | 1 + upstream/STM32CubeF4 | 1 + upstream/cmsis_device_f4 | 1 + upstream/stm32square | 1 + 31 files changed, 3370 insertions(+) create mode 100644 .gitmodules create mode 100644 demo/fw/.gitignore create mode 100644 demo/fw/Makefile create mode 100644 demo/fw/openocd.cfg create mode 100644 demo/fw/src/con_usart.c create mode 100644 demo/fw/src/con_usart.h create mode 100644 demo/fw/src/dma_util.c create mode 100644 demo/fw/src/dma_util.h create mode 100644 demo/fw/src/gpio_helpers.c create mode 100644 demo/fw/src/gpio_helpers.h create mode 100644 demo/fw/src/jl_global.h create mode 100644 demo/fw/src/main.c create mode 100644 demo/fw/src/serial.c create mode 100644 demo/fw/src/serial.h create mode 100644 demo/fw/src/spi.c create mode 100644 demo/fw/src/spi.h create mode 100644 demo/fw/src/startup_stm32f407xx.s create mode 100644 demo/fw/src/stm32f4_isr.h create mode 100644 demo/fw/src/system_stm32f4xx.c create mode 100644 demo/fw/stm32f407.ld create mode 160000 demo/fw/tinyprintf create mode 100644 demo/fw/tools/ldparser.py create mode 100644 demo/fw/tools/linkmem.py create mode 100644 demo/fw/tools/linksize.py create mode 100644 demo/fw/tools/linktracer.py create mode 100644 demo/fw/tools/mapparse.py create mode 160000 upstream/CMSIS_5 create mode 160000 upstream/PyCortexMDebug create mode 160000 upstream/STM32CubeF4 create mode 160000 upstream/cmsis_device_f4 create mode 160000 upstream/stm32square diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..bb13ea3 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,19 @@ +[submodule "demo/fw/tinyprintf"] + path = demo/fw/tinyprintf + url = https://github.com/cjlano/tinyprintf +[submodule "upstream/PyCortexMDebug"] + path = upstream/PyCortexMDebug + url = https://github.com/bnahill/PyCortexMDebug +[submodule "upstream/stm32square"] + path = upstream/stm32square + url = https://gitlab.com/neinseg/stm32square + branch = release +[submodule "upstream/STM32CubeF4"] + path = upstream/STM32CubeF4 + url = https://github.com/STMicroelectronics/STM32CubeF4 +[submodule "upstream/cmsis_device_f4"] + path = upstream/cmsis_device_f4 + url = https://github.com/STMicroelectronics/cmsis_device_f4 +[submodule "upstream/CMSIS_5"] + path = upstream/CMSIS_5 + url = https://github.com/ARM-software/CMSIS_5 diff --git a/demo/fw/.gitignore b/demo/fw/.gitignore new file mode 100644 index 0000000..8432802 --- /dev/null +++ b/demo/fw/.gitignore @@ -0,0 +1,2 @@ +build +venv diff --git a/demo/fw/Makefile b/demo/fw/Makefile new file mode 100644 index 0000000..1b74b8d --- /dev/null +++ b/demo/fw/Makefile @@ -0,0 +1,172 @@ + +######################################################################################################################## +# Dependency directories +######################################################################################################################## + +CUBE_CMSIS_DIR ?= ../../upstream/cmsis_device_f4 +CMSIS_DIR ?= ../../upstream/CMSIS_5 +MUSL_DIR ?= ../../upstream/musl + +######################################################################################################################## +# Sources +######################################################################################################################## + +C_SOURCES := src/main.c +C_SOURCES += src/con_usart.c +C_SOURCES += src/serial.c +C_SOURCES += src/spi.c +C_SOURCES += src/gpio_helpers.c +C_SOURCES += src/dma_util.c +C_SOURCES += tinyprintf/tinyprintf.c + +MUSL_SOURCES := +MUSL_SOURCES := $(addprefix $(MUSL_DIR)/src/,$(MUSL_SOURCES)) + +C_SOURCES += $(MUSL_SOURCES) + +CXX_SOURCES += + +BUILDDIR ?= build +BINARY := tachibana-demo.elf +LDSCRIPT := stm32f407.ld + +######################################################################################################################## +# Build parameters +######################################################################################################################## + +PREFIX ?= arm-none-eabi- + +DEBUG ?= 1 + +CC := $(PREFIX)gcc +CXX := $(PREFIX)g++ +LD := $(PREFIX)gcc +AR := $(PREFIX)ar +AS := $(PREFIX)as +SIZE := $(PREFIX)size +NM := $(PREFIX)nm +OBJCOPY := $(PREFIX)objcopy +OBJDUMP := $(PREFIX)objdump +GDB := $(PREFIX)gdb + +HOST_CC ?= $(HOST_PREFIX)gcc +HOST_CXX ?= $(HOST_PREFIX)g++ +HOST_LD ?= $(HOST_PREFIX)gcc +HOST_AR ?= $(HOST_PREFIX)ar +HOST_AS ?= $(HOST_PREFIX)as +HOST_OBJCOPY ?= $(HOST_PREFIX)objcopy +HOST_OBJDUMP ?= $(HOST_PREFIX)objdump + +PYTHON3 ?= python3 +DOT ?= dot + +CMSIS_DIR_ABS := $(abspath $(CMSIS_DIR)) +MSPDEBUG_DIR_ABS := $(abspath $(MSPDEBUG_DIR)) +LIBSODIUM_DIR_ABS := $(abspath $(LIBSODIUM_DIR)) +TINYAES_DIR_ABS := $(abspath $(TINYAES_DIR)) +MUSL_DIR_ABS := $(abspath $(MUSL_DIR)) + +ARCH_FLAGS ?= -mthumb -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 +SYSTEM_FLAGS ?= -nostdlib -ffreestanding -nostartfiles + +#CFLAGS += -I$(abspath musl_include_shims) +CFLAGS += -I$(CUBE_CMSIS_DIR)/Include -I$(CMSIS_DIR)/CMSIS/Core/Include +CFLAGS += -Itinyprintf +COMMON_CFLAGS += -I$(BUILDDIR) -Isrc + +COMMON_CFLAGS += -O0 -std=gnu11 -g -DSTM32F407xx -DSTM32F4 -DDEBUG=$(DEBUG) +CFLAGS += $(ARCH_FLAGS) $(SYSTEM_FLAGS) +#SIM_CFLAGS += -mthumb -mcpu=cortex-m4 -mfloat-abi=soft +CFLAGS += -fno-common -ffunction-sections -fdata-sections + +# for musl +#CFLAGS += -Dhidden= + +SIM_CFLAGS += -lm -DSIMULATION +SIM_CFLAGS += -Wall -Wextra -Wpedantic -Wshadow -Wimplicit-function-declaration -Wundef -Wno-unused-parameter + +INT_CFLAGS += -Wall -Wextra -Wpedantic -Wshadow -Wimplicit-function-declaration -Wundef -Wno-unused-parameter +INT_CFLAGS += -Wredundant-decls -Wmissing-prototypes -Wstrict-prototypes + +CXXFLAGS += -Os -g +CXXFLAGS += $(ARCH_FLAGS) $(SYSTEM_FLAGS) +CXXFLAGS += -fno-common -ffunction-sections -fdata-sections +CXXFLAGS += -Wall -Wextra -Wshadow -Wundef -Wredundant-decls +CXXFLAGS += -I. + +LDFLAGS += $(ARCH_FLAGS) $(SYSTEM_FLAGS) + +LIBS += -lgcc +LDFLAGS += -Wl,--gc-sections + +LINKMEM_FLAGS ?= --trim-stubs=startup_stm32f407xx.o --trace-sections .isr_vector --highlight-subdirs $(BUILDDIR) + +OBJS := $(addprefix $(BUILDDIR)/,$(C_SOURCES:.c=.o) $(CXX_SOURCES:.cpp=.o)) + +ALL_OBJS := $(OBJS) +ALL_OBJS += $(BUILDDIR)/src/startup_stm32f407xx.o +ALL_OBJS += $(BUILDDIR)/src/system_stm32f4xx.o + +######################################################################################################################## +# Rules +######################################################################################################################## + +all: binsize + +.PHONY: binsize +binsize: $(BUILDDIR)/$(BINARY) $(BUILDDIR)/$(BINARY:.elf=-symbol-sizes.pdf) + $(LD) -T$(LDSCRIPT) $(LDFLAGS) -Wl,--print-memory-usage -o /dev/null $(ALL_OBJS) $(LIBS) + @echo + @echo "▐▬▬▬▌ SyMbOL sIzE HiGhScORe LiSt ▐▬▬▬▌" + $(NM) --print-size --size-sort --radix=d $< | tail -n 20 + +# $(BUILDDIR)/generated/dsss_butter_filter.h +$(BUILDDIR)/generated: ; mkdir -p $@ + +.PRECIOUS: $(BUILDDIR)/$(BINARY) +$(BUILDDIR)/$(BINARY) $(BUILDDIR)/$(BINARY:.elf=.map) &: $(ALL_OBJS) + $(LD) -T$(LDSCRIPT) $(LDFLAGS) -o $@ -Wl,-Map=$(BUILDDIR)/$(BINARY:.elf=.map) $^ $(LIBS) + +build/$(BINARY:.elf=-symbol-sizes.dot): $(ALL_OBJS) + $(PYTHON3) tools/linkmem.py $(LINKMEM_FLAGS) $(LD) -T$(LDSCRIPT) $(LDFLAGS) $^ $(LIBS) > $@ + +%.pdf: %.dot + $(DOT) -T pdf $< -o $@ + +%.dot: %.elf + r2 -a arm -qc 'aa;agRd' $< 2>/dev/null >$@ + +$(BUILDDIR)/src/%.o: src/%.s + mkdir -p $(@D) + $(CC) $(COMMON_CFLAGS) $(CFLAGS) $(INT_CFLAGS) -o $@ -c $< + +$(BUILDDIR)/src/%.o: src/%.c + mkdir -p $(@D) + $(CC) $(COMMON_CFLAGS) $(CFLAGS) $(INT_CFLAGS) -o $@ -c $< + +$(BUILDDIR)/src/%.o: src/%.cpp + mkdir -p $(@D) + $(CXX) $(CXXFLAGS) -o $@ -c $< + +$(BUILDDIR)/generated/%.o: $(BUILDDIR)/generated/%.c + mkdir -p $(@D) + $(CC) $(COMMON_CFLAGS) $(CFLAGS) $(INT_CFLAGS) -o $@ -c $< + +$(BUILDDIR)/%.o: %.c + mkdir -p $(@D) + $(CC) $(COMMON_CFLAGS) $(CFLAGS) $(EXT_CFLAGS) -o $@ -c $< + +clean: + rm -rf $(BUILDDIR)/src + rm -rf $(BUILDDIR)/generated + rm -f $(BUILDDIR)/$(BINARY) + rm -f $(BUILDDIR)/$(BINARY:.elf=.map) + rm -f $(BUILDDIR)/$(BINARY:.elf=-symbol-sizes.dot) + rm -f $(BUILDDIR)/$(BINARY:.elf=-symbol-sizes.pdf) + +mrproper: clean + rm -rf build + +.PHONY: clean mrproper + +-include $(OBJS:.o=.d) diff --git a/demo/fw/openocd.cfg b/demo/fw/openocd.cfg new file mode 100644 index 0000000..65492e2 --- /dev/null +++ b/demo/fw/openocd.cfg @@ -0,0 +1,16 @@ +telnet_port 4444 +gdb_port 3333 + +source [find interface/stlink-v2.cfg] +#interface jlink +#interface stlink-v2 +#adapter_khz 10000 +#transport select swd + +#source /usr/share/openocd/scripts/target/stm32f0x.cfg +source [find target/stm32f4x.cfg] + +init +arm semihosting enable + +#flash bank sysflash.alias stm32f0x 0x00000000 0 0 0 $_TARGETNAME diff --git a/demo/fw/src/con_usart.c b/demo/fw/src/con_usart.c new file mode 100644 index 0000000..3fafe11 --- /dev/null +++ b/demo/fw/src/con_usart.c @@ -0,0 +1,54 @@ +/* + * This file is part of the tachibana project + * + * Copyright (C) 2021 jaseg + * + * + * libusbhost is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + * + */ + + +#include +#include "con_usart.h" + +volatile struct usart_desc con_usart = { + .le_usart = USART1, + .le_usart_irqn = USART1_IRQn, + .tx_dmas = DMA2_Stream7, + .tx_dma_sn = 7, + .tx_dma_ch = 4, + .tx_dma = DMA2, + .tx_dma_irqn = DMA2_Stream7_IRQn, +}; + +void con_usart_init() { + RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN | RCC_AHB1ENR_DMA2EN; + RCC->APB2ENR |= RCC_APB2ENR_USART1EN; + + /* GPIO config: A9 (TX), A10 (RX) */ + GPIOA->MODER &= ~GPIO_MODER_MODER9_Msk & ~GPIO_MODER_MODER10_Msk; + GPIOA->MODER |= (2<OSPEEDR &= ~GPIO_OSPEEDR_OSPEED9_Msk & ~GPIO_OSPEEDR_OSPEED10_Msk; + GPIOA->OSPEEDR |= (2<AFR[1] &= ~GPIO_AFRH_AFSEL9_Msk & ~GPIO_AFRH_AFSEL10_Msk; + GPIOA->AFR[1] |= (7< + * + * + * libusbhost is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + * + */ + +#ifndef __CON_USART_H__ +#define __CON_USART_H__ + +#include "serial.h" + +extern volatile struct usart_desc con_usart; + +#define con_printf(...) usart_printf(&con_usart, __VA_ARGS__) +#define con_printf_blocking(...) usart_printf_blocking(&con_usart, __VA_ARGS__) + +#ifndef CON_USART_BAUDRATE +#define CON_USART_BAUDRATE 500000 +#endif + +void con_usart_init(void); + +#endif /* __CON_USART_H__ */ diff --git a/demo/fw/src/dma_util.c b/demo/fw/src/dma_util.c new file mode 100644 index 0000000..48de215 --- /dev/null +++ b/demo/fw/src/dma_util.c @@ -0,0 +1,46 @@ + +#include + +#include "dma_util.h" + +uint8_t dma_get_isr_and_clear(DMA_TypeDef *dma, int ch) { + uint8_t isr_val; + switch(ch) { + case 0: + isr_val = dma->LISR & 0x3f; + dma->LIFCR = isr_val; + return isr_val; + case 1: + isr_val = dma->LISR>>6 & 0x3f; + dma->LIFCR = isr_val<<6; + return isr_val; + case 2: + isr_val = dma->LISR>>16 & 0x3f; + dma->LIFCR = isr_val<<16; + return isr_val; + case 3: + isr_val = dma->LISR>>6>>16 & 0x3f; + dma->LIFCR = isr_val<<6<<16; + return isr_val; + case 4: + isr_val = dma->HISR & 0x3f; + dma->HIFCR = isr_val; + return isr_val; + case 5: + isr_val = dma->HISR>>6 & 0x3f; + dma->HIFCR = isr_val<<6; + return isr_val; + case 6: + isr_val = dma->HISR>>16 & 0x3f; + dma->HIFCR = isr_val<<16; + return isr_val; + case 7: + isr_val = dma->HISR>>6>>16 & 0x3f; + dma->HIFCR = isr_val<<6<<16; + return isr_val; + default: + assert(0); + return 0; + } +} + diff --git a/demo/fw/src/dma_util.h b/demo/fw/src/dma_util.h new file mode 100644 index 0000000..eba7219 --- /dev/null +++ b/demo/fw/src/dma_util.h @@ -0,0 +1,10 @@ +#ifndef __DMA_UTIL_H__ +#define __DMA_UTIL_H__ + +#include + +#include "jl_global.h" + +uint8_t dma_get_isr_and_clear(DMA_TypeDef *dma, int ch); + +#endif /* __DMA_UTIL_H__ */ diff --git a/demo/fw/src/gpio_helpers.c b/demo/fw/src/gpio_helpers.c new file mode 100644 index 0000000..07b9a33 --- /dev/null +++ b/demo/fw/src/gpio_helpers.c @@ -0,0 +1,46 @@ + +#include "gpio_helpers.h" + +void gpio_pin_mode(GPIO_TypeDef *gpio, int pin, int mode) { + gpio->MODER &= ~(3 << (2*pin)); + gpio->MODER |= mode << (2*pin); +} + +void gpio_pin_setup(GPIO_TypeDef *gpio, int pin, int mode, int speed, int pullups, int afsel) { + int gpio_idx = ((uint32_t)gpio>>10) & 0xf; + RCC->AHB1ENR |= 1<MODER &= ~(3 << (2*pin)); + gpio->MODER |= mode << (2*pin); + gpio->OSPEEDR &= ~(3 << (2*pin)); + gpio->OSPEEDR |= speed << (2*pin); + gpio->PUPDR &= ~(3 << (2*pin)); + gpio->PUPDR |= pullups << (2*pin); + gpio->AFR[pin>>3] &= ~(0xf << (4*(pin&7))); + gpio->AFR[pin>>3] |= afsel << (4*(pin&7)); + gpio->BSRR = 1<MODER &= ~(3 << (2*pin)); + else + gpio->MODER |= 1 << (2*pin); +} + +void gpio_pin_input(GPIO_TypeDef *gpio, int pin, int pullups) { + gpio_pin_setup(gpio, pin, 0, 0, pullups, 0); +} + +void gpio_pin_af(GPIO_TypeDef *gpio, int pin, int speed, int pullups, int afsel) { + gpio_pin_setup(gpio, pin, 2, speed, pullups, afsel); +} + +void gpio_pin_analog(GPIO_TypeDef *gpio, int pin) { + gpio_pin_setup(gpio, pin, 3, 0, 0, 0); +} + diff --git a/demo/fw/src/gpio_helpers.h b/demo/fw/src/gpio_helpers.h new file mode 100644 index 0000000..abe2e85 --- /dev/null +++ b/demo/fw/src/gpio_helpers.h @@ -0,0 +1,14 @@ +#ifndef __GPIO_HELPERS_H__ +#define __GPIO_HELPERS_H__ + +#include + +void gpio_pin_mode(GPIO_TypeDef *gpio, int pin, int mode); +void gpio_pin_setup(GPIO_TypeDef *gpio, int pin, int mode, int speed, int pullups, int afsel); +void gpio_pin_output(GPIO_TypeDef *gpio, int pin, int speed); +void gpio_pin_input(GPIO_TypeDef *gpio, int pin, int pullups); +void gpio_pin_af(GPIO_TypeDef *gpio, int pin, int speed, int pullups, int afsel); +void gpio_pin_analog(GPIO_TypeDef *gpio, int pin); +void gpio_pin_tristate(GPIO_TypeDef *gpio, int pin, int tristate); + +#endif /* __GPIO_HELPERS_H__ */ diff --git a/demo/fw/src/jl_global.h b/demo/fw/src/jl_global.h new file mode 100644 index 0000000..20383b3 --- /dev/null +++ b/demo/fw/src/jl_global.h @@ -0,0 +1,35 @@ +#ifndef __jl_GLOBAL_H__ +#define __jl_GLOBAL_H__ + +#include +#include + +#ifndef SIMULATION +#include +#include +#endif + +#define UNUSED(x) ((void) x) +#define ARRAY_LENGTH(x) (sizeof(x) / sizeof(x[0])) + +#define unused_a __attribute__((unused)) + +extern unsigned int sysclk_speed; +extern unsigned int apb1_speed; +extern unsigned int apb2_speed; +extern unsigned int auxclk_speed; +extern unsigned int apb1_timer_speed; +extern unsigned int apb2_timer_speed; + +extern struct leds { + unsigned int comm_tx; +} leds; +static inline uint16_t htole(uint16_t val) { return val; } + +void __libc_init_array(void); + +static inline void panic(void) { + asm volatile ("bkpt"); +} + +#endif /* __jl_GLOBAL_H__ */ diff --git a/demo/fw/src/main.c b/demo/fw/src/main.c new file mode 100644 index 0000000..1bf4511 --- /dev/null +++ b/demo/fw/src/main.c @@ -0,0 +1,282 @@ +/* + * This file is part of the tachibana project + * + * Copyright (C) 2021 jaseg + * + * + * libusbhost is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + * + */ + + +#include +#include +#include +#include +#include + +#include + +#include "jl_global.h" +#include "con_usart.h" +#include "spi.h" + +unsigned int sysclk_speed = 0; +unsigned int apb1_speed = 0; +unsigned int apb2_speed = 0; +unsigned int auxclk_speed = 0; +unsigned int apb1_timer_speed = 0; +unsigned int apb2_timer_speed = 0; + +struct leds leds; +struct spi_fpga_if spif; + +void __libc_init_array(void) { /* we don't need this. */ } +void __assert_func (unused_a const char *file, unused_a int line, unused_a const char *function, unused_a const char *expr) { + asm volatile ("bkpt"); + while(1) {} +} + +static void clock_setup(void) +{ + /* 8MHz HSE clock as PLL source. */ +#define HSE_SPEED 8000000 + /* Divide by 8 -> 1 MHz */ +#define PLL_M 8 + /* Multiply by 336 -> 336 MHz VCO frequency */ +#define PLL_N 336 + /* Divide by 4 -> 84 MHz (max freq for our chip) */ +#define PLL_P 2 + /* Aux clock for USB OTG, SDIO, RNG: divide VCO frequency (336 MHz) by 7 -> 48 MHz (required by USB OTG) */ +#define PLL_Q 7 + + if (((RCC->CFGR & RCC_CFGR_SWS_Msk) >> RCC_CFGR_SW_Pos) != 0) + asm volatile ("bkpt"); + if (RCC->CR & RCC_CR_HSEON) + asm volatile ("bkpt"); + + RCC->CR |= RCC_CR_HSEON; + while(!(RCC->CR & RCC_CR_HSERDY)) + ; + + RCC->APB1ENR |= RCC_APB1ENR_PWREN; + + /* set voltage scale to 1 for max frequency + * (0b0) scale 2 for fCLK <= 144 Mhz + * (0b1) scale 1 for 144 Mhz < fCLK <= 168 Mhz + */ + PWR->CR |= PWR_CR_VOS; + + /* set AHB prescaler to /1 (CFGR:bits 7:4) */ + RCC->CFGR |= (0 << RCC_CFGR_HPRE_Pos); + /* set ABP1 prescaler to 4 -> 42MHz */ + RCC->CFGR |= (5 << RCC_CFGR_PPRE1_Pos); + /* set ABP2 prescaler to 2 -> 84MHz */ + RCC->CFGR |= (4 << RCC_CFGR_PPRE2_Pos); + + if (RCC->CR & RCC_CR_PLLON) + asm volatile ("bkpt"); + /* Configure PLL */ + static_assert(PLL_P % 2 == 0); + static_assert(PLL_P >= 2 && PLL_P <= 8); + static_assert(PLL_N >= 50 && PLL_N <= 432); + static_assert(PLL_M >= 2 && PLL_M <= 63); + static_assert(PLL_Q >= 2 && PLL_Q <= 15); + uint32_t old = RCC->PLLCFGR & ~(RCC_PLLCFGR_PLLM_Msk + | RCC_PLLCFGR_PLLN_Msk + | RCC_PLLCFGR_PLLP_Msk + | RCC_PLLCFGR_PLLQ_Msk + | RCC_PLLCFGR_PLLSRC); + RCC->PLLCFGR = old | (PLL_M<CR |= RCC_CR_PLLON; + + sysclk_speed = HSE_SPEED / PLL_M * PLL_N / PLL_P; + auxclk_speed = HSE_SPEED / PLL_M * PLL_N / PLL_Q; + apb1_speed = sysclk_speed / 4; + apb1_timer_speed = apb1_speed * 2; + apb2_speed = sysclk_speed / 2; + apb2_timer_speed = apb2_speed * 2; + + /* Wait for main PLL */ + while(!(RCC->CR & RCC_CR_PLLRDY)) + ; + + /* Configure Flash: enable prefetch, insn cache, data cache; set latency = 5 wait states + * See reference manual (RM0090), Section 3.5.1, Table 10 (p. 80) + */ + FLASH->ACR = FLASH_ACR_PRFTEN | FLASH_ACR_ICEN | FLASH_ACR_DCEN | (5<CFGR &= ~RCC_CFGR_SW_Msk; + RCC->CFGR |= 2 << RCC_CFGR_SW_Pos; + + /* Wait for clock to switch over */ + while ((RCC->CFGR & RCC_CFGR_SWS_Msk)>>RCC_CFGR_SWS_Pos != 2) + ; +} + +static void led_setup(void) +{ + RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN | RCC_AHB1ENR_GPIOBEN; + /* onboard leds */ + GPIOA->MODER |= (1<MODER |= (1<BSRR = 0xf << 11; +} + +static void spi_fpga_if_set_cs(bool val) { + if (val) + GPIOA->BSRR = 1<<4; + else + GPIOA->BSRR = 1<<(4+16); +} + +static void spi_fpga_setup(void) +{ + RCC->AHB1ENR |= RCC_AHB1ENR_GPIOBEN; + + /* SPI1: SCK -> PA5, MISO -> PA6, MOSI -> PA7, ~CS -> PA4 */ + GPIOA->MODER &= ~GPIO_MODER_MODER5_Msk & ~GPIO_MODER_MODER6_Msk & ~GPIO_MODER_MODER7_Msk & ~GPIO_MODER_MODER4_Msk; + GPIOA->MODER |= (2<OSPEEDR &= ~GPIO_OSPEEDR_OSPEED5_Msk & ~GPIO_OSPEEDR_OSPEED6_Msk + & ~GPIO_OSPEEDR_OSPEED7_Msk & ~GPIO_OSPEEDR_OSPEED4_Msk; + GPIOA->OSPEEDR |= (2<AFR[0] &= ~GPIO_AFRL_AFSEL5_Msk & ~GPIO_AFRL_AFSEL6_Msk & ~GPIO_AFRL_AFSEL7_Msk; + GPIOA->AFR[0] |= (5<APB2ENR |= RCC_APB2ENR_SPI1EN; + RCC->APB2RSTR |= RCC_APB2RSTR_SPI1RST; + RCC->APB2RSTR &= ~RCC_APB2RSTR_SPI1RST; + + spif_init(&spif, SPI1, &spi_fpga_if_set_cs); +} + +int main(void) +{ + if (((SCB->CPACR>>20) & 0xf) != 0xf) { + asm volatile ("bkpt"); + } + + clock_setup(); + con_usart_init(); + con_printf("\033[0m\033[2J\033[HBooting...\r\n"); + + led_setup(); + + spi_fpga_setup(); + +#if DEBUG + /* TIM1 CC1 (ADC trigger) on pin A8 */ + GPIOA->MODER &= ~GPIO_MODER_MODER8_Msk; + GPIOA->MODER |= (2<AFR[1] &= ~GPIO_AFRH_AFSEL8_Msk; + GPIOA->AFR[1] |= 1<MODER |= (1<= 4 && k < 12) + spif_printf(&spif, "\033[3%dm", k-4+1); + if (k >= 12 && k < 20) + spif_printf(&spif, "\033[9%dm", k-12+1); + spif_printf(&spif, "loop #%u \033[4%dmloop #u \033[10%dmloop #u\033[0m\n", i, k%8, (k+1)%8); + i++; + k = (k + 1) % 40; + if (k == 0) { + spif_printf(&spif, "\033[H\033[0m\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\033[H"); + + uint8_t buf[128]; + spif_capture_read(&spif, sizeof(buf), buf); + con_printf("\r\n"); + con_printf("\r\n"); + con_printf("buffer capture:\r\n"); + for (size_t e=0; e + * + * + * libusbhost is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + * + */ + +#include +#include +#include + +#include "dma_util.h" +#include "jl_global.h" +#include "serial.h" + +#include + +static void usart_schedule_dma(volatile struct usart_desc *us); +static void usart_dma_reset(volatile struct usart_desc *us); +static void usart_putc_nonblocking_tpf(void *us, char c); +static void usart_wait_chunk_free(volatile struct usart_desc *us); +static void usart_putc_blocking_tpf(void *us, char c); + +void usart_dma_reset(volatile struct usart_desc *us) { + us->tx_buf.xfr_start = -1; + us->tx_buf.xfr_end = 0; + us->tx_buf.wr_pos = 0; + us->tx_buf.wr_idx = 0; + us->tx_buf.xfr_next = 0; + us->tx_buf.wraparound = false; + + for (size_t i=0; itx_buf.chunk_end); i++) + us->tx_buf.chunk_end[i] = -1; +} + +void usart_dma_init(volatile struct usart_desc *us, unsigned int baudrate) { + usart_dma_reset(us); + + /* Configure DMA 1 Channel 2 to handle uart transmission */ + us->tx_dmas->PAR = (uint32_t)&(us->le_usart->DR); + us->tx_dmas->CR = + (us->tx_dma_ch<tx_dma_irqn); + NVIC_SetPriority(us->tx_dma_irqn, 30); + + us->le_usart->CR1 = USART_CR1_TE; + /* Set divider for 115.2kBd @48MHz system clock. */ + us->le_usart->BRR = apb2_speed * 16 / baudrate / 16; /* 250kBd */ + us->le_usart->CR3 |= USART_CR3_DMAT; /* TX DMA enable */ + + /* And... go! */ + us->le_usart->CR1 |= USART_CR1_UE; +} + +void usart_schedule_dma(volatile struct usart_desc *us) { + volatile struct dma_tx_buf *buf = &us->tx_buf; + + ssize_t xfr_start, xfr_end, xfr_len; + if (buf->wraparound) { + buf->wraparound = false; + xfr_start = 0; + xfr_len = buf->xfr_end; + xfr_end = buf->xfr_end; + + } else { + if (buf->chunk_end[buf->xfr_next] == -1) + return; /* Nothing to trasnmit */ + + xfr_start = buf->xfr_end; + xfr_end = buf->chunk_end[buf->xfr_next]; + buf->chunk_end[buf->xfr_next] = -1; + buf->xfr_next = (buf->xfr_next + 1) % ARRAY_LENGTH(buf->chunk_end); + + if (xfr_end > xfr_start) { /* no wraparound */ + xfr_len = xfr_end - xfr_start; + + } else { /* wraparound */ + if (xfr_end != 0) + buf->wraparound = true; + xfr_len = sizeof(us->data) - xfr_start; + } + } + + buf->xfr_start = xfr_start; + buf->xfr_end = xfr_end; + + us->comm_led = 100; + + /* initiate transmission of new buffer */ + us->tx_dmas->M0AR = (uint32_t)(us->data + xfr_start); + us->tx_dmas->NDTR = xfr_len; + us->tx_dmas->CR |= DMA_SxCR_EN; +} + +void usart_dma_stream_irq(volatile struct usart_desc *us) { + uint8_t iflags = dma_get_isr_and_clear(us->tx_dma, us->tx_dma_sn); + + if (iflags & DMA_LISR_TCIF0) { /* Transfer complete */ + us->tx_dmas->CR &= ~DMA_SxCR_EN; + //if (us->tx_buf.wraparound) + usart_schedule_dma(us); + } + + if (iflags & DMA_LISR_FEIF0) + us->tx_errors++; +} + +int usart_putc_nonblocking(volatile struct usart_desc *us, char c) { + volatile struct dma_tx_buf *buf = &us->tx_buf; + + if (buf->wr_pos == buf->xfr_start) { + us->tx_byte_overruns++; + return -EBUSY; + } + + buf->data[buf->wr_pos] = c; + buf->wr_pos = (buf->wr_pos + 1) % sizeof(us->data); + return 0; +} + +int usart_putc_blocking(volatile struct usart_desc *us, char c) { + volatile struct dma_tx_buf *buf = &us->tx_buf; + + while (buf->wr_pos == buf->xfr_start) + ; + + buf->data[buf->wr_pos] = c; + buf->wr_pos = (buf->wr_pos + 1) % sizeof(us->data); + return 0; +} + +void usart_putc_nonblocking_tpf(void *us, char c) { + usart_putc_nonblocking((struct usart_desc *)us, c); +} + +void usart_putc_blocking_tpf(void *us, char c) { + usart_putc_blocking((struct usart_desc *)us, c); +} + +int usart_send_chunk_nonblocking(volatile struct usart_desc *us, const char *chunk, size_t chunk_len) { + for (size_t i=0; itx_buf.chunk_end[us->tx_buf.wr_idx] != -1) + ; +} + +int usart_flush(volatile struct usart_desc *us) { + /* Find a free slot for this chunk */ + if (us->tx_buf.chunk_end[us->tx_buf.wr_idx] != -1) { + us->tx_chunk_overruns++; + return -EBUSY; + } + + us->tx_buf.chunk_end[us->tx_buf.wr_idx] = us->tx_buf.wr_pos; + us->tx_buf.wr_idx = (us->tx_buf.wr_idx + 1) % ARRAY_LENGTH(us->tx_buf.chunk_end); + + if (!(us->tx_dmas->CR & DMA_SxCR_EN)) + usart_schedule_dma(us); + return 0; +} + +int usart_printf(volatile struct usart_desc *us, const char *fmt, ...) { + va_list va; + va_start(va, fmt); + tfp_format((void *)us, usart_putc_nonblocking_tpf, fmt, va); + return usart_flush(us); +} + +int usart_printf_blocking_va(volatile struct usart_desc *us, const char *fmt, va_list va) { + tfp_format((void *)us, usart_putc_blocking_tpf, fmt, va); + usart_wait_chunk_free(us); + return usart_flush(us); +} + +int usart_printf_blocking(volatile struct usart_desc *us, const char *fmt, ...) { + va_list va; + va_start(va, fmt); + return usart_printf_blocking_va(us, fmt, va); +} + diff --git a/demo/fw/src/serial.h b/demo/fw/src/serial.h new file mode 100644 index 0000000..53eafb2 --- /dev/null +++ b/demo/fw/src/serial.h @@ -0,0 +1,84 @@ +/* + * This file is part of the tachibana project + * + * Copyright (C) 2021 jaseg + * + * + * libusbhost is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + * + */ + +#ifndef __SERIAL_H__ +#define __SERIAL_H__ + +#include +#include +#include +#include +#include + +#include "jl_global.h" + +struct dma_tx_buf { + /* The following fields are accessed only from DMA ISR */ + ssize_t xfr_start; /* Start index of running DMA transfer */ + ssize_t xfr_end; /* End index of running DMA transfer plus one */ + bool wraparound; + ssize_t xfr_next; + + /* The following fields are written only from non-interrupt code */ + ssize_t wr_pos; /* Next index to be written */ + ssize_t wr_idx; + ssize_t chunk_end[8]; + +/* Make GCC shut up about the zero-size array member. */ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpedantic" + /* Written outside ISR by usart_send_chunk_nonblocking, read via DMA */ + uint8_t data[0]; +#pragma GCC diagnostic pop +}; + +struct usart_desc { + struct dma_tx_buf tx_buf; + uint8_t data[512]; + + uint32_t tx_chunk_overruns, tx_byte_overruns; + uint32_t tx_errors; + + volatile uint8_t rx_buf[32]; + + int comm_led; + + USART_TypeDef *le_usart; + int le_usart_irqn; + DMA_Stream_TypeDef *tx_dmas; + int tx_dma_sn; + int tx_dma_ch; + DMA_TypeDef *tx_dma; + int tx_dma_irqn; +}; + +void usart_dma_init(volatile struct usart_desc *us, unsigned int baudrate); +int usart_send_chunk_nonblocking(volatile struct usart_desc *us, const char *chunk, size_t chunk_len); +int usart_putc_nonblocking(volatile struct usart_desc *us, char c); +int usart_putc_blocking(volatile struct usart_desc *us, char c); + +void usart_dma_stream_irq(volatile struct usart_desc *us); +int usart_flush(volatile struct usart_desc *us); +int usart_printf(volatile struct usart_desc *us, const char *fmt, ...); +int usart_printf_blocking(volatile struct usart_desc *us, const char *fmt, ...); +int usart_printf_blocking_va(volatile struct usart_desc *us, const char *fmt, va_list va); + +#endif // __SERIAL_H__ diff --git a/demo/fw/src/spi.c b/demo/fw/src/spi.c new file mode 100644 index 0000000..d2f39e0 --- /dev/null +++ b/demo/fw/src/spi.c @@ -0,0 +1,97 @@ +/* + * This file is part of the tachibana project + * + * Copyright (C) 2021 jaseg + * + * + * libusbhost is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + * + */ + +#include + +#include "spi.h" + +static uint8_t spi_xfer(struct spi_fpga_if *spif, uint8_t b); +static uint8_t spi_read(struct spi_fpga_if *spif); +static void spi_write(struct spi_fpga_if *spif, uint8_t b); +static void spi_putc_blocking_tpf(void *spif, char c); + +uint8_t spi_xfer(struct spi_fpga_if *spif, uint8_t b) { + while (!(spif->spi->SR & SPI_SR_TXE)) + ; + (void) spif->spi->DR; /* perform dummy read to clear RXNE flag */ + *((uint8_t *)&(spif->spi->DR)) = b; + while (!(spif->spi->SR & SPI_SR_RXNE)) + ; + return *((uint8_t *)&(spif->spi->DR)); +} + +uint8_t spi_read(struct spi_fpga_if *spif) { + return spi_xfer(spif, 0); +} + +void spi_write(struct spi_fpga_if *spif, uint8_t b) { + (void)spi_xfer(spif, b); +} + +void spif_init(struct spi_fpga_if *spif, SPI_TypeDef *spi, void (*cs)(bool val)) { + spif->spi = spi; + spif->cs = cs; + spif->cs(1); + + spi->CR1 = (4<cs(0); + spi_write(spif, cmd); + + size_t len_min = arglen < outlen ? arglen : outlen; + for (size_t i=0; ics(1); +} + +void spif_term_send(struct spi_fpga_if *spif, size_t buflen, const char *buf) { + spif_command(spif, 0x23, buflen, (const uint8_t *)buf, 0, NULL); +} + +void spif_capture_read(struct spi_fpga_if *spif, size_t buflen, uint8_t *buf) { + spif_command(spif, 0x22, 0, NULL, buflen, buf); +} + +static void spi_putc_blocking_tpf(void *spif, char c) { + spif_term_send((struct spi_fpga_if *)spif, 1, &c); +} + +int spif_printf(struct spi_fpga_if *spif, const char *fmt, ...) { + va_list va; + va_start(va, fmt); + tfp_format((void *)spif, spi_putc_blocking_tpf, fmt, va); + return 0; +} + diff --git a/demo/fw/src/spi.h b/demo/fw/src/spi.h new file mode 100644 index 0000000..1bc00d7 --- /dev/null +++ b/demo/fw/src/spi.h @@ -0,0 +1,22 @@ +#ifndef __SPI_FLASH_H__ +#define __SPI_FLASH_H__ + +#include +#include + +#include + +struct spi_fpga_if { + volatile SPI_TypeDef *spi; + void (*cs)(bool val); +}; + +void spif_init(struct spi_fpga_if *spif, SPI_TypeDef *spi, void (*cs)(bool val)); +void spif_command(struct spi_fpga_if *spif, uint8_t cmd, size_t arglen, const uint8_t *args, size_t outlen, uint8_t *out); + +void spif_term_send(struct spi_fpga_if *spif, size_t buflen, const char *buf); +void spif_capture_read(struct spi_fpga_if *spif, size_t buflen, uint8_t *buf); + +int spif_printf(struct spi_fpga_if *spif, const char *fmt, ...); + +#endif /* __SPI_FLASH_H__ */ diff --git a/demo/fw/src/startup_stm32f407xx.s b/demo/fw/src/startup_stm32f407xx.s new file mode 100644 index 0000000..aeeeb22 --- /dev/null +++ b/demo/fw/src/startup_stm32f407xx.s @@ -0,0 +1,521 @@ +/** + ****************************************************************************** + * @file startup_stm32f407xx.s + * @author MCD Application Team + * @brief STM32F407xx Devices vector table for GCC based toolchains. + * This module performs: + * - Set the initial SP + * - Set the initial PC == Reset_Handler, + * - Set the vector table entries with the exceptions ISR address + * - 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 + * + *

© COPYRIGHT 2017 STMicroelectronics

+ * + * 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 +/* stack used for SystemInit_ExtMemCtl; always internal RAM used */ + +/** + * @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 /* 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 + bx lr +.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 M3. 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 + + /* External Interrupts */ + .word WWDG_IRQHandler /* Window WatchDog */ + .word PVD_IRQHandler /* PVD through EXTI Line detection */ + .word TAMP_STAMP_IRQHandler /* Tamper and TimeStamps through the EXTI line */ + .word RTC_WKUP_IRQHandler /* RTC Wakeup through the EXTI line */ + .word FLASH_IRQHandler /* FLASH */ + .word RCC_IRQHandler /* RCC */ + .word EXTI0_IRQHandler /* EXTI Line0 */ + .word EXTI1_IRQHandler /* EXTI Line1 */ + .word EXTI2_IRQHandler /* EXTI Line2 */ + .word EXTI3_IRQHandler /* EXTI Line3 */ + .word EXTI4_IRQHandler /* EXTI Line4 */ + .word DMA1_Stream0_IRQHandler /* DMA1 Stream 0 */ + .word DMA1_Stream1_IRQHandler /* DMA1 Stream 1 */ + .word DMA1_Stream2_IRQHandler /* DMA1 Stream 2 */ + .word DMA1_Stream3_IRQHandler /* DMA1 Stream 3 */ + .word DMA1_Stream4_IRQHandler /* DMA1 Stream 4 */ + .word DMA1_Stream5_IRQHandler /* DMA1 Stream 5 */ + .word DMA1_Stream6_IRQHandler /* DMA1 Stream 6 */ + .word ADC_IRQHandler /* ADC1, ADC2 and ADC3s */ + .word CAN1_TX_IRQHandler /* CAN1 TX */ + .word CAN1_RX0_IRQHandler /* CAN1 RX0 */ + .word CAN1_RX1_IRQHandler /* CAN1 RX1 */ + .word CAN1_SCE_IRQHandler /* CAN1 SCE */ + .word EXTI9_5_IRQHandler /* External Line[9:5]s */ + .word TIM1_BRK_TIM9_IRQHandler /* TIM1 Break and TIM9 */ + .word TIM1_UP_TIM10_IRQHandler /* TIM1 Update and TIM10 */ + .word TIM1_TRG_COM_TIM11_IRQHandler /* TIM1 Trigger and Commutation and TIM11 */ + .word TIM1_CC_IRQHandler /* TIM1 Capture Compare */ + .word TIM2_IRQHandler /* TIM2 */ + .word TIM3_IRQHandler /* TIM3 */ + .word TIM4_IRQHandler /* TIM4 */ + .word I2C1_EV_IRQHandler /* I2C1 Event */ + .word I2C1_ER_IRQHandler /* I2C1 Error */ + .word I2C2_EV_IRQHandler /* I2C2 Event */ + .word I2C2_ER_IRQHandler /* I2C2 Error */ + .word SPI1_IRQHandler /* SPI1 */ + .word SPI2_IRQHandler /* SPI2 */ + .word USART1_IRQHandler /* USART1 */ + .word USART2_IRQHandler /* USART2 */ + .word USART3_IRQHandler /* USART3 */ + .word EXTI15_10_IRQHandler /* External Line[15:10]s */ + .word RTC_Alarm_IRQHandler /* RTC Alarm (A and B) through EXTI Line */ + .word OTG_FS_WKUP_IRQHandler /* USB OTG FS Wakeup through EXTI line */ + .word TIM8_BRK_TIM12_IRQHandler /* TIM8 Break and TIM12 */ + .word TIM8_UP_TIM13_IRQHandler /* TIM8 Update and TIM13 */ + .word TIM8_TRG_COM_TIM14_IRQHandler /* TIM8 Trigger and Commutation and TIM14 */ + .word TIM8_CC_IRQHandler /* TIM8 Capture Compare */ + .word DMA1_Stream7_IRQHandler /* DMA1 Stream7 */ + .word FSMC_IRQHandler /* FSMC */ + .word SDIO_IRQHandler /* SDIO */ + .word TIM5_IRQHandler /* TIM5 */ + .word SPI3_IRQHandler /* SPI3 */ + .word UART4_IRQHandler /* UART4 */ + .word UART5_IRQHandler /* UART5 */ + .word TIM6_DAC_IRQHandler /* TIM6 and DAC1&2 underrun errors */ + .word TIM7_IRQHandler /* TIM7 */ + .word DMA2_Stream0_IRQHandler /* DMA2 Stream 0 */ + .word DMA2_Stream1_IRQHandler /* DMA2 Stream 1 */ + .word DMA2_Stream2_IRQHandler /* DMA2 Stream 2 */ + .word DMA2_Stream3_IRQHandler /* DMA2 Stream 3 */ + .word DMA2_Stream4_IRQHandler /* DMA2 Stream 4 */ + .word ETH_IRQHandler /* Ethernet */ + .word ETH_WKUP_IRQHandler /* Ethernet Wakeup through EXTI line */ + .word CAN2_TX_IRQHandler /* CAN2 TX */ + .word CAN2_RX0_IRQHandler /* CAN2 RX0 */ + .word CAN2_RX1_IRQHandler /* CAN2 RX1 */ + .word CAN2_SCE_IRQHandler /* CAN2 SCE */ + .word OTG_FS_IRQHandler /* USB OTG FS */ + .word DMA2_Stream5_IRQHandler /* DMA2 Stream 5 */ + .word DMA2_Stream6_IRQHandler /* DMA2 Stream 6 */ + .word DMA2_Stream7_IRQHandler /* DMA2 Stream 7 */ + .word USART6_IRQHandler /* USART6 */ + .word I2C3_EV_IRQHandler /* I2C3 event */ + .word I2C3_ER_IRQHandler /* I2C3 error */ + .word OTG_HS_EP1_OUT_IRQHandler /* USB OTG HS End Point 1 Out */ + .word OTG_HS_EP1_IN_IRQHandler /* USB OTG HS End Point 1 In */ + .word OTG_HS_WKUP_IRQHandler /* USB OTG HS Wakeup through EXTI */ + .word OTG_HS_IRQHandler /* USB OTG HS */ + .word DCMI_IRQHandler /* DCMI */ + .word 0 /* CRYP crypto */ + .word HASH_RNG_IRQHandler /* Hash and Rng */ + .word FPU_IRQHandler /* FPU */ + + +/******************************************************************************* +* +* 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_IRQHandler + .thumb_set PVD_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_Stream0_IRQHandler + .thumb_set DMA1_Stream0_IRQHandler,Default_Handler + + .weak DMA1_Stream1_IRQHandler + .thumb_set DMA1_Stream1_IRQHandler,Default_Handler + + .weak DMA1_Stream2_IRQHandler + .thumb_set DMA1_Stream2_IRQHandler,Default_Handler + + .weak DMA1_Stream3_IRQHandler + .thumb_set DMA1_Stream3_IRQHandler,Default_Handler + + .weak DMA1_Stream4_IRQHandler + .thumb_set DMA1_Stream4_IRQHandler,Default_Handler + + .weak DMA1_Stream5_IRQHandler + .thumb_set DMA1_Stream5_IRQHandler,Default_Handler + + .weak DMA1_Stream6_IRQHandler + .thumb_set DMA1_Stream6_IRQHandler,Default_Handler + + .weak ADC_IRQHandler + .thumb_set ADC_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_TIM9_IRQHandler + .thumb_set TIM1_BRK_TIM9_IRQHandler,Default_Handler + + .weak TIM1_UP_TIM10_IRQHandler + .thumb_set TIM1_UP_TIM10_IRQHandler,Default_Handler + + .weak TIM1_TRG_COM_TIM11_IRQHandler + .thumb_set TIM1_TRG_COM_TIM11_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 OTG_FS_WKUP_IRQHandler + .thumb_set OTG_FS_WKUP_IRQHandler,Default_Handler + + .weak TIM8_BRK_TIM12_IRQHandler + .thumb_set TIM8_BRK_TIM12_IRQHandler,Default_Handler + + .weak TIM8_UP_TIM13_IRQHandler + .thumb_set TIM8_UP_TIM13_IRQHandler,Default_Handler + + .weak TIM8_TRG_COM_TIM14_IRQHandler + .thumb_set TIM8_TRG_COM_TIM14_IRQHandler,Default_Handler + + .weak TIM8_CC_IRQHandler + .thumb_set TIM8_CC_IRQHandler,Default_Handler + + .weak DMA1_Stream7_IRQHandler + .thumb_set DMA1_Stream7_IRQHandler,Default_Handler + + .weak FSMC_IRQHandler + .thumb_set FSMC_IRQHandler,Default_Handler + + .weak SDIO_IRQHandler + .thumb_set SDIO_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_Stream0_IRQHandler + .thumb_set DMA2_Stream0_IRQHandler,Default_Handler + + .weak DMA2_Stream1_IRQHandler + .thumb_set DMA2_Stream1_IRQHandler,Default_Handler + + .weak DMA2_Stream2_IRQHandler + .thumb_set DMA2_Stream2_IRQHandler,Default_Handler + + .weak DMA2_Stream3_IRQHandler + .thumb_set DMA2_Stream3_IRQHandler,Default_Handler + + .weak DMA2_Stream4_IRQHandler + .thumb_set DMA2_Stream4_IRQHandler,Default_Handler + + .weak ETH_IRQHandler + .thumb_set ETH_IRQHandler,Default_Handler + + .weak ETH_WKUP_IRQHandler + .thumb_set ETH_WKUP_IRQHandler,Default_Handler + + .weak CAN2_TX_IRQHandler + .thumb_set CAN2_TX_IRQHandler,Default_Handler + + .weak CAN2_RX0_IRQHandler + .thumb_set CAN2_RX0_IRQHandler,Default_Handler + + .weak CAN2_RX1_IRQHandler + .thumb_set CAN2_RX1_IRQHandler,Default_Handler + + .weak CAN2_SCE_IRQHandler + .thumb_set CAN2_SCE_IRQHandler,Default_Handler + + .weak OTG_FS_IRQHandler + .thumb_set OTG_FS_IRQHandler,Default_Handler + + .weak DMA2_Stream5_IRQHandler + .thumb_set DMA2_Stream5_IRQHandler,Default_Handler + + .weak DMA2_Stream6_IRQHandler + .thumb_set DMA2_Stream6_IRQHandler,Default_Handler + + .weak DMA2_Stream7_IRQHandler + .thumb_set DMA2_Stream7_IRQHandler,Default_Handler + + .weak USART6_IRQHandler + .thumb_set USART6_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 OTG_HS_EP1_OUT_IRQHandler + .thumb_set OTG_HS_EP1_OUT_IRQHandler,Default_Handler + + .weak OTG_HS_EP1_IN_IRQHandler + .thumb_set OTG_HS_EP1_IN_IRQHandler,Default_Handler + + .weak OTG_HS_WKUP_IRQHandler + .thumb_set OTG_HS_WKUP_IRQHandler,Default_Handler + + .weak OTG_HS_IRQHandler + .thumb_set OTG_HS_IRQHandler,Default_Handler + + .weak DCMI_IRQHandler + .thumb_set DCMI_IRQHandler,Default_Handler + + .weak HASH_RNG_IRQHandler + .thumb_set HASH_RNG_IRQHandler,Default_Handler + + .weak FPU_IRQHandler + .thumb_set FPU_IRQHandler,Default_Handler + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/demo/fw/src/stm32f4_isr.h b/demo/fw/src/stm32f4_isr.h new file mode 100644 index 0000000..bc16421 --- /dev/null +++ b/demo/fw/src/stm32f4_isr.h @@ -0,0 +1,98 @@ + +#ifndef __STM32F4_ISR_H__ +#define __STM32F4_ISR_H__ + +void Reset_Handler(void); +void NMI_Handler(void); +void HardFault_Handler(void); +void MemManage_Handler(void); +void BusFault_Handler(void); +void UsageFault_Handler(void); +void SVC_Handler(void); +void DebugMon_Handler(void); +void PendSV_Handler(void); +void SysTick_Handler(void); + +void WWDG_IRQHandler(void); +void PVD_IRQHandler(void); +void TAMP_STAMP_IRQHandler(void); +void RTC_WKUP_IRQHandler(void); +void FLASH_IRQHandler(void); +void RCC_IRQHandler(void); +void EXTI0_IRQHandler(void); +void EXTI1_IRQHandler(void); +void EXTI2_IRQHandler(void); +void EXTI3_IRQHandler(void); +void EXTI4_IRQHandler(void); +void DMA1_Stream0_IRQHandler(void); +void DMA1_Stream1_IRQHandler(void); +void DMA1_Stream2_IRQHandler(void); +void DMA1_Stream3_IRQHandler(void); +void DMA1_Stream4_IRQHandler(void); +void DMA1_Stream5_IRQHandler(void); +void DMA1_Stream6_IRQHandler(void); +void ADC_IRQHandler(void); +void CAN1_TX_IRQHandler(void); +void CAN1_RX0_IRQHandler(void); +void CAN1_RX1_IRQHandler(void); +void CAN1_SCE_IRQHandler(void); +void EXTI9_5_IRQHandler(void); +void TIM1_BRK_TIM9_IRQHandler(void); +void TIM1_UP_TIM10_IRQHandler(void); +void TIM1_TRG_COM_TIM11_IRQHandler(void); +void TIM1_CC_IRQHandler(void); +void TIM2_IRQHandler(void); +void TIM3_IRQHandler(void); +void TIM4_IRQHandler(void); +void I2C1_EV_IRQHandler(void); +void I2C1_ER_IRQHandler(void); +void I2C2_EV_IRQHandler(void); +void I2C2_ER_IRQHandler(void); +void SPI1_IRQHandler(void); +void SPI2_IRQHandler(void); +void USART1_IRQHandler(void); +void USART2_IRQHandler(void); +void USART3_IRQHandler(void); +void EXTI15_10_IRQHandler(void); +void RTC_Alarm_IRQHandler(void); +void OTG_FS_WKUP_IRQHandler(void); +void TIM8_BRK_TIM12_IRQHandler(void); +void TIM8_UP_TIM13_IRQHandler(void); +void TIM8_TRG_COM_TIM14_IRQHandler(void); +void TIM8_CC_IRQHandler(void); +void DMA1_Stream7_IRQHandler(void); +void FSMC_IRQHandler(void); +void SDIO_IRQHandler(void); +void TIM5_IRQHandler(void); +void SPI3_IRQHandler(void); +void UART4_IRQHandler(void); +void UART5_IRQHandler(void); +void TIM6_DAC_IRQHandler(void); +void TIM7_IRQHandler(void); +void DMA2_Stream0_IRQHandler(void); +void DMA2_Stream1_IRQHandler(void); +void DMA2_Stream2_IRQHandler(void); +void DMA2_Stream3_IRQHandler(void); +void DMA2_Stream4_IRQHandler(void); +void ETH_IRQHandler(void); +void ETH_WKUP_IRQHandler(void); +void CAN2_TX_IRQHandler(void); +void CAN2_RX0_IRQHandler(void); +void CAN2_RX1_IRQHandler(void); +void CAN2_SCE_IRQHandler(void); +void OTG_FS_IRQHandler(void); +void DMA2_Stream5_IRQHandler(void); +void DMA2_Stream6_IRQHandler(void); +void DMA2_Stream7_IRQHandler(void); +void USART6_IRQHandler(void); +void I2C3_EV_IRQHandler(void); +void I2C3_ER_IRQHandler(void); +void OTG_HS_EP1_OUT_IRQHandler(void); +void OTG_HS_EP1_IN_IRQHandler(void); +void OTG_HS_WKUP_IRQHandler(void); +void OTG_HS_IRQHandler(void); +void DCMI_IRQHandler(void); +void HASH_RNG_IRQHandler(void); +void FPU_IRQHandler(void); + +#endif /* __STM32F4_ISR_H__ */ diff --git a/demo/fw/src/system_stm32f4xx.c b/demo/fw/src/system_stm32f4xx.c new file mode 100644 index 0000000..5d005ed --- /dev/null +++ b/demo/fw/src/system_stm32f4xx.c @@ -0,0 +1,742 @@ +/** + ****************************************************************************** + * @file system_stm32f4xx.c + * @author MCD Application Team + * @brief CMSIS Cortex-M4 Device Peripheral Access Layer System Source File. + * + * This file provides two functions and one global variable to be called from + * user application: + * - SystemInit(): This function is called at startup just after reset and + * before branch to main program. This call is made inside + * the "startup_stm32f4xx.s" file. + * + * - SystemCoreClock variable: Contains the core clock (HCLK), it can be used + * by the user application to setup the SysTick + * timer or configure other parameters. + * + * - SystemCoreClockUpdate(): Updates the variable SystemCoreClock and must + * be called whenever the core clock is changed + * during program execution. + * + * + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2017 STMicroelectronics

+ * + * 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. + * + ****************************************************************************** + */ + +/** @addtogroup CMSIS + * @{ + */ + +/** @addtogroup stm32f4xx_system + * @{ + */ + +/** @addtogroup STM32F4xx_System_Private_Includes + * @{ + */ + + +#include "stm32f4xx.h" + +#if !defined (HSE_VALUE) + #define HSE_VALUE ((uint32_t)25000000) /*!< Default value of the External oscillator in Hz */ +#endif /* HSE_VALUE */ + +#if !defined (HSI_VALUE) + #define HSI_VALUE ((uint32_t)16000000) /*!< Value of the Internal oscillator in Hz*/ +#endif /* HSI_VALUE */ + +/** + * @} + */ + +/** @addtogroup STM32F4xx_System_Private_TypesDefinitions + * @{ + */ + +/** + * @} + */ + +/** @addtogroup STM32F4xx_System_Private_Defines + * @{ + */ + +/************************* Miscellaneous Configuration ************************/ +/*!< Uncomment the following line if you need to use external SRAM or SDRAM as data memory */ +#if defined(STM32F405xx) || defined(STM32F415xx) || defined(STM32F407xx) || defined(STM32F417xx)\ + || defined(STM32F427xx) || defined(STM32F437xx) || defined(STM32F429xx) || defined(STM32F439xx)\ + || defined(STM32F469xx) || defined(STM32F479xx) || defined(STM32F412Zx) || defined(STM32F412Vx) +/* #define DATA_IN_ExtSRAM */ +#endif /* STM32F40xxx || STM32F41xxx || STM32F42xxx || STM32F43xxx || STM32F469xx || STM32F479xx ||\ + STM32F412Zx || STM32F412Vx */ + +#if defined(STM32F427xx) || defined(STM32F437xx) || defined(STM32F429xx) || defined(STM32F439xx)\ + || defined(STM32F446xx) || defined(STM32F469xx) || defined(STM32F479xx) +/* #define DATA_IN_ExtSDRAM */ +#endif /* STM32F427xx || STM32F437xx || STM32F429xx || STM32F439xx || STM32F446xx || STM32F469xx ||\ + STM32F479xx */ + +/*!< 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. */ +/******************************************************************************/ + +/** + * @} + */ + +/** @addtogroup STM32F4xx_System_Private_Macros + * @{ + */ + +/** + * @} + */ + +/** @addtogroup STM32F4xx_System_Private_Variables + * @{ + */ + /* This variable is updated in three ways: + 1) by calling CMSIS function SystemCoreClockUpdate() + 2) by calling HAL API function HAL_RCC_GetHCLKFreq() + 3) each time HAL_RCC_ClockConfig() is called to configure the system clock frequency + Note: If you use this function to configure the system clock; then there + is no need to call the 2 first functions listed above, since SystemCoreClock + variable is updated automatically. + */ +uint32_t SystemCoreClock = 16000000; +const uint8_t AHBPrescTable[16] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9}; +const uint8_t APBPrescTable[8] = {0, 0, 0, 0, 1, 2, 3, 4}; +/** + * @} + */ + +/** @addtogroup STM32F4xx_System_Private_FunctionPrototypes + * @{ + */ + +#if defined (DATA_IN_ExtSRAM) || defined (DATA_IN_ExtSDRAM) + static void SystemInit_ExtMemCtl(void); +#endif /* DATA_IN_ExtSRAM || DATA_IN_ExtSDRAM */ + +/** + * @} + */ + +/** @addtogroup STM32F4xx_System_Private_Functions + * @{ + */ + +/** + * @brief Setup the microcontroller system + * Initialize the FPU setting, vector table location and External memory + * configuration. + * @param None + * @retval None + */ +void SystemInit(void) +{ + SCB->CPACR |= ((3UL << 10*2)|(3UL << 11*2)); /* set CP10 and CP11 Full Access */ + __DSB(); + __ISB(); + +#if defined (DATA_IN_ExtSRAM) || defined (DATA_IN_ExtSDRAM) + SystemInit_ExtMemCtl(); +#endif /* DATA_IN_ExtSRAM || DATA_IN_ExtSDRAM */ + + /* 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 +} + +/** + * @brief Update SystemCoreClock variable according to Clock Register Values. + * The SystemCoreClock variable contains the core clock (HCLK), it can + * be used by the user application to setup the SysTick timer or configure + * other parameters. + * + * @note Each time the core clock (HCLK) changes, this function must be called + * to update SystemCoreClock variable value. Otherwise, any configuration + * based on this variable will be incorrect. + * + * @note - The system frequency computed by this function is not the real + * frequency in the chip. It is calculated based on the predefined + * constant and the selected clock source: + * + * - If SYSCLK source is HSI, SystemCoreClock will contain the HSI_VALUE(*) + * + * - If SYSCLK source is HSE, SystemCoreClock will contain the HSE_VALUE(**) + * + * - If SYSCLK source is PLL, SystemCoreClock will contain the HSE_VALUE(**) + * or HSI_VALUE(*) multiplied/divided by the PLL factors. + * + * (*) HSI_VALUE is a constant defined in stm32f4xx_hal_conf.h file (default value + * 16 MHz) but the real value may vary depending on the variations + * in voltage and temperature. + * + * (**) HSE_VALUE is a constant defined in stm32f4xx_hal_conf.h file (its value + * depends on the application requirements), user has to ensure that HSE_VALUE + * is same as the real frequency of the crystal used. Otherwise, this function + * may have wrong result. + * + * - The result of this function could be not correct when using fractional + * value for HSE crystal. + * + * @param None + * @retval None + */ +void SystemCoreClockUpdate(void) +{ + uint32_t tmp = 0, pllvco = 0, pllp = 2, pllsource = 0, pllm = 2; + + /* Get SYSCLK source -------------------------------------------------------*/ + tmp = RCC->CFGR & RCC_CFGR_SWS; + + switch (tmp) + { + case 0x00: /* HSI used as system clock source */ + SystemCoreClock = HSI_VALUE; + break; + case 0x04: /* HSE used as system clock source */ + SystemCoreClock = HSE_VALUE; + break; + case 0x08: /* PLL used as system clock source */ + + /* PLL_VCO = (HSE_VALUE or HSI_VALUE / PLL_M) * PLL_N + SYSCLK = PLL_VCO / PLL_P + */ + pllsource = (RCC->PLLCFGR & RCC_PLLCFGR_PLLSRC) >> 22; + pllm = RCC->PLLCFGR & RCC_PLLCFGR_PLLM; + + if (pllsource != 0) + { + /* HSE used as PLL clock source */ + pllvco = (HSE_VALUE / pllm) * ((RCC->PLLCFGR & RCC_PLLCFGR_PLLN) >> 6); + } + else + { + /* HSI used as PLL clock source */ + pllvco = (HSI_VALUE / pllm) * ((RCC->PLLCFGR & RCC_PLLCFGR_PLLN) >> 6); + } + + pllp = (((RCC->PLLCFGR & RCC_PLLCFGR_PLLP) >>16) + 1 ) *2; + SystemCoreClock = pllvco/pllp; + break; + default: + SystemCoreClock = HSI_VALUE; + break; + } + /* Compute HCLK frequency --------------------------------------------------*/ + /* Get HCLK prescaler */ + tmp = AHBPrescTable[((RCC->CFGR & RCC_CFGR_HPRE) >> 4)]; + /* HCLK frequency */ + SystemCoreClock >>= tmp; +} + +#if defined (DATA_IN_ExtSRAM) && defined (DATA_IN_ExtSDRAM) +#if defined(STM32F427xx) || defined(STM32F437xx) || defined(STM32F429xx) || defined(STM32F439xx)\ + || defined(STM32F469xx) || defined(STM32F479xx) +/** + * @brief Setup the external memory controller. + * Called in startup_stm32f4xx.s before jump to main. + * This function configures the external memories (SRAM/SDRAM) + * This SRAM/SDRAM will be used as program data memory (including heap and stack). + * @param None + * @retval None + */ +void SystemInit_ExtMemCtl(void) +{ + __IO uint32_t tmp = 0x00; + + register uint32_t tmpreg = 0, timeout = 0xFFFF; + register __IO uint32_t index; + + /* Enable GPIOC, GPIOD, GPIOE, GPIOF, GPIOG, GPIOH and GPIOI interface clock */ + RCC->AHB1ENR |= 0x000001F8; + + /* Delay after an RCC peripheral clock enabling */ + tmp = READ_BIT(RCC->AHB1ENR, RCC_AHB1ENR_GPIOCEN); + + /* Connect PDx pins to FMC Alternate function */ + GPIOD->AFR[0] = 0x00CCC0CC; + GPIOD->AFR[1] = 0xCCCCCCCC; + /* Configure PDx pins in Alternate function mode */ + GPIOD->MODER = 0xAAAA0A8A; + /* Configure PDx pins speed to 100 MHz */ + GPIOD->OSPEEDR = 0xFFFF0FCF; + /* Configure PDx pins Output type to push-pull */ + GPIOD->OTYPER = 0x00000000; + /* No pull-up, pull-down for PDx pins */ + GPIOD->PUPDR = 0x00000000; + + /* Connect PEx pins to FMC Alternate function */ + GPIOE->AFR[0] = 0xC00CC0CC; + GPIOE->AFR[1] = 0xCCCCCCCC; + /* Configure PEx pins in Alternate function mode */ + GPIOE->MODER = 0xAAAA828A; + /* Configure PEx pins speed to 100 MHz */ + GPIOE->OSPEEDR = 0xFFFFC3CF; + /* Configure PEx pins Output type to push-pull */ + GPIOE->OTYPER = 0x00000000; + /* No pull-up, pull-down for PEx pins */ + GPIOE->PUPDR = 0x00000000; + + /* Connect PFx pins to FMC Alternate function */ + GPIOF->AFR[0] = 0xCCCCCCCC; + GPIOF->AFR[1] = 0xCCCCCCCC; + /* Configure PFx pins in Alternate function mode */ + GPIOF->MODER = 0xAA800AAA; + /* Configure PFx pins speed to 50 MHz */ + GPIOF->OSPEEDR = 0xAA800AAA; + /* Configure PFx pins Output type to push-pull */ + GPIOF->OTYPER = 0x00000000; + /* No pull-up, pull-down for PFx pins */ + GPIOF->PUPDR = 0x00000000; + + /* Connect PGx pins to FMC Alternate function */ + GPIOG->AFR[0] = 0xCCCCCCCC; + GPIOG->AFR[1] = 0xCCCCCCCC; + /* Configure PGx pins in Alternate function mode */ + GPIOG->MODER = 0xAAAAAAAA; + /* Configure PGx pins speed to 50 MHz */ + GPIOG->OSPEEDR = 0xAAAAAAAA; + /* Configure PGx pins Output type to push-pull */ + GPIOG->OTYPER = 0x00000000; + /* No pull-up, pull-down for PGx pins */ + GPIOG->PUPDR = 0x00000000; + + /* Connect PHx pins to FMC Alternate function */ + GPIOH->AFR[0] = 0x00C0CC00; + GPIOH->AFR[1] = 0xCCCCCCCC; + /* Configure PHx pins in Alternate function mode */ + GPIOH->MODER = 0xAAAA08A0; + /* Configure PHx pins speed to 50 MHz */ + GPIOH->OSPEEDR = 0xAAAA08A0; + /* Configure PHx pins Output type to push-pull */ + GPIOH->OTYPER = 0x00000000; + /* No pull-up, pull-down for PHx pins */ + GPIOH->PUPDR = 0x00000000; + + /* Connect PIx pins to FMC Alternate function */ + GPIOI->AFR[0] = 0xCCCCCCCC; + GPIOI->AFR[1] = 0x00000CC0; + /* Configure PIx pins in Alternate function mode */ + GPIOI->MODER = 0x0028AAAA; + /* Configure PIx pins speed to 50 MHz */ + GPIOI->OSPEEDR = 0x0028AAAA; + /* Configure PIx pins Output type to push-pull */ + GPIOI->OTYPER = 0x00000000; + /* No pull-up, pull-down for PIx pins */ + GPIOI->PUPDR = 0x00000000; + +/*-- FMC Configuration -------------------------------------------------------*/ + /* Enable the FMC interface clock */ + RCC->AHB3ENR |= 0x00000001; + /* Delay after an RCC peripheral clock enabling */ + tmp = READ_BIT(RCC->AHB3ENR, RCC_AHB3ENR_FMCEN); + + FMC_Bank5_6->SDCR[0] = 0x000019E4; + FMC_Bank5_6->SDTR[0] = 0x01115351; + + /* SDRAM initialization sequence */ + /* Clock enable command */ + FMC_Bank5_6->SDCMR = 0x00000011; + tmpreg = FMC_Bank5_6->SDSR & 0x00000020; + while((tmpreg != 0) && (timeout-- > 0)) + { + tmpreg = FMC_Bank5_6->SDSR & 0x00000020; + } + + /* Delay */ + for (index = 0; index<1000; index++); + + /* PALL command */ + FMC_Bank5_6->SDCMR = 0x00000012; + timeout = 0xFFFF; + while((tmpreg != 0) && (timeout-- > 0)) + { + tmpreg = FMC_Bank5_6->SDSR & 0x00000020; + } + + /* Auto refresh command */ + FMC_Bank5_6->SDCMR = 0x00000073; + timeout = 0xFFFF; + while((tmpreg != 0) && (timeout-- > 0)) + { + tmpreg = FMC_Bank5_6->SDSR & 0x00000020; + } + + /* MRD register program */ + FMC_Bank5_6->SDCMR = 0x00046014; + timeout = 0xFFFF; + while((tmpreg != 0) && (timeout-- > 0)) + { + tmpreg = FMC_Bank5_6->SDSR & 0x00000020; + } + + /* Set refresh count */ + tmpreg = FMC_Bank5_6->SDRTR; + FMC_Bank5_6->SDRTR = (tmpreg | (0x0000027C<<1)); + + /* Disable write protection */ + tmpreg = FMC_Bank5_6->SDCR[0]; + FMC_Bank5_6->SDCR[0] = (tmpreg & 0xFFFFFDFF); + +#if defined(STM32F427xx) || defined(STM32F437xx) || defined(STM32F429xx) || defined(STM32F439xx) + /* Configure and enable Bank1_SRAM2 */ + FMC_Bank1->BTCR[2] = 0x00001011; + FMC_Bank1->BTCR[3] = 0x00000201; + FMC_Bank1E->BWTR[2] = 0x0fffffff; +#endif /* STM32F427xx || STM32F437xx || STM32F429xx || STM32F439xx */ +#if defined(STM32F469xx) || defined(STM32F479xx) + /* Configure and enable Bank1_SRAM2 */ + FMC_Bank1->BTCR[2] = 0x00001091; + FMC_Bank1->BTCR[3] = 0x00110212; + FMC_Bank1E->BWTR[2] = 0x0fffffff; +#endif /* STM32F469xx || STM32F479xx */ + + (void)(tmp); +} +#endif /* STM32F427xx || STM32F437xx || STM32F429xx || STM32F439xx || STM32F469xx || STM32F479xx */ +#elif defined (DATA_IN_ExtSRAM) || defined (DATA_IN_ExtSDRAM) +/** + * @brief Setup the external memory controller. + * Called in startup_stm32f4xx.s before jump to main. + * This function configures the external memories (SRAM/SDRAM) + * This SRAM/SDRAM will be used as program data memory (including heap and stack). + * @param None + * @retval None + */ +void SystemInit_ExtMemCtl(void) +{ + __IO uint32_t tmp = 0x00; +#if defined(STM32F427xx) || defined(STM32F437xx) || defined(STM32F429xx) || defined(STM32F439xx)\ + || defined(STM32F446xx) || defined(STM32F469xx) || defined(STM32F479xx) +#if defined (DATA_IN_ExtSDRAM) + register uint32_t tmpreg = 0, timeout = 0xFFFF; + register __IO uint32_t index; + +#if defined(STM32F446xx) + /* Enable GPIOA, GPIOC, GPIOD, GPIOE, GPIOF, GPIOG interface + clock */ + RCC->AHB1ENR |= 0x0000007D; +#else + /* Enable GPIOC, GPIOD, GPIOE, GPIOF, GPIOG, GPIOH and GPIOI interface + clock */ + RCC->AHB1ENR |= 0x000001F8; +#endif /* STM32F446xx */ + /* Delay after an RCC peripheral clock enabling */ + tmp = READ_BIT(RCC->AHB1ENR, RCC_AHB1ENR_GPIOCEN); + +#if defined(STM32F446xx) + /* Connect PAx pins to FMC Alternate function */ + GPIOA->AFR[0] |= 0xC0000000; + GPIOA->AFR[1] |= 0x00000000; + /* Configure PDx pins in Alternate function mode */ + GPIOA->MODER |= 0x00008000; + /* Configure PDx pins speed to 50 MHz */ + GPIOA->OSPEEDR |= 0x00008000; + /* Configure PDx pins Output type to push-pull */ + GPIOA->OTYPER |= 0x00000000; + /* No pull-up, pull-down for PDx pins */ + GPIOA->PUPDR |= 0x00000000; + + /* Connect PCx pins to FMC Alternate function */ + GPIOC->AFR[0] |= 0x00CC0000; + GPIOC->AFR[1] |= 0x00000000; + /* Configure PDx pins in Alternate function mode */ + GPIOC->MODER |= 0x00000A00; + /* Configure PDx pins speed to 50 MHz */ + GPIOC->OSPEEDR |= 0x00000A00; + /* Configure PDx pins Output type to push-pull */ + GPIOC->OTYPER |= 0x00000000; + /* No pull-up, pull-down for PDx pins */ + GPIOC->PUPDR |= 0x00000000; +#endif /* STM32F446xx */ + + /* Connect PDx pins to FMC Alternate function */ + GPIOD->AFR[0] = 0x000000CC; + GPIOD->AFR[1] = 0xCC000CCC; + /* Configure PDx pins in Alternate function mode */ + GPIOD->MODER = 0xA02A000A; + /* Configure PDx pins speed to 50 MHz */ + GPIOD->OSPEEDR = 0xA02A000A; + /* Configure PDx pins Output type to push-pull */ + GPIOD->OTYPER = 0x00000000; + /* No pull-up, pull-down for PDx pins */ + GPIOD->PUPDR = 0x00000000; + + /* Connect PEx pins to FMC Alternate function */ + GPIOE->AFR[0] = 0xC00000CC; + GPIOE->AFR[1] = 0xCCCCCCCC; + /* Configure PEx pins in Alternate function mode */ + GPIOE->MODER = 0xAAAA800A; + /* Configure PEx pins speed to 50 MHz */ + GPIOE->OSPEEDR = 0xAAAA800A; + /* Configure PEx pins Output type to push-pull */ + GPIOE->OTYPER = 0x00000000; + /* No pull-up, pull-down for PEx pins */ + GPIOE->PUPDR = 0x00000000; + + /* Connect PFx pins to FMC Alternate function */ + GPIOF->AFR[0] = 0xCCCCCCCC; + GPIOF->AFR[1] = 0xCCCCCCCC; + /* Configure PFx pins in Alternate function mode */ + GPIOF->MODER = 0xAA800AAA; + /* Configure PFx pins speed to 50 MHz */ + GPIOF->OSPEEDR = 0xAA800AAA; + /* Configure PFx pins Output type to push-pull */ + GPIOF->OTYPER = 0x00000000; + /* No pull-up, pull-down for PFx pins */ + GPIOF->PUPDR = 0x00000000; + + /* Connect PGx pins to FMC Alternate function */ + GPIOG->AFR[0] = 0xCCCCCCCC; + GPIOG->AFR[1] = 0xCCCCCCCC; + /* Configure PGx pins in Alternate function mode */ + GPIOG->MODER = 0xAAAAAAAA; + /* Configure PGx pins speed to 50 MHz */ + GPIOG->OSPEEDR = 0xAAAAAAAA; + /* Configure PGx pins Output type to push-pull */ + GPIOG->OTYPER = 0x00000000; + /* No pull-up, pull-down for PGx pins */ + GPIOG->PUPDR = 0x00000000; + +#if defined(STM32F427xx) || defined(STM32F437xx) || defined(STM32F429xx) || defined(STM32F439xx)\ + || defined(STM32F469xx) || defined(STM32F479xx) + /* Connect PHx pins to FMC Alternate function */ + GPIOH->AFR[0] = 0x00C0CC00; + GPIOH->AFR[1] = 0xCCCCCCCC; + /* Configure PHx pins in Alternate function mode */ + GPIOH->MODER = 0xAAAA08A0; + /* Configure PHx pins speed to 50 MHz */ + GPIOH->OSPEEDR = 0xAAAA08A0; + /* Configure PHx pins Output type to push-pull */ + GPIOH->OTYPER = 0x00000000; + /* No pull-up, pull-down for PHx pins */ + GPIOH->PUPDR = 0x00000000; + + /* Connect PIx pins to FMC Alternate function */ + GPIOI->AFR[0] = 0xCCCCCCCC; + GPIOI->AFR[1] = 0x00000CC0; + /* Configure PIx pins in Alternate function mode */ + GPIOI->MODER = 0x0028AAAA; + /* Configure PIx pins speed to 50 MHz */ + GPIOI->OSPEEDR = 0x0028AAAA; + /* Configure PIx pins Output type to push-pull */ + GPIOI->OTYPER = 0x00000000; + /* No pull-up, pull-down for PIx pins */ + GPIOI->PUPDR = 0x00000000; +#endif /* STM32F427xx || STM32F437xx || STM32F429xx || STM32F439xx || STM32F469xx || STM32F479xx */ + +/*-- FMC Configuration -------------------------------------------------------*/ + /* Enable the FMC interface clock */ + RCC->AHB3ENR |= 0x00000001; + /* Delay after an RCC peripheral clock enabling */ + tmp = READ_BIT(RCC->AHB3ENR, RCC_AHB3ENR_FMCEN); + + /* Configure and enable SDRAM bank1 */ +#if defined(STM32F446xx) + FMC_Bank5_6->SDCR[0] = 0x00001954; +#else + FMC_Bank5_6->SDCR[0] = 0x000019E4; +#endif /* STM32F446xx */ + FMC_Bank5_6->SDTR[0] = 0x01115351; + + /* SDRAM initialization sequence */ + /* Clock enable command */ + FMC_Bank5_6->SDCMR = 0x00000011; + tmpreg = FMC_Bank5_6->SDSR & 0x00000020; + while((tmpreg != 0) && (timeout-- > 0)) + { + tmpreg = FMC_Bank5_6->SDSR & 0x00000020; + } + + /* Delay */ + for (index = 0; index<1000; index++); + + /* PALL command */ + FMC_Bank5_6->SDCMR = 0x00000012; + timeout = 0xFFFF; + while((tmpreg != 0) && (timeout-- > 0)) + { + tmpreg = FMC_Bank5_6->SDSR & 0x00000020; + } + + /* Auto refresh command */ +#if defined(STM32F446xx) + FMC_Bank5_6->SDCMR = 0x000000F3; +#else + FMC_Bank5_6->SDCMR = 0x00000073; +#endif /* STM32F446xx */ + timeout = 0xFFFF; + while((tmpreg != 0) && (timeout-- > 0)) + { + tmpreg = FMC_Bank5_6->SDSR & 0x00000020; + } + + /* MRD register program */ +#if defined(STM32F446xx) + FMC_Bank5_6->SDCMR = 0x00044014; +#else + FMC_Bank5_6->SDCMR = 0x00046014; +#endif /* STM32F446xx */ + timeout = 0xFFFF; + while((tmpreg != 0) && (timeout-- > 0)) + { + tmpreg = FMC_Bank5_6->SDSR & 0x00000020; + } + + /* Set refresh count */ + tmpreg = FMC_Bank5_6->SDRTR; +#if defined(STM32F446xx) + FMC_Bank5_6->SDRTR = (tmpreg | (0x0000050C<<1)); +#else + FMC_Bank5_6->SDRTR = (tmpreg | (0x0000027C<<1)); +#endif /* STM32F446xx */ + + /* Disable write protection */ + tmpreg = FMC_Bank5_6->SDCR[0]; + FMC_Bank5_6->SDCR[0] = (tmpreg & 0xFFFFFDFF); +#endif /* DATA_IN_ExtSDRAM */ +#endif /* STM32F427xx || STM32F437xx || STM32F429xx || STM32F439xx || STM32F446xx || STM32F469xx || STM32F479xx */ + +#if defined(STM32F405xx) || defined(STM32F415xx) || defined(STM32F407xx) || defined(STM32F417xx)\ + || defined(STM32F427xx) || defined(STM32F437xx) || defined(STM32F429xx) || defined(STM32F439xx)\ + || defined(STM32F469xx) || defined(STM32F479xx) || defined(STM32F412Zx) || defined(STM32F412Vx) + +#if defined(DATA_IN_ExtSRAM) +/*-- GPIOs Configuration -----------------------------------------------------*/ + /* Enable GPIOD, GPIOE, GPIOF and GPIOG interface clock */ + RCC->AHB1ENR |= 0x00000078; + /* Delay after an RCC peripheral clock enabling */ + tmp = READ_BIT(RCC->AHB1ENR, RCC_AHB1ENR_GPIODEN); + + /* Connect PDx pins to FMC Alternate function */ + GPIOD->AFR[0] = 0x00CCC0CC; + GPIOD->AFR[1] = 0xCCCCCCCC; + /* Configure PDx pins in Alternate function mode */ + GPIOD->MODER = 0xAAAA0A8A; + /* Configure PDx pins speed to 100 MHz */ + GPIOD->OSPEEDR = 0xFFFF0FCF; + /* Configure PDx pins Output type to push-pull */ + GPIOD->OTYPER = 0x00000000; + /* No pull-up, pull-down for PDx pins */ + GPIOD->PUPDR = 0x00000000; + + /* Connect PEx pins to FMC Alternate function */ + GPIOE->AFR[0] = 0xC00CC0CC; + GPIOE->AFR[1] = 0xCCCCCCCC; + /* Configure PEx pins in Alternate function mode */ + GPIOE->MODER = 0xAAAA828A; + /* Configure PEx pins speed to 100 MHz */ + GPIOE->OSPEEDR = 0xFFFFC3CF; + /* Configure PEx pins Output type to push-pull */ + GPIOE->OTYPER = 0x00000000; + /* No pull-up, pull-down for PEx pins */ + GPIOE->PUPDR = 0x00000000; + + /* Connect PFx pins to FMC Alternate function */ + GPIOF->AFR[0] = 0x00CCCCCC; + GPIOF->AFR[1] = 0xCCCC0000; + /* Configure PFx pins in Alternate function mode */ + GPIOF->MODER = 0xAA000AAA; + /* Configure PFx pins speed to 100 MHz */ + GPIOF->OSPEEDR = 0xFF000FFF; + /* Configure PFx pins Output type to push-pull */ + GPIOF->OTYPER = 0x00000000; + /* No pull-up, pull-down for PFx pins */ + GPIOF->PUPDR = 0x00000000; + + /* Connect PGx pins to FMC Alternate function */ + GPIOG->AFR[0] = 0x00CCCCCC; + GPIOG->AFR[1] = 0x000000C0; + /* Configure PGx pins in Alternate function mode */ + GPIOG->MODER = 0x00085AAA; + /* Configure PGx pins speed to 100 MHz */ + GPIOG->OSPEEDR = 0x000CAFFF; + /* Configure PGx pins Output type to push-pull */ + GPIOG->OTYPER = 0x00000000; + /* No pull-up, pull-down for PGx pins */ + GPIOG->PUPDR = 0x00000000; + +/*-- FMC/FSMC Configuration --------------------------------------------------*/ + /* Enable the FMC/FSMC interface clock */ + RCC->AHB3ENR |= 0x00000001; + +#if defined(STM32F427xx) || defined(STM32F437xx) || defined(STM32F429xx) || defined(STM32F439xx) + /* Delay after an RCC peripheral clock enabling */ + tmp = READ_BIT(RCC->AHB3ENR, RCC_AHB3ENR_FMCEN); + /* Configure and enable Bank1_SRAM2 */ + FMC_Bank1->BTCR[2] = 0x00001011; + FMC_Bank1->BTCR[3] = 0x00000201; + FMC_Bank1E->BWTR[2] = 0x0fffffff; +#endif /* STM32F427xx || STM32F437xx || STM32F429xx || STM32F439xx */ +#if defined(STM32F469xx) || defined(STM32F479xx) + /* Delay after an RCC peripheral clock enabling */ + tmp = READ_BIT(RCC->AHB3ENR, RCC_AHB3ENR_FMCEN); + /* Configure and enable Bank1_SRAM2 */ + FMC_Bank1->BTCR[2] = 0x00001091; + FMC_Bank1->BTCR[3] = 0x00110212; + FMC_Bank1E->BWTR[2] = 0x0fffffff; +#endif /* STM32F469xx || STM32F479xx */ +#if defined(STM32F405xx) || defined(STM32F415xx) || defined(STM32F407xx)|| defined(STM32F417xx)\ + || defined(STM32F412Zx) || defined(STM32F412Vx) + /* Delay after an RCC peripheral clock enabling */ + tmp = READ_BIT(RCC->AHB3ENR, RCC_AHB3ENR_FSMCEN); + /* Configure and enable Bank1_SRAM2 */ + FSMC_Bank1->BTCR[2] = 0x00001011; + FSMC_Bank1->BTCR[3] = 0x00000201; + FSMC_Bank1E->BWTR[2] = 0x0FFFFFFF; +#endif /* STM32F405xx || STM32F415xx || STM32F407xx || STM32F417xx || STM32F412Zx || STM32F412Vx */ + +#endif /* DATA_IN_ExtSRAM */ +#endif /* STM32F405xx || STM32F415xx || STM32F407xx || STM32F417xx || STM32F427xx || STM32F437xx ||\ + STM32F429xx || STM32F439xx || STM32F469xx || STM32F479xx || STM32F412Zx || STM32F412Vx */ + (void)(tmp); +} +#endif /* DATA_IN_ExtSRAM && DATA_IN_ExtSDRAM */ +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/demo/fw/stm32f407.ld b/demo/fw/stm32f407.ld new file mode 100644 index 0000000..f998b4a --- /dev/null +++ b/demo/fw/stm32f407.ld @@ -0,0 +1,148 @@ +MEMORY +{ + FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 512K + RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 128K + CCMRAM (rwx) : ORIGIN = 0x10000000, LENGTH = 64K + BACKUP (rwx) : ORIGIN = 0x40024000, LENGTH = 4K +} + +/* Entry Point */ +ENTRY(Reset_Handler) + +/* Highest address of the user mode stack */ +_estack = 0x20020000; /* end of RAM */ +/* Generate a link error if heap and stack don't fit into RAM */ +_Min_Heap_Size = 0x200;; /* required amount of heap */ +_Min_Stack_Size = 0x400;; /* required amount of stack */ + +/* Define output sections */ +SECTIONS +{ + /* The startup code goes first into FLASH */ + .isr_vector : + { + . = ALIGN(4); + KEEP(*(.isr_vector)) /* Startup code */ + . = ALIGN(4); + } >FLASH + + /* The program code and other data goes into FLASH */ + .text : + { + . = ALIGN(4); + *(.text) /* .text sections (code) */ + *(.text*) /* .text* sections (code) */ + *(.glue_7) /* glue arm to thumb code */ + *(.glue_7t) /* glue thumb to arm code */ + *(.eh_frame) + + KEEP (*(.init)) + KEEP (*(.fini)) + + . = ALIGN(4); + _etext = .; /* define a global symbols at end of code */ + } >FLASH + + /* Constant data goes into FLASH */ + .rodata : + { + . = ALIGN(4); + *(.rodata) /* .rodata sections (constants, strings, etc.) */ + *(.rodata*) /* .rodata* sections (constants, strings, etc.) */ + . = ALIGN(4); + } >FLASH + + .ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >FLASH + .ARM : { + __exidx_start = .; + *(.ARM.exidx*) + __exidx_end = .; + } >FLASH + + .preinit_array : + { + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array*)) + PROVIDE_HIDDEN (__preinit_array_end = .); + } >FLASH + .init_array : + { + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array*)) + PROVIDE_HIDDEN (__init_array_end = .); + } >FLASH + .fini_array : + { + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(SORT(.fini_array.*))) + KEEP (*(.fini_array*)) + PROVIDE_HIDDEN (__fini_array_end = .); + } >FLASH + + /* used by the startup to initialize data */ + _sidata = LOADADDR(.data); + + /* Initialized data sections goes into RAM, load LMA copy after code */ + .data : + { + . = ALIGN(4); + _sdata = .; /* create a global symbol at data start */ + *(.data) /* .data sections */ + *(.data*) /* .data* sections */ + + . = ALIGN(4); + _edata = .; /* define a global symbol at data end */ + } >RAM AT> FLASH + + _siccmram = LOADADDR(.ccmram); + + /* CCM-RAM section + * + * IMPORTANT NOTE! + * If initialized variables will be placed in this section, + * the startup code needs to be modified to copy the init-values. + */ + .ccmram : + { + . = ALIGN(4); + _sccmram = .; /* create a global symbol at ccmram start */ + *(.ccmram) + *(.ccmram*) + + . = ALIGN(4); + _eccmram = .; /* create a global symbol at ccmram end */ + } >CCMRAM AT> FLASH + + + /* Uninitialized data section */ + . = ALIGN(4); + .bss : + { + /* This is used by the startup in order to initialize the .bss secion */ + _sbss = .; /* define a global symbol at bss start */ + __bss_start__ = _sbss; + *(.bss) + *(.bss*) + *(COMMON) + + . = ALIGN(4); + _ebss = .; /* define a global symbol at bss end */ + __bss_end__ = _ebss; + } >RAM + + /* User_heap_stack section, used to check that there is enough RAM left */ + ._user_heap_stack : + { + . = ALIGN(4); + PROVIDE ( end = . ); + PROVIDE ( _end = . ); + . = . + _Min_Heap_Size; + . = . + _Min_Stack_Size; + . = ALIGN(4); + } >RAM + + .ARM.attributes 0 : { *(.ARM.attributes) } +} + + diff --git a/demo/fw/tinyprintf b/demo/fw/tinyprintf new file mode 160000 index 0000000..2ee3012 --- /dev/null +++ b/demo/fw/tinyprintf @@ -0,0 +1 @@ +Subproject commit 2ee30120ec15e321566b43f83c731d060bb437f5 diff --git a/demo/fw/tools/ldparser.py b/demo/fw/tools/ldparser.py new file mode 100644 index 0000000..c620fe2 --- /dev/null +++ b/demo/fw/tools/ldparser.py @@ -0,0 +1,126 @@ + +import sys + +import pyparsing as pp +from pyparsing import pyparsing_common as ppc + +LPAREN, RPAREN, LBRACE, RBRACE, LBROK, RBROK, COLON, SEMICOLON, EQUALS, COMMA = map(pp.Suppress, '(){}<>:;=,') + +parse_suffix_int = lambda lit: int(lit[:-1]) * (10**(3*(1 + 'kmgtpe'.find(lit[-1].lower())))) +si_suffix = pp.oneOf('k m g t p e', caseless=True) + +numeric_literal = pp.Regex('0x[0-9a-fA-F]+').setName('hex int').setParseAction(pp.tokenMap(int, 16)) \ + | (pp.Regex('[0-9]+[kKmMgGtTpPeE]')).setName('size int').setParseAction(pp.tokenMap(parse_suffix_int)) \ + | pp.Word(pp.nums).setName('int').setParseAction(pp.tokenMap(int)) +access_def = pp.Regex('[rR]?[wW]?[xX]?').setName('access literal').setParseAction(pp.tokenMap(str.lower)) + +origin_expr = pp.Suppress(pp.CaselessKeyword('ORIGIN')) + EQUALS + numeric_literal +length_expr = pp.Suppress(pp.CaselessKeyword('LENGTH')) + EQUALS + numeric_literal +mem_expr = pp.Group(ppc.identifier + LPAREN + access_def + RPAREN + COLON + origin_expr + COMMA + length_expr) +mem_contents = pp.ZeroOrMore(mem_expr) + +mem_toplevel = pp.CaselessKeyword("MEMORY") + pp.Group(LBRACE + pp.Optional(mem_contents, []) + RBRACE) + +glob = pp.Word(pp.alphanums + '._*') +match_expr = pp.Forward() +assignment = pp.Forward() +funccall = pp.Group(pp.Word(pp.alphas + '_') + LPAREN + (assignment | numeric_literal | match_expr | glob | ppc.identifier) + RPAREN + pp.Optional(SEMICOLON)) +value = numeric_literal | funccall | ppc.identifier | '.' +formula = (value + pp.oneOf('+ = * / %') + value) | value +# suppress stray semicolons +assignment << (SEMICOLON | pp.Group((ppc.identifier | '.') + EQUALS + (formula | value) + pp.Optional(SEMICOLON))) +match_expr << (glob + LPAREN + pp.OneOrMore(funccall | glob) + RPAREN) + +section_contents = pp.ZeroOrMore(assignment | funccall | match_expr); + +section_name = pp.Regex('\.[a-zA-Z0-9_.]+') +section_def = pp.Group(section_name + pp.Optional(numeric_literal) + COLON + LBRACE + pp.Group(section_contents) + + RBRACE + pp.Optional(RBROK + ppc.identifier + pp.Optional('AT' + RBROK + ppc.identifier))) +sec_contents = pp.ZeroOrMore(section_def | assignment) + +sections_toplevel = pp.Group(pp.CaselessKeyword("SECTIONS").suppress() + LBRACE + sec_contents + RBRACE) + +toplevel_elements = mem_toplevel | funccall | sections_toplevel | assignment +ldscript = pp.Group(pp.ZeroOrMore(toplevel_elements)) +ldscript.ignore(pp.cppStyleComment) + +if __name__ == '__main__': + import argparse + parser = argparse.ArgumentParser() + parser.add_argument('linker_script', type=argparse.FileType('r')) + args = parser.parse_args() + + #print(mem_expr.parseString('FLASH (rx) : ORIGIN = 0x0800000, LENGTH = 512K', parseAll=True)) + # print(ldscript.parseString(''' + # /* Entry Point */ + # ENTRY(Reset_Handler) + # + # /* Highest address of the user mode stack */ + # _estack = 0x20020000; /* end of RAM */ + # /* Generate a link error if heap and stack don't fit into RAM */ + # _Min_Heap_Size = 0x200;; /* required amount of heap */ + # _Min_Stack_Size = 0x400;; /* required amount of stack */ + # ''', parseAll=True)) + + print(ldscript.parseFile(args.linker_script, parseAll=True)) + #print(funccall.parseString('KEEP(*(.isr_vector))')) + #print(section_contents.parseString(''' + # . = ALIGN(4); + # KEEP(*(.isr_vector)) /* Startup code */ + # . = ALIGN(4); + # ''', parseAll=True)) + + #print(section_def.parseString(''' + # .text : + # { + # . = ALIGN(4); + # *(.text) /* .text sections (code) */ + # *(.text*) /* .text* sections (code) */ + # *(.glue_7) /* glue arm to thumb code */ + # *(.glue_7t) /* glue thumb to arm code */ + # *(.eh_frame) + # + # KEEP (*(.init)) + # KEEP (*(.fini)) + # + # . = ALIGN(4); + # _etext = .; /* define a global symbols at end of code */ + # } >FLASH + # ''', parseAll=True)) + + #print(section_def.parseString('.ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >FLASH', parseAll=True)) + + #print(assignment.parseString('__preinit_array_start = .', parseAll=True)) + #print(assignment.parseString('a = 23', parseAll=True)) + #print(funccall.parseString('foo (a=23)', parseAll=True)) + #print(funccall.parseString('PROVIDE_HIDDEN (__preinit_array_start = .);', parseAll=True)) + #print(section_def.parseString(''' + # .preinit_array : + # { + # PROVIDE_HIDDEN (__preinit_array_start = .); + # KEEP (*(.preinit_array*)) + # PROVIDE_HIDDEN (__preinit_array_end = .); + # } >FLASH''', parseAll=True)) + #print(match_expr.parseString('*(SORT(.init_array.*))', parseAll=True)) + #print(funccall.parseString('KEEP (*(SORT(.init_array.*)))', parseAll=True)) + #print(section_def.parseString(''' + # .init_array : + # { + # PROVIDE_HIDDEN (__init_array_start = .); + # KEEP (*(SORT(.init_array.*))) + # KEEP (*(.init_array*)) + # PROVIDE_HIDDEN (__init_array_end = .); + # } >FLASH + # ''', parseAll=True)) + + #print(match_expr.parseString('*(.ARM.extab* .gnu.linkonce.armextab.*)', parseAll=True)) + #print(formula.parseString('. + _Min_Heap_Size', parseAll=True)) + #print(assignment.parseString('. = . + _Min_Heap_Size;', parseAll=True)) + #print(sections_toplevel.parseString(''' + # SECTIONS + # { + # .ARMattributes : { } + # } + # ''', parseAll=True)) + #sys.exit(0) + diff --git a/demo/fw/tools/linkmem.py b/demo/fw/tools/linkmem.py new file mode 100644 index 0000000..934a571 --- /dev/null +++ b/demo/fw/tools/linkmem.py @@ -0,0 +1,276 @@ + +import tempfile +import os +from os import path +import sys +import re +import subprocess +from contextlib import contextmanager +from collections import defaultdict +import colorsys + +import cxxfilt +from elftools.elf.elffile import ELFFile +from elftools.elf.enums import ENUM_ST_SHNDX +from elftools.elf.descriptions import describe_symbol_type, describe_sh_type +import libarchive +import matplotlib.cm + +@contextmanager +def chdir(newdir): + old_cwd = os.getcwd() + try: + os.chdir(newdir) + yield + finally: + os.chdir(old_cwd) + +def keep_last(it, first=None): + last = first + for elem in it: + yield last, elem + last = elem + +def delim(start, end, it, first_only=True): + found = False + for elem in it: + if end(elem): + if first_only: + return + found = False + elif start(elem): + found = True + elif found: + yield elem + +def delim_prefix(start, end, it): + yield from delim(lambda l: l.startswith(start), lambda l: end is not None and l.startswith(end), it) + +def trace_source_files(linker, cmdline, trace_sections=[], total_sections=['.text', '.data', '.rodata']): + with tempfile.TemporaryDirectory() as tempdir: + out_path = path.join(tempdir, 'output.elf') + output = subprocess.check_output([linker, '-o', out_path, f'-Wl,--print-map', *cmdline]) + lines = [ line.strip() for line in output.decode().splitlines() ] + # FIXME also find isr vector table references + + defs = {} + objs = defaultdict(lambda: 0) + aliases = {} + sec_name = None + last_loc = None + last_sym = None + line_cont = None + for last_line, line in keep_last(delim_prefix('Linker script and memory map', 'OUTPUT', lines), first=''): + if not line or line.startswith('LOAD '): + sec_name = None + continue + + # first part of continuation line + if m := re.match('^(\.[0-9a-zA-Z-_.]+)$', line): + line_cont = line + sec_name = None + continue + + if line_cont: + line = line_cont + ' ' + line + line_cont = None + + # -ffunction-sections/-fdata-sections section + if m := re.match('^(\.[0-9a-zA-Z-_.]+)\.([0-9a-zA-Z-_.]+)\s+(0x[0-9a-f]+)\s+(0x[0-9a-f]+)\s+(\S+)$', line): + sec, sym, loc, size, obj = m.groups() + *_, sym = sym.rpartition('.') + sym = cxxfilt.demangle(sym) + size = int(size, 16) + obj = path.abspath(obj) + + if sec not in total_sections: + size = 0 + + objs[obj] += size + defs[sym] = (sec, size, obj) + + sec_name, last_loc, last_sym = sec, loc, sym + continue + + # regular (no -ffunction-sections/-fdata-sections) section + if m := re.match('^(\.[0-9a-zA-Z-_]+)\s+(0x[0-9a-f]+)\s+(0x[0-9a-f]+)\s+(\S+)$', line): + sec, _loc, size, obj = m.groups() + size = int(size, 16) + obj = path.abspath(obj) + + if sec in total_sections: + objs[obj] += size + + sec_name = sec + last_loc, last_sym = None, None + continue + + # symbol def + if m := re.match('^(0x[0-9a-f]+)\s+(\S+)$', line): + loc, sym = m.groups() + sym = cxxfilt.demangle(sym) + loc = int(loc, 16) + if sym in defs: + continue + + if loc == last_loc: + assert last_sym is not None + aliases[sym] = last_sym + else: + assert sec_name + defs[sym] = (sec_name, None, obj) + last_loc, last_sym = loc, sym + + continue + + refs = defaultdict(lambda: set()) + for sym, (sec, size, obj) in defs.items(): + fn, _, member = re.match('^([^()]+)(\((.+)\))?$', obj).groups() + fn = path.abspath(fn) + + if member: + subprocess.check_call(['ar', 'x', '--output', tempdir, fn, member]) + fn = path.join(tempdir, member) + + with open(fn, 'rb') as f: + elf = ELFFile(f) + + symtab = elf.get_section_by_name('.symtab') + + symtab_demangled = { cxxfilt.demangle(nsym.name).replace(' ', ''): i + for i, nsym in enumerate(symtab.iter_symbols()) } + + s = set() + sec_map = { sec.name: i for i, sec in enumerate(elf.iter_sections()) } + matches = [ i for name, i in sec_map.items() if re.match(f'\.rel\..*\.{sym}', name) ] + if matches: + sec = elf.get_section(matches[0]) + for reloc in sec.iter_relocations(): + refsym = symtab.get_symbol(reloc['r_info_sym']) + name = refsym.name if refsym.name else elf.get_section(refsym['st_shndx']).name.split('.')[-1] + s.add(name) + refs[sym] = s + + for tsec in trace_sections: + matches = [ i for name, i in sec_map.items() if name == f'.rel{tsec}' ] + s = set() + if matches: + sec = elf.get_section(matches[0]) + for reloc in sec.iter_relocations(): + refsym = symtab.get_symbol(reloc['r_info_sym']) + s.add(refsym.name) + refs[tsec.replace('.', '_')] |= s + + return objs, aliases, defs, refs + +@contextmanager +def wrap(leader='', print=print, left='{', right='}'): + print(leader, left) + yield lambda *args, **kwargs: print(' ', *args, **kwargs) + print(right) + +def mangle(name): + return re.sub('[^a-zA-Z0-9_]', '_', name) + +hexcolor = lambda r, g, b, *_a: f'#{int(r*255):02x}{int(g*255):02x}{int(b*255):02x}' +def vhex(val): + r,g,b,_a = matplotlib.cm.viridis(1.0-val) + fc = hexcolor(r, g, b) + h,s,v = colorsys.rgb_to_hsv(r,g,b) + cc = '#000000' if v > 0.8 else '#ffffff' + return fc, cc + +if __name__ == '__main__': + import argparse + parser = argparse.ArgumentParser() + parser.add_argument('--trace-sections', type=str, action='append', default=[]) + parser.add_argument('--trim-stubs', type=str, action='append', default=[]) + parser.add_argument('--highlight-subdirs', type=str, default=None) + parser.add_argument('linker_binary') + parser.add_argument('linker_args', nargs=argparse.REMAINDER) + args = parser.parse_args() + + trace_sections = args.trace_sections + trace_sections_mangled = { sec.replace('.', '_') for sec in trace_sections } + objs, aliases, syms, refs = trace_source_files(args.linker_binary, args.linker_args, trace_sections) + + clusters = defaultdict(lambda: []) + for sym, (sec, size, obj) in syms.items(): + clusters[obj].append((sym, sec, size)) + + max_ssize = max(size or 0 for _sec, size, _obj in syms.values()) + max_osize = max(objs.values()) + + subdir_prefix = path.abspath(args.highlight_subdirs) + '/' if args.highlight_subdirs else '### NO HIGHLIGHT ###' + first_comp = lambda le_path: path.dirname(le_path).partition(os.sep)[0] + subdir_colors = sorted({ first_comp(obj[len(subdir_prefix):]) for obj in objs if obj.startswith(subdir_prefix) }) + subdir_colors = { path: hexcolor(*matplotlib.cm.Pastel1(i/len(subdir_colors))) for i, path in enumerate(subdir_colors) } + + subdir_sizes = defaultdict(lambda: 0) + for obj, size in objs.items(): + if not isinstance(size, int): + continue + if obj.startswith(subdir_prefix): + subdir_sizes[first_comp(obj[len(subdir_prefix):])] += size + else: + subdir_sizes[''] += size + + print('Subdir sizes:', file=sys.stderr) + for subdir, size in sorted(subdir_sizes.items(), key=lambda x: x[1]): + print(f'{subdir:>20}: {size:>6,d} B', file=sys.stderr) + + def lookup_highlight(path): + if args.highlight_subdirs: + if obj.startswith(subdir_prefix): + highlight_head = first_comp(path[len(subdir_prefix):]) + return subdir_colors[highlight_head], highlight_head + else: + return '#e0e0e0', None + else: + return '#ddf7f4', None + + with wrap('digraph G', print) as lvl1print: + print('size="23.4,16.5!";') + print('graph [fontsize=40];') + print('node [fontsize=40];') + #print('ratio="fill";') + + print('rankdir=LR;') + print('ranksep=5;') + print('nodesep=0.2;') + print() + + for i, (obj, obj_syms) in enumerate(clusters.items()): + with wrap(f'subgraph cluster_{i}', lvl1print) as lvl2print: + print('style = "filled";') + highlight_color, highlight_head = lookup_highlight(obj) + print(f'bgcolor = "{highlight_color}";') + print('pencolor = none;') + fc, cc = vhex(objs[obj]/max_osize) + highlight_subdir_part = f'{highlight_head} / ' if highlight_head else '' + lvl2print(f'label = <
' + f'{highlight_subdir_part}' + f'{path.basename(obj)} ({objs[obj]}B)' + f'
>;') + lvl2print() + for sym, sec, size in obj_syms: + has_size = isinstance(size, int) and size > 0 + size_s = f' ({size}B)' if has_size else '' + fc, cc = vhex(size/max_ssize) if has_size else ('#ffffff', '#000000') + shape = 'box' if sec == '.text' else 'oval' + lvl2print(f'{mangle(sym)}[label = "{sym}{size_s}", style="rounded,filled", shape="{shape}", fillcolor="{fc}", fontname="carlito", fontcolor="{cc}" color=none];') + lvl1print() + + edges = set() + for start, ends in refs.items(): + for end in ends: + end = aliases.get(end, end) + if (start in syms or start in trace_sections_mangled) and end in syms: + edges.add((start, end)) + + for start, end in edges: + lvl1print(f'{mangle(start)} -> {mangle(end)} [style="bold", color="#333333"];') + + for sec in trace_sections: + lvl1print(f'{sec.replace(".", "_")} [label = "section {sec}", shape="box", style="filled,bold"];') + diff --git a/demo/fw/tools/linksize.py b/demo/fw/tools/linksize.py new file mode 100644 index 0000000..c41a951 --- /dev/null +++ b/demo/fw/tools/linksize.py @@ -0,0 +1,62 @@ +#!/usr/bin/env python3 + +def parse_linker_script(data): + pass + +def link(groups): + defined_symbols = {} + undefined_symbols = set() + for group, files in groups: + while True: + found_something = False + + for fn in files: + symbols = load_symbols(fn) + for symbol in symbols: + if symbol in defined_symbols: + + if not group or not found_something: + break + + +if __name__ == '__main__': + + import argparse + parser = argparse.ArgumentParser() + parser.add_argument('-T', '--script', type=str, help='Linker script to use') + parser.add_argument('-o', '--output', type=str, help='Output file to produce') + args, rest = parser.parse_known_intermixed_args() + print(rest) + + addprefix = lambda *xs: [ prefix + opt for opt in xs for prefix in ('', '-Wl,') ] + START_GROUP = addprefix('-(', '--start-group') + END_GROUP = addprefix('-)', '--end-group') + GROUP_OPTS = [*START_GROUP, *END_GROUP] + input_files = [ arg for arg in rest if not arg.startswith('-') or arg in GROUP_OPTS ] + + def input_file_iter(input_files): + group = False + files = [] + for arg in input_files: + if arg in START_GROUP: + assert not group + + if files: + yield False, files # nested -Wl,--start-group + group, files = True, [] + + elif arg in END_GROUP: + assert group # missing -Wl,--start-group + if files: + yield True, files + group, files = False, [] + + else: + files.append(arg) + + assert not group # missing -Wl,--end-group + if files: + yield False, files + + + diff --git a/demo/fw/tools/linktracer.py b/demo/fw/tools/linktracer.py new file mode 100644 index 0000000..0c53a60 --- /dev/null +++ b/demo/fw/tools/linktracer.py @@ -0,0 +1,118 @@ +#!/usr/bin/env python3 + +import re +import subprocess +import tempfile +import pprint + +ARCHIVE_RE = r'([^(]*)(\([^)]*\))?' + +def trace_source_files(linker, cmdline): + with tempfile.NamedTemporaryFile() as mapfile: + output = subprocess.check_output([linker, f'-Wl,--Map={mapfile.name}', *cmdline]) + + # intentionally use generator here + idx = 0 + lines = [ line.rstrip() for line in mapfile.read().decode().splitlines() if line.strip() ] + + for idx, line in enumerate(lines[idx:], start=idx): + #print('Dropping', line) + if line == 'Linker script and memory map': + break + + idx += 1 + objects = [] + symbols = {} + sections = {} + current_object = None + last_offset = None + last_symbol = None + cont_sec = None + cont_ind = None + current_section = None + for idx, line in enumerate(lines[idx:], start=idx): + print(f'Processing >{line}') + if line.startswith('LOAD'): + _load, obj = line.split() + objects.append(obj) + continue + + if line.startswith('OUTPUT'): + break + + m = re.match(r'^( ?)([^ ]+)? +(0x[0-9a-z]+) +(0x[0-9a-z]+)?(.*)?$', line) + if m is None: + m = re.match(r'^( ?)([^ ]+)?$', line) + if m: + cont_ind, cont_sec = m.groups() + else: + cont_ind, cont_sec = None, None + last_offset, last_symbol = None, None + continue + indent, sec, offx, size, sym_or_src = m.groups() + if sec is None: + sec = cont_sec + ind = cont_ind + cont_sec = None + cont_ind = None + print(f'vals: indent={indent} sec={sec} offx={offx} size={size} sym_or_src={sym_or_src}') + if not re.match('^[a-zA-Z_0-9<>():*]+$', sym_or_src): + continue + + if indent == '': + print(f'Section: {sec} 0x{size:x}') + current_section = sec + sections[sec] = size + last_offset = None + last_symbol = None + continue + + if offx is not None: + offx = int(offx, 16) + if size is not None: + size = int(size, 16) + + if size is not None and sym_or_src is not None: + # archive/object line + archive, _member = re.match(ARCHIVE_RE, sym_or_src).groups() + current_object = archive + last_offset = offx + else: + if sym_or_src is not None: + assert size is None + if last_offset is not None: + last_size = offx - last_offset + symbols[last_symbol] = (last_size, current_section) + print(f'Symbol: {last_symbol} 0x{last_size:x} @{current_section}') + last_offset = offx + last_symbol = sym_or_src + + idx += 1 + + for idx, line in enumerate(lines[idx:], start=idx): + if line == 'Cross Reference Table': + break + + idx += 1 + + # map which symbol was pulled from which object in the end + used_defs = {} + for line in lines: + *left, right = line.split() + + archive, _member = re.match(ARCHIVE_RE, right).groups() + if left: + used_defs[''.join(left)] = archive + + #pprint.pprint(symbols) + + +if __name__ == '__main__': + import argparse + parser = argparse.ArgumentParser() + parser.add_argument('linker_binary') + parser.add_argument('linker_args', nargs=argparse.REMAINDER) + args = parser.parse_args() + + source_files = trace_source_files(args.linker_binary, args.linker_args) + diff --git a/demo/fw/tools/mapparse.py b/demo/fw/tools/mapparse.py new file mode 100644 index 0000000..c1f460a --- /dev/null +++ b/demo/fw/tools/mapparse.py @@ -0,0 +1,129 @@ + +import re +from collections import defaultdict, namedtuple + +Section = namedtuple('Section', ['name', 'offset', 'objects']) +ObjectEntry = namedtuple('ObjectEntry', ['filename', 'object', 'offset', 'size']) +FileEntry = namedtuple('FileEntry', ['section', 'object', 'offset', 'length']) + +class Memory: + def __init__(self, name, origin, length, attrs=''): + self.name, self.origin, self.length, self.attrs = name, origin, length, attrs + self.sections = {} + self.files = defaultdict(lambda: []) + self.totals = defaultdict(lambda: 0) + + def add_toplevel(self, name, offx, length): + self.sections[name] = Section(offx, length, []) + + def add_obj(self, name, offx, length, fn, obj): + base_section, sep, subsec = name[1:].partition('.') + base_section = '.'+base_section + if base_section in self.sections: + sec = secname, secoffx, secobjs = self.sections[base_section] + secobjs.append(ObjectEntry(fn, obj, offx, length)) + else: + sec = None + self.files[fn].append(FileEntry(sec, obj, offx, length)) + self.totals[fn] += length + +class MapFile: + def __init__(self, s): + self._lines = s.splitlines() + self.memcfg = {} + self.defaultmem = Memory('default', 0, 0xffffffffffffffff) + self._parse() + + def __getitem__(self, offx_or_name): + ''' Lookup a memory area by name or address ''' + if offx_or_name in self.memcfg: + return self.memcfg[offx_or_name] + + elif isinstance(offx_or_name, int): + for mem in self.memcfg.values(): + if mem.origin <= offx_or_name < mem.origin+mem.length: + return mem + else: + return self.defaultmem + + raise ValueError('Invalid argument type for indexing') + + def _skip(self, regex): + matcher = re.compile(regex) + for l in self: + if matcher.match(l): + break + + def __iter__(self): + while self._lines: + yield self._lines.pop(0) + + def _parse(self): + self._skip('^Memory Configuration') + + # Parse memory segmentation info + self._skip('^Name') + for l in self: + if not l: + break + name, origin, length, *attrs = l.split() + if not name.startswith('*'): + self.memcfg[name] = Memory(name, int(origin, 16), int(length, 16), attrs[0] if attrs else '') + + # Parse section information + toplevel_m = re.compile('^(\.[a-zA-Z0-9_.]+)\s+(0x[0-9a-fA-F]+)\s+(0x[0-9a-fA-F]+)') + secondlevel_m = re.compile('^ (\.[a-zA-Z0-9_.]+)\s+(0x[0-9a-fA-F]+)\s+(0x[0-9a-fA-F]+)\s+(.*)$') + secondlevel_linebreak_m = re.compile('^ (\.[a-zA-Z0-9_.]+)\n') + filelike = re.compile('^(/?[^()]*\.[a-zA-Z0-9-_]+)(\(.*\))?') + linebreak_section = None + for l in self: + # Toplevel section + match = toplevel_m.match(l) + if match: + name, offx, length = match.groups() + offx, length = int(offx, 16), int(length, 16) + self[offx].add_toplevel(name, offx, length) + + match = secondlevel_linebreak_m.match(l) + if match: + linebreak_section, = match.groups() + continue + + if linebreak_section: + l = ' {} {}'.format(linebreak_section, l) + linebreak_section = None + + # Second-level section + match = secondlevel_m.match(l) + if match: + name, offx, length, misc = match.groups() + match = filelike.match(misc) + if match: + fn, obj = match.groups() + obj = obj.strip('()') if obj else None + offx, length = int(offx, 16), int(length, 16) + self[offx].add_obj(name, offx, length, fn, obj) + + +if __name__ == '__main__': + import argparse + parser = argparse.ArgumentParser(description='Parser GCC map file') + parser.add_argument('mapfile', type=argparse.FileType('r'), help='The GCC .map file to parse') + parser.add_argument('-m', '--memory', type=str, help='The memory segments to print, comma-separated') + args = parser.parse_args() + mf = MapFile(args.mapfile.read()) + args.mapfile.close() + + mems = args.memory.split(',') if args.memory else mf.memcfg.keys() + + for name in mems: + mem = mf.memcfg[name] + print('Symbols by file for memory', name) + for tot, fn in reversed(sorted( (tot, fn) for fn, tot in mem.totals.items() )): + print(' {:>8} {}'.format(tot, fn)) + for length, offx, sec, obj in reversed(sorted(( (length, offx, sec, obj) for sec, obj, offx, length in + mem.files[fn] ), key=lambda e: e[0] )): + name = sec.name if sec else None + print(' {:>8} {:>#08x} {}'.format(length, offx, obj)) + #print('{:>16} 0x{:016x} 0x{:016x} ({:>24}) {}'.format(name, origin, length, length, attrs)) + diff --git a/upstream/CMSIS_5 b/upstream/CMSIS_5 new file mode 160000 index 0000000..3623c46 --- /dev/null +++ b/upstream/CMSIS_5 @@ -0,0 +1 @@ +Subproject commit 3623c466819b80d9af6b0830e92f1f21a75d8243 diff --git a/upstream/PyCortexMDebug b/upstream/PyCortexMDebug new file mode 160000 index 0000000..e672ff4 --- /dev/null +++ b/upstream/PyCortexMDebug @@ -0,0 +1 @@ +Subproject commit e672ff4e0514802383e064972d75657a5e46e294 diff --git a/upstream/STM32CubeF4 b/upstream/STM32CubeF4 new file mode 160000 index 0000000..2f3b26f --- /dev/null +++ b/upstream/STM32CubeF4 @@ -0,0 +1 @@ +Subproject commit 2f3b26f16559f7af495727a98253067a31182cfc diff --git a/upstream/cmsis_device_f4 b/upstream/cmsis_device_f4 new file mode 160000 index 0000000..3d7a3c1 --- /dev/null +++ b/upstream/cmsis_device_f4 @@ -0,0 +1 @@ +Subproject commit 3d7a3c1bae597f1ff36431145a2e34ae82fdeecb diff --git a/upstream/stm32square b/upstream/stm32square new file mode 160000 index 0000000..8bb6e8c --- /dev/null +++ b/upstream/stm32square @@ -0,0 +1 @@ +Subproject commit 8bb6e8c614fd3e1ee90bddfbd191e8a8c4e72207