Initial commit, demo works

This commit is contained in:
jaseg 2021-06-27 13:44:21 +02:00
commit 7bc4391185
31 changed files with 3370 additions and 0 deletions

19
.gitmodules vendored Normal file
View file

@ -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

2
demo/fw/.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
build
venv

172
demo/fw/Makefile Normal file
View file

@ -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)

16
demo/fw/openocd.cfg Normal file
View file

@ -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

54
demo/fw/src/con_usart.c Normal file
View file

@ -0,0 +1,54 @@
/*
* This file is part of the tachibana project
*
* Copyright (C) 2021 jaseg <code@jaseg.de>
*
*
* 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 <http://www.gnu.org/licenses/>.
*
*/
#include <stm32f4_isr.h>
#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<<GPIO_MODER_MODER9_Pos) | (2<<GPIO_MODER_MODER10_Pos);
GPIOA->OSPEEDR &= ~GPIO_OSPEEDR_OSPEED9_Msk & ~GPIO_OSPEEDR_OSPEED10_Msk;
GPIOA->OSPEEDR |= (2<<GPIO_OSPEEDR_OSPEED9_Pos) | (2<<GPIO_OSPEEDR_OSPEED10_Pos);
GPIOA->AFR[1] &= ~GPIO_AFRH_AFSEL9_Msk & ~GPIO_AFRH_AFSEL10_Msk;
GPIOA->AFR[1] |= (7<<GPIO_AFRH_AFSEL9_Pos) | (7<<GPIO_AFRH_AFSEL10_Pos);
usart_dma_init(&con_usart, CON_USART_BAUDRATE);
}
void DMA2_Stream7_IRQHandler(void) {
usart_dma_stream_irq(&con_usart);
}

38
demo/fw/src/con_usart.h Normal file
View file

@ -0,0 +1,38 @@
/*
* This file is part of the tachibana project
*
* Copyright (C) 2021 jaseg <code@jaseg.de>
*
*
* 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 <http://www.gnu.org/licenses/>.
*
*/
#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__ */

46
demo/fw/src/dma_util.c Normal file
View file

@ -0,0 +1,46 @@
#include <assert.h>
#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;
}
}

10
demo/fw/src/dma_util.h Normal file
View file

@ -0,0 +1,10 @@
#ifndef __DMA_UTIL_H__
#define __DMA_UTIL_H__
#include <stdint.h>
#include "jl_global.h"
uint8_t dma_get_isr_and_clear(DMA_TypeDef *dma, int ch);
#endif /* __DMA_UTIL_H__ */

View file

@ -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<<gpio_idx;
gpio->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<<pin<<16;
}
void gpio_pin_output(GPIO_TypeDef *gpio, int pin, int speed) {
gpio_pin_setup(gpio, pin, 1, speed, 0, 0);
}
void gpio_pin_tristate(GPIO_TypeDef *gpio, int pin, int tristate) {
if (tristate)
gpio->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);
}

View file

@ -0,0 +1,14 @@
#ifndef __GPIO_HELPERS_H__
#define __GPIO_HELPERS_H__
#include <stm32f407xx.h>
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__ */

35
demo/fw/src/jl_global.h Normal file
View file

@ -0,0 +1,35 @@
#ifndef __jl_GLOBAL_H__
#define __jl_GLOBAL_H__
#include <stdint.h>
#include <sys/types.h>
#ifndef SIMULATION
#include <stm32f407xx.h>
#include <stm32f4_isr.h>
#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__ */

282
demo/fw/src/main.c Normal file
View file

@ -0,0 +1,282 @@
/*
* This file is part of the tachibana project
*
* Copyright (C) 2021 jaseg <code@jaseg.de>
*
*
* 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 <http://www.gnu.org/licenses/>.
*
*/
#include <stdbool.h>
#include <stdint.h>
#include <assert.h>
#include <string.h>
#include <math.h>
#include <stm32f407xx.h>
#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<<RCC_PLLCFGR_PLLM_Pos)
| (PLL_N << RCC_PLLCFGR_PLLN_Pos)
| ((PLL_P/2 - 1) << RCC_PLLCFGR_PLLP_Pos)
| (PLL_Q << RCC_PLLCFGR_PLLQ_Pos)
| RCC_PLLCFGR_PLLSRC; /* select HSE as PLL source */
RCC->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<<FLASH_ACR_LATENCY_Pos);
/* Select PLL as system clock source */
RCC->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<<GPIO_MODER_MODER6_Pos) | (1<<GPIO_MODER_MODER7_Pos);
GPIOB->MODER |= (1<<GPIO_MODER_MODER11_Pos) | (1<<GPIO_MODER_MODER12_Pos) | (1<<GPIO_MODER_MODER13_Pos)| (1<<GPIO_MODER_MODER14_Pos);
GPIOB->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<<GPIO_MODER_MODER5_Pos) /* SCK */
| (2<<GPIO_MODER_MODER6_Pos) /* MISO */
| (2<<GPIO_MODER_MODER7_Pos) /* MOSI */
| (1<<GPIO_MODER_MODER4_Pos); /* CS */
GPIOA->OSPEEDR &= ~GPIO_OSPEEDR_OSPEED5_Msk & ~GPIO_OSPEEDR_OSPEED6_Msk
& ~GPIO_OSPEEDR_OSPEED7_Msk & ~GPIO_OSPEEDR_OSPEED4_Msk;
GPIOA->OSPEEDR |= (2<<GPIO_OSPEEDR_OSPEED5_Pos) /* SCK */
| (2<<GPIO_OSPEEDR_OSPEED6_Pos) /* MISO */
| (2<<GPIO_OSPEEDR_OSPEED7_Pos) /* MOSI */
| (2<<GPIO_OSPEEDR_OSPEED4_Pos); /* CS */
GPIOA->AFR[0] &= ~GPIO_AFRL_AFSEL5_Msk & ~GPIO_AFRL_AFSEL6_Msk & ~GPIO_AFRL_AFSEL7_Msk;
GPIOA->AFR[0] |= (5<<GPIO_AFRL_AFSEL5_Pos) | (5<<GPIO_AFRL_AFSEL6_Pos) | (5<<GPIO_AFRL_AFSEL7_Pos);
RCC->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<<GPIO_MODER_MODER8_Pos);
GPIOA->AFR[1] &= ~GPIO_AFRH_AFSEL8_Msk;
GPIOA->AFR[1] |= 1<<GPIO_AFRH_AFSEL8_Pos;
GPIOA->MODER |= (1<<GPIO_MODER_MODER11_Pos) | (1<<GPIO_MODER_MODER12_Pos) | (1<<GPIO_MODER_MODER15_Pos);
#endif
con_printf("Booted.\r\n");
unsigned int i = 0;
int k = 0;
con_printf("loop");
while (23) {
con_printf(" #%u", i);
if (k == 0)
spif_printf(&spif, "\33[1m");
if (k == 1)
spif_printf(&spif, "\33[4m");
if (k == 2)
spif_printf(&spif, "\33[1;4m");
if (k >= 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<sizeof(buf); e += 16) {
uint8_t *p = buf + e;
con_printf(" %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\r\n",
p[0x00], buf[0x01], buf[0x02], buf[0x03], buf[0x04], buf[0x05], buf[0x06], buf[0x07],
p[0x08], buf[0x09], buf[0x0a], buf[0x0b], buf[0x0c], buf[0x0d], buf[0x0e], buf[0x0f]);
}
con_printf("\r\n");
con_printf("loop");
}
for (int j=0; j<1000000; j++) {
/* pass */
}
}
return 0;
}
void NMI_Handler(void) {
asm volatile ("bkpt #1");
}
void HardFault_Handler(void) {
asm volatile ("bkpt #2");
}
void MemManage_Handler(void) {
asm volatile ("bkpt #3");
}
void BusFault_Handler(void) {
asm volatile ("bkpt #4");
}
void UsageFault_Handler(void) {
asm volatile ("bkpt #5");
}
void SVC_Handler(void) {
asm volatile ("bkpt #6");
}
void DebugMon_Handler(void) {
asm volatile ("bkpt #7");
}
void PendSV_Handler(void) {
asm volatile ("bkpt #8");
}
void SysTick_Handler(void) {
asm volatile ("bkpt #9");
}

207
demo/fw/src/serial.c Normal file
View file

@ -0,0 +1,207 @@
/*
* This file is part of the tachibana project
*
* Copyright (C) 2021 jaseg <code@jaseg.de>
*
*
* 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 <http://www.gnu.org/licenses/>.
*
*/
#include <string.h>
#include <stdarg.h>
#include <stdlib.h>
#include "dma_util.h"
#include "jl_global.h"
#include "serial.h"
#include <tinyprintf.h>
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; i<ARRAY_LENGTH(us->tx_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<<DMA_SxCR_CHSEL_Pos)
| (0<<DMA_SxCR_PL_Pos)
| (1<<DMA_SxCR_DIR_Pos)
| (0<<DMA_SxCR_MSIZE_Pos) /* 8 bit */
| (0<<DMA_SxCR_PSIZE_Pos) /* 8 bit */
| DMA_SxCR_MINC
| DMA_SxCR_TCIE; /* Enable transfer complete interrupt. */
/* triggered on transfer completion. We use this to process the ADC data */
NVIC_EnableIRQ(us->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; i<chunk_len; i++)
usart_putc_nonblocking(us, chunk[i]);
return usart_flush(us);
}
void usart_wait_chunk_free(volatile struct usart_desc *us) {
while (us->tx_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);
}

84
demo/fw/src/serial.h Normal file
View file

@ -0,0 +1,84 @@
/*
* This file is part of the tachibana project
*
* Copyright (C) 2021 jaseg <code@jaseg.de>
*
*
* 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 <http://www.gnu.org/licenses/>.
*
*/
#ifndef __SERIAL_H__
#define __SERIAL_H__
#include <stdint.h>
#include <stddef.h>
#include <stdarg.h>
#include <errno.h>
#include <stdbool.h>
#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__

97
demo/fw/src/spi.c Normal file
View file

@ -0,0 +1,97 @@
/*
* This file is part of the tachibana project
*
* Copyright (C) 2021 jaseg <code@jaseg.de>
*
*
* 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 <http://www.gnu.org/licenses/>.
*
*/
#include <tinyprintf.h>
#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<<SPI_CR1_BR_Pos) | SPI_CR1_SSM | SPI_CR1_SSI | SPI_CR1_SPE | SPI_CR1_MSTR;
}
void spif_command(struct spi_fpga_if *spif, uint8_t cmd, size_t arglen, const uint8_t *args, size_t outlen, uint8_t *out) {
spif->cs(0);
spi_write(spif, cmd);
size_t len_min = arglen < outlen ? arglen : outlen;
for (size_t i=0; i<len_min; i++) {
out[i] = spi_xfer(spif, args[i]);
}
/* write remaining argument bytes if any, ... */
for (size_t i=len_min; i<arglen; i++) {
spi_write(spif, args[i]);
}
/* ... or read remaining response bytes. */
for (size_t i=len_min; i<outlen; i++) {
out[i] = spi_read(spif);
}
spif->cs(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;
}

22
demo/fw/src/spi.h Normal file
View file

@ -0,0 +1,22 @@
#ifndef __SPI_FLASH_H__
#define __SPI_FLASH_H__
#include <stdbool.h>
#include <unistd.h>
#include <stm32f407xx.h>
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__ */

View file

@ -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
*
* <h2><center>&copy; COPYRIGHT 2017 STMicroelectronics</center></h2>
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of STMicroelectronics nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
******************************************************************************
*/
.syntax unified
.cpu cortex-m4
.fpu softvfp
.thumb
.global g_pfnVectors
.global Default_Handler
/* start address for the initialization values of the .data section.
defined in linker script */
.word _sidata
/* start address for the .data section. defined in linker script */
.word _sdata
/* end address for the .data section. defined in linker script */
.word _edata
/* start address for the .bss section. defined in linker script */
.word _sbss
/* end address for the .bss section. defined in linker script */
.word _ebss
/* 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****/

98
demo/fw/src/stm32f4_isr.h Normal file
View file

@ -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__ */

View file

@ -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
*
* <h2><center>&copy; COPYRIGHT 2017 STMicroelectronics</center></h2>
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of STMicroelectronics nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
******************************************************************************
*/
/** @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****/

148
demo/fw/stm32f407.ld Normal file
View file

@ -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) }
}

1
demo/fw/tinyprintf Submodule

@ -0,0 +1 @@
Subproject commit 2ee30120ec15e321566b43f83c731d060bb437f5

126
demo/fw/tools/ldparser.py Normal file
View file

@ -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)

276
demo/fw/tools/linkmem.py Normal file
View file

@ -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['<others>'] += 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'<font face="carlito" color="{cc}" point-size="40">{highlight_head} / </font>' if highlight_head else ''
lvl2print(f'label = <<table border="0"><tr><td border="0" cellpadding="5" bgcolor="{fc}">'
f'{highlight_subdir_part}'
f'<font face="carlito" color="{cc}"><b>{path.basename(obj)} ({objs[obj]}B)</b></font>'
f'</td></tr></table>>;')
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"];')

62
demo/fw/tools/linksize.py Normal file
View file

@ -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

118
demo/fw/tools/linktracer.py Normal file
View file

@ -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)

129
demo/fw/tools/mapparse.py Normal file
View file

@ -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))

1
upstream/CMSIS_5 Submodule

@ -0,0 +1 @@
Subproject commit 3623c466819b80d9af6b0830e92f1f21a75d8243

@ -0,0 +1 @@
Subproject commit e672ff4e0514802383e064972d75657a5e46e294

1
upstream/STM32CubeF4 Submodule

@ -0,0 +1 @@
Subproject commit 2f3b26f16559f7af495727a98253067a31182cfc

@ -0,0 +1 @@
Subproject commit 3d7a3c1bae597f1ff36431145a2e34ae82fdeecb

1
upstream/stm32square Submodule

@ -0,0 +1 @@
Subproject commit 8bb6e8c614fd3e1ee90bddfbd191e8a8c4e72207