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