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_LOAD    PORTA,2
49
 
50
    #define LED      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
    udata
65
    STATUSsave  res 1
66
    FSRsave     res 1
67
    PCLATHsave  res 1
68
    Index       res 1           ; Index to receive buffer
69
    Temp        res 1           ;
70
    in_loop    res 1           ; Loop for the shift registe
71
    in_byte    res 1
72
    i2c_recv    res 1
73
 
74
 
75
 
76
; device.
77
;---------------------------------------------------------------------
78
; Vectors
79
;---------------------------------------------------------------------
80
STARTUP code 0x00
81
    nop
82
    goto    Startup ;
83
    nop             ; 0x0002
84
    nop             ; 0x0003
85
    goto    ISR     ; 0x0004
86
PROG code
87
;---------------------------------------------------------------------
88
; Macros
89
;---------------------------------------------------------------------
90
memset macro Buf_addr,Value,Length
91
    movlw   Length      ; This macro loads a range of data memory
92
    movwf   Temp        ; with a specified value. The starting
93
    movlw   Buf_addr    ; address and number of bytes are also
94
    movwf   FSR         ; specified.
95
SetNext movlw Value
96
    movwf   INDF
97
    incf    FSR,F
98
    decfsz  Temp,F
99
    goto    SetNext
100
    endm
101
LFSR macro Address,Offset   ; This macro loads the correct value
102
    movlw   Address         ; into the FSR given an initial data
103
    movwf   FSR             ; memory address and offset value.
104
    movf    Offset,W
105
    addwf   FSR,F
106
    endm
107
 
108
;---------------------------------------------------------------------
109
; Main Code
110
;---------------------------------------------------------------------
111
Startup
112
    bcf     STATUS,RP1
113
    bsf     STATUS,RP0
114
    call    Setup
115
    bsf     SR_LOAD
116
    bcf     SR_CLOCK
117
 
118
Main clrwdt ; Clear the watchdog timer.
119
    banksel PORTA
120
    call    shift_in
121
    movfw   in_byte
122
    movwf   RXBuffer
123
 
124
    goto    Main ; Loop forever.
125
 
126
shift_in
127
    clrf    in_byte
128
 
129
    movlw   .8          ; Do this 8 times (Once per bit)
130
    movwf   in_loop
131
 
132
    bcf     SR_LOAD         ; Strobe to have SR load values
133
    nop
134
    bsf     SR_LOAD
135
 
136
bit_in
137
                            ; Values are oppsite due to PULL-UP resistors
138
    btfss   SR_DATA         ; If DATA is low
139
    bsf     STATUS,C        ;   -> Set high
140
    btfsc   SR_DATA
141
    bcf     STATUS,C
142
    rlf     in_byte,f       ; Right rotate (we recieve lowest bit first)
143
 
144
    bsf     SR_CLOCK    ; Strobe a clock to move to next bit
145
    nop
146
    bcf     SR_CLOCK
147
 
148
    decfsz  in_loop,f
149
    goto    bit_in
150
 
151
    return
152
 
153
;---------------------------------------------------------------------
154
; Interrupt Code
155
;---------------------------------------------------------------------
156
ISR
157
    movwf   WREGsave    ; Save WREG
158
    movf    STATUS,W    ; Get STATUS register
159
    banksel STATUSsave  ; Switch banks, if needed.
160
    movwf   STATUSsave  ; Save the STATUS register
161
    movf    PCLATH,W    ;
162
    movwf   PCLATHsave  ; Save PCLATH
163
    movf    FSR,W       ;
164
    movwf   FSRsave     ; Save FSR
165
    banksel PIR1
166
    btfss   PIR1,SSPIF  ; Is this a SSP interrupt?
167
    goto    $           ; No, just trap here.
168
    bcf     PIR1,SSPIF
169
    call    SSP_Handler ; Yes, service SSP interrupt.
170
    banksel FSRsave
171
    movf    FSRsave,W   ;
172
    movwf   FSR         ; Restore FSR
173
    movf    PCLATHsave,W;
174
    movwf   PCLATH      ; Restore PCLATH
175
    movf    STATUSsave,W;
176
    movwf   STATUS      ; Restore STATUS
177
    swapf   WREGsave,F  ;
178
    swapf   WREGsave,W  ; Restore WREG
179
    retfie              ; Return from interrupt.
180
;---------------------------------------------------------------------
181
Setup
182
;
183
; Initializes program variables and peripheral registers.
184
;---------------------------------------------------------------------
185
    banksel PCON
186
    bsf     PCON,NOT_POR
187
    bsf     PCON,NOT_BOR
188
    banksel ANSEL
189
    movlw   0x00
190
    movwf   ANSEL
191
    banksel Index       ; Clear various program variables
192
    clrf    Index
193
    clrf    PORTB
194
    clrf    PIR1
195
 
196
    banksel TRISB
197
    clrf    TRISB
198
    bsf     TRISB,4
199
    bsf     TRISB,1
200
 
201
    banksel TRISA
202
    clrf    TRISA
203
    bsf     TRISA,0     ; PortA,2: SR_Load is an input
204
    bcf     LED
205
 
206
    banksel i2c_recv
207
    clrf    i2c_recv
208
 
209
    movlw   0x36        ; Setup SSP module for 7-bit
210
    banksel SSPCON
211
    movwf   SSPCON      ; address, slave mode
212
    movlw   NODE_ADDR
213
    banksel SSPADD
214
    movwf   SSPADD
215
    clrf    SSPSTAT
216
    banksel PIE1        ; Enable interrupts
217
    bsf     PIE1,SSPIE
218
    bsf     INTCON,PEIE ; Enable all peripheral interrupts
219
    bsf     INTCON,GIE  ; Enable global interrupts
220
    bcf     STATUS,RP0
221
    return
222
;---------------------------------------------------------------------
223
SSP_Handler
224
 
225
;---------------------------------------------------------------------
226
; The I2C code below checks for 5 states:
227
;---------------------------------------------------------------------
228
; State 1: I2C write operation, last byte was an address byte.
229
; SSPSTAT bits: S = 1, D_A = 0, R_W = 0, BF = 1
230
;
231
; State 2: I2C write operation, last byte was a data byte.
232
; SSPSTAT bits: S = 1, D_A = 1, R_W = 0, BF = 1
233
;
234
; State 3: I2C read operation, last byte was an address byte.
235
; SSPSTAT bits: S = 1, D_A = 0, R_W = 1 (see Appendix C for more information)
236
;
237
; State 4: I2C read operation, last byte was a data byte.
238
; SSPSTAT bits: S = 1, D_A = 1, R_W = 1, BF = 0
239
;
240
; State 5: Slave I2C logic reset by NACK from master.
241
; SSPSTAT bits: S = 1, D_A = 1, BF = 0 (see Appendix C for more information)
242
;
243
; For convenience, WriteI2C and ReadI2C functions have been used.
244
;----------------------------------------------------------------------
245
    banksel SSPSTAT
246
    movf    SSPSTAT,W   ; Get the value of SSPSTAT
247
    andlw   b'00101101' ; Mask out unimportant bits in SSPSTAT.
248
    banksel Temp        ; Put masked value in Temp
249
    movwf   Temp        ; for comparision checking.
250
State1:                 ; Write operation, last byte was an
251
    movlw   b'00001001' ; address, buffer is full.
252
    xorwf   Temp,W      ;
253
    btfss   STATUS,Z    ; Are we in State1?
254
    goto    State2      ; No, check for next state.....
255
    memset RXBuffer,0,RX_BUF_LEN ; Clear the receive buffer.
256
    clrf    Index       ; Clear the buffer index.
257
    banksel SSPBUF      ; Do a dummy read of the SSPBUF.
258
    movf    SSPBUF,W
259
    return
260
State2:                 ; Write operation, last byte was data,
261
    movlw   b'00101001' ; buffer is full.
262
    xorwf   Temp,W
263
    btfss   STATUS,Z    ; Are we in State2?
264
    goto    State3      ; No, check for next state.....
265
    LFSR RXBuffer,Index ; Point to the buffer.
266
    banksel SSPBUF      ; Get the byte from the SSP.
267
    movf    SSPBUF,W
268
    movwf   INDF        ; Put it in the buffer.
269
    incf    Index,F     ; Increment the buffer pointer.
270
    movf    Index,W     ; Get the current buffer index.
271
    sublw   RX_BUF_LEN  ; Subtract the buffer length.
272
    btfsc   STATUS,Z    ; Has the index exceeded the buffer length?
273
    clrf    Index       ; Yes, clear the buffer index.
274
    bsf     i2c_recv,0  ; Data received on i2c
275
    return
276
State3:                 ; Read operation, last byte was an address,
277
    movf    Temp,W ;
278
    andlw   b'00101100' ; Mask BF bit in SSPSTAT
279
    xorlw   b'00001100'
280
    btfss   STATUS,Z    ; Are we in State3?
281
    goto    State4      ; No, check for next state.....
282
    clrf    Index       ; Clear the buffer index.
283
    LFSR RXBuffer,Index ; Point to the buffer
284
    movf    INDF,W      ; Get the byte from buffer.
285
    call    WriteI2C    ; Write the byte to SSPBUF
286
    incf    Index,F     ; Increment the buffer index.
287
    return
288
State4:                 ; Read operation, last byte was data,
289
    banksel SSPCON      ; buffer is empty.
290
    btfsc   SSPCON, CKP
291
    goto    State5
292
 
293
    movlw   b'00101100'
294
    xorwf   Temp,W
295
    btfss   STATUS,Z    ; Are we in State4?
296
    goto    State5      ; No, check for next state....
297
    movf    Index,W     ; Get the current buffer index.
298
    sublw   RX_BUF_LEN  ; Subtract the buffer length.
299
    btfsc   STATUS,Z    ; Has the index exceeded the buffer length?
300
    clrf    Index       ; Yes, clear the buffer index.
301
    LFSR RXBuffer,Index ; Point to the buffer
302
    movf    INDF,W      ; Get the byte
303
    call    WriteI2C    ; Write to SSPBUF
304
    incf    Index,F     ; Increment the buffer index.
305
    return
306
 
307
State5:
308
    movf    Temp,W      ; NACK received when sending data to the master
309
    andlw   b'00101000' ; Mask RW bit in SSPSTAT
310
    xorlw   b'00101000' ;
311
    btfss   STATUS,Z    ;
312
    goto    I2CErr  ;
313
    return              ; If we aren?t in State5, then something is
314
                        ; wrong.
315
I2CErr nop
316
    banksel PORTB       ; Something went wrong! Set LED
317
    bsf     PORTB,2     ; and loop forever. WDT will reset
318
    goto    $           ; device, if enabled.
319
    return
320
;---------------------------------------------------------------------
321
; WriteI2C
322
;---------------------------------------------------------------------
323
WriteI2C
324
    banksel SSPSTAT
325
    btfsc   SSPSTAT,BF  ; Is the buffer full?
326
    goto    WriteI2C    ; Yes, keep waiting.
327
    banksel SSPCON      ; No, continue.
328
DoI2CWrite
329
    bcf     SSPCON,WCOL ; Clear the WCOL flag.
330
    movwf   SSPBUF      ; Write the byte in WREG
331
    btfsc   SSPCON,WCOL ; Was there a write collision?
332
    goto    DoI2CWrite
333
    bsf     SSPCON,CKP  ; Release the clock.
334
    return
335
 
336
end
337
 
338
 
339