aboutsummaryrefslogtreecommitdiff
path: root/fw
diff options
context:
space:
mode:
authorjaseg <git@jaseg.net>2018-12-20 18:54:41 +0900
committerjaseg <git@jaseg.net>2018-12-20 18:54:41 +0900
commit90038f4378b7cdbe98e32ed1e5e3055dbe4776f2 (patch)
tree3982be300f99a7eabd1d6a5c9be973822bac3044 /fw
parent111b7a6bf37a271125f453bd2904cd72fd8f5b38 (diff)
download8seg-90038f4378b7cdbe98e32ed1e5e3055dbe4776f2.tar.gz
8seg-90038f4378b7cdbe98e32ed1e5e3055dbe4776f2.tar.bz2
8seg-90038f4378b7cdbe98e32ed1e5e3055dbe4776f2.zip
Add initial center firmware
Diffstat (limited to 'fw')
-rw-r--r--fw/.gitignore11
-rw-r--r--fw/8b10b.c190
-rw-r--r--fw/8b10b.h38
-rw-r--r--fw/8b10b_test.c78
-rw-r--r--fw/Makefile101
-rw-r--r--fw/base.c21
-rw-r--r--fw/cmsis_exports.c0
-rw-r--r--fw/global.h48
-rw-r--r--fw/main.c103
-rw-r--r--fw/openocd.cfg16
-rw-r--r--fw/startup_stm32f030x6.s273
-rw-r--r--fw/stm32_flash.ld136
-rw-r--r--fw/system_stm32f0xx.c336
-rw-r--r--fw/tools/gen_cmsis_exports.py30
14 files changed, 1381 insertions, 0 deletions
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<sizeof(k_sym_map)/sizeof(k_sym_map[0]); i++) {
+ if (pattern == k_sym_map[i])
+ return -i;
+ }
+
+ int p3b = map_4b3b[pattern & 0xf];
+ int p5b = map_6b5b[pattern >> 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 <stdint.h>
+#include <stdbool.h>
+
+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 <stdio.h>
+
+#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 <code@jaseg.net>
+#
+# 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 <http://www.gnu.org/licenses/>.
+
+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 <unistd.h>
+
+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
--- /dev/null
+++ b/fw/cmsis_exports.c
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 <code@jaseg.net>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __GLOBAL_H__
+#define __GLOBAL_H__
+
+/* Workaround for sub-par ST libraries */
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wstrict-aliasing"
+#include <stm32f0xx.h>
+#include <stm32f0xx_ll_utils.h>
+#include <stm32f0xx_ll_spi.h>
+#pragma GCC diagnostic pop
+
+#include <system_stm32f0xx.h>
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <string.h>
+#include <unistd.h>
+
+/* 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 <code@jaseg.net>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#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<<RCC_CFGR_PLLMUL_Pos) | RCC_CFGR_PLLSRC_HSE_PREDIV; /* PLL x4 -> 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<<RCC_CFGR_SW_Pos);
+ SystemCoreClockUpdate();
+
+ /* Turn on lots of neat things */
+ RCC->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<<GPIO_MODER_MODER0_Pos) /* PA0 - Vmeas_A */
+ | (3<<GPIO_MODER_MODER1_Pos) /* PA1 - Vmeas_B */
+ | (1<<GPIO_MODER_MODER2_Pos) /* PA2 - LOAD */
+ | (1<<GPIO_MODER_MODER3_Pos) /* PA3 - CH0 */
+ | (1<<GPIO_MODER_MODER4_Pos) /* PA4 - CH3 */
+ | (0<<GPIO_MODER_MODER5_Pos) /* PA5 - TP1 */
+ | (1<<GPIO_MODER_MODER6_Pos) /* PA6 - CH2 */
+ | (1<<GPIO_MODER_MODER7_Pos) /* PA7 - CH1 */
+ | (0<<GPIO_MODER_MODER9_Pos) /* PA9 - TP2 */
+ | (0<<GPIO_MODER_MODER10_Pos);/* PA10 - TP3 */
+
+ /* Set shift register IO GPIO output speed */
+ GPIOA->OSPEEDR |=
+ (2<<GPIO_OSPEEDR_OSPEEDR2_Pos) /* LOAD */
+ | (2<<GPIO_OSPEEDR_OSPEEDR3_Pos) /* CH0 */
+ | (2<<GPIO_OSPEEDR_OSPEEDR4_Pos) /* CH3 */
+ | (2<<GPIO_OSPEEDR_OSPEEDR6_Pos) /* CH2 */
+ | (2<<GPIO_OSPEEDR_OSPEEDR7_Pos); /* CH1 */
+
+ SysTick_Config(SystemCoreClock/1000); /* 1ms interval */
+
+ void set_outputs(uint8_t val) {
+ int a=!!(val&1), b=!!(val&2), c=!!(val&4), d=!!(val&8);
+ GPIOA->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; i<FOO; i++) ;
+ set_outputs(0x1);
+ for (int i=0; i<FOO; i++) ;
+ set_outputs(0x2);
+ for (int i=0; i<FOO; i++) ;
+ set_outputs(0x4);
+ for (int i=0; i<FOO; i++) ;
+ set_outputs(0x8);
+ }
+}
+
+void NMI_Handler(void) {
+}
+
+void HardFault_Handler(void) __attribute__((naked));
+void HardFault_Handler() {
+ asm volatile ("bkpt");
+}
+
+void SVC_Handler(void) {
+}
+
+
+void PendSV_Handler(void) {
+}
+
+void SysTick_Handler(void) {
+ static int n = 0;
+ sys_time++;
+ if (n++ == 1000) {
+ n = 0;
+ sys_time_seconds++;
+ }
+}
+
diff --git a/fw/openocd.cfg b/fw/openocd.cfg
new file mode 100644
index 0000000..4c52fdc
--- /dev/null
+++ b/fw/openocd.cfg
@@ -0,0 +1,16 @@
+telnet_port 4444
+gdb_port 3333
+
+source [find interface/stlink-v2.cfg]
+#interface jlink
+#interface stlink-v2
+#adapter_khz 10000
+#transport select swd
+
+#source /usr/share/openocd/scripts/target/stm32f0x.cfg
+source [find target/stm32f0x_stlink.cfg]
+
+init
+arm semihosting enable
+
+#flash bank sysflash.alias stm32f0x 0x00000000 0 0 0 $_TARGETNAME
diff --git a/fw/startup_stm32f030x6.s b/fw/startup_stm32f030x6.s
new file mode 100644
index 0000000..2f0eb42
--- /dev/null
+++ b/fw/startup_stm32f030x6.s
@@ -0,0 +1,273 @@
+/**
+ ******************************************************************************
+ * @file startup_stm32f030x6.s
+ * copied from: STM32Cube/Drivers/CMSIS/Device/ST/STM32F0xx/Source/Templates/gcc
+ * @author MCD Application Team
+ * @version V2.3.1
+ * @date 04-November-2016
+ * @brief STM32F030x4/STM32F030x6 devices vector table for Atollic TrueSTUDIO toolchain.
+ * 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-M0 processor is in Thread mode,
+ * priority is Privileged, and the Stack is set to Main.
+ ******************************************************************************
+ *
+ * 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-m0
+ .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
+
+ .section .text.Reset_Handler
+ .weak Reset_Handler
+ .type Reset_Handler, %function
+Reset_Handler:
+ ldr r0, =_estack
+ mov sp, r0 /* 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]
+ adds r2, r2, #4
+
+
+LoopFillZerobss:
+ ldr r3, = _ebss
+ cmp r2, r3
+ bcc FillZerobss
+
+/* Call the clock system intitialization function.*/
+ bl SystemInit
+/* Call static constructors */
+// bl __libc_init_array
+/* Call the application's entry point.*/
+ bl main
+
+LoopForever:
+ b LoopForever
+
+
+.size Reset_Handler, .-Reset_Handler
+
+/**
+ * @brief This is the code that gets called when the processor receives an
+ * unexpected interrupt. This simply enters an infinite loop, preserving
+ * the system state for examination by a debugger.
+ *
+ * @param None
+ * @retval : None
+*/
+ .section .text.Default_Handler,"ax",%progbits
+Default_Handler:
+Infinite_Loop:
+ b Infinite_Loop
+ .size Default_Handler, .-Default_Handler
+/******************************************************************************
+*
+* The minimal vector table for a Cortex M0. 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 0
+ .word 0
+ .word 0
+ .word 0
+ .word 0
+ .word 0
+ .word 0
+ .word SVC_Handler
+ .word 0
+ .word 0
+ .word PendSV_Handler
+ .word SysTick_Handler
+ .word WWDG_IRQHandler /* Window WatchDog */
+ .word 0 /* Reserved */
+ .word RTC_IRQHandler /* RTC through the EXTI line */
+ .word FLASH_IRQHandler /* FLASH */
+ .word RCC_IRQHandler /* RCC */
+ .word EXTI0_1_IRQHandler /* EXTI Line 0 and 1 */
+ .word EXTI2_3_IRQHandler /* EXTI Line 2 and 3 */
+ .word EXTI4_15_IRQHandler /* EXTI Line 4 to 15 */
+ .word 0 /* Reserved */
+ .word DMA1_Channel1_IRQHandler /* DMA1 Channel 1 */
+ .word DMA1_Channel2_3_IRQHandler /* DMA1 Channel 2 and Channel 3 */
+ .word DMA1_Channel4_5_IRQHandler /* DMA1 Channel 4 and Channel 5 */
+ .word ADC1_IRQHandler /* ADC1 */
+ .word TIM1_BRK_UP_TRG_COM_IRQHandler /* TIM1 Break, Update, Trigger and Commutation */
+ .word TIM1_CC_IRQHandler /* TIM1 Capture Compare */
+ .word 0 /* Reserved */
+ .word TIM3_IRQHandler /* TIM3 */
+ .word 0 /* Reserved */
+ .word 0 /* Reserved */
+ .word TIM14_IRQHandler /* TIM14 */
+ .word 0 /* Reserved */
+ .word TIM16_IRQHandler /* TIM16 */
+ .word TIM17_IRQHandler /* TIM17 */
+ .word I2C1_IRQHandler /* I2C1 */
+ .word 0 /* Reserved */
+ .word SPI1_IRQHandler /* SPI1 */
+ .word 0 /* Reserved */
+ .word USART1_IRQHandler /* USART1 */
+ .word 0 /* Reserved */
+ .word 0 /* Reserved */
+ .word 0 /* Reserved */
+ .word 0 /* Reserved */
+
+/*******************************************************************************
+*
+* 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 SVC_Handler
+ .thumb_set SVC_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 RTC_IRQHandler
+ .thumb_set RTC_IRQHandler,Default_Handler
+
+ .weak FLASH_IRQHandler
+ .thumb_set FLASH_IRQHandler,Default_Handler
+
+ .weak RCC_IRQHandler
+ .thumb_set RCC_IRQHandler,Default_Handler
+
+ .weak EXTI0_1_IRQHandler
+ .thumb_set EXTI0_1_IRQHandler,Default_Handler
+
+ .weak EXTI2_3_IRQHandler
+ .thumb_set EXTI2_3_IRQHandler,Default_Handler
+
+ .weak EXTI4_15_IRQHandler
+ .thumb_set EXTI4_15_IRQHandler,Default_Handler
+
+ .weak DMA1_Channel1_IRQHandler
+ .thumb_set DMA1_Channel1_IRQHandler,Default_Handler
+
+ .weak DMA1_Channel2_3_IRQHandler
+ .thumb_set DMA1_Channel2_3_IRQHandler,Default_Handler
+
+ .weak DMA1_Channel4_5_IRQHandler
+ .thumb_set DMA1_Channel4_5_IRQHandler,Default_Handler
+
+ .weak ADC1_IRQHandler
+ .thumb_set ADC1_IRQHandler,Default_Handler
+
+ .weak TIM1_BRK_UP_TRG_COM_IRQHandler
+ .thumb_set TIM1_BRK_UP_TRG_COM_IRQHandler,Default_Handler
+
+ .weak TIM1_CC_IRQHandler
+ .thumb_set TIM1_CC_IRQHandler,Default_Handler
+
+ .weak TIM3_IRQHandler
+ .thumb_set TIM3_IRQHandler,Default_Handler
+
+ .weak TIM14_IRQHandler
+ .thumb_set TIM14_IRQHandler,Default_Handler
+
+ .weak TIM16_IRQHandler
+ .thumb_set TIM16_IRQHandler,Default_Handler
+
+ .weak TIM17_IRQHandler
+ .thumb_set TIM17_IRQHandler,Default_Handler
+
+ .weak I2C1_IRQHandler
+ .thumb_set I2C1_IRQHandler,Default_Handler
+
+ .weak SPI1_IRQHandler
+ .thumb_set SPI1_IRQHandler,Default_Handler
+
+ .weak USART1_IRQHandler
+ .thumb_set USART1_IRQHandler,Default_Handler
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
+
diff --git a/fw/stm32_flash.ld b/fw/stm32_flash.ld
new file mode 100644
index 0000000..cba7577
--- /dev/null
+++ b/fw/stm32_flash.ld
@@ -0,0 +1,136 @@
+
+ENTRY(Reset_Handler)
+
+MEMORY {
+ FLASH (rx): ORIGIN = 0x08000000, LENGTH = 0x3C00
+ CONFIGFLASH (rw): ORIGIN = 0x08003C00, LENGTH = 0x400
+ RAM (xrw): ORIGIN = 0x20000000, LENGTH = 4K
+}
+
+/* highest address of the user mode stack */
+_estack = 0x20001000;
+
+SECTIONS {
+ /* for Cortex devices, the beginning of the startup code is stored in the .isr_vector section, which goes to FLASH */
+ .isr_vector : {
+ . = ALIGN(4);
+ KEEP(*(.isr_vector)) /* Startup code */
+ . = ALIGN(4);
+ } >FLASH
+
+ /* 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
+ *
+ * <h2><center>&copy; COPYRIGHT(c) 2016 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 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__')
+