From 90038f4378b7cdbe98e32ed1e5e3055dbe4776f2 Mon Sep 17 00:00:00 2001 From: jaseg Date: Thu, 20 Dec 2018 18:54:41 +0900 Subject: Add initial center firmware --- fw/.gitignore | 11 ++ fw/8b10b.c | 190 ++++++++++++++++++++++++ fw/8b10b.h | 38 +++++ fw/8b10b_test.c | 78 ++++++++++ fw/Makefile | 101 +++++++++++++ fw/base.c | 21 +++ fw/cmsis_exports.c | 0 fw/global.h | 48 ++++++ fw/main.c | 103 +++++++++++++ fw/openocd.cfg | 16 ++ fw/startup_stm32f030x6.s | 273 ++++++++++++++++++++++++++++++++++ fw/stm32_flash.ld | 136 +++++++++++++++++ fw/system_stm32f0xx.c | 336 ++++++++++++++++++++++++++++++++++++++++++ fw/tools/gen_cmsis_exports.py | 30 ++++ 14 files changed, 1381 insertions(+) create mode 100644 fw/.gitignore create mode 100644 fw/8b10b.c create mode 100644 fw/8b10b.h create mode 100644 fw/8b10b_test.c create mode 100644 fw/Makefile create mode 100644 fw/base.c create mode 100644 fw/cmsis_exports.c create mode 100644 fw/global.h create mode 100644 fw/main.c create mode 100644 fw/openocd.cfg create mode 100644 fw/startup_stm32f030x6.s create mode 100644 fw/stm32_flash.ld create mode 100644 fw/system_stm32f0xx.c create mode 100644 fw/tools/gen_cmsis_exports.py (limited to 'fw') diff --git a/fw/.gitignore b/fw/.gitignore new file mode 100644 index 0000000..3e36fab --- /dev/null +++ b/fw/.gitignore @@ -0,0 +1,11 @@ +*.elf +*.o +*.expand +*.hex +*.lst +*.map +*.bin +sources.c +sources.tar.xz +sources.tar.xz.zip +8b10b_test diff --git a/fw/8b10b.c b/fw/8b10b.c new file mode 100644 index 0000000..550e87c --- /dev/null +++ b/fw/8b10b.c @@ -0,0 +1,190 @@ + +#include "8b10b.h" + +static const struct entry_5b6b map_5b6b[32] = { + {0b100111, 0b011000}, /* D.00 */ + {0b011101, 0b100010}, /* D.01 */ + {0b101101, 0b010010}, /* D.02 */ + {0b110001, 0b110001}, /* D.03 */ + {0b110101, 0b001010}, /* D.04 */ + {0b101001, 0b101001}, /* D.05 */ + {0b011001, 0b011001}, /* D.06 */ + {0b111000, 0b000111}, /* D.07 */ + {0b111001, 0b000110}, /* D.08 */ + {0b100101, 0b100101}, /* D.09 */ + {0b010101, 0b010101}, /* D.10 */ + {0b110100, 0b110100}, /* D.11 */ + {0b001101, 0b001101}, /* D.12 */ + {0b101100, 0b101100}, /* D.13 */ + {0b011100, 0b011100}, /* D.14 */ + {0b010111, 0b101000}, /* D.15 */ + {0b011011, 0b100100}, /* D.16 */ + {0b100011, 0b100011}, /* D.17 */ + {0b010011, 0b010011}, /* D.18 */ + {0b110010, 0b110010}, /* D.19 */ + {0b001011, 0b001011}, /* D.20 */ + {0b101010, 0b101010}, /* D.21 */ + {0b011010, 0b011010}, /* D.22 */ + {0b111010, 0b000101}, /* D.23 */ + {0b110011, 0b001100}, /* D.24 */ + {0b100110, 0b100110}, /* D.25 */ + {0b010110, 0b010110}, /* D.26 */ + {0b110110, 0b001001}, /* D.27 */ + {0b001110, 0b001110}, /* D.28 */ + {0b101110, 0b010001}, /* D.29 */ + {0b011110, 0b100001}, /* D.30 */ + {0b101011, 0b010100} /* D.31 */ +}; + +static const int8_t map_6b5b[64] = { + [0b000101] = 23, /* rd = +1 */ + [0b000110] = 8, /* rd = +1 */ + [0b000111] = 7, /* rd = +1 */ + [0b001001] = 27, /* rd = +1 */ + [0b001010] = 4, /* rd = +1 */ + [0b001011] = 20, /* rd = +1 */ + [0b001100] = 24, /* rd = +1 */ + [0b001101] = 12, /* rd = +1 */ + [0b001101] = 12, /* rd = -1 */ + [0b001110] = 28, /* rd = +1 */ + [0b010001] = 29, /* rd = +1 */ + [0b010010] = 2, /* rd = +1 */ + [0b010011] = 18, /* rd = +1 */ + [0b010100] = 31, /* rd = +1 */ + [0b010101] = 10, /* rd = +1 */ + [0b010101] = 10, /* rd = -1 */ + [0b010110] = 26, /* rd = +1 */ + [0b010111] = 15, /* rd = -1 */ + [0b011000] = -1, /* rd = +1 */ + [0b011001] = 6, /* rd = +1 */ + [0b011010] = 22, /* rd = +1 */ + [0b011011] = 16, /* rd = -1 */ + [0b011100] = 14, /* rd = -1 */ + [0b011101] = 1, /* rd = -1 */ + [0b011110] = 30, /* rd = -1 */ + [0b100001] = 30, /* rd = +1 */ + [0b100010] = 1, /* rd = +1 */ + [0b100011] = 17, /* rd = -1 */ + [0b100100] = 16, /* rd = +1 */ + [0b100101] = 9, /* rd = -1 */ + [0b100110] = 25, /* rd = -1 */ + [0b100111] = -1, /* rd = -1 */ + [0b101000] = 15, /* rd = +1 */ + [0b101001] = 5, /* rd = -1 */ + [0b101010] = 21, /* rd = -1 */ + [0b101011] = 31, /* rd = -1 */ + [0b101100] = 13, /* rd = -1 */ + [0b101101] = 2, /* rd = -1 */ + [0b101110] = 29, /* rd = -1 */ + [0b110001] = 3, /* rd = -1 */ + [0b110010] = 19, /* rd = -1 */ + [0b110011] = 24, /* rd = -1 */ + [0b110100] = 11, /* rd = -1 */ + [0b110101] = 4, /* rd = -1 */ + [0b110110] = 27, /* rd = -1 */ + [0b111000] = 7, /* rd = -1 */ + [0b111001] = 8, /* rd = -1 */ + [0b111010] = 23 /* rd = -1 */ +}; + +static const struct entry_5b6b K28 = {0b001111, 0b110000}; + +static const struct entry_3b4b map_d_3b4b[7] = { + {0b1011, 0b0100}, /* D.x.0 */ + {0b1001, 0b1001}, /* D.x.1 */ + {0b0101, 0b0101}, /* D.x.2 */ + {0b1100, 0b0011}, /* D.x.3 */ + {0b1101, 0b0010}, /* D.x.4 */ + {0b1010, 0b1010}, /* D.x.5 */ + {0b0110, 0b0110} /* D.x.6 */ +}; + +static const struct entry_3b4b Dx_P7 = {0b1110, 0b0001}, + Dx_A7 = {0b0111, 0b1000}; + +static const struct entry_3b4b map_3b4b_k[8] = { + {0b1011, 0b0100}, /* K.x.0 */ + {0b0110, 0b1001}, /* K.x.1 */ + {0b1010, 0b0101}, /* K.x.2 */ + {0b1100, 0b0011}, /* K.x.3 */ + {0b1101, 0b0010}, /* K.x.4 */ + {0b0101, 0b1010}, /* K.x.5 */ + {0b1001, 0b0110}, /* K.x.6 */ + {0b0111, 0b1000} /* K.x.7 */ +}; + +static const int8_t map_4b3b[16] = { + [0b0001] = 7, /* DxP7 rd = +1 */ + [0b0010] = 4, /* rd = +1 */ + [0b0011] = 3, /* rd = +1 */ + [0b0100] = -1, /* rd = +1 */ + [0b0101] = 2, /* rd = -1 */ + [0b0110] = 6, /* rd = -1 */ + [0b0111] = 7, /* DxA7 rd = -1 */ + [0b1000] = 7, /* DxA7 rd = +1 */ + [0b1001] = 1, /* rd = -1 */ + [0b1010] = 5, /* rd = -1 */ + [0b1011] = -1, /* rd = -1 */ + [0b1100] = 3, /* rd = -1 */ + [0b1101] = 4, /* rd = -1 */ + [0b1110] = 7, /* DxP7 rd = -1 */ + [0b1111] = 0, /* invalid */ + [0b0000] = 0 /* invalid */ +}; + +static const uint16_t k_sym_map[K_CODES_LAST] = { + [K28_0] = 0b0011110100, + [K28_1] = 0b0011111001, + [K28_2] = 0b0011110101, + [K28_3] = 0b0011110011, + [K28_4] = 0b0011110010, + [K28_5] = 0b0011111010, + [K28_6] = 0b0011110110, + [K28_7] = 0b0011111000, + [K23_7] = 0b1110101000, + [K27_7] = 0b1101101000, + [K29_7] = 0b1011101000, + [K30_7] = 0b0111101000 +}; + +void xfr_8b10b_reset(struct state_8b10b *st) { + st->rx = 0; + st->bit_ctr = 0; /* unsynchronized */ +} + +int xfr_8b10b_feed_bit(struct state_8b10b *st, int bit) { + uint32_t pattern = st->rx = (st->rx<<1 | !!bit) & 0x3ff; + uint16_t comma = k_sym_map[K28_1]; + if (pattern == comma || pattern == ((~comma)&0x3ff)) { + st->bit_ctr = 1; + return -K28_1; + } + + if (st->bit_ctr == 10) { + st->bit_ctr = 1; + + for (int i=1; i> 4]; + + if (p3b == 0 || p5b == 0) + return -DECODING_ERROR; + + p3b = (p3b == -1) ? 0 : p3b; + p5b = (p5b == -1) ? 0 : p5b; + return p3b<<5 | p5b; + + } else if (st->bit_ctr > 0) { + st->bit_ctr++; + } /* else we do not have sync yet */ + return -DECODING_IN_PROGRESS; +} + +bool xfr_8b10b_has_sync(struct state_8b10b *st) { + return st->bit_ctr != 0; +} + diff --git a/fw/8b10b.h b/fw/8b10b.h new file mode 100644 index 0000000..84763b1 --- /dev/null +++ b/fw/8b10b.h @@ -0,0 +1,38 @@ +#ifndef __8B10B_H__ +#define __8B10B_H__ + +#include +#include + +enum k_code { + K28_0=1, K28_1, K28_2, K28_3, + K28_4, K28_5, K28_6, K28_7, + K23_7, K27_7, K29_7, K30_7, + K_CODES_LAST +}; + +enum decoder_return_codes { + _K_CODES_LAST = K_CODES_LAST, + DECODING_ERROR, + DECODING_IN_PROGRESS +}; + +struct entry_3b4b { + uint8_t rd_neg, rd_pos; +}; + +struct entry_5b6b { + uint8_t rd_neg, rd_pos; +}; + +struct state_8b10b { + uint32_t rx; + int bit_ctr; +}; + + +void xfr_8b10b_reset(struct state_8b10b *st); +int xfr_8b10b_feed_bit(struct state_8b10b *st, int bit); +bool xfr_8b10b_has_sync(struct state_8b10b *st); + +#endif diff --git a/fw/8b10b_test.c b/fw/8b10b_test.c new file mode 100644 index 0000000..d11e6b2 --- /dev/null +++ b/fw/8b10b_test.c @@ -0,0 +1,78 @@ + +#include + +#include "8b10b.h" + +static const char * const rc_names[] = { + [K28_0] = "K.28.0", + [K28_1] = "K.28.1", + [K28_2] = "K.28.2", + [K28_3] = "K.28.3", + [K28_4] = "K.28.4", + [K28_5] = "K.28.5", + [K28_6] = "K.28.6", + [K28_7] = "K.28.7", + [K23_7] = "K.23.7", + [K27_7] = "K.27.7", + [K29_7] = "K.29.7", + [K30_7] = "K.30.7", + [DECODING_ERROR] = "ERROR", + [DECODING_IN_PROGRESS] = "." +}; + +int main(void) { + struct state_8b10b st; + + xfr_8b10b_reset(&st); + + int c; + int comment = 0; + while ((c=fgetc(stdin)) != EOF) { + int bit; + + if (comment) { + if (c == '\n') + comment = 0; + continue; + } + + if (c == '\r' || c == ' ' || c == '\t' || c == '\n') + continue; + + if (c == '#') { + comment = 1; + continue; + } + + if (c == '0') { + bit = 0; + } else if (c == '1') { + bit = 1; + } else { + fprintf(stderr, "Parse error: Bit must be 0 or 1, not '%c'. Exiting.\n", c); + return 1; + } + + int read_result = xfr_8b10b_feed_bit(&st, bit); + char sync_status = xfr_8b10b_has_sync(&st) ? 'S' : 'U'; + + if (read_result >= 0) { + fprintf(stdout, "%c%02x ", sync_status, read_result); + + } else { + if (-read_result > sizeof(rc_names)/sizeof(rc_names[0])) { + fprintf(stderr, "Illegal read result %d. Exiting.\n", read_result); + return 2; + } + + const char * const msg = rc_names[-read_result]; + if (!msg) { + fprintf(stderr, "Illegal read result %d. Exiting.\n", read_result); + return 2; + } + + fprintf(stdout, "%c%s ", sync_status, msg); + } + } +} + diff --git a/fw/Makefile b/fw/Makefile new file mode 100644 index 0000000..1098717 --- /dev/null +++ b/fw/Makefile @@ -0,0 +1,101 @@ +# Megumin LED display firmware +# Copyright (C) 2018 Sebastian Götte +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +CUBE_PATH ?= $(wildcard ~)/resource/STM32CubeF0 +CMSIS_PATH ?= $(CUBE_PATH)/Drivers/CMSIS +CMSIS_DEV_PATH ?= $(CMSIS_PATH)/Device/ST/STM32F0xx +HAL_PATH ?= $(CUBE_PATH)/Drivers/STM32F0xx_HAL_Driver + +MAC_ADDR ?= 0xdeadbeef + +CC := arm-none-eabi-gcc +LD := arm-none-eabi-ld +OBJCOPY := arm-none-eabi-objcopy +OBJDUMP := arm-none-eabi-objdump +SIZE := arm-none-eabi-size + +CFLAGS = -g -Wall -std=gnu11 -O0 -fdump-rtl-expand -DMAC_ADDR=$(MAC_ADDR) +CFLAGS += -mlittle-endian -mcpu=cortex-m0 -march=armv6-m -mthumb +#CFLAGS += -ffunction-sections -fdata-sections +LDFLAGS = -nostartfiles +#LDFLAGS += -specs=rdimon.specs -DSEMIHOSTING +LDFLAGS += -Wl,-Map=main.map -nostdlib +#LDFLAGS += -Wl,--gc-sections +LIBS = -lgcc +#LIBS += -lrdimon + +# Technically we're using an STM32F030F4, but apart from the TSSOP20 package that one is largely identical to the +# STM32F030*6 and there is no separate device header provided for it, so we're faking a *6 device here. This is +# even documented in stm32f0xx.h. Thanks ST! +CFLAGS += -DSTM32F030x6 -DHSE_VALUE=8000000 + +LDFLAGS += -Tstm32_flash.ld +CFLAGS += -I$(CMSIS_DEV_PATH)/Include -I$(CMSIS_PATH)/Include -I$(HAL_PATH)/Inc -Iconfig -Wno-unused +LDFLAGS += -L$(CMSIS_PATH)/Lib/GCC -larm_cortexM0l_math + +################################################### + +.PHONY: program clean + +all: main.elf + +cmsis_exports.c: $(CMSIS_DEV_PATH)/Include/stm32f030x6.h $(CMSIS_PATH)/Include/core_cm0.h + python3 tools/gen_cmsis_exports.py $^ > $@ + +%.o: %.c + $(CC) -c $(CFLAGS) -o $@ $^ +# $(CC) -E $(CFLAGS) -o $(@:.o=.pp) $^ + +%.o: %.s + $(CC) -c $(CFLAGS) -o $@ $^ +# $(CC) -E $(CFLAGS) -o $(@:.o=.pp) $^ + +%.dot: %.elf + r2 -a arm -qc 'aa;agC' $< 2>/dev/null >$@ + +sources.tar.xz: main.c Makefile + tar -caf $@ $^ + +# don't ask... +sources.tar.xz.zip: sources.tar.xz + zip $@ $^ + +sources.c: sources.tar.xz.zip + xxd -i $< | head -n -1 | sed 's/=/__attribute__((section(".source_tarball"))) =/' > $@ + +main.elf: main.o startup_stm32f030x6.o system_stm32f0xx.o $(HAL_PATH)/Src/stm32f0xx_ll_utils.o base.o cmsis_exports.o 8b10b.o sources.o + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LIBS) + $(OBJCOPY) -O ihex $@ $(@:.elf=.hex) + $(OBJCOPY) -O binary $@ $(@:.elf=.bin) + $(OBJDUMP) -St $@ >$(@:.elf=.lst) + $(SIZE) $@ + +program: main.elf openocd.cfg + openocd -f openocd.cfg -c "program $< verify reset exit" + +8b10b_test: 8b10b_test.c 8b10b.c + gcc -o $@ $^ + +clean: + rm -f **.o + rm -f main.elf main.hex main.bin main.map main.lst + rm -f **.expand + rm -f cmsis_exports.c + rm -f sources.tar.xz + rm -f sources.tar.xz.zip + rm -f sources.c + rm -f *.dot + diff --git a/fw/base.c b/fw/base.c new file mode 100644 index 0000000..277c662 --- /dev/null +++ b/fw/base.c @@ -0,0 +1,21 @@ + +#include + +int __errno = 0; +void *_impure_ptr = NULL; + +void __sinit(void) { +} + +void *memset(void *s, int c, size_t n) { + char *end = (char *)s + n; + for (char *p = (char *)s; p < end; p++) + *p = (char)c; + return s; +} + +size_t strlen(const char *s) { + const char *start = s; + while (*s++); + return s - start - 1; +} diff --git a/fw/cmsis_exports.c b/fw/cmsis_exports.c new file mode 100644 index 0000000..e69de29 diff --git a/fw/global.h b/fw/global.h new file mode 100644 index 0000000..03d3920 --- /dev/null +++ b/fw/global.h @@ -0,0 +1,48 @@ +/* Megumin LED display firmware + * Copyright (C) 2018 Sebastian Götte + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef __GLOBAL_H__ +#define __GLOBAL_H__ + +/* Workaround for sub-par ST libraries */ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wstrict-aliasing" +#include +#include +#include +#pragma GCC diagnostic pop + +#include + +#include +#include +#include +#include + +/* Microcontroller part number: STM32F030F4C6 */ + +/* Things used for module status reporting. */ +#define FIRMWARE_VERSION 2 +#define HARDWARE_VERSION 4 + +#define TS_CAL1 (*(uint16_t *)0x1FFFF7B8) +#define VREFINT_CAL (*(uint16_t *)0x1FFFF7BA) + +extern volatile unsigned int sys_time; +extern volatile unsigned int sys_time_seconds; + +#endif/*__GLOBAL_H__*/ diff --git a/fw/main.c b/fw/main.c new file mode 100644 index 0000000..b599cff --- /dev/null +++ b/fw/main.c @@ -0,0 +1,103 @@ +/* Megumin LED display firmware + * Copyright (C) 2018 Sebastian Götte + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "global.h" + +volatile unsigned int sys_time = 0; +volatile unsigned int sys_time_seconds = 0; + +int main(void) { + RCC->CR |= RCC_CR_HSEON; + while (!(RCC->CR&RCC_CR_HSERDY)); + RCC->CFGR &= ~RCC_CFGR_PLLMUL_Msk & ~RCC_CFGR_SW_Msk & ~RCC_CFGR_PPRE_Msk & ~RCC_CFGR_HPRE_Msk; + RCC->CFGR |= (2< 32.0MHz */ + RCC->CFGR2 &= ~RCC_CFGR2_PREDIV_Msk; + RCC->CFGR2 |= RCC_CFGR2_PREDIV_DIV2; /* prediv :2 -> 4.0MHz */ + RCC->CR |= RCC_CR_PLLON; + while (!(RCC->CR&RCC_CR_PLLRDY)); + RCC->CFGR |= (2<AHBENR |= RCC_AHBENR_GPIOAEN | RCC_AHBENR_FLITFEN; + RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN | RCC_APB2ENR_DBGMCUEN | RCC_APB2ENR_TIM1EN; + RCC->APB1ENR |= RCC_APB1ENR_TIM3EN; + + GPIOA->MODER |= + (3<OSPEEDR |= + (2<ODR &= ~(!a<<3 | !b<<7 | c<<6 | d<<4); + GPIOA->ODR |= a<<3 | b<<7 | !c<<6 | !d<<4; + } + while (42) { +#define FOO 500000 + for (int i=0; iFLASH + + /* the program code is stored in the .text section, which goes to Flash */ + .text : { + . = ALIGN(4); + + *(.text) /* normal code */ + *(.text.*) /* -ffunction-sections code */ + *(.rodata) /* read-only data (constants) */ + *(.rodata*) /* -fdata-sections read only data */ + *(.glue_7) /* TBD - needed ? */ + *(.glue_7t) /* TBD - needed ? */ + + *(.source_tarball) + + /* Necessary KEEP sections (see http://sourceware.org/ml/newlib/2005/msg00255.html) */ + KEEP (*(.init)) + KEEP (*(.fini)) + KEEP (*(.source_tarball)) + + . = ALIGN(4); + _etext = .; + /* This is used by the startup in order to initialize the .data section */ + _sidata = _etext; + } >FLASH + + /* + .configflash : { + . = ALIGN(0x400); + *(.configdata) + _econfig = .; + } >FLASH + */ + + /* This is the initialized data section + The program executes knowing that the data is in the RAM + but the loader puts the initial values in the FLASH (inidata). + It is one task of the startup to copy the initial values from FLASH to RAM. */ + .data : AT ( _sidata ) { + . = ALIGN(4); + /* This is used by the startup in order to initialize the .data secion */ + _sdata = . ; + _data = . ; + + *(.data) + *(.data.*) + *(.RAMtext) + + . = ALIGN(4); + /* This is used by the startup in order to initialize the .data secion */ + _edata = . ; + } >RAM + + /* This is the uninitialized data section */ + .bss : { + . = ALIGN(4); + /* This is used by the startup in order to initialize the .bss secion */ + _sbss = .; + _bss = .; + + *(.bss) + *(.bss.*) /* patched by elias - allows the use of -fdata-sections */ + *(COMMON) + + . = ALIGN(4); + /* This is used by the startup in order to initialize the .bss secion */ + _ebss = . ; + } >RAM + + PROVIDE ( end = _ebss); + PROVIDE (_end = _ebss); + + __exidx_start = .; + __exidx_end = .; + + /* after that it's only debugging information. */ + + /* remove the debugging information from the standard libraries */ +/* /DISCARD/ : { + libc.a ( * ) + libm.a ( * ) + libgcc.a ( * ) + }*/ + + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } +} diff --git a/fw/system_stm32f0xx.c b/fw/system_stm32f0xx.c new file mode 100644 index 0000000..a43c3d6 --- /dev/null +++ b/fw/system_stm32f0xx.c @@ -0,0 +1,336 @@ +/** + ****************************************************************************** + * @file system_stm32f0xx.c + * copied from: STM32Cube/Drivers/CMSIS/Device/ST/STM32F0xx/Source/Templates + * @author MCD Application Team + * @version V2.3.1 + * @date 04-November-2016 + * @brief CMSIS Cortex-M0 Device Peripheral Access Layer System Source File. + * + * 1. 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_stm32f0xx.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. + * + * 2. After each device reset the HSI (8 MHz) is used as system clock source. + * Then SystemInit() function is called, in "startup_stm32f0xx.s" file, to + * configure the system clock before to branch to main program. + * + * 3. This file configures the system clock as follows: + *============================================================================= + * Supported STM32F0xx device + *----------------------------------------------------------------------------- + * System Clock source | HSI + *----------------------------------------------------------------------------- + * SYSCLK(Hz) | 8000000 + *----------------------------------------------------------------------------- + * HCLK(Hz) | 8000000 + *----------------------------------------------------------------------------- + * AHB Prescaler | 1 + *----------------------------------------------------------------------------- + * APB1 Prescaler | 1 + *----------------------------------------------------------------------------- + *============================================================================= + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2016 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/** @addtogroup CMSIS + * @{ + */ + +/** @addtogroup stm32f0xx_system + * @{ + */ + +/** @addtogroup STM32F0xx_System_Private_Includes + * @{ + */ + +#include "stm32f0xx.h" + +/** + * @} + */ + +/** @addtogroup STM32F0xx_System_Private_TypesDefinitions + * @{ + */ + +/** + * @} + */ + +/** @addtogroup STM32F0xx_System_Private_Defines + * @{ + */ +#if !defined (HSE_VALUE) + #define HSE_VALUE ((uint32_t)8000000) /*!< Default value of the External oscillator in Hz. + This value can be provided and adapted by the user application. */ +#endif /* HSE_VALUE */ + +#if !defined (HSI_VALUE) + #define HSI_VALUE ((uint32_t)8000000) /*!< Default value of the Internal oscillator in Hz. + This value can be provided and adapted by the user application. */ +#endif /* HSI_VALUE */ + +#if !defined (HSI48_VALUE) +#define HSI48_VALUE ((uint32_t)48000000) /*!< Default value of the HSI48 Internal oscillator in Hz. + This value can be provided and adapted by the user application. */ +#endif /* HSI48_VALUE */ +/** + * @} + */ + +/** @addtogroup STM32F0xx_System_Private_Macros + * @{ + */ + +/** + * @} + */ + +/** @addtogroup STM32F0xx_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 there is no need to + call the 2 first functions listed above, since SystemCoreClock variable is + updated automatically. + */ +uint32_t SystemCoreClock = 8000000; + +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 STM32F0xx_System_Private_FunctionPrototypes + * @{ + */ + +/** + * @} + */ + +/** @addtogroup STM32F0xx_System_Private_Functions + * @{ + */ + +/** + * @brief Setup the microcontroller system. + * Initialize the default HSI clock source, vector table location and the PLL configuration is reset. + * @param None + * @retval None + */ +void SystemInit(void) +{ + /* Reset the RCC clock configuration to the default reset state ------------*/ + /* Set HSION bit */ + RCC->CR |= (uint32_t)0x00000001U; + +#if defined (STM32F051x8) || defined (STM32F058x8) + /* Reset SW[1:0], HPRE[3:0], PPRE[2:0], ADCPRE and MCOSEL[2:0] bits */ + RCC->CFGR &= (uint32_t)0xF8FFB80CU; +#else + /* Reset SW[1:0], HPRE[3:0], PPRE[2:0], ADCPRE, MCOSEL[2:0], MCOPRE[2:0] and PLLNODIV bits */ + RCC->CFGR &= (uint32_t)0x08FFB80CU; +#endif /* STM32F051x8 or STM32F058x8 */ + + /* Reset HSEON, CSSON and PLLON bits */ + RCC->CR &= (uint32_t)0xFEF6FFFFU; + + /* Reset HSEBYP bit */ + RCC->CR &= (uint32_t)0xFFFBFFFFU; + + /* Reset PLLSRC, PLLXTPRE and PLLMUL[3:0] bits */ + RCC->CFGR &= (uint32_t)0xFFC0FFFFU; + + /* Reset PREDIV[3:0] bits */ + RCC->CFGR2 &= (uint32_t)0xFFFFFFF0U; + +#if defined (STM32F072xB) || defined (STM32F078xx) + /* Reset USART2SW[1:0], USART1SW[1:0], I2C1SW, CECSW, USBSW and ADCSW bits */ + RCC->CFGR3 &= (uint32_t)0xFFFCFE2CU; +#elif defined (STM32F071xB) + /* Reset USART2SW[1:0], USART1SW[1:0], I2C1SW, CECSW and ADCSW bits */ + RCC->CFGR3 &= (uint32_t)0xFFFFCEACU; +#elif defined (STM32F091xC) || defined (STM32F098xx) + /* Reset USART3SW[1:0], USART2SW[1:0], USART1SW[1:0], I2C1SW, CECSW and ADCSW bits */ + RCC->CFGR3 &= (uint32_t)0xFFF0FEACU; +#elif defined (STM32F030x6) || defined (STM32F030x8) || defined (STM32F031x6) || defined (STM32F038xx) || defined (STM32F030xC) + /* Reset USART1SW[1:0], I2C1SW and ADCSW bits */ + RCC->CFGR3 &= (uint32_t)0xFFFFFEECU; +#elif defined (STM32F051x8) || defined (STM32F058xx) + /* Reset USART1SW[1:0], I2C1SW, CECSW and ADCSW bits */ + RCC->CFGR3 &= (uint32_t)0xFFFFFEACU; +#elif defined (STM32F042x6) || defined (STM32F048xx) + /* Reset USART1SW[1:0], I2C1SW, CECSW, USBSW and ADCSW bits */ + RCC->CFGR3 &= (uint32_t)0xFFFFFE2CU; +#elif defined (STM32F070x6) || defined (STM32F070xB) + /* Reset USART1SW[1:0], I2C1SW, USBSW and ADCSW bits */ + RCC->CFGR3 &= (uint32_t)0xFFFFFE6CU; + /* Set default USB clock to PLLCLK, since there is no HSI48 */ + RCC->CFGR3 |= (uint32_t)0x00000080U; +#else + #warning "No target selected" +#endif + + /* Reset HSI14 bit */ + RCC->CR2 &= (uint32_t)0xFFFFFFFEU; + + /* Disable all interrupts */ + RCC->CIR = 0x00000000U; + +} + +/** + * @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 stm32f0xx_hal.h file (default value + * 8 MHz) but the real value may vary depending on the variations + * in voltage and temperature. + * + * (**) HSE_VALUE is a constant defined in stm32f0xx_hal.h file (default value + * 8 MHz), 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, pllmull = 0, pllsource = 0, predivfactor = 0; + + /* Get SYSCLK source -------------------------------------------------------*/ + tmp = RCC->CFGR & RCC_CFGR_SWS; + + switch (tmp) + { + case RCC_CFGR_SWS_HSI: /* HSI used as system clock */ + SystemCoreClock = HSI_VALUE; + break; + case RCC_CFGR_SWS_HSE: /* HSE used as system clock */ + SystemCoreClock = HSE_VALUE; + break; + case RCC_CFGR_SWS_PLL: /* PLL used as system clock */ + /* Get PLL clock source and multiplication factor ----------------------*/ + pllmull = RCC->CFGR & RCC_CFGR_PLLMUL; + pllsource = RCC->CFGR & RCC_CFGR_PLLSRC; + pllmull = ( pllmull >> 18) + 2; + predivfactor = (RCC->CFGR2 & RCC_CFGR2_PREDIV) + 1; + + if (pllsource == RCC_CFGR_PLLSRC_HSE_PREDIV) + { + /* HSE used as PLL clock source : SystemCoreClock = HSE/PREDIV * PLLMUL */ + SystemCoreClock = (HSE_VALUE/predivfactor) * pllmull; + } +#if defined(STM32F042x6) || defined(STM32F048xx) || defined(STM32F072xB) || defined(STM32F078xx) || defined(STM32F091xC) || defined(STM32F098xx) + else if (pllsource == RCC_CFGR_PLLSRC_HSI48_PREDIV) + { + /* HSI48 used as PLL clock source : SystemCoreClock = HSI48/PREDIV * PLLMUL */ + SystemCoreClock = (HSI48_VALUE/predivfactor) * pllmull; + } +#endif /* STM32F042x6 || STM32F048xx || STM32F072xB || STM32F078xx || STM32F091xC || STM32F098xx */ + else + { +#if defined(STM32F042x6) || defined(STM32F048xx) || defined(STM32F070x6) \ + || defined(STM32F078xx) || defined(STM32F071xB) || defined(STM32F072xB) \ + || defined(STM32F070xB) || defined(STM32F091xC) || defined(STM32F098xx) || defined(STM32F030xC) + /* HSI used as PLL clock source : SystemCoreClock = HSI/PREDIV * PLLMUL */ + SystemCoreClock = (HSI_VALUE/predivfactor) * pllmull; +#else + /* HSI used as PLL clock source : SystemCoreClock = HSI/2 * PLLMUL */ + SystemCoreClock = (HSI_VALUE >> 1) * pllmull; +#endif /* STM32F042x6 || STM32F048xx || STM32F070x6 || + STM32F071xB || STM32F072xB || STM32F078xx || STM32F070xB || + STM32F091xC || STM32F098xx || STM32F030xC */ + } + break; + default: /* HSI used as system clock */ + SystemCoreClock = HSI_VALUE; + break; + } + /* Compute HCLK clock frequency ----------------*/ + /* Get HCLK prescaler */ + tmp = AHBPrescTable[((RCC->CFGR & RCC_CFGR_HPRE) >> 4)]; + /* HCLK clock frequency */ + SystemCoreClock >>= tmp; +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ + diff --git a/fw/tools/gen_cmsis_exports.py b/fw/tools/gen_cmsis_exports.py new file mode 100644 index 0000000..ba3422b --- /dev/null +++ b/fw/tools/gen_cmsis_exports.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python3 +import re +import os + +if __name__ == '__main__': + import argparse + + parser = argparse.ArgumentParser() + parser.add_argument('cmsis_device_header', nargs='+', type=argparse.FileType('rb')) + args = parser.parse_args() + + print('#ifndef __GENERATED_CMSIS_HEADER_EXPORTS__') + print('#define __GENERATED_CMSIS_HEADER_EXPORTS__') + print() + for header in args.cmsis_device_header: + lines = header.readlines() + name = os.path.basename(header.name) + print('#include <{}>'.format(name)) + print() + + print('/* {} */'.format(name)) + for l in lines: + match = re.match(b'^#define (\w+)\s+\W*(\w+_TypeDef|\w+_Type).*$', l) + if match: + inst, typedef = match.groups() + inst, typedef = inst.decode(), typedef.decode() + print('{} *{} = {};'.format(typedef, inst.lower(), inst)) + print() + print('#endif//__GENERATED_CMSIS_HEADER_EXPORTS__') + -- cgit