summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorfishsoupisgood <github@madingley.org>2020-05-26 14:33:34 +0100
committerfishsoupisgood <github@madingley.org>2020-05-26 14:33:34 +0100
commitf0d941bef6a9b6e3af78cfc68e1f82d6b47ccb2f (patch)
tree22a88d00cb28e075b5397ff5db586d548023f2f2
downloadheating-f0d941bef6a9b6e3af78cfc68e1f82d6b47ccb2f.tar.gz
heating-f0d941bef6a9b6e3af78cfc68e1f82d6b47ccb2f.tar.bz2
heating-f0d941bef6a9b6e3af78cfc68e1f82d6b47ccb2f.zip
happy
-rw-r--r--.gitmodules6
-rw-r--r--DOCS/41hpa-warranty-registration.pdfbin0 -> 37952 bytes
-rw-r--r--DOCS/Opentherm Protocol v2-2.pdfbin0 -> 285534 bytes
m---------otmonitor0
-rw-r--r--pic/.gitignore8
-rw-r--r--pic/16f88.lkr76
-rw-r--r--pic/Makefile22
-rw-r--r--pic/build.asm2
-rw-r--r--pic/docs/otgw-big-sch.pngbin0 -> 77271 bytes
-rw-r--r--pic/docs/pinout.txt33
-rw-r--r--pic/gateway.asm296
-rw-r--r--pic/selfprog.asm391
-rw-r--r--stm32/.gitignore16
-rw-r--r--stm32/Makefile8
-rw-r--r--stm32/Makefile.include44
-rw-r--r--stm32/Makefile.rules261
-rw-r--r--stm32/app/1wire.c392
-rw-r--r--stm32/app/1wire.h10
-rw-r--r--stm32/app/Makefile132
-rw-r--r--stm32/app/adc.c121
-rw-r--r--stm32/app/boiler.ld31
-rw-r--r--stm32/app/cmd.c55
-rw-r--r--stm32/app/commit.c3
-rw-r--r--stm32/app/ds1820.c93
-rw-r--r--stm32/app/gdb.script2
-rw-r--r--stm32/app/led.c101
-rw-r--r--stm32/app/main.c135
-rw-r--r--stm32/app/ot.c413
-rw-r--r--stm32/app/ot_phy_rx.c177
-rw-r--r--stm32/app/ot_phy_tx.c121
-rw-r--r--stm32/app/pic.c52
-rw-r--r--stm32/app/pins.h53
-rw-r--r--stm32/app/pressure.c79
-rw-r--r--stm32/app/project.h30
-rw-r--r--stm32/app/prototypes.h108
-rw-r--r--stm32/app/ring.c77
-rw-r--r--stm32/app/ring.h13
-rw-r--r--stm32/app/stdio.c77
-rw-r--r--stm32/app/temp.c72
-rw-r--r--stm32/app/ticker.c103
-rw-r--r--stm32/app/usart.c175
-rw-r--r--stm32/app/util.c14
-rw-r--r--stm32/docs/pinout.txt24
-rw-r--r--stm32/docs/pm0056.pdfbin0 -> 2098835 bytes
-rw-r--r--stm32/docs/rm0008.pdfbin0 -> 13016697 bytes
-rw-r--r--stm32/docs/stm32f103c8.pdfbin0 -> 1697666 bytes
-rw-r--r--stm32/docs/stm32f103c8t6_pinout_voltage01.pngbin0 -> 679565 bytes
m---------stm32/libopencm30
48 files changed, 3826 insertions, 0 deletions
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..4d99ada
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,6 @@
+[submodule "otmonitor"]
+ path = otmonitor
+ url = git://git.panaceas.org/heating/otmonitor
+[submodule "stm32/libopencm3"]
+ path = stm32/libopencm3
+ url = git://git.panaceas.org/stm32/libopencm3
diff --git a/DOCS/41hpa-warranty-registration.pdf b/DOCS/41hpa-warranty-registration.pdf
new file mode 100644
index 0000000..f42b06d
--- /dev/null
+++ b/DOCS/41hpa-warranty-registration.pdf
Binary files differ
diff --git a/DOCS/Opentherm Protocol v2-2.pdf b/DOCS/Opentherm Protocol v2-2.pdf
new file mode 100644
index 0000000..47a7f59
--- /dev/null
+++ b/DOCS/Opentherm Protocol v2-2.pdf
Binary files differ
diff --git a/otmonitor b/otmonitor
new file mode 160000
+Subproject 6ef7f2b1455ea10c5f7147216d442326c1ccfdd
diff --git a/pic/.gitignore b/pic/.gitignore
new file mode 100644
index 0000000..f8ab154
--- /dev/null
+++ b/pic/.gitignore
@@ -0,0 +1,8 @@
+*.err
+*.swp
+*.swo
+*.lst
+*.o
+*.hex
+*.map
+*.cod
diff --git a/pic/16f88.lkr b/pic/16f88.lkr
new file mode 100644
index 0000000..b2b3e95
--- /dev/null
+++ b/pic/16f88.lkr
@@ -0,0 +1,76 @@
+// File: 16F88_g.lkr
+// Generic linker script for the PIC16F88 processor
+
+#IFDEF _DEBUG
+
+LIBPATH .
+
+CODEPAGE NAME=page0 START=0x0 END=0x7FF
+CODEPAGE NAME=page1 START=0x800 END=0xEFF
+CODEPAGE NAME=debug START=0xF00 END=0xFFF PROTECTED
+CODEPAGE NAME=.idlocs START=0x2000 END=0x2003 PROTECTED
+CODEPAGE NAME=.device_id START=0x2006 END=0x2006 PROTECTED
+CODEPAGE NAME=.config START=0x2007 END=0x2009 PROTECTED
+CODEPAGE NAME=eedata START=0x2100 END=0x21FF PROTECTED
+
+DATABANK NAME=sfr0 START=0x0 END=0x1F PROTECTED
+DATABANK NAME=sfr1 START=0x80 END=0x9F PROTECTED
+DATABANK NAME=sfr2 START=0x100 END=0x10F PROTECTED
+DATABANK NAME=sfr3 START=0x180 END=0x18F PROTECTED
+
+SHAREBANK NAME=dbgnobnk START=0x70 END=0x70 PROTECTED
+SHAREBANK NAME=dbgnobnk START=0xF0 END=0xF0 PROTECTED
+SHAREBANK NAME=dbgnobnk START=0x170 END=0x170 PROTECTED
+SHAREBANK NAME=dbgnobnk START=0x1F0 END=0x1F0 PROTECTED
+
+SHAREBANK NAME=sfrnobnk START=0x71 END=0x7F
+SHAREBANK NAME=sfrnobnk START=0xF1 END=0xFF PROTECTED
+SHAREBANK NAME=sfrnobnk START=0x171 END=0x17F PROTECTED
+SHAREBANK NAME=sfrnobnk START=0x1F1 END=0x1FF PROTECTED
+
+DATABANK NAME=gpr0 START=0x20 END=0x6F
+DATABANK NAME=gpr1 START=0xA0 END=0xEF
+DATABANK NAME=gpr2 START=0x110 END=0x16F
+DATABANK NAME=gpr3 START=0x190 END=0x1E4
+DATABANK NAME=dbg3 START=0x1E5 END=0x1EF PROTECTED
+
+SECTION NAME=PROG0 ROM=page0 // ROM code space
+SECTION NAME=PROG1 ROM=page1 // ROM code space
+SECTION NAME=DEBUG ROM=debug // ICD debug executive
+SECTION NAME=IDLOCS ROM=.idlocs // ID locations
+SECTION NAME=DEVICEID ROM=.device_id // Device ID
+SECTION NAME=DEEPROM ROM=eedata // Data EEPROM
+
+#ELSE
+
+LIBPATH .
+
+CODEPAGE NAME=page0 START=0x0 END=0x7FF
+CODEPAGE NAME=page1 START=0x800 END=0xFFF
+CODEPAGE NAME=.idlocs START=0x2000 END=0x2003 PROTECTED
+CODEPAGE NAME=.device_id START=0x2006 END=0x2006 PROTECTED
+CODEPAGE NAME=.config START=0x2007 END=0x2009 PROTECTED
+CODEPAGE NAME=eedata START=0x2100 END=0x21FF PROTECTED
+
+DATABANK NAME=sfr0 START=0x0 END=0x1F PROTECTED
+DATABANK NAME=sfr1 START=0x80 END=0x9F PROTECTED
+DATABANK NAME=sfr2 START=0x100 END=0x10F PROTECTED
+DATABANK NAME=sfr3 START=0x180 END=0x18F PROTECTED
+
+SHAREBANK NAME=sfrnobnk START=0x70 END=0x7F
+SHAREBANK NAME=sfrnobnk START=0xF0 END=0xFF PROTECTED
+SHAREBANK NAME=sfrnobnk START=0x170 END=0x17F PROTECTED
+SHAREBANK NAME=sfrnobnk START=0x1F0 END=0x1FF PROTECTED
+
+DATABANK NAME=gpr0 START=0x20 END=0x6F
+DATABANK NAME=gpr1 START=0xA0 END=0xEF
+DATABANK NAME=gpr2 START=0x110 END=0x16F
+DATABANK NAME=gpr3 START=0x190 END=0x1EF
+
+SECTION NAME=PROG0 ROM=page0 // ROM code space
+SECTION NAME=PROG1 ROM=page1 // ROM code space
+SECTION NAME=IDLOCS ROM=.idlocs // ID locations
+SECTION NAME=DEVICEID ROM=.device_id // Device ID
+SECTION NAME=DEEPROM ROM=eedata // Data EEPROM
+
+#FI
diff --git a/pic/Makefile b/pic/Makefile
new file mode 100644
index 0000000..31ab11c
--- /dev/null
+++ b/pic/Makefile
@@ -0,0 +1,22 @@
+AFLAGS=-k -p 16F88 -k
+LDFLAGS=-m -s 16f88.lkr
+
+PROG=gateway
+ASRCS=${PROG}.asm selfprog.asm
+OBJS=${ASRCS:%.asm=%.o}
+LSTS=${ASRCS:%.asm=%.err}
+ERRS=${ASRCS:%.asm=%.lst}
+
+default:${PROG}.hex
+
+%.o:%.asm
+ gpasm ${AFLAGS} -c -o $@ $<
+
+${PROG}.hex:${OBJS}
+ gplink ${LDFLAGS} -o $@ ${OBJS}
+
+
+clean:
+ /bin/rm -f ${PROG}.hex ${PROG}.map ${PROG}.cod ${OBJS} ${LSTS} ${ERRS}
+
+
diff --git a/pic/build.asm b/pic/build.asm
new file mode 100644
index 0000000..67d0747
--- /dev/null
+++ b/pic/build.asm
@@ -0,0 +1,2 @@
+#define build "1"
+#define tstamp "17:59 20-10-2015"
diff --git a/pic/docs/otgw-big-sch.png b/pic/docs/otgw-big-sch.png
new file mode 100644
index 0000000..114e65b
--- /dev/null
+++ b/pic/docs/otgw-big-sch.png
Binary files differ
diff --git a/pic/docs/pinout.txt b/pic/docs/pinout.txt
new file mode 100644
index 0000000..a3db674
--- /dev/null
+++ b/pic/docs/pinout.txt
@@ -0,0 +1,33 @@
+
+headers:
+
+left
+
+GND - STM32
+GPIO_B <- STM32 B9
+GPIO_A <- STM32 B8
+5V -> STM32
+LED_D -> STM32 B7
+LED_C -> STM32 B6
+LED_B -> NC
+LED_A -> NC
+
+
+middle
+
+GND - NC
+NC - NC
+NC -
+PIC RX <- STM32 B10
+PIC TX -> STM32 B11
+*RESET <- STM32 B1
+
+
+right
+
+5V -> MR3020
+NC
+GND - MR3020
+
+
+
diff --git a/pic/gateway.asm b/pic/gateway.asm
new file mode 100644
index 0000000..b1c6324
--- /dev/null
+++ b/pic/gateway.asm
@@ -0,0 +1,296 @@
+ title "OpenTherm Gateway"
+ list p=16F88, b=8, r=dec
+
+;Copyright (c) 2009 Schelte Bron
+
+#define version "4.2"
+#define phase "." ;a=alpha, b=beta, .=production
+#define patch "5" ;Comment out when not applicable
+;#define bugfix "1" ;Comment out when not applicable
+#include build.asm
+
+;See the file "license.txt" for information on usage and redistribution of
+;this file, and for a DISCLAIMER OF ALL WARRANTIES.
+
+#ifndef LVP
+ __config H'2007', B'10111101110100'
+#else
+ __config H'2007', B'10111111110100'
+#endif
+ __config H'2008', B'11111111111111'
+
+ errorlevel -302
+
+;#######################################################################
+;Comparator 1 is used for requests. The input is connected to the thermostat.
+;In monitor mode, the output is connected to the boiler.
+;Comparator 2 is used for responses. The input is connected to the Boiler.
+;In monitor mode, the output is connected to the thermostat.
+
+;The AUSART is configured for full duplex asynchronous serial communication at
+;9600 baud, 8 bits, no parity. It is used for reporting about opentherm messages
+;and receiving commands.
+
+;Analog input 0 is used to measure the voltage level on the opentherm line to
+;the thermostat. This way the code can distinguish between a real opentherm
+;thermostat and a simple on/off thermostat. An opentherm thermostat will keep
+;the line at a few volts (low) or between 15 and 18 volts (high). An on/off
+;thermostat will either short-circuit the line (0 volts) or leave the line open
+;(20+ volts).
+
+#include "p16f88.inc"
+
+;Define the speed of the PIC clock
+#define mhzstr "4"
+
+;BAUD contains the SPBRG value for 9600 baud
+ constant BAUD=25
+
+ extern SelfProg
+
+;Variables accessible from all RAM banks
+ UDATA_SHR
+loopcounter res 1
+
+Bank0data UDATA 0x20
+rxbuffer res 16 ;Serial receive buffer
+
+;Variables for longer lasting storage
+rxpointer res 1
+txpointer res 1
+
+temp res 1
+
+Bank1data UDATA 0xA0
+
+Bank1values UDATA 0xE0
+
+Bank2data UDATA 0x110
+Bank2values UDATA 0x160
+
+Bank3data UDATA 0x190
+;Use all available RAM in bank 3 for the transmit buffer
+ constant TXBUFSIZE=80
+txbuffer res TXBUFSIZE
+Bank3values UDATA 0x1E0
+
+;I/O map
+#define MasterIn CMCON,C1OUT
+#define SlaveIn CMCON,C2OUT
+#define SlaveOut PORTA,3
+#define MasterOut PORTA,4
+#define RXD PORTB,2
+#define TXD PORTB,5
+#define CCP1 PORTB,0
+#define LED_A PORTB,3
+#define LED_B PORTB,4
+#define LED_C PORTB,6
+#define LED_D PORTB,7
+#define RSET PORTB,1 ;Used by self-programming
+
+#define SlaveMask b'00001000'
+#define MasterMask b'00010000'
+
+package macro pkg
+pkg code
+pkg
+ endm
+
+pcall macro rtn
+ lcall rtn
+ pagesel $
+ endm
+
+;Skip the next instruction (bit 7 of PCLATH is always 0)
+skip macro
+ btfsc PCLATH,7
+ endm
+
+;Get the output of the active comparator into the carry bit
+getcompout macro
+ bsf STATUS,RP0
+ rlf CMCON,W ;Get the output of comparator 2
+ bcf STATUS,RP0
+ btfsc Request ;A request goes through comparator 1
+ addlw b'10000000' ;Cause a carry if C1OUT is high
+ endm
+
+;The first thing to do upon a reset is to allow the firmware to be updated.
+;So no matter how buggy freshly loaded firmware is, if the first two command
+;have not been messed up, the device can always be recovered without the need
+;for a PIC programmer. The self-programming code times out and returns after
+;a second when no firmware update is performed.
+;
+
+ResetVector code 0x0000
+ lcall SelfProg ;Always allow a firmware update on boot
+ lgoto Start ;Start the opentherm gateway program
+
+InterruptVector code 0x0004
+ retfie ;End of interrupt routine
+
+ package Interrupt
+
+;########################################################################
+; Main program
+;########################################################################
+
+ package Main
+Break tstf RCREG ;Clear the RCIF interrupt flag
+ bcf STATUS,RP1
+ bcf STATUS,RP0 ;bank 0
+ movlw 128
+ call Pause
+ pcall SelfProg ;Jump to the self-programming code
+Start bcf STATUS,RP1
+ bcf STATUS,RP0 ;bank 0
+ clrf PORTB ;Flash the LED's on startup
+ bsf STATUS,RP0
+ movlw b'01100000' ;Internal oscillator set to 4MHz
+ movwf OSCCON ;Configure the oscillator
+
+ ;Configure I/O pins
+ ;Power on defaults all pins to inputs
+ ;Port A
+ ;Pins 0 and 1 are used as comparator inputs
+ ;Pin 2 is used as VREF (must be configured as input!)
+ ;Pins 3 and 4 are (comparator) ouputs
+ ;Pin 5 is master reset input
+ ;Pins 6 and 7 are GPIO
+ movlw b'11100111'
+ movwf TRISA
+
+ ;Port B
+ ;Pins 2 and 5 are used by the USART and don't need to be configured
+ ;Pins 3, 4, 6, and 7 are used to indicate events for debugging
+#ifndef LVP
+ movlw b'00100111'
+#else
+ ;Can't use RB3 if LVP is enabled
+ movlw b'00101111'
+#endif
+ movwf TRISB
+
+ movlw b'11'
+ movwf PCON
+
+ ;Configure Timer 0 & Watchdog Timer
+ ;Bit 7 RBPU = 1 - Port B pull up disabled
+ ;Bit 6 INTEDG = 1 - Interrupt on rising edge
+ ;Bit 5 T0CS = 0 - Internal clock
+ ;Bit 4 T0SE = 1 - High to low transition
+ ;Bit 3 PSA = 0 - Prescaler assigned to Timer 0
+ ;Bit 2-0 PS = 5 - 1:64 Prescaler
+ movlw b'11010101'
+ movwf OPTION_REG
+
+
+ ;Configure comparator module
+ ;Bit 7 C2OUT = R/O
+ ;Bit 6 C1OUT = R/O
+ ;Bit 5 C2INV = 0 - Not inverted
+ ;Bit 4 C1INV = 0 - Not inverted
+ ;Bit 3 CIS = 0 - Irrelevant
+ ;Bit 2-0 = 3 - Common reference / 6 - with outputs
+ movlw b'00000011' ;Common reference mode
+ movwf CMCON
+
+ movlw b'00000111' ;A0 through A2 are used for analog I/O
+ movwf ANSEL
+
+ ;Configure the serial interface
+ movlw BAUD
+ movwf SPBRG
+ bsf TXSTA,BRGH ;9600 baud
+ bcf TXSTA,SYNC ;Asynchronous
+ bsf TXSTA,TXEN ;Enable transmit
+ bcf STATUS,RP0
+ bsf RCSTA,SPEN ;Enable serial port
+ bsf RCSTA,CREN ;Enable receive
+
+ ;Configure A/D converter
+ movlw b'01000001' ;A/D on, channel 0, Fosc/8
+ movwf ADCON0
+
+ ;Configure the voltage reference module
+ ;The reference voltage must be set to 1.3V
+ ;Bit 7 VREN = 1 - VREF Enabled
+ ;Bit 6 VROE = 1 - Output on pin RA2
+ ;Bit 5 VRR = 1 - Low range
+ ;Bit 3-0 VR = 6 - 1.25V (7 - 1.46V)
+ movlw b'11100110'
+ bsf STATUS,RP0
+ movwf CVRCON ;Set the reference voltage
+
+
+ clrf STATUS
+ bcf PIR2,CMIF ;Clear any comparator interrupt
+
+ movlw 0x41
+ movwf TXREG
+
+
+
+
+MainLoop clrwdt
+
+ ; Copy CMCON bits 7 and 6 from to PORTB bits 7 and 6 (comparitor outputs to LED_C and LED_D pins)
+ bsf STATUS,RP0
+ movfw CMCON
+ bcf STATUS,RP0
+
+ andlw b'11000000'
+ iorwf PORTB,F
+ iorlw b'00111111'
+ andwf PORTB,F
+
+ ; Copy PORTA bits 7 and 6 to PORTA bits 4 and 3 (GPIO inputs to transmitter outputs)
+ rrf PORTA,W
+ movwf temp
+ rrf temp,F
+ rrf temp,W
+
+ andlw b'00011000'
+ iorwf PORTA,F
+ iorlw b'11100111'
+ andwf PORTA,F
+
+ ; And port B bits 4 and 3 (LED_A and LED_B)
+
+ andlw b'00011000'
+ iorwf PORTB,F
+ iorlw b'11100111'
+ andwf PORTB,F
+
+
+ btfss PIR1,RCIF ;Activity on the serial receiver?
+ goto MainLoop
+ tstf RCREG
+
+ ;FERR is only relevant if RCIF is set
+ btfsc RCSTA,FERR ;Check for framing error (break)
+ goto Break
+ btfss RCSTA,OERR ;Check for overrun error
+ goto serial_recv
+ bcf RCSTA,CREN ;Procedure to clear an overrun error
+ bsf RCSTA,CREN ;Re-enable the serial interface
+serial_recv movfw RCREG
+ ;movwf TXREG
+ xorlw 0x4
+ skpnz
+ goto Break
+ goto MainLoop
+
+Pause clrwdt
+ btfsc PIR1,RCIF
+ return
+ btfss INTCON,TMR0IF
+ goto Pause
+ bcf INTCON,TMR0IF
+ addlw -1
+ skpz
+ goto Pause
+ return
+
+
+ end
diff --git a/pic/selfprog.asm b/pic/selfprog.asm
new file mode 100644
index 0000000..9e18769
--- /dev/null
+++ b/pic/selfprog.asm
@@ -0,0 +1,391 @@
+ title "Self Programming"
+ list b=8, r=dec
+
+;########################################################################
+; Self programming, based on Microchip AN851
+;########################################################################
+; This code has been optimized for size so it would fit in 0x100 code words.
+; To achieve this, some special tricks had to be used. As a result the code
+; may be a little hard to read
+;
+; The functionality differs from that described in AN851 in the following
+; respects:
+; 1. No auto baud detection. Communication must take place at 9600 baud.
+; 2. Dropped the first <STX> that was used for auto baud detection.
+; 3. Dropped the third address byte as it would always be 0.
+; 4. The code does not check the last byte of EEPROM data memory to enter boot
+; mode. Instead it transmits a <ETX> character and waits up to 1 second for
+; a <STX> character.
+; 5. The code is designed to be placed in the highest part of memory. That way
+; it doesn't interfere with the interrupt code address. It does rely on the
+; main program to call the self-program code at an appropriate time.
+; 6. Due to the location of the boot loader code, it cannot be protected using
+; the code protection bits in the configuration word. This means that the
+; boot loader code can also be updated, if necessary.
+; 7. The Erase Flash command has been implemented for the PIC16F device.
+; 8. The device reset command is 0x08, not any command with a 0 length.
+; 9. The version command can be called with a data length of 1-3 words. It will
+; report the following information:
+; 1. Version
+; 2. Boot loader start address
+; 3. Boot loader end address
+; The software used to reflash the device can use the last two pieces of
+; information to determine which part of memory should not be touched.
+
+#include "p16f88.inc"
+
+ errorlevel -302, -306
+
+#define MAJOR_VERSION 1
+#define MINOR_VERSION 1
+
+#define STX 0x0F
+#define ETX 0x04
+#define DLE 0x05
+
+CHKSUM equ 0x70
+COUNTER equ 0x71
+RXDATA equ 0x72
+TXDATA equ 0x73
+TEMP equ 0x74
+
+DATA_BUFF equ 0x10 ;Start of receive buffer
+COMMAND equ 0x10 ;Data mapped in receive buffer
+DATA_COUNT equ 0x11
+ADDRESS_L equ 0x12
+ADDRESS_H equ 0x13
+PACKET_DATA equ 0x14
+
+#define SELFRESET PORTB,1
+#define RX PORTB,2
+#define TX PORTB,5
+
+#ifdef SELFPROGNEW
+ #define SELFPROG SelfProgNew
+ #define STARTADDRESS 0x0700
+#else
+ #define SELFPROG SelfProg
+ #define STARTADDRESS 0x0f00
+#endif
+
+ global SELFPROG
+SELFPROG code STARTADDRESS
+ ;Do not go into selfprog mode after a watchdog timeout reset
+SELFPROG btfss STATUS,NOT_TO
+ return ;Let the main code handle a timeout
+
+ bcf INTCON,GIE ;Ignore interrupts
+
+ banksel OSCCON
+ movlw b'01100000' ;Internal oscillator set to 4MHz
+ movwf OSCCON ;Configure the oscillator
+
+ ;Set the LEDS as outputs
+#ifndef LVP
+ movlw b'00100111'
+#else
+ movlw b'00101111'
+#endif
+ movwf TRISB
+
+ ;Configure the comparators and voltage reference
+ ;Allow communication between thermostat and boiler to continue
+ ;while reprogramming the device
+ movlw b'11100111' ;Pins 3 and 4 are digital ouputs
+ movwf TRISA
+ movlw b'00000111' ;A0 through A2 are used for analog I/O
+ movwf ANSEL
+ movlw b'11100110' ;Voltage reference at 1.25V
+ movwf CVRCON
+ movlw b'00000110' ;Two common reference comps with output
+ movwf CMCON
+
+ ;Configure Timer 0 & Watchdog Timer
+ ;Bit 7 RBPU = 1 - Port B pull up disabled
+ ;Bit 6 INTEDG = 1 - Interrupt on rising edge
+ ;Bit 5 T0CS = 0 - Internal clock
+ ;Bit 4 T0SE = 1 - High to low transition
+ ;Bit 3 PSA = 0 - Prescaler assigned to Timer 0
+ ;Bit 2-0 PS = 7 - 1:256 Prescaler
+ movlw b'11010111'
+ movwf OPTION_REG
+
+ movlw 25 ;9600 baud
+ movwf SPBRG
+ movlw b'00100110'
+ movwf TXSTA ;High speed, Asynchronous, Enabled
+ bcf STATUS,RP0
+ bsf RCSTA,SPEN ;Enable serial port
+ bsf RCSTA,CREN ;Enable receive
+
+ ;Clear the LEDS
+ movlw b'11111111'
+ movwf PORTB
+
+ clrf TMR0
+ movlw 1
+ call Pause
+;Notify the external programming software (Pause returns <ETX>)
+ call WrRS232
+;Programmer should react within 1 second
+ movlw 16
+ call Pause
+ btfss PIR1,RCIF
+;No data received, resume the normal program
+ return
+;Check that the received character is <STX>
+ call RdRS232
+ skpz
+;Other serial data received, resume normal program
+ return
+
+ bsf STATUS,IRP
+ReSync movlw DATA_BUFF
+ movwf FSR
+ clrf CHKSUM
+GetNextDat call RdRS232 ;Get the data
+ skpnz
+ goto ReSync ;Found unprotected STX
+ xorlw STX ^ ETX ;Check for ETX
+ skpnz
+ goto CheckSum ;Yes, examine checksum
+ xorlw ETX ^ DLE ;Check for DLE
+ skpnz
+ call RdRS232 ;Yes, get the next byte
+ movfw RXDATA
+ movwf INDF ;Store the data
+ addwf CHKSUM,F ;Get sum
+ incf FSR,F
+ goto GetNextDat
+
+CheckSum tstf CHKSUM
+ skpz
+ goto StartOfLine
+ bsf STATUS,RP1
+ movfw ADDRESS_L
+ movwf EEADR
+ movfw ADDRESS_H
+ movwf EEADRH
+ movlw PACKET_DATA
+ movwf FSR
+ movfw DATA_COUNT
+ movwf COUNTER
+CheckCommand
+#ifdef SELFPROGNEW
+ movlw high ($ + 0x800)
+#else
+ movlw high $
+#endif
+ movwf PCLATH
+ movfw COMMAND
+ sublw 8
+ sublw 8
+ skpc
+ goto StartOfLine
+ addwf PCL,F
+ goto ReadVersion ;0 Read Version Information
+ goto ReadProgMem ;1 Read Program Memory
+ goto WriteProgMem ;2 Write Program Memory
+ goto EraseProgMem ;3 Erase Program Memory
+ goto ReadEE ;4 Read EEDATA Memory
+ goto WriteEE ;5 Write EEDATA Memory
+ goto StartOfLine ;6 Read Config Memory
+ goto StartOfLine ;7 Write Config Memory
+ goto VReset ;8 Reset
+
+VersionData data (MAJOR_VERSION << 8) | MINOR_VERSION
+#ifdef SELFPROGNEW
+ data SELFPROG + 0x800, SelfProgEnd + 0x800
+#else
+ data SELFPROG, SelfProgEnd
+#endif
+
+ReadVersion movlw low VersionData
+ movwf EEADR
+#ifdef SELFPROGNEW
+ movlw high (VersionData + 0x800)
+#else
+ movlw high VersionData
+#endif
+ movwf EEADRH
+ movlw DATA_BUFF + 2
+ movwf FSR
+ReadProgMem bsf STATUS,RP0
+ bsf EECON1,EEPGD
+ bsf EECON1,RD
+ nop
+ nop
+ bcf STATUS,RP0
+ movfw EEDATA
+ movwf INDF
+ incf FSR,F
+ movfw EEDATH
+ movwf INDF
+ incf FSR,F
+ incf EEADR,F
+ skpnz
+ incf EEADRH,F
+ decfsz COUNTER,F
+ goto ReadProgMem
+WritePacket movlw DATA_BUFF
+ subwf FSR,W
+WritePacketJ1 movwf COUNTER
+ movlw STX
+ call WrRS232
+ clrf CHKSUM
+ movlw DATA_BUFF
+ movwf FSR
+SendNext movfw INDF
+ addwf CHKSUM,F
+ incf FSR,F
+ call WrData
+ decfsz COUNTER,F
+ goto SendNext
+ comf CHKSUM,W
+ addlw 1
+ call WrData ;WrData returns <ETX>
+ call WrRS232
+StartOfLine bcf STATUS,RP1
+ call RdRS232 ;Look for a start of line
+ skpnz
+ goto ReSync
+ goto StartOfLine
+
+WriteProgMem movlw b'10000100'
+ call LoadEECon1
+ movlw b'11111100'
+ andwf EEADR,F
+ movlw 4
+ movwf TEMP
+Lp1 movfw INDF
+ movwf EEDATA
+ incf FSR,F
+ movfw INDF
+ movwf EEDATH
+ incf FSR,F
+ call StartWrite
+ decfsz TEMP,F
+ goto Lp1
+ decfsz COUNTER,F
+ goto WriteProgMem
+ goto WritePacketJ1
+
+EraseProgMem movlw b'10010100'
+ call LoadEECon1
+ movlw 0x1F
+ iorwf EEADR,F
+ call StartWrite
+ decfsz COUNTER,F
+ goto EraseProgMem
+ goto WritePacketJ1
+
+ReadEE bsf STATUS,RP0
+ clrf EECON1
+ bsf EECON1,RD
+ bcf STATUS,RP0
+ movfw EEDATA
+ movwf INDF
+ incf FSR,F
+ incf EEADR,F
+ decfsz COUNTER,F
+ goto ReadEE
+ goto WritePacket
+
+WriteEE movlw b'00000100'
+ call LoadEECon1
+ movfw INDF
+ movwf EEDATA
+ incf FSR,F
+ call StartWrite
+ decfsz COUNTER,F
+ goto WriteEE
+ goto WritePacketJ1
+
+WrData movwf TXDATA
+ xorlw STX
+ skpnz
+ goto WrDLE
+ xorlw STX ^ ETX
+ skpnz
+ goto WrDLE
+ xorlw ETX ^ DLE
+ skpz
+ goto WrNext
+WrDLE movlw DLE
+ call WrRS232
+WrNext movfw TXDATA
+WrRS232 clrwdt
+ bcf STATUS,RP1
+WaitTxEmpty btfss PIR1,TXIF
+ goto WaitTxEmpty
+ movwf TXREG
+ retlw ETX
+
+RdRS232 btfsc RCSTA,OERR
+ goto VReset
+RdLp1 clrwdt
+ btfss PIR1,RCIF
+ goto RdLp1
+ movfw RCREG
+ movwf RXDATA
+ xorlw STX
+ return
+
+LoadEECon1 bsf STATUS,RP0
+ movwf EECON1
+ bcf STATUS,RP0
+ return
+
+StartWrite clrwdt
+ bsf STATUS,RP0
+ movlw 0x55
+ movwf EECON2
+ movlw 0xAA
+ movwf EECON2
+ bsf EECON1,WR
+WaitEEWrite btfsc EECON1,WR ;Skipped when writing program memory
+ goto WaitEEWrite ;Skipped when writing program memory
+ bcf STATUS,RP0
+ incf EEADR,F
+ skpnz
+ incf EEADRH,F
+ retlw 1 ;Return length of acknowledgement
+
+Pause clrwdt
+ btfsc PIR1,RCIF
+ return
+ btfss INTCON,TMR0IF
+ goto Pause
+ bcf INTCON,TMR0IF
+ addlw -1
+ skpz
+ goto Pause
+ retlw ETX
+
+;Reset the device via an external connection from an I/O pin to the reset pin.
+VReset bcf STATUS,RP1
+ bcf SELFRESET ;Prepare the output latch
+ bsf STATUS,RP0
+ bcf SELFRESET ;Switch the pin to output
+
+;If resetting via the output pin doesn't work, restore all used registers to
+;their power-on defaults and jump to address 0.
+;Do not simply return because the code that called this routine may have been
+;wiped and reprogrammed to something completely different.
+ movlw b'11111111'
+ movwf TRISA
+ movwf TRISB
+ movwf OPTION_REG
+ movwf ANSEL
+ movlw b'00000111'
+ movwf CMCON
+ clrf TXSTA
+ clrf SPBRG
+ clrf STATUS
+ clrf RCSTA
+ clrf INTCON
+ clrf PCLATH
+ clrwdt
+SelfProgEnd goto 0
+
+ end
diff --git a/stm32/.gitignore b/stm32/.gitignore
new file mode 100644
index 0000000..08e4672
--- /dev/null
+++ b/stm32/.gitignore
@@ -0,0 +1,16 @@
+.gitmodules
+*.o
+*.d
+*.map
+*.hex
+*.elf
+*.swp
+*~
+*.dfu
+plot/data
+plot/script
+*.bin
+scmversion
+commit.h
+opencm3.build.stamp
+*.orig
diff --git a/stm32/Makefile b/stm32/Makefile
new file mode 100644
index 0000000..e1cd497
--- /dev/null
+++ b/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/stm32/Makefile.include b/stm32/Makefile.include
new file mode 100644
index 0000000..4f5cbd9
--- /dev/null
+++ b/stm32/Makefile.include
@@ -0,0 +1,44 @@
+##
+## This file is part of the libopencm3 project.
+##
+## Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
+## Copyright (C) 2010 Piotr Esden-Tempski <piotr@esden.net>
+##
+## 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 <http://www.gnu.org/licenses/>.
+##
+
+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/stm32/Makefile.rules b/stm32/Makefile.rules
new file mode 100644
index 0000000..a723e6f
--- /dev/null
+++ b/stm32/Makefile.rules
@@ -0,0 +1,261 @@
+#
+## This file is part of the libopencm3 project.
+##
+## Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
+## Copyright (C) 2010 Piotr Esden-Tempski <piotr@esden.net>
+## Copyright (C) 2013 Frantisek Burian <BuFran@seznam.cz>
+##
+## 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 <http://www.gnu.org/licenses/>.
+##
+
+# 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/stm32/app/1wire.c b/stm32/app/1wire.c
new file mode 100644
index 0000000..c374c5c
--- /dev/null
+++ b/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/stm32/app/1wire.h b/stm32/app/1wire.h
new file mode 100644
index 0000000..4a31418
--- /dev/null
+++ b/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/stm32/app/Makefile b/stm32/app/Makefile
new file mode 100644
index 0000000..d4a4f5b
--- /dev/null
+++ b/stm32/app/Makefile
@@ -0,0 +1,132 @@
+##
+## This file is part of the libopencm3 project.
+##
+## Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
+##
+## 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 <http://www.gnu.org/licenses/>.
+##
+
+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=10.32.96.18
+#TARGET2=10.32.96.107
+
+#soup: ${PROG}.hex
+# rsync -vaP ${PROG}.hex ${TARGET2}:/tmp/boiler.hex
+# RV=$$(arm-none-eabi-objdump --disassemble=reset_handler ${PROG}.elf | awk '/^0/ { print "0x"$$1 }') && \
+# ssh ${TARGET2} "$(OOCD) -f $(OOCD_INTERFACE) \
+# -f $(OOCD_BOARD) \
+# -c init -c \"reset init\" \
+# -c \"flash write_image erase /tmp/boiler.hex\" \
+# -c \"reset halt\" \
+# -c \"resume $${RV}\" \
+# -c shutdown" $(NULL) && \
+# echo reset_handler is at $${RV}
+#
+
+
+
+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/stm32/app/adc.c b/stm32/app/adc.c
new file mode 100644
index 0000000..ee6a4f3
--- /dev/null
+++ b/stm32/app/adc.c
@@ -0,0 +1,121 @@
+#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;
+}
+
+
+
+
+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/stm32/app/boiler.ld b/stm32/app/boiler.ld
new file mode 100644
index 0000000..e15beca
--- /dev/null
+++ b/stm32/app/boiler.ld
@@ -0,0 +1,31 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+/* 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/stm32/app/cmd.c b/stm32/app/cmd.c
new file mode 100644
index 0000000..7e1975a
--- /dev/null
+++ b/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/stm32/app/commit.c b/stm32/app/commit.c
new file mode 100644
index 0000000..207448f
--- /dev/null
+++ b/stm32/app/commit.c
@@ -0,0 +1,3 @@
+#include "commit.h"
+
+char scm_version[] = COMMIT_ID;
diff --git a/stm32/app/ds1820.c b/stm32/app/ds1820.c
new file mode 100644
index 0000000..0da63fb
--- /dev/null
+++ b/stm32/app/ds1820.c
@@ -0,0 +1,93 @@
+#include "project.h"
+
+#define DS1820_READ_SCRATCHPAD 0xbe
+#define DS1820_CONVERT_T 0x44
+
+
+#define TIMEOUT 150
+
+
+
+unsigned extract_leu16 (uint8_t *d)
+{
+ uint32_t u;
+
+ u = (uint32_t) d[0] | (((uint32_t) d[1]) << 8);
+ return u;
+}
+
+
+
+int extract_les16 (uint8_t *d)
+{
+ uint32_t u;
+ u = extract_leu16 (d);
+
+ if (u & 0x8000) u |= 0xffff0000;
+
+ return (int) u;
+}
+
+
+
+
+
+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;
+}
+
+
+
+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/stm32/app/gdb.script b/stm32/app/gdb.script
new file mode 100644
index 0000000..7cf9d09
--- /dev/null
+++ b/stm32/app/gdb.script
@@ -0,0 +1,2 @@
+target remote localhost:3333
+cont
diff --git a/stm32/app/led.c b/stm32/app/led.c
new file mode 100644
index 0000000..bdfd084
--- /dev/null
+++ b/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/stm32/app/main.c b/stm32/app/main.c
new file mode 100644
index 0000000..70c22b2
--- /dev/null
+++ b/stm32/app/main.c
@@ -0,0 +1,135 @@
+#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();
+ pressure_dispatch();
+
+ }
+
+
+ return 0;
+}
diff --git a/stm32/app/ot.c b/stm32/app/ot.c
new file mode 100644
index 0000000..e604b50
--- /dev/null
+++ b/stm32/app/ot.c
@@ -0,0 +1,413 @@
+#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
+
+
+
+unsigned ot_override_ch = 0;
+unsigned ot_override_dhw = 0;
+
+
+static inline int parity (uint8_t v)
+{
+ return (0x6996u >> ((v ^ (v >> 4)) & 0xf)) & 1;
+}
+
+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",
+ "<Read ACK",
+ "<Write ACK",
+ "<Data Invalid",
+ "<Unknown DataID"
+};
+
+static void ot_debug (char *who, uint8_t *msg, char *what)
+{
+ unsigned type = (msg[0] >> 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;
+ }
+}
+
+void ot_rx_blr (uint8_t *msg, int error)
+{
+ unsigned type = (msg[0] >> 4) & 7;
+ unsigned id = msg[1];
+ uint16_t t;
+ unsigned handled = 0 ;
+
+ 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)) {
+ switch (idx) {
+ case OT_IDX_CH_WATER_PRESSURE:
+ t = pressure_ch();
+ handled = 1;
+ break;
+
+ case OT_IDX_RETURN_WATER_TEMP:
+ t = temp_ch_return();
+ handled = 1;
+ break;
+
+ }
+
+ if (handled) {
+
+ type = OT_READ_ACK;
+
+ msg[0] &= 0x8f;
+ msg[0] |= type << 4;
+ msg[2] = t >> 8;
+ msg[3] = t & 0xff;
+ ot_debug ("B", msg, "");
+ }
+ }
+
+ 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 send temp set points\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);
+ }
+
+ ot_request_ovr (OT_READ_DATA, OT_IDX_CH_WATER_PRESSURE, NULL);
+ ot_request_ovr (OT_READ_DATA, OT_IDX_RETURN_WATER_TEMP, NULL);
+
+}
+
+
+
+
+static void ot_4hz_ticker (void)
+{
+ static unsigned i;
+ i++;
+
+ 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 (i >= 120) {
+ ot_30s_ticker();
+ i = 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/stm32/app/ot_phy_rx.c b/stm32/app/ot_phy_rx.c
new file mode 100644
index 0000000..9348d24
--- /dev/null
+++ b/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/stm32/app/ot_phy_tx.c b/stm32/app/ot_phy_tx.c
new file mode 100644
index 0000000..36fbcc5
--- /dev/null
+++ b/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/stm32/app/pic.c b/stm32/app/pic.c
new file mode 100644
index 0000000..b478766
--- /dev/null
+++ b/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/stm32/app/pins.h b/stm32/app/pins.h
new file mode 100644
index 0000000..9ea01cf
--- /dev/null
+++ b/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/stm32/app/pressure.c b/stm32/app/pressure.c
new file mode 100644
index 0000000..6b90d93
--- /dev/null
+++ b/stm32/app/pressure.c
@@ -0,0 +1,79 @@
+#include "project.h"
+
+#define PRESSURE GPIO0
+#define PRESSURE_PORT GPIOA
+#define PRESSURE_CHANNEL ADC_CHANNEL0
+#define VREF_CHANNEL ADC_CHANNEL17
+
+static unsigned poke;
+
+static int pressure;
+
+uint16_t pressure_ch (void)
+{
+ return pressure;
+}
+
+
+
+
+void pressure_tick (void)
+{
+ static unsigned ticker;
+
+ ticker++;
+
+ if (ticker < MS_TO_TICKS (2500))
+ return;
+
+ ticker = 0;
+ poke = 1;
+
+}
+
+
+
+
+void pressure_dispatch (void)
+{
+ int v, r;
+
+ if (!poke) return;
+
+ poke = 0;
+
+ if (adc_calibrate()) {
+ pressure = 0;
+ return;
+ }
+
+ v = adc_convert (PRESSURE_CHANNEL);
+ r = adc_convert (VREF_CHANNEL);
+
+
+ /* 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;
+ }
+
+ pressure = ((v * 552) / r) - 221;
+
+ if (pressure < 0) pressure = 0;
+
+ printf ("QP: %d %d %d\r\n", v, r, (pressure * 100) / 256);
+
+}
+
+
+
+void pressure_init (void)
+{
+ MAP_ANALOG (PRESSURE);
+}
+
+
+
+
diff --git a/stm32/app/project.h b/stm32/app/project.h
new file mode 100644
index 0000000..d1bfa52
--- /dev/null
+++ b/stm32/app/project.h
@@ -0,0 +1,30 @@
+#include <stdlib.h>
+#include <libopencm3/stm32/rcc.h>
+#include <libopencm3/stm32/gpio.h>
+#include <libopencm3/stm32/usart.h>
+#include <libopencm3/stm32/usb.h>
+#include <libopencm3/stm32/exti.h>
+#include <libopencm3/stm32/adc.h>
+#include <libopencm3/cm3/systick.h>
+#include <libopencm3/cm3/nvic.h>
+#include <libopencm3/cm3/cortex.h>
+#include <libopencm3/cm3/scb.h>
+#include <libopencm3/cm3/dwt.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#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/stm32/app/prototypes.h b/stm32/app/prototypes.h
new file mode 100644
index 0000000..d9afd3a
--- /dev/null
+++ b/stm32/app/prototypes.h
@@ -0,0 +1,108 @@
+/* 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_parity(uint8_t *data);
+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 volatile uint32_t ticks;
+extern void delay_us(uint32_t d);
+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);
+/* ds1820.c */
+extern unsigned extract_leu16(uint8_t *d);
+extern int extract_les16(uint8_t *d);
+extern int ds1820_read_sp(const Onewire_addr *a, unsigned page, uint8_t *buf, unsigned len);
+extern int ds1820_convert_t(const Onewire_addr *a);
+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_dispatch(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 unsigned adc_convert(unsigned channel);
+extern void adc_init(void);
diff --git a/stm32/app/ring.c b/stm32/app/ring.c
new file mode 100644
index 0000000..973f345
--- /dev/null
+++ b/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/stm32/app/ring.h b/stm32/app/ring.h
new file mode 100644
index 0000000..a329354
--- /dev/null
+++ b/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/stm32/app/stdio.c b/stm32/app/stdio.c
new file mode 100644
index 0000000..bcdd5c7
--- /dev/null
+++ b/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/stm32/app/temp.c b/stm32/app/temp.c
new file mode 100644
index 0000000..25a5de3
--- /dev/null
+++ b/stm32/app/temp.c
@@ -0,0 +1,72 @@
+#include "project.h"
+
+
+#define N_SENSORS 2
+
+#define SENSOR_INDEX_CH_RETURN 0
+#define SENSOR_INDEX_DHW_FEED 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\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];
+}
diff --git a/stm32/app/ticker.c b/stm32/app/ticker.c
new file mode 100644
index 0000000..5fbf316
--- /dev/null
+++ b/stm32/app/ticker.c
@@ -0,0 +1,103 @@
+#include "project.h"
+
+
+static volatile uint32_t delay_hms_count;
+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/stm32/app/usart.c b/stm32/app/usart.c
new file mode 100644
index 0000000..28676a0
--- /dev/null
+++ b/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/stm32/app/util.c b/stm32/app/util.c
new file mode 100644
index 0000000..bf65510
--- /dev/null
+++ b/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/stm32/docs/pinout.txt b/stm32/docs/pinout.txt
new file mode 100644
index 0000000..03abe35
--- /dev/null
+++ b/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/stm32/docs/pm0056.pdf b/stm32/docs/pm0056.pdf
new file mode 100644
index 0000000..659c9de
--- /dev/null
+++ b/stm32/docs/pm0056.pdf
Binary files differ
diff --git a/stm32/docs/rm0008.pdf b/stm32/docs/rm0008.pdf
new file mode 100644
index 0000000..8f3d0e1
--- /dev/null
+++ b/stm32/docs/rm0008.pdf
Binary files differ
diff --git a/stm32/docs/stm32f103c8.pdf b/stm32/docs/stm32f103c8.pdf
new file mode 100644
index 0000000..2723cee
--- /dev/null
+++ b/stm32/docs/stm32f103c8.pdf
Binary files differ
diff --git a/stm32/docs/stm32f103c8t6_pinout_voltage01.png b/stm32/docs/stm32f103c8t6_pinout_voltage01.png
new file mode 100644
index 0000000..2c22a74
--- /dev/null
+++ b/stm32/docs/stm32f103c8t6_pinout_voltage01.png
Binary files differ
diff --git a/stm32/libopencm3 b/stm32/libopencm3
new file mode 160000
+Subproject 5c73d601763dd140bff020be8d6d06f03c2bea7