aboutsummaryrefslogtreecommitdiff
path: root/fw
diff options
context:
space:
mode:
Diffstat (limited to 'fw')
-rw-r--r--fw/8b10b.c230
-rw-r--r--fw/8b10b.h41
-rw-r--r--fw/8b10b_test_decode.c86
-rw-r--r--fw/8b10b_test_encode.c108
-rwxr-xr-xfw/8b10b_test_vector_gen.py43
-rw-r--r--fw/Makefile6
-rw-r--r--fw/adc.c118
-rw-r--r--fw/adc.h36
-rw-r--r--fw/cmsis_exports.c48
-rw-r--r--fw/main.c36
10 files changed, 233 insertions, 519 deletions
diff --git a/fw/8b10b.c b/fw/8b10b.c
deleted file mode 100644
index c5a52ca..0000000
--- a/fw/8b10b.c
+++ /dev/null
@@ -1,230 +0,0 @@
-
-#include <assert.h>
-#include <stdio.h>
-
-#include "8b10b.h"
-
-static const struct entry map_5b6b[32] = {
- {0b100111, 0b011000, 2}, /* D.00 */
- {0b011101, 0b100010, 2}, /* D.01 */
- {0b101101, 0b010010, 2}, /* D.02 */
- {0b110001, 0b110001, 0}, /* D.03 */
- {0b110101, 0b001010, 2}, /* D.04 */
- {0b101001, 0b101001, 0}, /* D.05 */
- {0b011001, 0b011001, 0}, /* D.06 */
- {0b111000, 0b000111, 0}, /* D.07 */
- {0b111001, 0b000110, 2}, /* D.08 */
- {0b100101, 0b100101, 0}, /* D.09 */
- {0b010101, 0b010101, 0}, /* D.10 */
- {0b110100, 0b110100, 0}, /* D.11 */
- {0b001101, 0b001101, 0}, /* D.12 */
- {0b101100, 0b101100, 0}, /* D.13 */
- {0b011100, 0b011100, 0}, /* D.14 */
- {0b010111, 0b101000, 2}, /* D.15 */
- {0b011011, 0b100100, 2}, /* D.16 */
- {0b100011, 0b100011, 0}, /* D.17 */
- {0b010011, 0b010011, 0}, /* D.18 */
- {0b110010, 0b110010, 0}, /* D.19 */
- {0b001011, 0b001011, 0}, /* D.20 */
- {0b101010, 0b101010, 0}, /* D.21 */
- {0b011010, 0b011010, 0}, /* D.22 */
- {0b111010, 0b000101, 2}, /* D.23 */
- {0b110011, 0b001100, 2}, /* D.24 */
- {0b100110, 0b100110, 0}, /* D.25 */
- {0b010110, 0b010110, 0}, /* D.26 */
- {0b110110, 0b001001, 2}, /* D.27 */
- {0b001110, 0b001110, 0}, /* D.28 */
- {0b101110, 0b010001, 2}, /* D.29 */
- {0b011110, 0b100001, 2}, /* D.30 */
- {0b101011, 0b010100, 2} /* 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 K28 = {0b001111, 0b110000};
-
-static const struct entry map_3b4b_d[8] = {
- {0b1011, 0b0100, 2}, /* D.x.0 */
- {0b1001, 0b1001, 0}, /* D.x.1 */
- {0b0101, 0b0101, 0}, /* D.x.2 */
- {0b1100, 0b0011, 0}, /* D.x.3 */
- {0b1101, 0b0010, 2}, /* D.x.4 */
- {0b1010, 0b1010, 0}, /* D.x.5 */
- {0b0110, 0b0110, 0}, /* D.x.6 */
- {0b1110, 0b0001, 2} /* D.x.P7 */
-};
-
-static const struct entry Dx_A7 = {0b0111, 0b1000, 2};
-
-static const struct entry 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_dec *st) {
- st->rx = 0;
- st->bit_ctr = 0; /* unsynchronized */
-}
-
-int xfr_8b10b_feed_bit(struct state_8b10b_dec *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_dec *st) {
- return st->bit_ctr != 0;
-}
-
-void xfr_8b10b_encode_reset(struct state_8b10b_enc *st) {
- st->rd = -1;
-}
-
-int xfr_8b10b_encode(struct state_8b10b_enc *st, int data) {
- if (data < 0) {
- if (-data >= sizeof(k_sym_map)/sizeof(k_sym_map[0]))
- return -EINVAL;
-
- return k_sym_map[-data];
- }
-
- if (data > 255)
- return -EINVAL;
-
- int p5b = data&0x1f, p3b = data>>5;
- //fprintf(stderr, "\nrd %d data %x p5b %d p3b %d\n", st->rd, data, p5b, p3b);
-
- int x5b = (st->rd == -1) ? map_5b6b[p5b].rd_neg : map_5b6b[p5b].rd_pos;
- st->rd -= map_5b6b[p5b].disp * st->rd;
- //fprintf(stderr, "\nnow: rd %d data %x p5b %d p3b %d\n", st->rd, data, p5b, p3b);
- assert(st->rd == -1 || st->rd == 1);
-
- int x3b = (st->rd == -1) ? map_3b4b_d[p3b].rd_neg : map_3b4b_d[p3b].rd_pos;
- if (p3b == 7) {
- if ( (st->rd == -1 && (p5b == 17 || p5b == 18 || p5b == 20))
- || (st->rd == 1 && (p5b == 11 || p5b == 13 || p5b == 14))) {
- //fprintf(stderr, "A7 override\n");
- x3b = (st->rd == -1) ? Dx_A7.rd_neg : Dx_A7.rd_pos;
- }
- }
- st->rd -= map_3b4b_d[p3b].disp * st->rd; /* D.x.A7 and D.x.P7 both have parity 2 */
- assert(st->rd == -1 || st->rd == 1);
-
- return x5b<<4 | x3b;
-}
-
diff --git a/fw/8b10b.h b/fw/8b10b.h
deleted file mode 100644
index 090faaf..0000000
--- a/fw/8b10b.h
+++ /dev/null
@@ -1,41 +0,0 @@
-#ifndef __8B10B_H__
-#define __8B10B_H__
-
-#include <stdint.h>
-#include <stdbool.h>
-#include <errno.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 {
- uint8_t rd_neg, rd_pos, disp;
-};
-
-struct state_8b10b_dec {
- uint32_t rx;
- int bit_ctr;
-};
-
-struct state_8b10b_enc {
- int rd;
-};
-
-void xfr_8b10b_reset(struct state_8b10b_dec *st);
-int xfr_8b10b_feed_bit(struct state_8b10b_dec *st, int bit);
-bool xfr_8b10b_has_sync(struct state_8b10b_dec *st);
-
-void xfr_8b10b_encode_reset(struct state_8b10b_enc *st);
-int xfr_8b10b_encode(struct state_8b10b_enc *st, int data);
-
-#endif
diff --git a/fw/8b10b_test_decode.c b/fw/8b10b_test_decode.c
deleted file mode 100644
index 433f7b8..0000000
--- a/fw/8b10b_test_decode.c
+++ /dev/null
@@ -1,86 +0,0 @@
-
-#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_dec st;
- xfr_8b10b_reset(&st);
-
- int c;
- int comment = 0;
- while ((c=fgetc(stdin)) != EOF) {
- int bit;
-
- if (comment) {
- if (c == '\n')
- comment = 0;
- printf("%c", c);
- continue;
- }
-
- if (c == '\r' || c == ' ' || c == '\t' || c == '\n') {
- printf("%c", c);
- continue;
- }
-
- if (c == '#') {
- comment = 1;
- printf("%c", c);
- 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);
- fprintf(stdout, "%02x", read_result);
-
- } else {
- if (-read_result == DECODING_IN_PROGRESS)
- continue;
-
- 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);
- fprintf(stdout, "%s", msg);
- }
- }
-}
-
diff --git a/fw/8b10b_test_encode.c b/fw/8b10b_test_encode.c
deleted file mode 100644
index 2ba75d9..0000000
--- a/fw/8b10b_test_encode.c
+++ /dev/null
@@ -1,108 +0,0 @@
-
-#include <stdio.h>
-#include <string.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",
-};
-
-int hex_to_uint(const char *s, size_t len) {
- if (len > 7)
- return -2;
-
- int acc = 0;
- for (int i=0; i<len; i++) {
- int digit = s[i];
- if ('0' <= digit && digit <= '9')
- digit -= '0';
- else if ('a' <= digit && digit <= 'f')
- digit -= 'a' - 0xa;
- else if ('A' <= digit && digit <= 'F')
- digit -= 'A' - 0xA;
- else return -1;
- acc = acc << 4 | digit;
- }
-
- return acc;
-}
-
-int main(void) {
- struct state_8b10b_enc st;
- xfr_8b10b_encode_reset(&st);
-
- int c;
- int comment = 0;
- char parse_buf[32];
- int parse_buf_pos = 0;
- while ((c=fgetc(stdin)) != EOF) {
- if (comment) {
- if (c == '\n')
- comment = 0;
- printf("%c", c);
- continue;
- }
-
- if (c == '#') {
- comment = 1;
- printf("%c", c);
- continue;
- }
-
- if (c != '\r' && c != ' ' && c != '\t' && c != '\n') {
- parse_buf[parse_buf_pos++] = (char)c;
- if (parse_buf_pos == sizeof(parse_buf)) {
- parse_buf[sizeof(parse_buf)-1] = '\0';
- fprintf(stderr, "Parse error: Token \"%s[...]\" too long. Exiting.\n", parse_buf);
- return 1;
- }
- continue;
- }
-
- if (parse_buf_pos == 0)
- continue;
-
- int data = 0;
- for (int i=1; i<sizeof(rc_names)/sizeof(rc_names[0]); i++) {
- if (!strncmp(rc_names[i], parse_buf, parse_buf_pos)) {
- data = -i;
- break;
- }
- }
-
- if (!data) {
- data = hex_to_uint(parse_buf, parse_buf_pos);
- if (data < 0) {
- parse_buf[parse_buf_pos] = '\0';
- fprintf(stderr, "Invalid hex number: \"%s\"\n", parse_buf);
- return 1;
- }
- }
-
- parse_buf_pos = 0; /* reset for next token */
-
- int encoded = xfr_8b10b_encode(&st, data);
- if (encoded < 0) {
- fprintf(stderr, "Invalid argument error encoding\n");
- return 2;
- }
-
- for (int i=0; i<10; i++)
- printf("%c", (encoded & (1<<(9-i))) ? '1' : '0');
-
- printf("%c", c); /* print whitespace character */
- }
-}
-
diff --git a/fw/8b10b_test_vector_gen.py b/fw/8b10b_test_vector_gen.py
deleted file mode 100755
index 12460c1..0000000
--- a/fw/8b10b_test_vector_gen.py
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/usr/bin/env python3
-
-def parse_size(s):
- s = s.lower()
- SUFFIXES = {'k': 1e3, 'm': 1e6, 'g': 1e9}
- if s[-1] in SUFFIXES:
- return int(int(s[:-1]) * SUFFIXES[s[-1]])
- return int(s)
-
-def hexdump(data, byte_per_line=64):
- for i in range(0, len(data), byte_per_line):
- out = data[i:i+byte_per_line]
- print(' '.join(f'{out[k]:02x}' for k in range(len(out)))) # use len(out) to handle partial lines
-
-if __name__ == '__main__':
- from itertools import product
- import os
- import argparse
-
- parser = argparse.ArgumentParser()
- parser.add_argument('cmd')
- parser.add_argument('-l', '--length', default='1M', help='Generate [length} byte test vector. Only applicable to random.')
- parser.add_argument('-s', '--syncfreq', default=None, help='Emit comma every [syncfreq] bytes. Default: don\'t emit any commas. Only applicable to random.')
- args = parser.parse_args()
-
- length = parse_size(args.length)
- syncfreq = parse_size(args.syncfreq)
-
-
- if args.cmd == 'exhaustive_separated':
- for i, j, k in product(range(256), range(256), range(256)):
- print(f'K.28.1 {i:02x} {j:02x} {k:02x}')
-
- elif args.cmd == 'exhaustive_block':
- print('K.28.1')
- for i, j, k in product(range(256), range(256), range(256)):
- print(f'{i:02x} {j:02x} {k:02x}')
-
- elif args.cmd == 'random':
- for chunk in range(0, length, syncfreq):
- print('K.28.1')
- hexdump(os.urandom(min(length-chunk, syncfreq)))
-
diff --git a/fw/Makefile b/fw/Makefile
index b779789..7795f0a 100644
--- a/fw/Makefile
+++ b/fw/Makefile
@@ -43,7 +43,7 @@ LIBS = -lgcc
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
+CFLAGS += -I$(CMSIS_DEV_PATH)/Include -I$(CMSIS_PATH)/Include -I$(HAL_PATH)/Inc -Iconfig -Wno-unused -I../common
LDFLAGS += -L$(CMSIS_PATH)/Lib/GCC -larm_cortexM0l_math
###################################################
@@ -66,7 +66,7 @@ cmsis_exports.c: $(CMSIS_DEV_PATH)/Include/stm32f030x6.h $(CMSIS_PATH)/Include/c
%.dot: %.elf
r2 -a arm -qc 'aa;agC' $< 2>/dev/null >$@
-sources.tar.xz: main.c Makefile
+sources.tar.xz: main.c adc.c ../common/8b10b.c Makefile
tar -caf $@ $^
# don't ask...
@@ -76,7 +76,7 @@ sources.tar.xz.zip: sources.tar.xz
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
+main.elf: main.o startup_stm32f030x6.o system_stm32f0xx.o $(HAL_PATH)/Src/stm32f0xx_ll_utils.o base.o cmsis_exports.o ../common/8b10b.o adc.o
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LIBS)
$(OBJCOPY) -O ihex $@ $(@:.elf=.hex)
$(OBJCOPY) -O binary $@ $(@:.elf=.bin)
diff --git a/fw/adc.c b/fw/adc.c
new file mode 100644
index 0000000..726e9a8
--- /dev/null
+++ b/fw/adc.c
@@ -0,0 +1,118 @@
+/* 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 "adc.h"
+
+volatile struct adc_measurements adc_data = {0};
+
+enum adc_channels {
+ VREF_CH,
+ VMEAS_A,
+ VMEAS_B,
+ TEMP_CH,
+ NCH
+};
+static volatile uint16_t adc_buf[NCH];
+
+void adc_init(void) {
+ /* The ADC is used for temperature measurement. To compute the temperature from an ADC reading of the internal
+ * temperature sensor, the supply voltage must also be measured. Thus we are using two channels.
+ *
+ * The ADC is triggered by compare channel 4 of timer 1. The trigger is set to falling edge to trigger on compare
+ * match, not overflow.
+ */
+ ADC1->CFGR1 = ADC_CFGR1_DMAEN | ADC_CFGR1_DMACFG | (2<<ADC_CFGR1_EXTEN_Pos) | (1<<ADC_CFGR1_EXTSEL_Pos);
+ /* Clock from PCLK/4 instead of the internal exclusive high-speed RC oscillator. */
+ ADC1->CFGR2 = (2<<ADC_CFGR2_CKMODE_Pos); /* Use PCLK/4=12MHz */
+ /* Sampling time 13.5 ADC clock cycles -> total conversion time 2.17us*/
+ ADC1->SMPR = (2<<ADC_SMPR_SMP_Pos);
+ /* Internal VCC and temperature sensor channels */
+ ADC1->CHSELR = ADC_CHSELR_CHSEL0 | ADC_CHSELR_CHSEL1 | ADC_CHSELR_CHSEL16 | ADC_CHSELR_CHSEL17;
+ /* Enable internal voltage reference and temperature sensor */
+ ADC->CCR = ADC_CCR_TSEN | ADC_CCR_VREFEN;
+ /* Perform ADC calibration */
+ ADC1->CR |= ADC_CR_ADCAL;
+ while (ADC1->CR & ADC_CR_ADCAL)
+ ;
+ /* Enable ADC */
+ ADC1->CR |= ADC_CR_ADEN;
+ ADC1->CR |= ADC_CR_ADSTART;
+
+ /* Configure DMA 1 Channel 1 to get rid of all the data */
+ DMA1_Channel1->CPAR = (unsigned int)&ADC1->DR;
+ DMA1_Channel1->CMAR = (unsigned int)&adc_buf;
+ DMA1_Channel1->CNDTR = NCH;
+ DMA1_Channel1->CCR = (0<<DMA_CCR_PL_Pos);
+ DMA1_Channel1->CCR |=
+ DMA_CCR_CIRC /* circular mode so we can leave it running indefinitely */
+ | (1<<DMA_CCR_MSIZE_Pos) /* 16 bit */
+ | (1<<DMA_CCR_PSIZE_Pos) /* 16 bit */
+ | DMA_CCR_MINC
+ | DMA_CCR_TCIE; /* Enable transfer complete interrupt. */
+ DMA1_Channel1->CCR |= DMA_CCR_EN; /* Enable channel */
+
+ /* triggered on transfer completion. We use this to process the ADC data */
+ NVIC_EnableIRQ(DMA1_Channel1_IRQn);
+ NVIC_SetPriority(DMA1_Channel1_IRQn, 3<<5);
+}
+
+uint16_t buf_a[256];
+uint16_t buf_b[256];
+int bufp = 0;
+
+void DMA1_Channel1_IRQHandler(void) {
+ /* This interrupt takes either 1.2us or 13us. It can be pre-empted by the more timing-critical UART and LED timer
+ * interrupts. */
+ static int count = 0; /* oversampling accumulator sample count */
+ static uint32_t adc_aggregate[NCH] = {0}; /* oversampling accumulator */
+
+ /* Clear the interrupt flag */
+ DMA1->IFCR |= DMA_IFCR_CGIF1;
+
+ for (int i=0; i<NCH; i++)
+ adc_aggregate[i] += adc_buf[i];
+
+ if (++count == (1<<ADC_OVERSAMPLING)) {
+ for (int i=0; i<NCH; i++)
+ adc_aggregate[i] >>= ADC_OVERSAMPLING;
+ /* This has been copied from the code examples to section 12.9 ADC>"Temperature sensor and internal reference
+ * voltage" in the reference manual with the extension that we actually measure the supply voltage instead of
+ * hardcoding it. This is not strictly necessary since we're running off a bored little LDO but it's free and
+ * the current supply voltage is a nice health value.
+ */
+ adc_data.adc_vcc_mv = (3300 * VREFINT_CAL)/(adc_aggregate[VREF_CH]);
+
+ int64_t read = adc_aggregate[TEMP_CH] * 10 * 10000;
+ int64_t vcc = adc_data.adc_vcc_mv;
+ int64_t cal = TS_CAL1 * 10 * 10000;
+ adc_data.adc_temp_celsius_tenths = 300 + ((read/4096 * vcc) - (cal/4096 * 3300))/43000;
+
+ adc_data.adc_vmeas_a_mv = (adc_aggregate[VMEAS_A]*13300L)/4096 * vcc / 3300;
+ adc_data.adc_vmeas_b_mv = (adc_aggregate[VMEAS_B]*13300L)/4096 * vcc / 3300;
+
+ buf_a[bufp] = adc_data.adc_vmeas_a_mv;
+ buf_b[bufp] = adc_data.adc_vmeas_b_mv;
+ if (++bufp >= sizeof(buf_a)/sizeof(buf_a[0])) {
+ bufp = 0;
+ }
+
+ count = 0;
+ for (int i=0; i<NCH; i++)
+ adc_aggregate[i] = 0;
+ }
+}
+
diff --git a/fw/adc.h b/fw/adc.h
new file mode 100644
index 0000000..8c0c6cc
--- /dev/null
+++ b/fw/adc.h
@@ -0,0 +1,36 @@
+/* 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 __ADC_H__
+#define __ADC_H__
+
+#include "global.h"
+
+#define ADC_OVERSAMPLING 0
+
+struct adc_measurements {
+ int16_t adc_vcc_mv;
+ int16_t adc_temp_celsius_tenths;
+ int16_t adc_vmeas_a_mv;
+ int16_t adc_vmeas_b_mv;
+};
+
+extern volatile struct adc_measurements adc_data;
+
+void adc_init(void);
+
+#endif/*__ADC_H__*/
diff --git a/fw/cmsis_exports.c b/fw/cmsis_exports.c
index e69de29..39874b5 100644
--- a/fw/cmsis_exports.c
+++ b/fw/cmsis_exports.c
@@ -0,0 +1,48 @@
+#ifndef __GENERATED_CMSIS_HEADER_EXPORTS__
+#define __GENERATED_CMSIS_HEADER_EXPORTS__
+
+#include <stm32f030x6.h>
+
+/* stm32f030x6.h */
+TIM_TypeDef *tim3 = TIM3;
+TIM_TypeDef *tim14 = TIM14;
+RTC_TypeDef *rtc = RTC;
+WWDG_TypeDef *wwdg = WWDG;
+IWDG_TypeDef *iwdg = IWDG;
+I2C_TypeDef *i2c1 = I2C1;
+PWR_TypeDef *pwr = PWR;
+SYSCFG_TypeDef *syscfg = SYSCFG;
+EXTI_TypeDef *exti = EXTI;
+ADC_TypeDef *adc1 = ADC1;
+ADC_Common_TypeDef *adc1_common = ADC1_COMMON;
+ADC_Common_TypeDef *adc = ADC;
+TIM_TypeDef *tim1 = TIM1;
+SPI_TypeDef *spi1 = SPI1;
+USART_TypeDef *usart1 = USART1;
+TIM_TypeDef *tim16 = TIM16;
+TIM_TypeDef *tim17 = TIM17;
+DBGMCU_TypeDef *dbgmcu = DBGMCU;
+DMA_TypeDef *dma1 = DMA1;
+DMA_Channel_TypeDef *dma1_channel1 = DMA1_Channel1;
+DMA_Channel_TypeDef *dma1_channel2 = DMA1_Channel2;
+DMA_Channel_TypeDef *dma1_channel3 = DMA1_Channel3;
+DMA_Channel_TypeDef *dma1_channel4 = DMA1_Channel4;
+DMA_Channel_TypeDef *dma1_channel5 = DMA1_Channel5;
+FLASH_TypeDef *flash = FLASH;
+OB_TypeDef *ob = OB;
+RCC_TypeDef *rcc = RCC;
+CRC_TypeDef *crc = CRC;
+GPIO_TypeDef *gpioa = GPIOA;
+GPIO_TypeDef *gpiob = GPIOB;
+GPIO_TypeDef *gpioc = GPIOC;
+GPIO_TypeDef *gpiod = GPIOD;
+GPIO_TypeDef *gpiof = GPIOF;
+
+#include <core_cm0.h>
+
+/* core_cm0.h */
+SCB_Type *scb = SCB;
+SysTick_Type *systick = SysTick;
+NVIC_Type *nvic = NVIC;
+
+#endif//__GENERATED_CMSIS_HEADER_EXPORTS__
diff --git a/fw/main.c b/fw/main.c
index e00f3a6..b766488 100644
--- a/fw/main.c
+++ b/fw/main.c
@@ -17,29 +17,34 @@
#include "global.h"
+#include "adc.h"
+
volatile unsigned int sys_time = 0;
volatile unsigned int sys_time_seconds = 0;
+void TIM1_BRK_UP_TRG_COM_Handler() {
+ TIM1->SR &= ~TIM_SR_UIF_Msk;
+}
+
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->CFGR |= ((6-2)<<RCC_CFGR_PLLMUL_Pos) | RCC_CFGR_PLLSRC_HSE_PREDIV; /* PLL x6 -> 48.0MHz */
RCC->CR |= RCC_CR_PLLON;
while (!(RCC->CR&RCC_CR_PLLRDY));
RCC->CFGR |= (2<<RCC_CFGR_SW_Pos);
SystemCoreClockUpdate();
+ SysTick_Config(SystemCoreClock/1000); /* 1ms interval */
/* 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->AHBENR |= RCC_AHBENR_DMAEN | RCC_AHBENR_GPIOAEN | RCC_AHBENR_FLITFEN;
+ RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN | RCC_APB2ENR_ADCEN| RCC_APB2ENR_DBGMCUEN | RCC_APB2ENR_TIM1EN | RCC_APB2ENR_TIM1EN;;
RCC->APB1ENR |= RCC_APB1ENR_TIM3EN;
GPIOA->MODER |=
- (0<<GPIO_MODER_MODER0_Pos) /* PA0 - Vmeas_A */
- | (0<<GPIO_MODER_MODER1_Pos) /* PA1 - Vmeas_B */
+ (3<<GPIO_MODER_MODER0_Pos) /* PA0 - Vmeas_A to ADC */
+ | (3<<GPIO_MODER_MODER1_Pos) /* PA1 - Vmeas_B to ADC */
| (1<<GPIO_MODER_MODER2_Pos) /* PA2 - LOAD */
| (1<<GPIO_MODER_MODER3_Pos) /* PA3 - CH0 */
| (1<<GPIO_MODER_MODER4_Pos) /* PA4 - CH3 */
@@ -57,7 +62,20 @@ int main(void) {
| (2<<GPIO_OSPEEDR_OSPEEDR6_Pos) /* CH2 */
| (2<<GPIO_OSPEEDR_OSPEEDR7_Pos); /* CH1 */
- SysTick_Config(SystemCoreClock/1000); /* 1ms interval */
+ /* Setup CC1 and CC2. CC2 generates the LED drivers' STROBE, CC1 triggers the IRQ handler */
+ TIM1->BDTR = TIM_BDTR_MOE;
+ TIM1->CCMR2 = (6<<TIM_CCMR2_OC4M_Pos); /* PWM Mode 1 */
+ TIM1->CCER = TIM_CCER_CC4E;
+ TIM1->CCR4 = 1;
+ TIM1->DIER = TIM_DIER_UIE;
+
+ TIM1->PSC = SystemCoreClock/1000000 - 1; /* 1.0us/tick */
+ TIM1->ARR = 20-1; /* 20us */
+ /* Preload all values */
+ TIM1->EGR |= TIM_EGR_UG;
+ TIM1->CR1 = TIM_CR1_ARPE;
+ /* And... go! */
+ TIM1->CR1 |= TIM_CR1_CEN;
void set_outputs(uint8_t val) {
int a=!!(val&1), b=!!(val&2), c=!!(val&4), d=!!(val&8);
@@ -66,6 +84,8 @@ int main(void) {
}
set_outputs(0);
+ adc_init();
+
uint8_t out_state = 0x01;
#define DEBOUNCE 100
int debounce_ctr = 0;