From 9d87c925a9eaa4fc256be3173c14a20d1469472d Mon Sep 17 00:00:00 2001 From: fishsoupisgood Date: Wed, 9 Sep 2020 11:53:37 +0100 Subject: everything, mostly, working --- boiler-monster/stm32/.gitignore | 15 + boiler-monster/stm32/Makefile | 8 + boiler-monster/stm32/Makefile.include | 44 ++ boiler-monster/stm32/Makefile.rules | 261 ++++++++++++ boiler-monster/stm32/app/1wire.c | 392 ++++++++++++++++++ boiler-monster/stm32/app/1wire.h | 10 + boiler-monster/stm32/app/Makefile | 113 ++++++ boiler-monster/stm32/app/adc.c | 154 +++++++ boiler-monster/stm32/app/boiler.ld | 31 ++ boiler-monster/stm32/app/cmd.c | 55 +++ boiler-monster/stm32/app/commit.c | 3 + boiler-monster/stm32/app/ds1820.c | 93 +++++ boiler-monster/stm32/app/gdb.script | 2 + boiler-monster/stm32/app/led.c | 101 +++++ boiler-monster/stm32/app/main.c | 134 ++++++ boiler-monster/stm32/app/ot.c | 452 +++++++++++++++++++++ boiler-monster/stm32/app/ot_phy_rx.c | 177 ++++++++ boiler-monster/stm32/app/ot_phy_tx.c | 121 ++++++ boiler-monster/stm32/app/pic.c | 52 +++ boiler-monster/stm32/app/pins.h | 53 +++ boiler-monster/stm32/app/pressure.c | 164 ++++++++ boiler-monster/stm32/app/project.h | 30 ++ boiler-monster/stm32/app/prototypes.h | 106 +++++ boiler-monster/stm32/app/ring.c | 77 ++++ boiler-monster/stm32/app/ring.h | 13 + boiler-monster/stm32/app/stdio.c | 77 ++++ boiler-monster/stm32/app/temp.c | 76 ++++ boiler-monster/stm32/app/ticker.c | 105 +++++ boiler-monster/stm32/app/usart.c | 175 ++++++++ boiler-monster/stm32/app/util.c | 14 + boiler-monster/stm32/docs/pinout.txt | 24 ++ boiler-monster/stm32/docs/pm0056.pdf | Bin 0 -> 2098835 bytes boiler-monster/stm32/docs/rm0008.pdf | Bin 0 -> 13016697 bytes boiler-monster/stm32/docs/stm32f103c8.pdf | Bin 0 -> 1697666 bytes .../stm32/docs/stm32f103c8t6_pinout_voltage01.png | Bin 0 -> 679565 bytes boiler-monster/stm32/libopencm3 | 1 + 36 files changed, 3133 insertions(+) create mode 100644 boiler-monster/stm32/.gitignore create mode 100644 boiler-monster/stm32/Makefile create mode 100644 boiler-monster/stm32/Makefile.include create mode 100644 boiler-monster/stm32/Makefile.rules create mode 100644 boiler-monster/stm32/app/1wire.c create mode 100644 boiler-monster/stm32/app/1wire.h create mode 100644 boiler-monster/stm32/app/Makefile create mode 100644 boiler-monster/stm32/app/adc.c create mode 100644 boiler-monster/stm32/app/boiler.ld create mode 100644 boiler-monster/stm32/app/cmd.c create mode 100644 boiler-monster/stm32/app/commit.c create mode 100644 boiler-monster/stm32/app/ds1820.c create mode 100644 boiler-monster/stm32/app/gdb.script create mode 100644 boiler-monster/stm32/app/led.c create mode 100644 boiler-monster/stm32/app/main.c create mode 100644 boiler-monster/stm32/app/ot.c create mode 100644 boiler-monster/stm32/app/ot_phy_rx.c create mode 100644 boiler-monster/stm32/app/ot_phy_tx.c create mode 100644 boiler-monster/stm32/app/pic.c create mode 100644 boiler-monster/stm32/app/pins.h create mode 100644 boiler-monster/stm32/app/pressure.c create mode 100644 boiler-monster/stm32/app/project.h create mode 100644 boiler-monster/stm32/app/prototypes.h create mode 100644 boiler-monster/stm32/app/ring.c create mode 100644 boiler-monster/stm32/app/ring.h create mode 100644 boiler-monster/stm32/app/stdio.c create mode 100644 boiler-monster/stm32/app/temp.c create mode 100644 boiler-monster/stm32/app/ticker.c create mode 100644 boiler-monster/stm32/app/usart.c create mode 100644 boiler-monster/stm32/app/util.c create mode 100644 boiler-monster/stm32/docs/pinout.txt create mode 100644 boiler-monster/stm32/docs/pm0056.pdf create mode 100644 boiler-monster/stm32/docs/rm0008.pdf create mode 100644 boiler-monster/stm32/docs/stm32f103c8.pdf create mode 100644 boiler-monster/stm32/docs/stm32f103c8t6_pinout_voltage01.png create mode 160000 boiler-monster/stm32/libopencm3 (limited to 'boiler-monster/stm32') diff --git a/boiler-monster/stm32/.gitignore b/boiler-monster/stm32/.gitignore new file mode 100644 index 0000000..64532f4 --- /dev/null +++ b/boiler-monster/stm32/.gitignore @@ -0,0 +1,15 @@ +*.o +*.d +*.map +*.hex +*.elf +*.swp +*~ +*.dfu +plot/data +plot/script +*.bin +scmversion +commit.h +opencm3.build.stamp +*.orig diff --git a/boiler-monster/stm32/Makefile b/boiler-monster/stm32/Makefile new file mode 100644 index 0000000..e1cd497 --- /dev/null +++ b/boiler-monster/stm32/Makefile @@ -0,0 +1,8 @@ + +default: + make -C libopencm3 + make -C app + +clean: + make -C libopencm3 clean + make -C app clean diff --git a/boiler-monster/stm32/Makefile.include b/boiler-monster/stm32/Makefile.include new file mode 100644 index 0000000..4f5cbd9 --- /dev/null +++ b/boiler-monster/stm32/Makefile.include @@ -0,0 +1,44 @@ +## +## This file is part of the libopencm3 project. +## +## Copyright (C) 2009 Uwe Hermann +## Copyright (C) 2010 Piotr Esden-Tempski +## +## This library is free software: you can redistribute it and/or modify +## it under the terms of the GNU Lesser General Public License as published by +## the Free Software Foundation, either version 3 of the License, or +## (at your option) any later version. +## +## This library is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU Lesser General Public License for more details. +## +## You should have received a copy of the GNU Lesser General Public License +## along with this library. If not, see . +## + +LIBNAME = opencm3_stm32f1 +DEFS = -DSTM32F1 + +FP_FLAGS ?= -msoft-float +ARCH_FLAGS = -mthumb -mcpu=cortex-m3 $(FP_FLAGS) -mfix-cortex-m3-ldrd + +################################################################################ +# OpenOCD specific variables + +OOCD ?= openocd +OOCD_INTERFACE ?= interface/stlink-v2.cfg +OOCD_BOARD ?= target/stm32f1x.cfg + +################################################################################ +# Black Magic Probe specific variables +# Set the BMP_PORT to a serial port and then BMP is used for flashing +BMP_PORT ?= + +################################################################################ +# texane/stlink specific variables +#STLINK_PORT ?= :4242 + + +include ../Makefile.rules diff --git a/boiler-monster/stm32/Makefile.rules b/boiler-monster/stm32/Makefile.rules new file mode 100644 index 0000000..a723e6f --- /dev/null +++ b/boiler-monster/stm32/Makefile.rules @@ -0,0 +1,261 @@ +# +## This file is part of the libopencm3 project. +## +## Copyright (C) 2009 Uwe Hermann +## Copyright (C) 2010 Piotr Esden-Tempski +## Copyright (C) 2013 Frantisek Burian +## +## This library is free software: you can redistribute it and/or modify +## it under the terms of the GNU Lesser General Public License as published by +## the Free Software Foundation, either version 3 of the License, or +## (at your option) any later version. +## +## This library is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU Lesser General Public License for more details. +## +## You should have received a copy of the GNU Lesser General Public License +## along with this library. If not, see . +## + +# Be silent per default, but 'make V=1' will show all compiler calls. +ifneq ($(V),1) +Q := @ +NULL := 2>/dev/null +endif + +############################################################################### +# Executables + +PREFIX ?= arm-none-eabi + +CC := $(PREFIX)-gcc +CXX := $(PREFIX)-g++ +LD := $(PREFIX)-gcc +AR := $(PREFIX)-ar +AS := $(PREFIX)-as +OBJCOPY := $(PREFIX)-objcopy +OBJDUMP := $(PREFIX)-objdump +GDB := $(PREFIX)-gdb +STFLASH = $(shell which st-flash) +STYLECHECK := /checkpatch.pl +STYLECHECKFLAGS := --no-tree -f --terse --mailback +STYLECHECKFILES := $(shell find . -name '*.[ch]') + + +############################################################################### +# Source files + +LDSCRIPT ?= $(BINARY).ld + +#OBJS += $(BINARY).o + + +ifeq ($(strip $(OPENCM3_DIR)),) +# user has not specified the library path, so we try to detect it + +# where we search for the library +LIBPATHS := ./libopencm3 ../libopencm3 + +OPENCM3_DIR := $(wildcard $(LIBPATHS:=/locm3.sublime-project)) +OPENCM3_DIR := $(firstword $(dir $(OPENCM3_DIR))) + +ifeq ($(strip $(OPENCM3_DIR)),) +$(warning Cannot find libopencm3 library in the standard search paths.) +$(error Please specify it through OPENCM3_DIR variable!) +endif +endif + +ifeq ($(V),1) +$(info Using $(OPENCM3_DIR) path to library) +endif + +INCLUDE_DIR = $(OPENCM3_DIR)/include +LIB_DIR = $(OPENCM3_DIR)/lib +SCRIPT_DIR = $(OPENCM3_DIR)/scripts + +############################################################################### +# C flags + +CFLAGS += -Os -g +CFLAGS += -Wextra -Wimplicit-function-declaration +CFLAGS += -Wmissing-prototypes -Wstrict-prototypes +CFLAGS += -fno-common -ffunction-sections -fdata-sections + +############################################################################### +# C++ flags + +CXXFLAGS += -Os -g +CXXFLAGS += -Wextra -Wshadow -Wredundant-decls -Weffc++ +CXXFLAGS += -fno-common -ffunction-sections -fdata-sections + +############################################################################### +# C & C++ preprocessor common flags + +CPPFLAGS += -MD +CPPFLAGS += -Wall -Wundef + +INCLUDES = -I$(INCLUDE_DIR) +DEFINES = $(DEFS) + +CPPFLAGS += $(INCLUDES) $(DEFINES) + +############################################################################### +# Linker flags + +LDFLAGS += --static -nostartfiles +LDFLAGS += -L$(LIB_DIR) +LDFLAGS += -T$(LDSCRIPT) +LDFLAGS += -Wl,-Map=$(*).map +LDFLAGS += -Wl,--gc-sections +ifeq ($(V),99) +LDFLAGS += -Wl,--print-gc-sections +endif + +############################################################################### +# Used libraries + +LDLIBS += -l$(LIBNAME) +LDLIBS += -Wl,--start-group -lc -lgcc -lnosys -Wl,--end-group + +############################################################################### +############################################################################### +############################################################################### + +.SUFFIXES: .elf .bin .hex .srec .list .map .images .dfu +.SECONDEXPANSION: +.SECONDARY: + +all: elf + + +elf: $(BINARY).elf +bin: $(BINARY).bin +hex: $(BINARY).hex +srec: $(BINARY).srec +list: $(BINARY).list + +images: $(BINARY).images +flash: $(BINARY).flash + +%.images: %.bin %.hex %.srec %.list %.map %.dfu + @#printf "*** $* images generated ***\n" + +%.bin: %.elf + @#printf " OBJCOPY $(*).bin\n" + $(Q)$(OBJCOPY) -Obinary $(*).elf $(*).bin + +%.hex: %.elf + @#printf " OBJCOPY $(*).hex\n" + $(Q)$(OBJCOPY) -Oihex $(*).elf $(*).hex + +%.dfu: %.elf + @#printf " OBJCOPY $(*).dfu\n" + $(Q)$(OBJCOPY) -Obinary $(*).elf $(*).dfu + +%.srec: %.elf + @#printf " OBJCOPY $(*).srec\n" + $(Q)$(OBJCOPY) -Osrec $(*).elf $(*).srec + +%.list: %.elf + @#printf " OBJDUMP $(*).list\n" + $(Q)$(OBJDUMP) -S $(*).elf > $(*).list + +fish: + echo %.elf %.map: $(OBJS) $(LDSCRIPT) $(LIB_DIR)/lib$(LIBNAME).a + echo $(BINARY).elf + +%.elf %.map: $(OBJS) $(LDSCRIPT) $(LIB_DIR)/lib$(LIBNAME).a + @#printf " LD $(*).elf\n" + $(Q)$(LD) $(LDFLAGS) $(ARCH_FLAGS) $(OBJS) $(LDLIBS) -o $(*).elf + +%.o: %.c $(OPENCM3_DIR)/../opencm3.build.stamp + @#printf " CC $(*).c\n" + $(Q)$(CC) $(CFLAGS) $(CPPFLAGS) $(ARCH_FLAGS) -o $(*).o -c $(*).c + +%.o: %.cxx $(OPENCM3_DIR)/../opencm3.build.stamp + @#printf " CXX $(*).cxx\n" + $(Q)$(CXX) $(CXXFLAGS) $(CPPFLAGS) $(ARCH_FLAGS) -o $(*).o -c $(*).cxx + +%.o: %.cpp $(OPENCM3_DIR)/../opencm3.build.stamp + @#printf " CXX $(*).cpp\n" + $(Q)$(CXX) $(CXXFLAGS) $(CPPFLAGS) $(ARCH_FLAGS) -o $(*).o -c $(*).cpp + +clean: + @#printf " CLEAN\n" + $(Q)$(RM) *.o *.d *.elf *.bin *.hex *.srec *.list *.map *~ *.dfu ${EXTRACLEANS} + +stylecheck: $(STYLECHECKFILES:=.stylecheck) +styleclean: $(STYLECHECKFILES:=.styleclean) + +# the cat is due to multithreaded nature - we like to have consistent chunks of text on the output +%.stylecheck: % + $(Q)$(SCRIPT_DIR)$(STYLECHECK) $(STYLECHECKFLAGS) $* > $*.stylecheck; \ + if [ -s $*.stylecheck ]; then \ + cat $*.stylecheck; \ + else \ + rm -f $*.stylecheck; \ + fi; + +%.styleclean: + $(Q)rm -f $*.stylecheck; + + +%.stlink-flash: %.bin + @printf " FLASH $<\n" + $(Q)$(STFLASH) write $(*).bin 0x8000000 + +ifeq ($(STLINK_PORT),) +ifeq ($(BMP_PORT),) +ifeq ($(OOCD_SERIAL),) +%.flash: %.hex + @printf " FLASH $<\n" + @# IMPORTANT: Don't use "resume", only "reset" will work correctly! + $(Q)$(OOCD) -f $(OOCD_INTERFACE) \ + -f $(OOCD_BOARD) \ + -c "init" -c "reset init" \ + -c "flash write_image erase $(*).hex" \ + -c "reset" \ + -c "shutdown" $(NULL) +else +%.flash: %.hex + @printf " FLASH $<\n" + @# IMPORTANT: Don't use "resume", only "reset" will work correctly! + $(Q)$(OOCD) -f $(OOCD_INTERFACE) \ + -f $(OOCD_BOARD) \ + -c "ft2232_serial $(OOCD_SERIAL)" \ + -c "init" -c "reset init" \ + -c "flash write_image erase $(*).hex" \ + -c "reset" \ + -c "shutdown" $(NULL) +endif +else +%.flash: %.elf + @printf " GDB $(*).elf (flash)\n" + $(Q)$(GDB) --batch \ + -ex 'target extended-remote $(BMP_PORT)' \ + -x $(SCRIPT_DIR)/black_magic_probe_flash.scr \ + $(*).elf +endif +else +%.flash: %.elf + @printf " GDB $(*).elf (flash)\n" + $(Q)$(GDB) --batch \ + -ex 'target extended-remote $(STLINK_PORT)' \ + -x $(SCRIPT_DIR)/stlink_flash.scr \ + $(*).elf +endif + +.PHONY: images clean stylecheck styleclean elf bin hex srec list + +-include $(OBJS:.o=.d) + + +$(LIB_DIR)/lib$(LIBNAME).a: $(OPENCM3_DIR)/../opencm3.build.stamp + + +$(OPENCM3_DIR)/../opencm3.build.stamp: + ${MAKE} -C ${OPENCM3_DIR} + touch $@ + diff --git a/boiler-monster/stm32/app/1wire.c b/boiler-monster/stm32/app/1wire.c new file mode 100644 index 0000000..c374c5c --- /dev/null +++ b/boiler-monster/stm32/app/1wire.c @@ -0,0 +1,392 @@ +#include "project.h" + +#define USART2_TX GPIO_USART2_TX +#define USART2_TX_PORT GPIOA + +#define BIT_ZERO '0' +#define BIT_ONE '1' +#define BIT_UNKNOWN 'U' +#define BIT_CONFLICT 'C' + + +static int poke; +static volatile unsigned exchange_timeout; + +void onewire_tick (void) +{ + static unsigned ticker; + + if (exchange_timeout) + exchange_timeout--; + + + ticker++; + + if (ticker < MS_TO_TICKS (5000)) + return; + + ticker = 0; + poke = 1; + + +} + + +static unsigned usart_send_ready (uint32_t usart) +{ + return (USART_SR (usart) & USART_SR_TXE); +} + + +static unsigned usart_recv_ready (uint32_t usart) +{ + return (USART_SR (usart) & USART_SR_RXNE); +} + + + +static int onewire_exchange (int tx, unsigned timeout) +{ + int rx; + (void) USART_SR (USART2); + (void) usart_recv (USART2); + + + exchange_timeout = MS_TO_TICKS (timeout); + + while (!usart_send_ready (USART2)) + if (!exchange_timeout) + return -1; + + usart_send (USART2, tx); + + exchange_timeout = MS_TO_TICKS (timeout); + + while (!usart_recv_ready (USART2)) + if (!exchange_timeout) + return -1; + + + rx = usart_recv (USART2); + + return rx; + +} + +/* returns 1 if nothing on bus or error */ +int +onewire_reset (void) +{ + int ret; + + usart_set_baudrate (USART2, 9600); + delay_ms (1); + ret = onewire_exchange (0xf0, 60); + usart_set_baudrate (USART2, 115200); + delay_ms (1); + + return (ret == 0xf0); +} + +static void +onewire_one (void) +{ + onewire_exchange (0xff, 3); +} + +static void +onewire_zero (void) +{ + onewire_exchange (0x00, 3); +} + +static int +onewire_read (void) +{ + uint8_t rx; + + rx = onewire_exchange (0xff, 3); + + return (rx == 0xff); +} + + +void +onewire_write_byte (uint8_t v) +{ + int c; + + + for (c = 0; c < 8; ++c) { + if (v & 1) + onewire_one(); + else + onewire_zero(); + + v >>= 1; + } +} + +uint8_t +onewire_read_byte (void) +{ + uint8_t v = 0; + int c; + + + for (c = 0; c < 8; ++c) { + v >>= 1; + + if (onewire_read()) + v |= 0x80; + } + + + return v; +} + + + +void +onewire_read_bytes (uint8_t *buf, int n) +{ + while (n--) + * (buf++) = onewire_read_byte(); +} + + +void +onewire_write_bytes (const uint8_t *buf, int n) +{ + while (n--) + onewire_write_byte (* (buf++)); +} + + +int onewire_select (const Onewire_addr *a) +{ + if (!a) + onewire_write_byte (ONEWIRE_SKIP_ROM); + else { + onewire_write_byte (ONEWIRE_MATCH_ROM); + onewire_write_bytes (a->a, 8); + } + + return 0; +} + + +int onewire_reset_and_select (const Onewire_addr *a) +{ + if (onewire_reset()) + return 1; + + if (onewire_select (a)) + return 1; + + return 0; +} + + + +int onewire_wait_complete (unsigned timeout) +{ + while (! (onewire_read())) { + delay_ms (10); + + if (! (timeout--)) + return 1; + } + + return 0; +} + + + +int +onewire_check_crc (uint8_t *buf, int n, uint8_t v) +{ + uint8_t crc = 0; + int i; + + while (n--) { + uint8_t v = * (buf++); + + for (i = 0; i < 8; ++i) { + uint8_t mix = (crc ^ v) & 0x01; + crc >>= 1; + + if (mix) + crc ^= 0x8C; + + v >>= 1; + } + } + + return ! (crc == v); + +} + +static int onewire_conduct_search (uint8_t *bits) +{ + unsigned i, ir, r; + + if (onewire_reset()) + return -1; + + onewire_write_byte (ONEWIRE_SEARCH_ROM); + + + for (i = 0; i < 64; ++i) { + + r = onewire_read(); + ir = onewire_read(); + +#if 0 + + if ((i == 27) || (i == 24) || (i == 39)) + ir = r = 0; + +#endif + + switch (bits[i]) { + case BIT_UNKNOWN: + + if (!r && ir) { /* Zero */ + bits[i] = BIT_ZERO; + onewire_zero(); + } else if (r && !ir) { /*One */ + bits[i] = BIT_ONE; + onewire_one(); + } else if (r && ir) { /*Nothing here */ + //MEH; + return -1; + } else if (!r && !ir) { /*Both */ + bits[i] = BIT_CONFLICT; + onewire_zero(); + } + + break; + + case BIT_CONFLICT: + if (!r && !ir) /*Both */ + onewire_zero(); + else { + //MEH; + return -1; + } + + break; + + case BIT_ZERO: + if (!r) + onewire_zero(); + else { + //MEH; + return -1; + } + + break; + + case BIT_ONE: + if (!ir) + onewire_one(); + else { + //MEH; + return -1; + } + + break; + } + } + + return 0; +} + +static int onewire_next (uint8_t *bits) +{ + unsigned i; + + for (i = 0; i < 64; ++i) { + + if (bits[63 - i] == BIT_CONFLICT) { + bits[63 - i] = BIT_ONE; + return 1; + } + + bits[63 - i] = BIT_UNKNOWN; + } + + return 0; +} + +static void onewire_bits_to_a (uint8_t *bits, Onewire_addr *a) +{ + unsigned i, j, c; + + for (i = 0, j = 0; i < 8; ++i) { + + a->a[i] = 0; + + for (c = 1; c < 0x100; c <<= 1, ++j) { + if (bits[j] == BIT_ONE) + a->a[i] |= c; + } + } +} + +int onewire_search (void) +{ + uint8_t bits[64]; + Onewire_addr a; + int r, c; + + delay_ms (2000); + + memset (bits, BIT_UNKNOWN, sizeof (bits)); + + do { + r = onewire_conduct_search (bits); + + if (!r) { + onewire_bits_to_a (bits, &a); + c = onewire_check_crc (&a.a[0], 7, a.a[7]); + + if (!c) { + printf ("QO: {0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x}\r\n", + a.a[0], + a.a[1], + a.a[2], + a.a[3], + a.a[4], + a.a[5], + a.a[6], + a.a[7]); + } + + } + + } while (onewire_next (bits)); + + + return 0; +} + + + +void +onewire_init (void) +{ + MAP_AF_OD (USART2_TX); + + usart_set_baudrate (USART2, 115200); + usart_set_databits (USART2, 8); + usart_set_stopbits (USART2, USART_STOPBITS_1); + usart_set_parity (USART2, USART_PARITY_NONE); + usart_set_flow_control (USART2, USART_FLOWCONTROL_NONE); + usart_set_mode (USART2, USART_MODE_TX_RX); + + USART_CR3 (USART2) |= USART_CR3_HDSEL; + + usart_enable (USART2); +} diff --git a/boiler-monster/stm32/app/1wire.h b/boiler-monster/stm32/app/1wire.h new file mode 100644 index 0000000..4a31418 --- /dev/null +++ b/boiler-monster/stm32/app/1wire.h @@ -0,0 +1,10 @@ +#define ONEWIRE_SKIP_ROM 0xcc +#define ONEWIRE_SEARCH_ROM 0xf0 +#define ONEWIRE_MATCH_ROM 0x55 + +#define ONEWIRE_ADDR_LEN 8 +typedef struct { + uint8_t a[ONEWIRE_ADDR_LEN]; +} Onewire_addr; + + diff --git a/boiler-monster/stm32/app/Makefile b/boiler-monster/stm32/app/Makefile new file mode 100644 index 0000000..23b4a74 --- /dev/null +++ b/boiler-monster/stm32/app/Makefile @@ -0,0 +1,113 @@ +## +## This file is part of the libopencm3 project. +## +## Copyright (C) 2009 Uwe Hermann +## +## This library is free software: you can redistribute it and/or modify +## it under the terms of the GNU Lesser General Public License as published by +## the Free Software Foundation, either version 3 of the License, or +## (at your option) any later version. +## +## This library is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU Lesser General Public License for more details. +## +## You should have received a copy of the GNU Lesser General Public License +## along with this library. If not, see . +## + +CPROTO=cproto +PROG=boiler + +CSRCS=main.c ot.c ot_phy_rx.c ot_phy_tx.c led.c ticker.c usart.c ring.c stdio.c util.c commit.c cmd.c pic.c 1wire.c temp.c ds1820.c pressure.c adc.c +HSRCS=pins.h project.h ring.h + +EXTRACLEANS=*.orig scmversion commit.h + +TARGET=boiler-monster + +V=1 +default: ${PROG}.fw.bin + rsync -vaP ${PROG}.fw.bin ${TARGET}:/tmp/boiler.fw + ssh ${TARGET} /etc/stm32/startup /tmp/boiler.fw + + +install: ${PROG}.fw.bin + rsync -vaP ${PROG}.fw.bin ${TARGET}:/etc/stm32/boiler.fw + + +128k_of_ff.bin: + dd if=/dev/zero bs=128k count=1 | tr '\0' '\377' > $@ + + +${PROG}.fw.bin:${PROG}.bin 128k_of_ff.bin + cat ${PROG}.bin 128k_of_ff.bin | dd of=$@ bs=128k iflag=fullblock count=1 + + +program: ${PROG}.elf + echo halt | nc -t localhost 4444 + echo flash write_image erase ${PWD}/$< 0x2000 | nc -t localhost 4444 + echo reset halt | nc -t localhost 4444 + RV=$$(arm-none-eabi-objdump --disassemble=reset_handler $< | awk '/^0/ { print "0x"$$1 }') && \ + echo resume $${RV} | nc -t localhost 4444 && \ + echo reset vector at $${RV} + +run:${PROG}.run + +%.run: %.hex + RV=$$(arm-none-eabi-objdump --disassemble=reset_handler $(*).elf | awk '/^0/ { print "0x"$$1 }') && \ + $(Q)$(OOCD) -f $(OOCD_INTERFACE) \ + -f $(OOCD_BOARD) \ + -c "init" -c "reset init" \ + -c "flash write_image erase $(*).hex" \ + -c "reset halt" \ + -c "resume $${RV}" \ + -c "shutdown" $(NULL) && \ + echo reset_handler is at $${RV} + + + + +BINARY = ${PROG} +OBJS = ${CSRCS:%.c=%.o} + +include ../Makefile.include + +CFLAGS+=-Wno-redundant-decls -Wno-unused-parameter -DDEBUG + +INCLUDES += -I.. + +protos: + echo -n > prototypes.h + ${CPROTO} $(INCLUDES) $(DEFINES) -e -v ${CSRCS} > prototypes.h.tmp + mv -f prototypes.h.tmp prototypes.h + +server: + $(OOCD) -f $(OOCD_INTERFACE) \ + -f $(OOCD_BOARD) + +debug: ${PROG}.elf + ${PREFIX}-gdb -x gdb.script ${PROG}.elf + +tidy: + astyle -A3 -s2 --attach-extern-c -L -c -w -Y -m0 -f -p -H -U -k3 -xj -xd ${CSRCS} ${HSRCS} + +HEAD_REF = $(shell git rev-parse --verify --short HEAD) +SCM_DIRTY = $(shell if ! git diff-index --quiet HEAD --; then echo "+dirty"; fi) +SCMVERSION = ${HEAD_REF}${SCM_DIRTY} + +scmversion: + echo -n ${SCMVERSION} > $@ + +.PHONY: scmversion + +commit.o: commit.h + +commit.h: scmversion + echo -n '#define COMMIT_ID "' > $@ + echo -n `cat scmversion` >> $@ + echo '"' >> $@ + + + diff --git a/boiler-monster/stm32/app/adc.c b/boiler-monster/stm32/app/adc.c new file mode 100644 index 0000000..2cfc4e3 --- /dev/null +++ b/boiler-monster/stm32/app/adc.c @@ -0,0 +1,154 @@ +#include "project.h" + +#define T do { printf("%s:%d\r\n",__FILE__,__LINE__); } while (0) + +void adc_dump (void) +{ + printf ("ADC_SR %x ADC_CR1 %x ADC_CR2 %x\r\n", (unsigned) ADC_SR (ADC1), + (unsigned) ADC_CR1 (ADC1), + (unsigned) ADC_CR2 (ADC1)); + +} + + +volatile unsigned timeout; + + +void adc_tick (void) +{ + if (timeout) timeout--; +} + + +static int adc_wait (volatile uint32_t *reg, uint32_t wait_while_set, uint32_t wait_while_clear, unsigned ms) +{ + timeout = MS_TO_TICKS (ms); + + + while ((*reg) & wait_while_set) + if (!timeout) { + printf ("QADC timeout\r\n"); + return -1; + } + + + while ((~ (*reg)) & wait_while_clear) + if (!timeout) { + printf ("QADC timeout\r\n"); + return -1; + } + + + return 0; +} + + + +int adc_calibrate (void) +{ + adc_off (ADC1); + adc_power_on (ADC1); + delay_ms (5); + + ADC_CR2 (ADC1) |= ADC_CR2_RSTCAL; + + if (adc_wait (&ADC_CR2 (ADC1), ADC_CR2_CAL, 0, 2)) return -1; + + ADC_CR2 (ADC1) |= ADC_CR2_CAL; + + if (adc_wait (&ADC_CR2 (ADC1), ADC_CR2_CAL, 0, 2)) return -1; + + return 0; +} + + + +int adc_convert_start (unsigned channel) +{ + uint8_t ch = channel; + + adc_set_regular_sequence (ADC1, 1, &ch); + + /* Start conversion on regular channels. */ + ADC_CR2 (ADC1) |= ADC_CR2_SWSTART; + +#if 0 + if (adc_wait (&ADC_CR2 (ADC1), ADC_CR2_SWSTART, 0, 2)) + return -1; +#endif + + return 0; +} + + + +int adc_convert_done(void) +{ + + if (ADC_SR(ADC1) & ADC_SR_EOC) + return 1; + + return 0; +} + +unsigned adc_convert_get(void) +{ + return adc_read_regular (ADC1); +} + + +unsigned adc_convert (unsigned channel) +{ + uint8_t ch = channel; + + adc_calibrate(); + + adc_set_regular_sequence (ADC1, 1, &ch); + + /* Start conversion on regular channels. */ + ADC_CR2 (ADC1) |= ADC_CR2_SWSTART; + + if (adc_wait (&ADC_CR2 (ADC1), ADC_CR2_SWSTART, 0, 2)) + return 0; + + if (adc_wait (&ADC_SR (ADC1), 0, ADC_SR_EOC, 2)) + return 0; + + return adc_read_regular (ADC1); +} + +void adc_init (void) +{ + /* main set ADC clock is 9Mhz */ + + adc_dump(); + + adc_off (ADC1); + rcc_periph_clock_enable (RCC_ADC1); +#if 0 + rcc_peripheral_reset (&RCC_APB2RSTR, RCC_APB2RSTR_ADC1RST); + rcc_peripheral_clear_reset (&RCC_APB2RSTR, RCC_APB2RSTR_ADC1RST); +#endif + + adc_set_dual_mode (ADC_CR1_DUALMOD_IND); + adc_disable_scan_mode (ADC1); + adc_enable_temperature_sensor (ADC1); + adc_set_single_conversion_mode (ADC1); + + adc_set_sample_time (ADC1, ADC_CHANNEL0, ADC_SMPR_SMP_239DOT5CYC); + adc_set_sample_time (ADC1, ADC_CHANNEL17, ADC_SMPR_SMP_239DOT5CYC); /*Want 17.1uS , which is 154 cycles */ + adc_enable_external_trigger_regular (ADC1, ADC_CR2_EXTSEL_SWSTART); + + adc_set_right_aligned (ADC1); + + + adc_dump(); + + adc_calibrate(); + + adc_dump(); + + + +} + diff --git a/boiler-monster/stm32/app/boiler.ld b/boiler-monster/stm32/app/boiler.ld new file mode 100644 index 0000000..e15beca --- /dev/null +++ b/boiler-monster/stm32/app/boiler.ld @@ -0,0 +1,31 @@ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2009 Uwe Hermann + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/* Linker script for Olimex STM32-H103 (STM32F103RBT6, 128K flash, 20K RAM). */ + +/* Define memory regions. */ +MEMORY +{ + rom (rx) : ORIGIN = 0x08000000, LENGTH = 128K + ram (rwx) : ORIGIN = 0x20000000, LENGTH = 20K +} + +/* Include the common ld script. */ +INCLUDE libopencm3_stm32f1.ld + diff --git a/boiler-monster/stm32/app/cmd.c b/boiler-monster/stm32/app/cmd.c new file mode 100644 index 0000000..7e1975a --- /dev/null +++ b/boiler-monster/stm32/app/cmd.c @@ -0,0 +1,55 @@ +#include "project.h" + + +static void cmd_dispatch (char *cmd) +{ + + printf ("Q received cmd %s\r\n", cmd); + + if (!strncmp (cmd, "CH=", 3)) { + ot_override_ch = atoi (cmd + 3); + printf ("Q CH override set to %d\r\n", ot_override_ch); + } + + + if (!strncmp (cmd, "DHW=", 4)) { + ot_override_dhw = atoi (cmd + 4); + printf ("Q DHW override set to %d\r\n", ot_override_dhw); + } + + if (!strcmp (cmd, "PIC")) { + ot_override_dhw = atoi (cmd + 4); + printf ("Q Entering PIC mode, reset to leave\r\n"); + pic_passthru(); + } + +} + + +void cmd_usart_dispatch (void) +{ + static char cmd[16]; + static unsigned cmd_ptr; + + uint8_t c; + + if (ring_read_byte (&rx1_ring, &c)) + return; + + + if ((c == '\n') || (c == '\r')) { + if (cmd_ptr) + cmd_dispatch (cmd); + + cmd_ptr = 0; + return; + } + + + if (cmd_ptr < (sizeof (cmd) - 1)) { + cmd[cmd_ptr++] = c; + cmd[cmd_ptr] = 0; + } +} + + diff --git a/boiler-monster/stm32/app/commit.c b/boiler-monster/stm32/app/commit.c new file mode 100644 index 0000000..207448f --- /dev/null +++ b/boiler-monster/stm32/app/commit.c @@ -0,0 +1,3 @@ +#include "commit.h" + +char scm_version[] = COMMIT_ID; diff --git a/boiler-monster/stm32/app/ds1820.c b/boiler-monster/stm32/app/ds1820.c new file mode 100644 index 0000000..200f4b7 --- /dev/null +++ b/boiler-monster/stm32/app/ds1820.c @@ -0,0 +1,93 @@ +#include "project.h" + +#define DS1820_READ_SCRATCHPAD 0xbe +#define DS1820_CONVERT_T 0x44 + + +#define TIMEOUT 150 + + + +static unsigned extract_leu16 (uint8_t *d) +{ + uint32_t u; + + u = (uint32_t) d[0] | (((uint32_t) d[1]) << 8); + return u; +} + + + +static int extract_les16 (uint8_t *d) +{ + uint32_t u; + u = extract_leu16 (d); + + if (u & 0x8000) u |= 0xffff0000; + + return (int) u; +} + + + + + +static int +ds1820_read_sp (const Onewire_addr *a, unsigned page, uint8_t *buf, unsigned len) +{ + if (onewire_reset_and_select (a)) + return ~0U; + + onewire_write_byte (DS1820_READ_SCRATCHPAD); + onewire_read_bytes (buf, len); + + if ((len == 9) && onewire_check_crc (buf, 8, buf[8])) + return ~0U; + + return 0; +} + + + +static int ds1820_convert_t (const Onewire_addr *a) +{ + + if (onewire_reset_and_select (a)) + return ~0U; + + onewire_write_byte (DS1820_CONVERT_T); + + if (onewire_wait_complete (TIMEOUT)) + return ~0U; + + return 0; +} + +int +ds1820_read (const Onewire_addr *a, int *temp) +{ + uint8_t buf[9]; + int t; + + if (ds1820_read_sp (a, 0, buf, 9)) + return 1; + + if (ds1820_convert_t (a)) + return 1; + + if (ds1820_read_sp (a, 0, buf, 9)) + return 1; + + t = extract_les16 (&buf[0]); + + t <<= 4 ; + + if (temp) + *temp = t; + + + return 0; +} + + + diff --git a/boiler-monster/stm32/app/gdb.script b/boiler-monster/stm32/app/gdb.script new file mode 100644 index 0000000..7cf9d09 --- /dev/null +++ b/boiler-monster/stm32/app/gdb.script @@ -0,0 +1,2 @@ +target remote localhost:3333 +cont diff --git a/boiler-monster/stm32/app/led.c b/boiler-monster/stm32/app/led.c new file mode 100644 index 0000000..bdfd084 --- /dev/null +++ b/boiler-monster/stm32/app/led.c @@ -0,0 +1,101 @@ +#include "project.h" + +#define LED_BOARD GPIO13 +#define LED_BOARD_PORT GPIOC + +#define LED_YELLOW GPIO11 +#define LED_YELLOW_PORT GPIOA + +#define LED_GREEN1 GPIO12 +#define LED_GREEN1_PORT GPIOA + +#define LED_GREEN2 GPIO15 +#define LED_GREEN2_PORT GPIOA + +#define LED_RED GPIO3 +#define LED_RED_PORT GPIOB + +static unsigned led, yellow; + + +void led_red_set (int i) +{ + if (i) + CLEAR (LED_RED); + else + SET (LED_RED); +} + +void led_green1_set (int i) +{ + if (i) + CLEAR (LED_GREEN1); + else + SET (LED_GREEN1); +} + +void led_green2_set (int i) +{ + if (i) + CLEAR (LED_GREEN2); + else + SET (LED_GREEN2); +} + +static void _led_yellow_set (int i) +{ + if (i) + CLEAR (LED_YELLOW); + else + SET (LED_YELLOW); +} + +static void led_board_set (int i) +{ + if (i) + CLEAR (LED_BOARD); + else + SET (LED_BOARD); +} + +void led_blink (void) +{ + led = MS_TO_TICKS (25); +} + + +void led_yellow_set (int i) +{ + yellow = !!i; +} + + +void +led_tick (void) +{ + if (led) { + led--; + + led_board_set (1); + _led_yellow_set (!yellow); + } else { + + led_board_set (0); + _led_yellow_set (yellow); + } +} + + +void +led_init (void) +{ + MAP_OUTPUT_PP (LED_BOARD); + MAP_OUTPUT_PP (LED_RED); + MAP_OUTPUT_PP (LED_GREEN1); + MAP_OUTPUT_PP (LED_GREEN2); + MAP_OUTPUT_PP (LED_YELLOW); + + CLEAR (LED_BOARD); +} + + diff --git a/boiler-monster/stm32/app/main.c b/boiler-monster/stm32/app/main.c new file mode 100644 index 0000000..5ceb4af --- /dev/null +++ b/boiler-monster/stm32/app/main.c @@ -0,0 +1,134 @@ +#include "project.h" +extern uint32_t dfu_flag; + +extern volatile uint32_t vector_table[]; + + +void reset_hardware (void) +{ + int i; + + rcc_periph_reset_pulse (RST_OTGFS); + rcc_periph_reset_pulse (RST_ETHMAC); + rcc_periph_reset_pulse (RST_AFIO); + rcc_periph_reset_pulse (RST_GPIOA); + rcc_periph_reset_pulse (RST_GPIOB); + rcc_periph_reset_pulse (RST_GPIOC); + rcc_periph_reset_pulse (RST_GPIOD); + rcc_periph_reset_pulse (RST_GPIOE); + rcc_periph_reset_pulse (RST_GPIOF); + rcc_periph_reset_pulse (RST_GPIOG); + rcc_periph_reset_pulse (RST_ADC1); + rcc_periph_reset_pulse (RST_ADC2); + rcc_periph_reset_pulse (RST_TIM1); + rcc_periph_reset_pulse (RST_SPI1); + rcc_periph_reset_pulse (RST_TIM8); + rcc_periph_reset_pulse (RST_USART1); + rcc_periph_reset_pulse (RST_ADC3); + rcc_periph_reset_pulse (RST_TIM15); + rcc_periph_reset_pulse (RST_TIM16); + rcc_periph_reset_pulse (RST_TIM17); + rcc_periph_reset_pulse (RST_TIM9); + rcc_periph_reset_pulse (RST_TIM10); + rcc_periph_reset_pulse (RST_TIM11); + rcc_periph_reset_pulse (RST_TIM2); + rcc_periph_reset_pulse (RST_TIM3); + rcc_periph_reset_pulse (RST_TIM4); + rcc_periph_reset_pulse (RST_TIM5); + rcc_periph_reset_pulse (RST_TIM6); + rcc_periph_reset_pulse (RST_TIM7); + rcc_periph_reset_pulse (RST_TIM12); + rcc_periph_reset_pulse (RST_TIM13); + rcc_periph_reset_pulse (RST_TIM14); + rcc_periph_reset_pulse (RST_WWDG); + rcc_periph_reset_pulse (RST_SPI2); + rcc_periph_reset_pulse (RST_SPI3); + rcc_periph_reset_pulse (RST_USART2); + rcc_periph_reset_pulse (RST_USART3); + rcc_periph_reset_pulse (RST_UART4); + rcc_periph_reset_pulse (RST_UART5); + rcc_periph_reset_pulse (RST_I2C1); + rcc_periph_reset_pulse (RST_I2C2); + rcc_periph_reset_pulse (RST_USB); + rcc_periph_reset_pulse (RST_CAN); + rcc_periph_reset_pulse (RST_CAN1); + rcc_periph_reset_pulse (RST_CAN2); + rcc_periph_reset_pulse (RST_BKP); + rcc_periph_reset_pulse (RST_PWR); + rcc_periph_reset_pulse (RST_DAC); + rcc_periph_reset_pulse (RST_CEC); + + + for (i = 0; i < NVIC_IRQ_COUNT; ++i) + nvic_disable_irq (i); + +} + + +int +main (void) +{ + + SCB_VTOR = (uint32_t) &vector_table; + asm volatile ("msr msp, %0"::"g" (vector_table[0])); + + reset_hardware(); + + + + // rcc_clock_setup_in_hsi_out_48mhz (); + //nvic_set_priority_grouping(NVIC_PriorityGroup_4); + + /*set up pll */ + rcc_clock_setup_in_hse_8mhz_out_72mhz(); + + /*turn on clocks to periferals */ + rcc_periph_clock_enable (RCC_GPIOA); + rcc_periph_clock_enable (RCC_GPIOB); + rcc_periph_clock_enable (RCC_GPIOC); + rcc_periph_clock_enable (RCC_AFIO); + rcc_periph_clock_enable (RCC_USART1); + rcc_periph_clock_enable (RCC_USART2); + rcc_periph_clock_enable (RCC_USART3); + rcc_periph_clock_enable (RCC_ADC1); + + dwt_enable_cycle_counter(); + + /*Change interrupt priorities so that USART trumps Timer trumps ATKBD */ + nvic_set_priority (NVIC_USART1_IRQ, 0x40); + nvic_set_priority (NVIC_USART2_IRQ, 0x40); + nvic_set_priority (NVIC_USART3_IRQ, 0x40); + nvic_set_priority (NVIC_SYSTICK_IRQ, 0x80); + nvic_set_priority (NVIC_EXTI9_5_IRQ, 0xc0); + + gpio_primary_remap (AFIO_MAPR_SWJ_CFG_JTAG_OFF_SW_ON, 0); + + led_init(); + + usart_init(); + ticker_init(); + + pic_init(); + ot_init(); + + onewire_init(); + + pressure_init(); + adc_init(); + + + printf ("STARTUP\r\n"); + printf ("%s\r\n", scm_version); + + + for (;;) { + if (!ring_empty (&rx1_ring)) + cmd_usart_dispatch(); + + temp_dispatch(); + + } + + + return 0; +} diff --git a/boiler-monster/stm32/app/ot.c b/boiler-monster/stm32/app/ot.c new file mode 100644 index 0000000..2a8ad36 --- /dev/null +++ b/boiler-monster/stm32/app/ot.c @@ -0,0 +1,452 @@ +#include "project.h" + + +typedef struct { + uint8_t flags: 5; + uint8_t type: 3; + uint8_t data[2]; +} OT_Msg; + + +#define FLAGS_PENDING_THM 1U << 0 +#define FLAGS_PROCESSED_THM 1U << 1 +#define FLAGS_PENDING_USR 1U << 2 +#define FLAGS_PROCESSED_USR 1U << 3 +#define FLAGS_PENDING_OVR 1U << 4 + +#define FLAGS_PENDING (FLAGS_PENDING_THM|FLAGS_PENDING_USR | FLAGS_PENDING_OVR) + +#define IDX_MAX 0x300 + +static OT_Msg ot_thm_req[IDX_MAX]; +static OT_Msg ot_blr_rsp[IDX_MAX]; + +#define OT_NEXT(a) (((a) < 0x2ff) ? ((a)+1):0) +#define OT_INDEX(t,id) ((((unsigned) (t) ) <<8 ) | ((unsigned) (id))) +#define OT_IDX_TO_ID(idx) ((idx) & 0xff) +#define OT_IDX_TO_TYPE(idx) ((idx) >> 8) + +static unsigned ot_req_idx; +static unsigned in_flight_req_type; +static unsigned blr_backoff; +static unsigned ot_status_wdt; + + +#define OT_READ_DATA 0x0 +#define OT_WRITE_DATA 0x1 +#define OT_INVALID_DATA 0x2 +#define OT_READ_ACK 0x4 +#define OT_WRITE_ACK 0x5 +#define OT_DATA_INVALID 0x6 +#define OT_UNKNOWN_DATAID 0x7 + + +#define OT_IDX_STATUS 0 +/*TX*/ +#define OT_IDX_STATUS_BIT_ENABLE_CH (1U << 0) +#define OT_IDX_STATUS_BIT_ENABLE_DHW (1U << 1) + +/*RX*/ +#define OT_IDX_STATUS_BIT_FAULT (1U << 0) +#define OT_IDX_STATUS_BIT_CH_MODE (1U << 1) +#define OT_IDX_STATUS_BIT_DHW_MODE (1U << 2) +#define OT_IDX_STATUS_BIT_FLAME (1U << 3) + +#define OT_IDX_CONTROL_SETPOINT 1 +#define OT_IDX_DHW_SETPOINT 56 + + +#define OT_IDX_CH_WATER_PRESSURE 18 +#define OT_IDX_RETURN_WATER_TEMP 28 +#define OT_IDX_SUPPLY_INLET_TEMP 80 + + + +unsigned ot_override_ch = 0; +unsigned ot_override_dhw = 0; + + +static inline int parity (uint8_t v) +{ + return (0x6996u >> ((v ^ (v >> 4)) & 0xf)) & 1; +} + +static void ot_parity (uint8_t *data) +{ + int p; + p = parity (data[0]); + p ^= parity (data[1]); + p ^= parity (data[2]); + p ^= parity (data[3]); + + if (p) data[0] ^= 0x80; +} + + +static const char *type_str[8] = { + ">Read Data", + ">Write Data", + ">Invalid Data", + ">Reserved", + "> 4) & 7; + + + printf ("%s%02x%02x%02x%02x %s %s\r\n", + who, + msg[0], + msg[1], + msg[2], + msg[3], + type_str[type], + what + ); +} + +static void send_reply_to_thm (unsigned idx) +{ + uint8_t reply[4]; + + if (ot_tx_thm (NULL)) return; + + reply[0] = ot_blr_rsp[idx].type << 4; + reply[1] = OT_IDX_TO_ID (idx); + reply[2] = ot_blr_rsp[idx].data[0]; + reply[3] = ot_blr_rsp[idx].data[1]; + + ot_debug ("B", reply, ""); + + ot_parity (reply); + ot_tx_thm (reply); + + ot_blr_rsp[idx].flags &= ~FLAGS_PROCESSED_THM; + +} + + +static int send_req_to_blr (unsigned idx) +{ + uint8_t req[4]; + + if (ot_tx_blr (NULL)) return -1; + + + + req[0] = ot_thm_req[ot_req_idx].type << 4; + req[1] = OT_IDX_TO_ID (ot_req_idx); + req[2] = ot_thm_req[ot_req_idx].data[0]; + req[3] = ot_thm_req[ot_req_idx].data[1]; + + ot_parity (req); + ot_debug (" S", req, ""); + + return ot_tx_blr (req); +} + + + + +void ot_rx_thm (uint8_t *msg, int error) +{ + unsigned type = (msg[0] >> 4) & 7; + unsigned id = msg[1]; + + unsigned idx; + + if (error) return; + + if (type > 2) { + ot_debug ("T", msg, "message type invalid for thermostat"); + return; + } + + if (ot_override_ch) { + if ((id == OT_IDX_STATUS) && (type == OT_READ_DATA)) /* Turn on heating */ + msg[2] |= OT_IDX_STATUS_BIT_ENABLE_CH; + + if ((id == OT_IDX_CONTROL_SETPOINT) && (type == OT_WRITE_DATA)) /* set water temp */ + msg[2] = ot_override_ch; + + } + + if (ot_override_dhw) { + if ((id == OT_IDX_STATUS) && (type == OT_READ_DATA)) /* Turn on hotwater */ + msg[2] |= OT_IDX_STATUS_BIT_ENABLE_DHW; + + if ((id == OT_IDX_DHW_SETPOINT) && (type == OT_WRITE_DATA)) /* set water temp */ + msg[2] = ot_override_dhw; + + } + + if ((id == OT_IDX_STATUS) && (type == OT_READ_DATA)) + ot_status_wdt = 0; + + ot_debug ("T", msg, ""); + + idx = OT_INDEX (type, id); + + if (ot_blr_rsp[idx].flags & FLAGS_PROCESSED_THM) + send_reply_to_thm (idx); + + else { + ot_thm_req[idx].type = type; + ot_thm_req[idx].data[0] = msg[2];; + ot_thm_req[idx].data[1] = msg[3];; + ot_thm_req[idx].flags |= FLAGS_PENDING_THM; + } +} + +static int ot_fake_read_ack (unsigned id, uint8_t *msg) +{ + unsigned t; + + switch (id) { + case OT_IDX_CH_WATER_PRESSURE: + t = pressure_ch(); + + if (!t) return -1; + + break; + + case OT_IDX_RETURN_WATER_TEMP: + t = temp_ch_return(); + + if (!t) return -1; + + break; + + case OT_IDX_SUPPLY_INLET_TEMP: + t = temp_supply_inlet(); + + if (!t) return -1; + + break; + + default: + return -1; + } + + + + msg[0] = OT_READ_ACK << 4; + msg[1] = id; + msg[2] = t >> 8; + msg[3] = t & 0xff; + + return 0; +} + + +void ot_rx_blr (uint8_t *msg, int error) +{ + unsigned type = (msg[0] >> 4) & 7; + unsigned id = msg[1]; + + unsigned idx; + + if (error) return; + + ot_debug (" A", msg, ""); + + idx = OT_INDEX (in_flight_req_type, id); + + if ((in_flight_req_type == OT_READ_DATA) && (type != OT_READ_ACK)) { + if (!ot_fake_read_ack (id, msg)) { + ot_debug (" A", msg, " (faked)"); + type = (msg[0] >> 4) & 7; + } + } + + ot_blr_rsp[idx].type = type; + ot_blr_rsp[idx].data[0] = msg[2];; + ot_blr_rsp[idx].data[1] = msg[3];; + ot_blr_rsp[idx].flags |= FLAGS_PROCESSED_THM | FLAGS_PROCESSED_USR; + + if (ot_thm_req[idx].flags & FLAGS_PENDING_THM) { + ot_thm_req[idx].flags &= ~FLAGS_PENDING_THM; + send_reply_to_thm (idx); + } + + if (ot_thm_req[idx].flags & FLAGS_PENDING_USR) { + ot_thm_req[idx].flags &= ~FLAGS_PENDING_USR; + //send_reply_to_usr (idx); + } + + if (ot_thm_req[idx].flags & FLAGS_PENDING_OVR) + ot_thm_req[idx].flags &= ~FLAGS_PENDING_OVR; + + blr_backoff = 0; + +} + + + +static void ot_boiler_worker (void) +{ + unsigned i; + + if (blr_backoff) { + blr_backoff--; + return; + } + + if (ot_tx_blr (NULL)) return; + + + for (i = 0; i < IDX_MAX; ++i, ot_req_idx = OT_NEXT (ot_req_idx)) { + + if (ot_thm_req[ot_req_idx].flags & FLAGS_PENDING) { + + if (!send_req_to_blr (ot_req_idx)) { + ot_thm_req[ot_req_idx].flags &= ~FLAGS_PENDING; + in_flight_req_type = OT_IDX_TO_TYPE (ot_req_idx); + blr_backoff = 10; + ot_req_idx = OT_NEXT (ot_req_idx); + return; + } + } + + } + +} + + +static void ot_request (unsigned flags, unsigned type, unsigned id, uint8_t *data) +{ + unsigned idx = OT_INDEX (type, id); + + ot_thm_req[idx].type = type; + + if (data) { + ot_thm_req[idx].data[0] = data[0]; + ot_thm_req[idx].data[1] = data[1]; + } else { + ot_thm_req[idx].data[0] = 0; + ot_thm_req[idx].data[1] = 0; + } + + ot_thm_req[idx].flags |= FLAGS_PENDING_USR; + +} + +void ot_request_usr (unsigned type, unsigned id, uint8_t *data) +{ + ot_request (FLAGS_PENDING_USR, type, id, data); +} +static void ot_request_ovr (unsigned type, unsigned id, uint8_t *data) +{ + ot_request (FLAGS_PENDING_OVR, type, id, data); +} + + + +static void ot_force_status (void) +{ + uint8_t data[2] = { (ot_override_ch ? OT_IDX_STATUS_BIT_ENABLE_CH : 0) | (ot_override_dhw ? OT_IDX_STATUS_BIT_ENABLE_DHW : 0), 0}; + + ot_request_ovr (OT_READ_DATA, OT_IDX_STATUS, data); + +} + +static void ot_30s_ticker (void) +{ + uint8_t data[2]; + + printf ("Q ot ticker - push control flags\r\n"); + + if (ot_override_ch) { + data[0] = ot_override_ch; + data[1] = 0; + ot_request_ovr (OT_WRITE_DATA, OT_IDX_CONTROL_SETPOINT, data); + } + + if (ot_override_dhw) { + + data[0] = ot_override_dhw; + data[1] = 0; + ot_request_ovr (OT_WRITE_DATA, OT_IDX_DHW_SETPOINT, data); + } + +} + +static void ot_2s_ticker (void) +{ + uint8_t msg[4]; + + if (!ot_fake_read_ack (OT_IDX_CH_WATER_PRESSURE, msg)) + ot_debug ("B", msg, " (fake request and reply)"); + + if (!ot_fake_read_ack (OT_IDX_RETURN_WATER_TEMP, msg)) + ot_debug ("B", msg, " (fake request and reply)"); + + if (!ot_fake_read_ack (OT_IDX_SUPPLY_INLET_TEMP, msg)) + ot_debug ("B", msg, " (fake request and reply)"); +} + + + + + +static void ot_4hz_ticker (void) +{ + static unsigned thirty, two; + thirty++; + two++; + + ot_boiler_worker(); + + ot_status_wdt++; + + if (ot_status_wdt > 120) { + printf ("Q forcing status packet\r\n"); + ot_force_status(); + ot_status_wdt = 0; + } + + + if (two >= 8) { + ot_2s_ticker(); + two = 0; + } + + + if (thirty >= 120) { + ot_30s_ticker(); + thirty = 0; + } + + + led_yellow_set (ot_blr_rsp[OT_INDEX (OT_READ_DATA, OT_IDX_STATUS)].data[1] & OT_IDX_STATUS_BIT_FAULT); + led_green1_set (ot_blr_rsp[OT_INDEX (OT_READ_DATA, OT_IDX_STATUS)].data[1] & OT_IDX_STATUS_BIT_CH_MODE); + led_green2_set (ot_blr_rsp[OT_INDEX (OT_READ_DATA, OT_IDX_STATUS)].data[1] & OT_IDX_STATUS_BIT_DHW_MODE); + led_red_set (ot_blr_rsp[OT_INDEX (OT_READ_DATA, OT_IDX_STATUS)].data[1] & OT_IDX_STATUS_BIT_FLAME); + +} + + +void ot_tick (void) +{ + static unsigned i; + i++; + + if (i >= 500) { + ot_4hz_ticker(); + i = 0; + } + + +} + + +void ot_init (void) +{ + ot_phy_rx_init(); + ot_phy_tx_init(); +} diff --git a/boiler-monster/stm32/app/ot_phy_rx.c b/boiler-monster/stm32/app/ot_phy_rx.c new file mode 100644 index 0000000..9348d24 --- /dev/null +++ b/boiler-monster/stm32/app/ot_phy_rx.c @@ -0,0 +1,177 @@ +#include "project.h" + +#define OT_THM_IN GPIO6 +#define OT_THM_IN_PORT GPIOB + +#define OT_BLR_IN GPIO7 +#define OT_BLR_IN_PORT GPIOB + + +#define OT_RX_IRQ NVIC_EXTI9_5_IRQ + + +typedef struct rx_phy { + uint32_t last_cycle; + int last_v; + unsigned half_bits; + unsigned data_bits; + int frame_error; + uint8_t data[10]; + int parity; +} RX_Phy; + + +static RX_Phy p_thm, p_blr; + + +static uint32_t +cycle_diff (uint32_t a, uint32_t b) +{ + return b - a; +} + + + + +static void ot_phy_rx_bit (RX_Phy *p) +{ + + + if (p->half_bits & 1) + p->frame_error = 1; + + if (!p->half_bits) { + if (!p->last_v) + p->frame_error = 1; + + return; + } + + if (p->data_bits < 32) { + if (p->last_v) p->data[p->data_bits >> 3] |= 0x80 >> (p->data_bits & 7); + + p->parity ^= p->last_v; + } else if (p->data_bits == 32) { + if ((!p->last_v) || (p->parity)) + p->frame_error = 1; + + led_blink(); + + if (p == &p_thm) + ot_rx_thm (p->data, p->frame_error); + else + ot_rx_blr (p->data, p->frame_error); + } + + + p->data_bits++; + +} + + +static void ot_phy_rx_worker (RX_Phy *p, int v) +{ + uint32_t now, diff; + + if (v == p->last_v) return; + + + now = dwt_read_cycle_counter(); + diff = cycle_diff (p->last_cycle, now); + + + if (diff < 10000) return; + + if (diff < 50000) { + if (! (p->half_bits & 1)) ot_phy_rx_bit (p); + + p->half_bits++; + } else if (diff < 85000) { + p->half_bits++; + ot_phy_rx_bit (p); + p->half_bits++; + } else { + p->parity = 0; + p->half_bits = 0; + p->frame_error = 0; + p->data_bits = 0; + memset (p->data, 0, sizeof (p->data)); + } + + p->last_cycle = now; + p->last_v = v; +} + + + +void +exti9_5_isr (void) +{ + int v; + + if (EXTI_PR & OT_THM_IN) { + EXTI_PR = OT_THM_IN; + v = !GET (OT_THM_IN); + +#if 0 + + if (v) + CLEAR (OT_BLR_OUT); + else + SET (OT_BLR_OUT); + +#endif + + ot_phy_rx_worker (&p_thm, v); + + + } + + if (EXTI_PR & OT_BLR_IN) { + EXTI_PR = OT_BLR_IN; + v = !GET (OT_BLR_IN); + +#if 0 + + if (v) + CLEAR (OT_THM_OUT); + else + SET (OT_THM_OUT); + +#endif + + ot_phy_rx_worker (&p_blr, v); + } + + return; +} + + +void ot_phy_rx_tick (void) +{ +} + + + +void ot_phy_rx_init (void) +{ + MAP_INPUT_PU (OT_THM_IN); + MAP_INPUT_PU (OT_BLR_IN); + + + exti_select_source (OT_THM_IN, OT_THM_IN_PORT); + exti_set_trigger (OT_THM_IN, EXTI_TRIGGER_BOTH); + exti_enable_request (OT_THM_IN); + exti_reset_request (OT_THM_IN); + + exti_select_source (OT_BLR_IN, OT_BLR_IN_PORT); + exti_set_trigger (OT_BLR_IN, EXTI_TRIGGER_BOTH); + exti_enable_request (OT_BLR_IN); + exti_reset_request (OT_BLR_IN); + + nvic_enable_irq (OT_RX_IRQ); + +} + + + diff --git a/boiler-monster/stm32/app/ot_phy_tx.c b/boiler-monster/stm32/app/ot_phy_tx.c new file mode 100644 index 0000000..36fbcc5 --- /dev/null +++ b/boiler-monster/stm32/app/ot_phy_tx.c @@ -0,0 +1,121 @@ +#include "project.h" + +#define OT_THM_OUT GPIO9 +#define OT_THM_OUT_PORT GPIOB + +#define OT_BLR_OUT GPIO8 +#define OT_BLR_OUT_PORT GPIOB + + +typedef struct tx_phy { + int busy; + unsigned half_bit; + uint8_t data[4]; +} TX_Phy; + + +static TX_Phy p_thm, p_blr; + + + +#if 0 +static uint32_t +cycle_diff (uint32_t a, uint32_t b) +{ + return b - a; +} +#endif + + +static int ot_phy_tx_worker (TX_Phy *p) +{ + int ret = p->half_bit & 1; + unsigned bit; + + + if (p->half_bit < 2) + ret ^= 1; + + else if (p->half_bit < 66) { + bit = (p->half_bit >> 1) - 1; + + if (p->data[bit >> 3] & (0x80 >> (bit & 7))) + ret ^= 1; + } else if (p->half_bit < 68) + + ret ^= 1; + + p->half_bit++; + + if (p->half_bit == 68) { + p->half_bit = 0; + p->busy = 0; + } + + return ret; +} + + +void ot_phy_tx_tick (void) +{ + int v; + + if (p_thm.busy) { + v = ot_phy_tx_worker (&p_thm); + + if (v) + CLEAR (OT_THM_OUT); + else + SET (OT_THM_OUT); + } + + + if (p_blr.busy) { + v = ot_phy_tx_worker (&p_blr); + + if (v) + CLEAR (OT_BLR_OUT); + else + SET (OT_BLR_OUT); + + } +} + + +int ot_tx_thm (uint8_t *data) +{ + if (p_thm.busy) return -1; + + if (!data) return 0; + + led_blink(); + + memcpy (p_thm.data, data, sizeof (p_thm.data)); + p_thm.busy = 1; + + return 0; +} + + +int ot_tx_blr (uint8_t *data) +{ + + if (p_blr.busy) return -1; + + if (!data) return 0; + + led_blink(); + + memcpy (p_blr.data, data, sizeof (p_blr.data)); + p_blr.busy = 1; + + return 0; +} + + + +void ot_phy_tx_init (void) +{ + MAP_OUTPUT_PP (OT_THM_OUT); + MAP_OUTPUT_PP (OT_BLR_OUT); +} diff --git a/boiler-monster/stm32/app/pic.c b/boiler-monster/stm32/app/pic.c new file mode 100644 index 0000000..b478766 --- /dev/null +++ b/boiler-monster/stm32/app/pic.c @@ -0,0 +1,52 @@ +#include "project.h" + +#define PIC_RESET GPIO1 +#define PIC_RESET_PORT GPIOB + + +static void pic_reset (void) +{ + SET (PIC_RESET); + delay_ms (1); + CLEAR (PIC_RESET); +} + + +void pic_passthru (void) +{ + uint8_t c; + + printf ("\r\nPIC MODE\r\n"); + usart1_drain(); + block_stdio = 1; + + while (!ring_read_byte (&rx3_ring, &c)); + + pic_reset(); + + + for (;;) { + if (!ring_read_byte (&rx1_ring, &c)) + usart3_queue (c); + + if (!ring_read_byte (&rx3_ring, &c)) + usart1_queue (c); + + } +} + + + + + + + +void pic_init (void) +{ + MAP_OUTPUT_PP (PIC_RESET); + + pic_reset(); + +} + + diff --git a/boiler-monster/stm32/app/pins.h b/boiler-monster/stm32/app/pins.h new file mode 100644 index 0000000..9ea01cf --- /dev/null +++ b/boiler-monster/stm32/app/pins.h @@ -0,0 +1,53 @@ +#ifndef _PINS_H_ +#define _PINS_H_ + +/* st seem to change these with every chip revision */ + +#define MAP_AF(a) do { \ + gpio_set_mode( a ## _PORT, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, a ); \ + } while (0) + +/* STM32F1 doesn't have AF pull up, but also doesn't disconnect af inputs so just use regular pull up */ +#define MAP_AF_PU(a) do { \ + gpio_set_mode( a ## _PORT, GPIO_MODE_INPUT, GPIO_CNF_INPUT_PULL_UPDOWN, a); \ + gpio_set( a ## _PORT, a); \ + } while (0) + +#define MAP_AF_OD(a) do { \ + gpio_set_mode( a ## _PORT, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_ALTFN_OPENDRAIN, a ); \ + } while (0) + + +#define MAP_OUTPUT_PP(a) do { \ + gpio_set_mode( a ## _PORT, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, a ); \ + } while (0) + + +#define MAP_OUTPUT_OD(a) do { \ + gpio_set_mode( a ## _PORT, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_OPENDRAIN, a ); \ + } while (0) + + +/* STM32F1 madly uses the output register to drive the other end of the resistor, so pull up */ +/* requires us to write a 1 there */ + +#define MAP_INPUT_PU(a) do { \ + gpio_set_mode( a ## _PORT, GPIO_MODE_INPUT, GPIO_CNF_INPUT_PULL_UPDOWN, a); \ + gpio_set( a ## _PORT, a); \ + } while (0) + + +#define MAP_INPUT(a) do { \ + gpio_set_mode( a ## _PORT, GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, a); \ + } while (0) + +#define MAP_ANALOG(a) do { \ + gpio_set_mode( a ## _PORT, GPIO_MODE_INPUT, GPIO_CNF_INPUT_ANALOG, a); \ + } while (0) + + +#define CLEAR(a) gpio_clear( a ## _PORT, a) +#define SET(a) gpio_set( a ## _PORT, a) +#define GET(a) gpio_get( a ## _PORT, a) + +#endif diff --git a/boiler-monster/stm32/app/pressure.c b/boiler-monster/stm32/app/pressure.c new file mode 100644 index 0000000..f719e4d --- /dev/null +++ b/boiler-monster/stm32/app/pressure.c @@ -0,0 +1,164 @@ +#include "project.h" + +#define PRESSURE GPIO0 +#define PRESSURE_PORT GPIOA +#define PRESSURE_CHANNEL ADC_CHANNEL0 +#define VREF_CHANNEL ADC_CHANNEL17 + +#define N_SAMPLES 1000 + +#define T do { printf("%s:%d\r\n",__FILE__,__LINE__); } while (0) + +static int pressure; + +struct avg { + int acc; + unsigned n; +}; + +static void avg_reset(struct avg *a) +{ +a->acc=0; +a->n=0; +return; +} +static void avg_add(struct avg *a, int v) +{ +a->acc+=v; +a->n++; +} +inline static unsigned avg_n(struct avg *a) +{ +return a->n; +} + +static int avg_get(struct avg *a) +{ +if (!a->n) return 0; +return (a->acc) / (a->n); +} + + +uint16_t pressure_ch (void) +{ + return pressure; +} + + +static void pressure_calculate (int v,int r) +{ + /* r is 1.25 volts, transducer is 0.5V -> 0 psi 4.5V -> 100psi */ + /* 100psi is 6.8947573 bar, and we want 256ths of bar */ + + + if (!r) { + pressure = 0; + // return; + } else { + pressure = ((v * 552) / r) - 221; + + if (pressure < 0) pressure = 0; + } + + printf ("QP: %d %d %d\r\n", v, r, (pressure * 100) / 256); +} + + + +void pressure_tick(void) +{ +static unsigned state; +static unsigned backoff=MS_TO_TICKS(1000); +static unsigned timeout; + +static struct avg vref_avg; +static struct avg pressure_avg; + + +timeout++; + +if (backoff) { + backoff--; + return; +} + + +switch (state) { +case 0: + adc_off (ADC1); + adc_power_on (ADC1); + backoff=MS_TO_TICKS(5); + state++; + break; +case 1: + ADC_CR2 (ADC1) |= ADC_CR2_RSTCAL; + backoff=MS_TO_TICKS(2); + state++; + break; +case 2: + if (ADC_CR2(ADC1) & ADC_CR2_CAL) + state=0; + ADC_CR2 (ADC1) |= ADC_CR2_CAL; + backoff=MS_TO_TICKS(2); + state++; + break; +case 3: + if (ADC_CR2(ADC1) & ADC_CR2_CAL) + state=0; + state++; + + avg_reset(&vref_avg); + avg_reset(&pressure_avg); + break; +case 4: + if (adc_convert_start(VREF_CHANNEL)) + state=0; + else { + timeout=0; + state++; + } + break; +case 5: + if (adc_convert_done()) { + avg_add(&vref_avg,adc_convert_get()); + state++; + } else if (timeout > MS_TO_TICKS(5)) + state=0; + break; +case 6: + if (adc_convert_start(PRESSURE_CHANNEL)) + state=0; + else { + timeout=0; + state++; + } + break; +case 7: + if (adc_convert_done()) { + avg_add(&pressure_avg,adc_convert_get()); + + if (avg_n(&pressure_avg) MS_TO_TICKS(5)) + state=0; + break; +case 8: + pressure_calculate(avg_get(&pressure_avg),avg_get(&vref_avg)); + state=0; + break; +} + +} + + + +void pressure_init (void) +{ + MAP_ANALOG (PRESSURE); +} + + + + diff --git a/boiler-monster/stm32/app/project.h b/boiler-monster/stm32/app/project.h new file mode 100644 index 0000000..d1bfa52 --- /dev/null +++ b/boiler-monster/stm32/app/project.h @@ -0,0 +1,30 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "ring.h" +#include "pins.h" +#include "1wire.h" + + +#define US (72) +#define MS (US * 1000) +#define HZ (MS * 1000) + +#define MS_TO_TICKS(a) ((a) *2) + + +#include "prototypes.h" diff --git a/boiler-monster/stm32/app/prototypes.h b/boiler-monster/stm32/app/prototypes.h new file mode 100644 index 0000000..5206734 --- /dev/null +++ b/boiler-monster/stm32/app/prototypes.h @@ -0,0 +1,106 @@ +/* main.c */ +extern void reset_hardware(void); +extern int main(void); +/* ot.c */ +extern unsigned ot_override_ch; +extern unsigned ot_override_dhw; +extern void ot_rx_thm(uint8_t *msg, int error); +extern void ot_rx_blr(uint8_t *msg, int error); +extern void ot_request_usr(unsigned type, unsigned id, uint8_t *data); +extern void ot_tick(void); +extern void ot_init(void); +/* ot_phy_rx.c */ +extern void exti9_5_isr(void); +extern void ot_phy_rx_tick(void); +extern void ot_phy_rx_init(void); +/* ot_phy_tx.c */ +extern void ot_phy_tx_tick(void); +extern int ot_tx_thm(uint8_t *data); +extern int ot_tx_blr(uint8_t *data); +extern void ot_phy_tx_init(void); +/* led.c */ +extern void led_red_set(int i); +extern void led_green1_set(int i); +extern void led_green2_set(int i); +extern void led_blink(void); +extern void led_yellow_set(int i); +extern void led_tick(void); +extern void led_init(void); +/* ticker.c */ +extern void delay_us(uint32_t d); +extern int tick_dispatch; +extern void sys_tick_handler(void); +extern void delay_ms(uint32_t d); +extern void ticker_init(void); +/* usart.c */ +extern ring_t rx1_ring; +extern ring_t tx1_ring; +extern ring_t rx3_ring; +extern ring_t tx3_ring; +extern void usart1_isr(void); +extern void usart1_queue(uint8_t d); +extern void usart1_drain(void); +extern int usart1_write(char *ptr, int len, int blocking); +extern void usart3_isr(void); +extern void usart3_queue(uint8_t d); +extern void usart3_drain(void); +extern int usart3_write(char *ptr, int len, int blocking); +extern void usart_init(void); +/* ring.c */ +extern void ring_init(volatile ring_t *r, uint8_t *buf, size_t len); +extern int ring_write_byte(volatile ring_t *r, uint8_t c); +extern int ring_read_byte(volatile ring_t *r, uint8_t *c); +extern int ring_write(volatile ring_t *r, uint8_t *buf, size_t len, int blocking); +extern int ring_empty(volatile ring_t *r); +/* stdio.c */ +extern unsigned block_stdio; +extern int _open(const char *name, int flags, int mode); +extern int _close(int file); +extern int _write(int file, char *buf, int nbytes); +extern int _read(int file, char *buf, int nbytes); +extern int _lseek(int file, int offset, int whence); +extern int isatty(int file); +extern void stdio_drain(void); +/* util.c */ +extern char int_to_hex_char(int a); +/* commit.c */ +extern char scm_version[]; +/* cmd.c */ +extern void cmd_usart_dispatch(void); +/* pic.c */ +extern void pic_passthru(void); +extern void pic_init(void); +/* 1wire.c */ +extern void onewire_tick(void); +extern int onewire_reset(void); +extern void onewire_write_byte(uint8_t v); +extern uint8_t onewire_read_byte(void); +extern void onewire_read_bytes(uint8_t *buf, int n); +extern void onewire_write_bytes(const uint8_t *buf, int n); +extern int onewire_select(const Onewire_addr *a); +extern int onewire_reset_and_select(const Onewire_addr *a); +extern int onewire_wait_complete(unsigned timeout); +extern int onewire_check_crc(uint8_t *buf, int n, uint8_t v); +extern int onewire_search(void); +extern void onewire_init(void); +/* temp.c */ +extern void temp_tick(void); +extern void temp_dispatch(void); +extern uint16_t temp_ch_return(void); +extern uint16_t temp_supply_inlet(void); +/* ds1820.c */ +extern int ds1820_read(const Onewire_addr *a, int *temp); +/* pressure.c */ +extern uint16_t pressure_ch(void); +extern void pressure_tick(void); +extern void pressure_init(void); +/* adc.c */ +extern void adc_dump(void); +extern volatile unsigned timeout; +extern void adc_tick(void); +extern int adc_calibrate(void); +extern int adc_convert_start(unsigned channel); +extern int adc_convert_done(void); +extern unsigned adc_convert_get(void); +extern unsigned adc_convert(unsigned channel); +extern void adc_init(void); diff --git a/boiler-monster/stm32/app/ring.c b/boiler-monster/stm32/app/ring.c new file mode 100644 index 0000000..973f345 --- /dev/null +++ b/boiler-monster/stm32/app/ring.c @@ -0,0 +1,77 @@ +#include "project.h" + + +static inline size_t +ring_next (volatile ring_t *r, size_t p) +{ + p++; + + if (p >= r->size) + p -= r->size; + + return p; +} + +void +ring_init (volatile ring_t *r, uint8_t *buf, size_t len) +{ + r->data = buf; + r->size = len; + r->write = 0; + r->read = 0; +} + +int +ring_write_byte (volatile ring_t *r, uint8_t c) +{ + size_t n = ring_next (r, r->write); + + if (n == r->read) + return -EAGAIN; + + r->data[r->write] = c; + + r->write = n; + + return 0; +} + + +int +ring_read_byte (volatile ring_t *r, uint8_t *c) +{ + size_t n = ring_next (r, r->read); + + if (r->read == r->write) + return -EAGAIN; + + *c = r->data[r->read]; + r->read = n; + + return 0; +} + +int +ring_write (volatile ring_t *r, uint8_t *buf, size_t len, int blocking) +{ + while (len--) { + if (blocking) { + while (ring_write_byte (r, *buf)); + + buf++; + } else { + if (ring_write_byte (r, * (buf++))) + return -EAGAIN; + } + } + + return 0; +} + + + +int +ring_empty (volatile ring_t *r) +{ + return (r->read == r->write) ? 1 : 0; +} diff --git a/boiler-monster/stm32/app/ring.h b/boiler-monster/stm32/app/ring.h new file mode 100644 index 0000000..a329354 --- /dev/null +++ b/boiler-monster/stm32/app/ring.h @@ -0,0 +1,13 @@ +#ifndef _RING_H_ +#define _RING_H_ + +typedef struct ring { + uint8_t *data; + size_t size; + size_t write; + size_t read; +} ring_t; + +#endif + + diff --git a/boiler-monster/stm32/app/stdio.c b/boiler-monster/stm32/app/stdio.c new file mode 100644 index 0000000..bcdd5c7 --- /dev/null +++ b/boiler-monster/stm32/app/stdio.c @@ -0,0 +1,77 @@ +#include "project.h" + +unsigned block_stdio; + +int +_open (const char *name, int flags, int mode) +{ + errno = ENOSYS; + return -1; /* Always fails */ + +} /* _open () */ + +int +_close (int file) +{ + errno = EBADF; + return -1; /* Always fails */ + +} /* _close () */ + +int +_write (int file, char *buf, int nbytes) +{ + + int ret = nbytes; + + if (!block_stdio) + ret = usart1_write (buf, nbytes, 1); + + if (ret < 0) { + errno = -ret; + return -1; + } + + return ret; +} /* _write () */ + + +int +_read (int file, char *buf, int nbytes) +{ + + errno = -EAGAIN; + return -1; /* EOF */ + +} /* _read () */ + +#if 0 +int +_fstat (int file, struct stat *st) +{ + st->st_mode = S_IFCHR; + return 0; + +} /* _fstat () */ +#endif + +int +_lseek (int file, int offset, int whence) +{ + return 0; + +} /* _lseek () */ + +int +isatty (int file) +{ + return 1; + +} /* _isatty () */ + + +void +stdio_drain (void) +{ + usart1_drain(); +} diff --git a/boiler-monster/stm32/app/temp.c b/boiler-monster/stm32/app/temp.c new file mode 100644 index 0000000..4548d01 --- /dev/null +++ b/boiler-monster/stm32/app/temp.c @@ -0,0 +1,76 @@ +#include "project.h" + + +#define N_SENSORS 2 + +#define SENSOR_INDEX_CH_RETURN 0 +#define SENSOR_INDEX_SUPPLY_INLET 1 + +static const Onewire_addr s_addr[N_SENSORS] = { + [0] = {{0x28, 0x60, 0x06, 0x53, 0x03, 0x00, 0x00, 0xf5}}, + [1] = {{0x28, 0xa4, 0x08, 0x53, 0x03, 0x00, 0x00, 0x14}}, +}; + + +static int s_temp[N_SENSORS]; + +static unsigned poke; + + +void temp_tick (void) +{ + static unsigned ticker; + + ticker++; + + if (ticker < 3000) + return; + + ticker = 0; + poke = 1; + +} + + + + + +void temp_dispatch (void) +{ + static unsigned sensor; + + if (!poke) return; + + poke = 0; + + if (sensor < N_SENSORS) { + if (ds1820_read (&s_addr[sensor], &s_temp[sensor])) + s_temp[sensor] = 0; + + + printf ("Q1W: sensor %d temp %d\r\n", sensor, (s_temp[sensor] * 100) / 256); + + + sensor++; + } else { +#if 0 + onewire_search(); +#endif + } + + if (sensor == N_SENSORS) + sensor = 0; + + +} + + + +uint16_t temp_ch_return (void) +{ + return s_temp[SENSOR_INDEX_CH_RETURN]; +} +uint16_t temp_supply_inlet (void) +{ + return s_temp[SENSOR_INDEX_SUPPLY_INLET]; +} diff --git a/boiler-monster/stm32/app/ticker.c b/boiler-monster/stm32/app/ticker.c new file mode 100644 index 0000000..9e268ca --- /dev/null +++ b/boiler-monster/stm32/app/ticker.c @@ -0,0 +1,105 @@ +#include "project.h" + + +static volatile uint32_t delay_hms_count; +static volatile uint32_t ticks; +static uint32_t scale = 7; + +void +delay_us (uint32_t d) +{ + d *= scale; + + while (d--) + __asm__ ("nop"); +} + + +void +sys_tick_handler (void) +{ + if (delay_hms_count) + delay_hms_count--; + + + led_tick(); + ot_phy_tx_tick(); + ot_tick(); + onewire_tick(); + temp_tick(); + adc_tick(); + pressure_tick(); + + + ticks++; +} + + + +void +delay_ms (uint32_t d) +{ + delay_hms_count = d << 1; + + while (delay_hms_count); +} + +#if 0 +int +timed_out (uint32_t then, unsigned int ms) +{ + then = ticks - then; + + if (then > ms) + return 1; + + return 0; +} + +int +timed_out_cycles (uint32_t then, unsigned int cycles) +{ + then = dwt_read_cycle_counter() - then; + + if (then > cycles) + return 1; + + return 0; +} +#endif + + + +void +ticker_init (void) +{ + uint32_t v, w; + + /*Start periodic timer */ + + systick_set_clocksource (STK_CSR_CLKSOURCE_AHB_DIV8); + /* 72MHz / 8 = > 9Mhz */ + systick_set_reload (4500); + /* 9MHz / 4500 => 2kHz */ + systick_interrupt_enable(); + systick_counter_enable(); + + /*Calibrate the delay loop */ + + + + do { + scale--; + v = ticks; + + while (v == ticks); + + delay_us (500); + w = ticks; + v++; + w -= v; + } while (w); + + + +} diff --git a/boiler-monster/stm32/app/usart.c b/boiler-monster/stm32/app/usart.c new file mode 100644 index 0000000..28676a0 --- /dev/null +++ b/boiler-monster/stm32/app/usart.c @@ -0,0 +1,175 @@ +#include "project.h" + +#define BUFFER_SIZE 256 + + +#define USART1_TX GPIO_USART1_TX +#define USART1_TX_PORT GPIOA + +#define USART1_RX GPIO_USART1_RX +#define USART1_RX_PORT GPIOA + +#define USART3_TX GPIO_USART3_TX +#define USART3_TX_PORT GPIOB + +#define USART3_RX GPIO_USART3_RX +#define USART3_RX_PORT GPIOB + + + +ring_t rx1_ring; +static uint8_t rx1_ring_buf[BUFFER_SIZE]; + +ring_t tx1_ring; +static uint8_t tx1_ring_buf[BUFFER_SIZE]; + +ring_t rx3_ring; +static uint8_t rx3_ring_buf[BUFFER_SIZE]; + +ring_t tx3_ring; +static uint8_t tx3_ring_buf[BUFFER_SIZE]; + +void +usart1_isr (void) +{ + uint8_t data; + + /* Check if we were called because of RXNE. */ + if (((USART_CR1 (USART1) & USART_CR1_RXNEIE) != 0) && + ((USART_SR (USART1) & USART_SR_RXNE) != 0)) { + data = usart_recv (USART1); + ring_write_byte (&rx1_ring, data); + } + + /* Check if we were called because of TXE. */ + if (((USART_CR1 (USART1) & USART_CR1_TXEIE) != 0) && + ((USART_SR (USART1) & USART_SR_TXE) != 0)) { + + if (ring_read_byte (&tx1_ring, &data)) { + /*No more data, Disable the TXE interrupt, it's no longer needed. */ + usart_disable_tx_interrupt (USART1); + } else + usart_send_blocking (USART1, data); + } + +} + +void +usart1_queue (uint8_t d) +{ + ring_write_byte (&tx1_ring, d); + usart_enable_tx_interrupt (USART1); +} + +void +usart1_drain (void) +{ + while (!ring_empty (&tx1_ring)); +} + + +int +usart1_write (char *ptr, int len, int blocking) +{ + int ret; + + ret = ring_write (&tx1_ring, (uint8_t *) ptr, len, blocking); + usart_enable_tx_interrupt (USART1); + return ret; +} + + +void +usart3_isr (void) +{ + uint8_t data; + + /* Check if we were called because of RXNE. */ + if (((USART_CR1 (USART3) & USART_CR1_RXNEIE) != 0) && + ((USART_SR (USART3) & USART_SR_RXNE) != 0)) { + data = usart_recv (USART3); + ring_write_byte (&rx3_ring, data); + } + + /* Check if we were called because of TXE. */ + if (((USART_CR1 (USART3) & USART_CR1_TXEIE) != 0) && + ((USART_SR (USART3) & USART_SR_TXE) != 0)) { + + if (ring_read_byte (&tx3_ring, &data)) { + /*No more data, Disable the TXE interrupt, it's no longer needed. */ + usart_disable_tx_interrupt (USART3); + } else + usart_send_blocking (USART3, data); + } + +} + +void +usart3_queue (uint8_t d) +{ + ring_write_byte (&tx3_ring, d); + usart_enable_tx_interrupt (USART3); +} + +void +usart3_drain (void) +{ + while (!ring_empty (&tx3_ring)); +} + + +int +usart3_write (char *ptr, int len, int blocking) +{ + int ret; + + ret = ring_write (&tx3_ring, (uint8_t *) ptr, len, blocking); + usart_enable_tx_interrupt (USART3); + return ret; +} + + +void +usart_init (void) +{ + ring_init (&rx1_ring, rx1_ring_buf, sizeof (rx1_ring_buf)); + ring_init (&tx1_ring, tx1_ring_buf, sizeof (tx1_ring_buf)); + + nvic_enable_irq (NVIC_USART1_IRQ); + + MAP_AF (USART1_TX); + MAP_AF_PU (USART1_RX); + + + usart_set_baudrate (USART1, 57600); + usart_set_databits (USART1, 8); + usart_set_stopbits (USART1, USART_STOPBITS_1); + usart_set_parity (USART1, USART_PARITY_NONE); + usart_set_flow_control (USART1, USART_FLOWCONTROL_NONE); + usart_set_mode (USART1, USART_MODE_TX_RX); + + USART_CR1 (USART1) |= USART_CR1_RXNEIE; + + usart_enable (USART1); + + + ring_init (&rx3_ring, rx3_ring_buf, sizeof (rx3_ring_buf)); + ring_init (&tx3_ring, tx3_ring_buf, sizeof (tx3_ring_buf)); + + + nvic_enable_irq (NVIC_USART3_IRQ); + + MAP_AF (USART3_TX); + MAP_AF_PU (USART3_RX); + + usart_set_baudrate (USART3, 9600); + usart_set_databits (USART3, 8); + usart_set_stopbits (USART3, USART_STOPBITS_1); + usart_set_parity (USART3, USART_PARITY_NONE); + usart_set_flow_control (USART3, USART_FLOWCONTROL_NONE); + usart_set_mode (USART3, USART_MODE_TX_RX); + + USART_CR1 (USART3) |= USART_CR1_RXNEIE; + + usart_enable (USART3); +} diff --git a/boiler-monster/stm32/app/util.c b/boiler-monster/stm32/app/util.c new file mode 100644 index 0000000..bf65510 --- /dev/null +++ b/boiler-monster/stm32/app/util.c @@ -0,0 +1,14 @@ +#include "project.h" + +char int_to_hex_char (int a) +{ + if (a < 0) return '?'; + + if (a < 0xa) return '0' + a; + + if (a < 0x10) return '7' + a; + + return '?'; +} + + diff --git a/boiler-monster/stm32/docs/pinout.txt b/boiler-monster/stm32/docs/pinout.txt new file mode 100644 index 0000000..03abe35 --- /dev/null +++ b/boiler-monster/stm32/docs/pinout.txt @@ -0,0 +1,24 @@ + +A0 <- pressure sensor +A2 <-> one wire bus +A11 -> yellow LED (OD) +A12 -> green LED 1 (OD) +A15 -> green LED 2 (OD) + +B1 -> PIC RESET +B3 -> red LED (OD) +B6 <- PIC B6 LED_C (from A0, OT from thermostat) +B7 <- PIC B7 LED_D (from A1, OT from boiler) +B8 -> PIC A6 GPIO_A (to A3, OT to boiler) +B9 -> PIC A7 GPIO_B (to A4, OT to thermostat) +B10 -> PIC RX +B11 <- PIX TX + +C13 -> onboard LED (OD) + +A2 -> MR3020 TX +A3 <- MR4020 RX +RST <- MR3020 GPIO5 + + + diff --git a/boiler-monster/stm32/docs/pm0056.pdf b/boiler-monster/stm32/docs/pm0056.pdf new file mode 100644 index 0000000..659c9de Binary files /dev/null and b/boiler-monster/stm32/docs/pm0056.pdf differ diff --git a/boiler-monster/stm32/docs/rm0008.pdf b/boiler-monster/stm32/docs/rm0008.pdf new file mode 100644 index 0000000..8f3d0e1 Binary files /dev/null and b/boiler-monster/stm32/docs/rm0008.pdf differ diff --git a/boiler-monster/stm32/docs/stm32f103c8.pdf b/boiler-monster/stm32/docs/stm32f103c8.pdf new file mode 100644 index 0000000..2723cee Binary files /dev/null and b/boiler-monster/stm32/docs/stm32f103c8.pdf differ diff --git a/boiler-monster/stm32/docs/stm32f103c8t6_pinout_voltage01.png b/boiler-monster/stm32/docs/stm32f103c8t6_pinout_voltage01.png new file mode 100644 index 0000000..2c22a74 Binary files /dev/null and b/boiler-monster/stm32/docs/stm32f103c8t6_pinout_voltage01.png differ diff --git a/boiler-monster/stm32/libopencm3 b/boiler-monster/stm32/libopencm3 new file mode 160000 index 0000000..5c73d60 --- /dev/null +++ b/boiler-monster/stm32/libopencm3 @@ -0,0 +1 @@ +Subproject commit 5c73d601763dd140bff020be8d6d06f03c2bea78 -- cgit v1.2.3