1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
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
|