Subversion Repositories group.electronics

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
5 pfowler 1
;---------------------------------------------------------------------
2
; File: an734_PIC16.asm
3
;
4
; Written By: Stephen Bowling, Microchip Technology
5
;
6
; Version: 1.00
7
;
8
; Assembled using Microchip Assembler
9
;
10
; Functionality:
11
;
12
; This code implements the basic functions for an I2C slave device
13
; using the SSP module. All I2C functions are handled in an ISR.
14
; Bytes written to the slave are stored in a buffer. After a number
15
; of bytes have been written, the master device can then read the
16
; bytes back from the buffer.
17
;
18
; Variables and Constants used in the program:
19
;
20
; The start address for the receive buffer is stored in the variable
21
; 'RXBuffer'. The length of the buffer is denoted by the constant
22
; value 'RX_BUF_LEN'. The current buffer index is stored in the
23
; variable 'Index'.
24
;
25
;--------------------------------------------------------------------
26
;
27
; The following files should be included in the MPLAB project:
28
;
29
; an734_PIC16.asm-- Main source code file
30
;
31
; 16f877a.lkr-- Linker script file
32
; (change this file for the device you are using)
33
;
34
;---------------------------------------------------------------------
35
;---------------------------------------------------------------------
36
; Include Files
37
;---------------------------------------------------------------------
38
list        p=16F88
39
#include <p16f88.inc> ; Change to device that you are using.
40
	__CONFIG	_CONFIG1, _CP_OFF & _CCP1_RB3 & _CCPMX_RB3 & _DEBUG_OFF & _WRT_PROTECT_OFF & _CPD_OFF & _LVP_OFF & _BODEN_OFF & _MCLR_ON & _PWRTE_ON & _WDT_ON & _HS_OSC
41
;---------------------------------------------------------------------
42
;Constant Definitions
43
;---------------------------------------------------------------------
44
#define NODE_ADDR 0x4d ; I2C address of slave 2
45
 
46
    #define SR_DATA     PORTA,0
47
    #define SR_CLOCK    PORTA,1
48
    #define SR_LATCH    PORTA,2
49
    #define LED         PORTA,3
50
    #define RECV        PORTA,4
51
; Change this value to address that
52
; you wish to use.
53
;---------------------------------------------------------------------
54
; Buffer Length Definition
55
;---------------------------------------------------------------------
56
#define RX_BUF_LEN 8 ; Length of receive buffer
57
;---------------------------------------------------------------------
58
; Variable declarations
59
;---------------------------------------------------------------------
60
    udata_shr
61
    WREGsave    res 1
62
    RXBuffer    res RX_BUF_LEN
63
 
64
 
65
    udata
66
    STATUSsave  res 1
67
    FSRsave     res 1
68
    PCLATHsave  res 1
69
    Index       res 1           ; Index to receive buffer
70
    Temp        res 1           ;
71
    out_loop    res 1           ; Loop for the shift registe
72
    out_byte    res 1
73
    i2c_recv    res 1
74
 
75
 
76
 
77
; device.
78
;---------------------------------------------------------------------
79
; Vectors
80
;---------------------------------------------------------------------
81
STARTUP code 0x00
82
    nop
83
    goto    Startup ;
84
    nop             ; 0x0002
85
    nop             ; 0x0003
86
    goto    ISR     ; 0x0004
87
PROG code
88
;---------------------------------------------------------------------
89
; Macros
90
;---------------------------------------------------------------------
91
memset macro Buf_addr,Value,Length
92
    movlw   Length      ; This macro loads a range of data memory
93
    movwf   Temp        ; with a specified value. The starting
94
    movlw   Buf_addr    ; address and number of bytes are also
95
    movwf   FSR         ; specified.
96
SetNext movlw Value
97
    movwf   INDF
98
    incf    FSR,F
99
    decfsz  Temp,F
100
    goto    SetNext
101
    endm
102
LFSR macro Address,Offset   ; This macro loads the correct value
103
    movlw   Address         ; into the FSR given an initial data
104
    movwf   FSR             ; memory address and offset value.
105
    movf    Offset,W
106
    addwf   FSR,F
107
    endm
108
 
109
;---------------------------------------------------------------------
110
; Main Code
111
;---------------------------------------------------------------------
112
Startup
113
    bcf     STATUS,RP1
114
    bsf     STATUS,RP0
115
    call    Setup
116
 
117
Main clrwdt ; Clear the watchdog timer.
118
    banksel PORTA
119
 
120
    btfsc   RXBuffer,7
121
    bsf     LED
122
    btfss   RXBuffer,7
123
    bcf     LED
124
 
125
    btfsc   i2c_recv,0
126
    bsf     RECV
127
    btfss   i2c_recv,0
128
    bcf     RECV
129
 
130
    btfsc   i2c_recv,0        ; Skip if no data received
131
    call    shift_out       ;  -> Otherwise, shift out
132
 
133
    goto    Main ; Loop forever.
134
 
135
shift_out
136
    bcf     i2c_recv,0  ; Clear the data recived bit
137
    movfw   RXBuffer
138
    movwf   out_byte
139
 
140
    movlw   .8          ; Do this 8 times (Once per bit)
141
    movwf   out_loop
142
 
143
bit_out
144
    rlf     out_byte,f     ; Left rorate bit into C
145
 
146
    btfss   STATUS,C    ; Check if bit is set
147
    bcf     SR_DATA     ;  -> Send it to SR_DATA line
148
    btfsc   STATUS,C
149
    bsf     SR_DATA
150
 
151
    bsf     SR_CLOCK    ; Strobe a clock
152
    nop
153
    bcf     SR_CLOCK
154
 
155
    decfsz  out_loop,f
156
    goto    bit_out
157
 
158
    bsf     SR_LATCH    ; Latch the values
159
    nop
160
    bcf     SR_LATCH
161
 
162
    return
163
 
164
;---------------------------------------------------------------------
165
; Interrupt Code
166
;---------------------------------------------------------------------
167
ISR
168
    movwf   WREGsave    ; Save WREG
169
    movf    STATUS,W    ; Get STATUS register
170
    banksel STATUSsave  ; Switch banks, if needed.
171
    movwf   STATUSsave  ; Save the STATUS register
172
    movf    PCLATH,W    ;
173
    movwf   PCLATHsave  ; Save PCLATH
174
    movf    FSR,W       ;
175
    movwf   FSRsave     ; Save FSR
176
    banksel PIR1
177
    btfss   PIR1,SSPIF  ; Is this a SSP interrupt?
178
    goto    $           ; No, just trap here.
179
    bcf     PIR1,SSPIF
180
    call    SSP_Handler ; Yes, service SSP interrupt.
181
    banksel FSRsave
182
    movf    FSRsave,W   ;
183
    movwf   FSR         ; Restore FSR
184
    movf    PCLATHsave,W;
185
    movwf   PCLATH      ; Restore PCLATH
186
    movf    STATUSsave,W;
187
    movwf   STATUS      ; Restore STATUS
188
    swapf   WREGsave,F  ;
189
    swapf   WREGsave,W  ; Restore WREG
190
    retfie              ; Return from interrupt.
191
;---------------------------------------------------------------------
192
Setup
193
;
194
; Initializes program variables and peripheral registers.
195
;---------------------------------------------------------------------
196
    banksel PCON
197
    bsf     PCON,NOT_POR
198
    bsf     PCON,NOT_BOR
199
    banksel ANSEL
200
    movlw   0x00
201
    movwf   ANSEL
202
    banksel Index       ; Clear various program variables
203
    clrf    Index
204
    clrf    PORTB
205
    clrf    PIR1
206
 
207
    banksel TRISB
208
    clrf    TRISB
209
    bsf     TRISB,4
210
    bsf     TRISB,1
211
 
212
    banksel TRISA
213
    clrf    TRISA
214
    bcf     LED
215
 
216
    banksel i2c_recv
217
    clrf    i2c_recv
218
 
219
    movlw   0x36        ; Setup SSP module for 7-bit
220
    banksel SSPCON
221
    movwf   SSPCON      ; address, slave mode
222
    movlw   NODE_ADDR
223
    banksel SSPADD
224
    movwf   SSPADD
225
    clrf    SSPSTAT
226
    banksel PIE1        ; Enable interrupts
227
    bsf     PIE1,SSPIE
228
    bsf     INTCON,PEIE ; Enable all peripheral interrupts
229
    bsf     INTCON,GIE  ; Enable global interrupts
230
    bcf     STATUS,RP0
231
    return
232
;---------------------------------------------------------------------
233
SSP_Handler
234
 
235
;---------------------------------------------------------------------
236
; The I2C code below checks for 5 states:
237
;---------------------------------------------------------------------
238
; State 1: I2C write operation, last byte was an address byte.
239
; SSPSTAT bits: S = 1, D_A = 0, R_W = 0, BF = 1
240
;
241
; State 2: I2C write operation, last byte was a data byte.
242
; SSPSTAT bits: S = 1, D_A = 1, R_W = 0, BF = 1
243
;
244
; State 3: I2C read operation, last byte was an address byte.
245
; SSPSTAT bits: S = 1, D_A = 0, R_W = 1 (see Appendix C for more information)
246
;
247
; State 4: I2C read operation, last byte was a data byte.
248
; SSPSTAT bits: S = 1, D_A = 1, R_W = 1, BF = 0
249
;
250
; State 5: Slave I2C logic reset by NACK from master.
251
; SSPSTAT bits: S = 1, D_A = 1, BF = 0 (see Appendix C for more information)
252
;
253
; For convenience, WriteI2C and ReadI2C functions have been used.
254
;----------------------------------------------------------------------
255
    banksel SSPSTAT
256
    movf    SSPSTAT,W   ; Get the value of SSPSTAT
257
    andlw   b'00101101' ; Mask out unimportant bits in SSPSTAT.
258
    banksel Temp        ; Put masked value in Temp
259
    movwf   Temp        ; for comparision checking.
260
State1:                 ; Write operation, last byte was an   
261
    movlw   b'00001001' ; address, buffer is full.
262
    xorwf   Temp,W      ;
263
    btfss   STATUS,Z    ; Are we in State1?
264
    goto    State2      ; No, check for next state.....
265
    memset RXBuffer,0,RX_BUF_LEN ; Clear the receive buffer.
266
    clrf    Index       ; Clear the buffer index.
267
    banksel SSPBUF      ; Do a dummy read of the SSPBUF.
268
    movf    SSPBUF,W
269
    return
270
State2:                 ; Write operation, last byte was data,
271
    movlw   b'00101001' ; buffer is full.
272
    xorwf   Temp,W
273
    btfss   STATUS,Z    ; Are we in State2?
274
    goto    State3      ; No, check for next state.....
275
    LFSR RXBuffer,Index ; Point to the buffer.
276
    banksel SSPBUF      ; Get the byte from the SSP.
277
    movf    SSPBUF,W
278
    movwf   INDF        ; Put it in the buffer.
279
    incf    Index,F     ; Increment the buffer pointer.
280
    movf    Index,W     ; Get the current buffer index.
281
    sublw   RX_BUF_LEN  ; Subtract the buffer length.
282
    btfsc   STATUS,Z    ; Has the index exceeded the buffer length?
283
    clrf    Index       ; Yes, clear the buffer index.
284
    bsf     i2c_recv,0  ; Data received on i2c
285
    return
286
State3:                 ; Read operation, last byte was an address,
287
    movf    Temp,W ;
288
    andlw   b'00101100' ; Mask BF bit in SSPSTAT
289
    xorlw   b'00001100'
290
    btfss   STATUS,Z    ; Are we in State3?
291
    goto    State4      ; No, check for next state.....
292
    clrf    Index       ; Clear the buffer index.
293
    LFSR RXBuffer,Index ; Point to the buffer
294
    movf    INDF,W      ; Get the byte from buffer.
295
    call    WriteI2C    ; Write the byte to SSPBUF
296
    incf    Index,F     ; Increment the buffer index.
297
    return
298
State4:                 ; Read operation, last byte was data,
299
    banksel SSPCON      ; buffer is empty.
300
    btfsc   SSPCON, CKP
301
    goto    State5
302
 
303
    movlw   b'00101100'
304
    xorwf   Temp,W
305
    btfss   STATUS,Z    ; Are we in State4?
306
    goto    State5      ; No, check for next state....
307
    movf    Index,W     ; Get the current buffer index.
308
    sublw   RX_BUF_LEN  ; Subtract the buffer length.
309
    btfsc   STATUS,Z    ; Has the index exceeded the buffer length?
310
    clrf    Index       ; Yes, clear the buffer index.
311
    LFSR RXBuffer,Index ; Point to the buffer
312
    movf    INDF,W      ; Get the byte
313
    call    WriteI2C    ; Write to SSPBUF
314
    incf    Index,F     ; Increment the buffer index.
315
    return
316
 
317
State5:
318
    movf    Temp,W      ; NACK received when sending data to the master
319
    andlw   b'00101000' ; Mask RW bit in SSPSTAT
320
    xorlw   b'00101000' ;
321
    btfss   STATUS,Z    ;
322
    goto    I2CErr  ;
323
    return              ; If we aren?t in State5, then something is
324
                        ; wrong.
325
I2CErr nop
326
    banksel PORTB       ; Something went wrong! Set LED
327
    bsf     PORTB,2     ; and loop forever. WDT will reset
328
    goto    $           ; device, if enabled.
329
    return
330
;---------------------------------------------------------------------
331
; WriteI2C
332
;---------------------------------------------------------------------
333
WriteI2C
334
    banksel SSPSTAT
335
    btfsc   SSPSTAT,BF  ; Is the buffer full?
336
    goto    WriteI2C    ; Yes, keep waiting.
337
    banksel SSPCON      ; No, continue.
338
DoI2CWrite
339
    bcf     SSPCON,WCOL ; Clear the WCOL flag.
340
    movwf   SSPBUF      ; Write the byte in WREG
341
    btfsc   SSPCON,WCOL ; Was there a write collision?
342
    goto    DoI2CWrite
343
    bsf     SSPCON,CKP  ; Release the clock.
344
    return
345
 
346
end