From f0d941bef6a9b6e3af78cfc68e1f82d6b47ccb2f Mon Sep 17 00:00:00 2001 From: fishsoupisgood Date: Tue, 26 May 2020 14:33:34 +0100 Subject: happy --- .gitmodules | 6 + DOCS/41hpa-warranty-registration.pdf | Bin 0 -> 37952 bytes DOCS/Opentherm Protocol v2-2.pdf | Bin 0 -> 285534 bytes otmonitor | 1 + pic/.gitignore | 8 + pic/16f88.lkr | 76 +++++ pic/Makefile | 22 ++ pic/build.asm | 2 + pic/docs/otgw-big-sch.png | Bin 0 -> 77271 bytes pic/docs/pinout.txt | 33 ++ pic/gateway.asm | 296 ++++++++++++++++++ pic/selfprog.asm | 391 ++++++++++++++++++++++++ stm32/.gitignore | 16 + stm32/Makefile | 8 + stm32/Makefile.include | 44 +++ stm32/Makefile.rules | 261 ++++++++++++++++ stm32/app/1wire.c | 392 ++++++++++++++++++++++++ stm32/app/1wire.h | 10 + stm32/app/Makefile | 132 ++++++++ stm32/app/adc.c | 121 ++++++++ stm32/app/boiler.ld | 31 ++ stm32/app/cmd.c | 55 ++++ stm32/app/commit.c | 3 + stm32/app/ds1820.c | 93 ++++++ stm32/app/gdb.script | 2 + stm32/app/led.c | 101 +++++++ stm32/app/main.c | 135 +++++++++ stm32/app/ot.c | 413 ++++++++++++++++++++++++++ stm32/app/ot_phy_rx.c | 177 +++++++++++ stm32/app/ot_phy_tx.c | 121 ++++++++ stm32/app/pic.c | 52 ++++ stm32/app/pins.h | 53 ++++ stm32/app/pressure.c | 79 +++++ stm32/app/project.h | 30 ++ stm32/app/prototypes.h | 108 +++++++ stm32/app/ring.c | 77 +++++ stm32/app/ring.h | 13 + stm32/app/stdio.c | 77 +++++ stm32/app/temp.c | 72 +++++ stm32/app/ticker.c | 103 +++++++ stm32/app/usart.c | 175 +++++++++++ stm32/app/util.c | 14 + stm32/docs/pinout.txt | 24 ++ stm32/docs/pm0056.pdf | Bin 0 -> 2098835 bytes stm32/docs/rm0008.pdf | Bin 0 -> 13016697 bytes stm32/docs/stm32f103c8.pdf | Bin 0 -> 1697666 bytes stm32/docs/stm32f103c8t6_pinout_voltage01.png | Bin 0 -> 679565 bytes stm32/libopencm3 | 1 + 48 files changed, 3828 insertions(+) create mode 100644 .gitmodules create mode 100644 DOCS/41hpa-warranty-registration.pdf create mode 100644 DOCS/Opentherm Protocol v2-2.pdf create mode 160000 otmonitor create mode 100644 pic/.gitignore create mode 100644 pic/16f88.lkr create mode 100644 pic/Makefile create mode 100644 pic/build.asm create mode 100644 pic/docs/otgw-big-sch.png create mode 100644 pic/docs/pinout.txt create mode 100644 pic/gateway.asm create mode 100644 pic/selfprog.asm create mode 100644 stm32/.gitignore create mode 100644 stm32/Makefile create mode 100644 stm32/Makefile.include create mode 100644 stm32/Makefile.rules create mode 100644 stm32/app/1wire.c create mode 100644 stm32/app/1wire.h create mode 100644 stm32/app/Makefile create mode 100644 stm32/app/adc.c create mode 100644 stm32/app/boiler.ld create mode 100644 stm32/app/cmd.c create mode 100644 stm32/app/commit.c create mode 100644 stm32/app/ds1820.c create mode 100644 stm32/app/gdb.script create mode 100644 stm32/app/led.c create mode 100644 stm32/app/main.c create mode 100644 stm32/app/ot.c create mode 100644 stm32/app/ot_phy_rx.c create mode 100644 stm32/app/ot_phy_tx.c create mode 100644 stm32/app/pic.c create mode 100644 stm32/app/pins.h create mode 100644 stm32/app/pressure.c create mode 100644 stm32/app/project.h create mode 100644 stm32/app/prototypes.h create mode 100644 stm32/app/ring.c create mode 100644 stm32/app/ring.h create mode 100644 stm32/app/stdio.c create mode 100644 stm32/app/temp.c create mode 100644 stm32/app/ticker.c create mode 100644 stm32/app/usart.c create mode 100644 stm32/app/util.c create mode 100644 stm32/docs/pinout.txt create mode 100644 stm32/docs/pm0056.pdf create mode 100644 stm32/docs/rm0008.pdf create mode 100644 stm32/docs/stm32f103c8.pdf create mode 100644 stm32/docs/stm32f103c8t6_pinout_voltage01.png create mode 160000 stm32/libopencm3 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 Binary files /dev/null and b/DOCS/41hpa-warranty-registration.pdf differ diff --git a/DOCS/Opentherm Protocol v2-2.pdf b/DOCS/Opentherm Protocol v2-2.pdf new file mode 100644 index 0000000..47a7f59 Binary files /dev/null and b/DOCS/Opentherm Protocol v2-2.pdf differ diff --git a/otmonitor b/otmonitor new file mode 160000 index 0000000..6ef7f2b --- /dev/null +++ b/otmonitor @@ -0,0 +1 @@ +Subproject commit 6ef7f2b1455ea10c5f7147216d442326c1ccfdd3 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 Binary files /dev/null and b/pic/docs/otgw-big-sch.png 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 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 character and waits up to 1 second for +; a 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 ) + 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 + 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 + 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 +## 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/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 +## 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/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 +## +## 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=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 + * + * 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/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", + "> 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 +#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/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 Binary files /dev/null and b/stm32/docs/pm0056.pdf differ diff --git a/stm32/docs/rm0008.pdf b/stm32/docs/rm0008.pdf new file mode 100644 index 0000000..8f3d0e1 Binary files /dev/null and b/stm32/docs/rm0008.pdf differ diff --git a/stm32/docs/stm32f103c8.pdf b/stm32/docs/stm32f103c8.pdf new file mode 100644 index 0000000..2723cee Binary files /dev/null and b/stm32/docs/stm32f103c8.pdf differ diff --git a/stm32/docs/stm32f103c8t6_pinout_voltage01.png b/stm32/docs/stm32f103c8t6_pinout_voltage01.png new file mode 100644 index 0000000..2c22a74 Binary files /dev/null and b/stm32/docs/stm32f103c8t6_pinout_voltage01.png differ diff --git a/stm32/libopencm3 b/stm32/libopencm3 new file mode 160000 index 0000000..5c73d60 --- /dev/null +++ b/stm32/libopencm3 @@ -0,0 +1 @@ +Subproject commit 5c73d601763dd140bff020be8d6d06f03c2bea78 -- cgit v1.2.3