-
Notifications
You must be signed in to change notification settings - Fork 8
/
mios_iic.inc
387 lines (364 loc) · 13.1 KB
/
mios_iic.inc
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
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
; $Id$
;
; MIOS IIC 1st layer routines
;
; ==========================================================================
;
; Copyright 1998-2006 Thorsten Klose (tk@midibox.org)
; Licensed for personal non-commercial use only.
; All other rights reserved.
;
; ==========================================================================
;; IIC Pins (SCL/SDA)
MIOS_IIC_PORT_SCL EQU PORTD
MIOS_IIC_LAT_SCL EQU LATD
MIOS_IIC_TRIS_SCL EQU TRISD
MIOS_IIC_PIN_SCL EQU 5
MIOS_IIC_PORT_SDA EQU PORTA
MIOS_IIC_LAT_SDA EQU LATA
MIOS_IIC_TRIS_SDA EQU TRISA
MIOS_IIC_PIN_SDA EQU 4
;; if RA4 is not an open drain driver, set this to 0 (e.g. PIC18F4620)
;; in this version, we always disable it to get an identical behaviour
#define RA4_IS_OPEN_DRAIN 0
;; --------------------------------------------------------------------------
;; Delay Routines
;; --------------------------------------------------------------------------
MIOS_IIC_Delay_600ns_Stretch
;; 2 cycles for the call
btfss MIOS_BOX_CFG1, MIOS_BOX_CFG1_IIC_STRETCH_CLK ; 1/2 for this bit test
return ; 2 cycles for the return
;; if clock stretching enabled:
bsf MIOS_IIC_TRIS_SCL, MIOS_IIC_PIN_SCL
MIOS_IIC_Delay_600ns_StretchLoop
BRA_IFCLR MIOS_IIC_PORT_SCL, MIOS_IIC_PIN_SCL, ACCESS, MIOS_IIC_Delay_600ns_StretchLoop
bcf MIOS_IIC_TRIS_SCL, MIOS_IIC_PIN_SCL
return
MIOS_IIC_Delay_600ns
;; 2 cycles for the call
nop ; 1 cycle for the nop
;; 2 cycles for the return
;; one for the following instruction
return
MIOS_IIC_Delay_1300ns
;; 2 cycles for the call
nop
nop
nop
nop
nop
nop
nop
;; 2 cycles for the return
;; one for the following instruction
return
;; --------------------------------------------------------------------------
;; FUNCTION: MIOS_IIC_Start
;; C_DECLARATION: void MIOS_IIC_Start(void)
;; DESCRIPTION: sends the IIC start condition (SCL=1, SDA 1->0)
;; IN: -
;; C_IN: -
;; OUT: -
;; C_OUT: -
;; USES: -
;; EXAMPLE:
;; see MIOS_IIC_ByteSend and MIOS_IIC_ByteReceive
;; C_EXAMPLE:
;; see MIOS_IIC_ByteSend and MIOS_IIC_ByteReceive
;; --------------------------------------------------------------------------
MIOS_IIC_Start
bsf MIOS_BOX_STAT, MIOS_BOX_STAT_BS_AVAILABLE
#if RA4_IS_OPEN_DRAIN == 0
bcf MIOS_IIC_TRIS_SDA, MIOS_IIC_PIN_SDA ; SDA = output
#endif
bsf MIOS_IIC_LAT_SDA, MIOS_IIC_PIN_SDA ; SDA -> 1
bsf MIOS_IIC_LAT_SCL, MIOS_IIC_PIN_SCL ; SCL -> 1
rcall MIOS_IIC_Delay_600ns_Stretch
bcf MIOS_IIC_LAT_SDA, MIOS_IIC_PIN_SDA ; SDA -> 0
rcall MIOS_IIC_Delay_600ns
bcf MIOS_IIC_LAT_SCL, MIOS_IIC_PIN_SCL ; SCL -> 0
return
;; --------------------------------------------------------------------------
;; FUNCTION: MIOS_IIC_Stop
;; C_DECLARATION: void MIOS_IIC_Stop(void)
;; DESCRIPTION: sends the IIC stop condition (SCL=0->1, SDA 0->1)
;; IN: -
;; C_IN: -
;; OUT: -
;; C_OUT: -
;; USES: -
;; EXAMPLE:
;; see MIOS_IIC_ByteSend and MIOS_IIC_ByteReceive
;; C_EXAMPLE:
;; see MIOS_IIC_ByteSend and MIOS_IIC_ByteReceive
;; --------------------------------------------------------------------------
MIOS_IIC_Stop
bcf MIOS_IIC_LAT_SCL, MIOS_IIC_PIN_SCL ; SCL -> 0
bcf MIOS_IIC_LAT_SDA, MIOS_IIC_PIN_SDA ; SDA -> 0
rcall MIOS_IIC_Delay_600ns
bsf MIOS_IIC_LAT_SCL, MIOS_IIC_PIN_SCL ; SCL -> 1
rcall MIOS_IIC_Delay_600ns_Stretch
bsf MIOS_IIC_LAT_SDA, MIOS_IIC_PIN_SDA ; SDA -> 1
return
;; --------------------------------------------------------------------------
;; Check Ack
;; --------------------------------------------------------------------------
MIOS_IIC_CheckAck
bsf MIOS_IIC_LAT_SDA, MIOS_IIC_PIN_SDA ; SDA = input
#if RA4_IS_OPEN_DRAIN == 0
bsf MIOS_IIC_TRIS_SDA, MIOS_IIC_PIN_SDA ; SDA = input
#endif
nop
nop
bsf MIOS_IIC_LAT_SCL, MIOS_IIC_PIN_SCL ; SCL -> 1
rcall MIOS_IIC_Delay_600ns_Stretch
btfsc MIOS_IIC_PORT_SDA, MIOS_IIC_PIN_SDA
bcf MIOS_BOX_STAT, MIOS_BOX_STAT_BS_AVAILABLE ; notify that EEPROM is not available
bcf MIOS_IIC_LAT_SCL, MIOS_IIC_PIN_SCL ; SCL -> 0
rcall MIOS_IIC_Delay_1300ns
#if RA4_IS_OPEN_DRAIN == 0
bcf MIOS_IIC_TRIS_SDA, MIOS_IIC_PIN_SDA ; SDA = output
#endif
;; supported since MIOS V1.9: set ZERO flag if NAK received
iorlw 0xff
btfss MIOS_BOX_STAT, MIOS_BOX_STAT_BS_AVAILABLE
andlw 0x00
return
;; --------------------------------------------------------------------------
;; FUNCTION: MIOS_IIC_NakSend
;; C_DECLARATION: void MIOS_IIC_NakSend(void)
;; DESCRIPTION: sends a NAK (not acknowledge) to the slave(s)
;; IN: -
;; C_IN: -
;; OUT: -
;; C_OUT: -
;; USES: -
;; EXAMPLE:
;; see MIOS_IIC_ByteSend and MIOS_IIC_ByteReceive
;; C_EXAMPLE:
;; see MIOS_IIC_ByteSend and MIOS_IIC_ByteReceive
;; --------------------------------------------------------------------------
MIOS_IIC_NakSend
;; currently SCL = 0 and SDA=1
bsf MIOS_IIC_LAT_SDA, MIOS_IIC_PIN_SDA ; SDA -> 1
rgoto MIOS_IIC_AckSend_Cont
;; --------------------------------------------------------------------------
;; FUNCTION: MIOS_IIC_AckSend
;; C_DECLARATION: void MIOS_IIC_AckSend
;; DESCRIPTION: sends a ACK (acknowledge) to the slave(s)
;; IN: -
;; C_IN: -
;; OUT: -
;; C_OUT: -
;; USES: -
;; EXAMPLE:
;; see MIOS_IIC_ByteSend and MIOS_IIC_ByteReceive
;; C_EXAMPLE:
;; see MIOS_IIC_ByteSend and MIOS_IIC_ByteReceive
;; --------------------------------------------------------------------------
MIOS_IIC_AckSend
;; currently SCL = 0 and SDA=1
bcf MIOS_IIC_LAT_SDA, MIOS_IIC_PIN_SDA ; SDA -> 0
MIOS_IIC_AckSend_Cont
#if RA4_IS_OPEN_DRAIN == 0
bcf MIOS_IIC_TRIS_SDA, MIOS_IIC_PIN_SDA ; SDA = output
#endif
nop ; wait > 100 ns
bsf MIOS_IIC_LAT_SCL, MIOS_IIC_PIN_SCL ; SCL -> 1
rcall MIOS_IIC_Delay_600ns_Stretch
bcf MIOS_IIC_LAT_SCL, MIOS_IIC_PIN_SCL ; SCL -> 0
rgoto MIOS_IIC_Delay_1300ns
;; --------------------------------------------------------------------------
;; FUNCTION: MIOS_IIC_ByteSend
;; C_DECLARATION: void MIOS_IIC_ByteSend(unsigned char b)
;; DESCRIPTION: sends a byte over the IIC bus and checks for acknowledge.<BR>
;; If the slave didn't send an acknowledge, the (MIOS_BOX_STAT_)BS_AVAILABLE
;; flag in MIOS_BOX_STAT will be cleared.
;; IN: byte which should be sent in WREG
;; C_IN: byte which should be sent in <b>
;; OUT: WREG==0x00 if NAK has been received, otherwise != 0x00
;; due to compatibility reasons, MIOS_BOX_STAT.MIOS_BOX_STAT_BS_AVAILABLE set so long ACK is received
;; C_OUT: returns 0x00 if NAK has been received, otherwise != 0x00
;; due to compatibility reasons, mios_box_stat.BS_AVAILABLE is set so long ACK is received
;; USES: BSR
;; EXAMPLE:
;;
;; ;; send 0x34, 0x56, 0x78 to the IIC slave with ID 0x12
;;
;; call MIOS_IIC_Start ; start IIC
;; movlw 0x12 ; send device address
;; call MIOS_IIC_ByteSend ; bit #0 cleared to notify a write!!!
;; movlw 0x34 ; send first data byte
;; call MIOS_IIC_ByteSend
;; movlw 0x56 ; send second data byte
;; call MIOS_IIC_ByteSend
;; movlw 0x78 ; send third data byte
;; call MIOS_IIC_ByteSend
;; call MIOS_IIC_Stop ; stop IIC
;;
;; For more details about the IIC protocol (officially called I2C), see
;; http://www.semiconductors.philips.com/buses/i2c/
;;
;; An enhanced example with retry can be
;; found at the MBHP_IIC_MIDI page
;; C_EXAMPLE:
;;
;; // send 0x34, 0x56, 0x78 to the IIC slave with ID 0x12
;;
;; MIOS_IIC_Start(); // start IIC
;; MIOS_IIC_ByteSend(0x12); // send device address
;; // bit #0 cleared to notify a write!!!
;; MIOS_IIC_ByteSend(0x34); // send first data byte
;; MIOS_IIC_ByteSend(0x56); // send second data byte
;; MIOS_IIC_ByteSend(0x78); // send third data byte
;; MIOS_IIC_Stop(); // stop IIC
;;
;; For more details about the IIC protocol (officially called I2C), see
;; http://www.semiconductors.philips.com/buses/i2c/
;;
;; An enhanced example with retry on NAK's can be
;; found at the MBHP_IIC_MIDI page
;; --------------------------------------------------------------------------
MIOS_IIC_ByteSend
SET_BSR MIOS_IIC_BUFFER
movwf MIOS_IIC_BUFFER, BANKED ; store value
movlw 0x08 ; loop 8 times
movwf MIOS_IIC_CTR, BANKED
MIOS_IIC_ByteSendLoop
btfsc MIOS_IIC_BUFFER, 7, BANKED
bsf MIOS_IIC_LAT_SDA, MIOS_IIC_PIN_SDA ; SDA -> 1
btfss MIOS_IIC_BUFFER, 7, BANKED
bcf MIOS_IIC_LAT_SDA, MIOS_IIC_PIN_SDA ; SDA -> 0
nop ; relax
nop
bsf MIOS_IIC_LAT_SCL, MIOS_IIC_PIN_SCL ; SCL -> 1
rcall MIOS_IIC_Delay_600ns_Stretch
bcf MIOS_IIC_LAT_SCL, MIOS_IIC_PIN_SCL ; SCL -> 0
; (wait > 1.3 us)
rcall MIOS_IIC_Delay_600ns
rlf MIOS_IIC_BUFFER, F, BANKED ; shift left value
decfsz MIOS_IIC_CTR, F, BANKED ; loop
rgoto MIOS_IIC_ByteSendLoop
rgoto MIOS_IIC_CheckAck ; check the acknowledge
;; --------------------------------------------------------------------------
;; FUNCTION: MIOS_IIC_ByteReceive
;; C_DECLARATION: unsigned char MIOS_IIC_ByteReceive(void)
;; DESCRIPTION: receives a byte from a IIC slave.
;; IN: -
;; C_IN: -
;; OUT: received byte in WREG
;; C_OUT: received byte in WREG
;; USES: BSR
;; EXAMPLE:
;;
;; ;; receive three bytes from the IIC slave with ID 0x12
;;
;; rcall MIOS_IIC_Start ; start IIC
;; movlw 0x12 | 1 ; send device address -
;; call MIOS_IIC_ByteSend ; set bit #0 to notify a read!!!
;; ;; don't continue if IIC device not available
;; BRA_IFCLR MIOS_BOX_STAT, MIOS_BOX_STAT_BS_AVAILABLE, ACCESS, ReadFailed
;;
;; call MIOS_IIC_ByteReceive ; read first byte
;; movwf TMP1 ; save it in TMP1
;; call MIOS_IIC_AckSend ; send acknowledge
;; call MIOS_IIC_ByteReceive ; read second byte
;; movwf TMP2 ; save it in TMP2
;; call MIOS_IIC_AckSend ; send acknowledge
;; call MIOS_IIC_ByteReceive ; read third byte
;; movwf TMP3 ; save it in TMP3
;; ReadFailed:
;; call MIOS_IIC_NakSend ; send disacknowledge!!!
;; call MIOS_IIC_Stop ; stop IIC
;;
;; For more details about the IIC protocol (officially called I2C), see
;; http://www.semiconductors.philips.com/buses/i2c/
;; C_EXAMPLE:
;;
;; // receive three bytes from the IIC slave with ID 0x12
;;
;; MIOS_IIC_Start(); // start IIC
;; MIOS_IIC_ByteSend(0x12 | 1); // send device address -
;; // set bit #0 to notify a read!!!
;; // don't continue if IIC device not available
;; if( MIOS_BOX_STAT.BS_AVAILABLE ) {
;; b0 = MIOS_IIC_ByteReceive(); // read first byte
;; MIOS_IIC_AckSend(); // send acknowledge
;; b1 = MIOS_IIC_ByteReceive(); // read second byte
;; MIOS_IIC_AckSend(); // send acknowledge
;; b2 = MIOS_IIC_ByteReceive(); // read third byte
;; }
;; MIOS_IIC_NakSend(); // send disacknowledge!!!
;; MIOS_IIC_Stop(); // stop IIC
;;
;; For more details about the IIC protocol (officially called I2C), see
;; http://www.semiconductors.philips.com/buses/i2c/
;; --------------------------------------------------------------------------
MIOS_IIC_ByteReceive
SET_BSR MIOS_IIC_BUFFER
clrf MIOS_IIC_BUFFER, BANKED
bsf MIOS_IIC_LAT_SDA, MIOS_IIC_PIN_SDA ; SDA = input
#if RA4_IS_OPEN_DRAIN == 0
bsf MIOS_IIC_TRIS_SDA, MIOS_IIC_PIN_SDA ; SDA = input
#endif
movlw 0x08 ; loop 8 times
movwf MIOS_IIC_CTR, BANKED
MIOS_IIC_ByteReceiveLoop
nop ; relax
nop
bsf MIOS_IIC_LAT_SCL, MIOS_IIC_PIN_SCL ; SCL -> 1
rcall MIOS_IIC_Delay_600ns_Stretch
rlf MIOS_IIC_BUFFER, F, BANKED ; shift left buffer
bcf MIOS_IIC_BUFFER, 0, BANKED ; copy status of SDA into rightmost bit
btfsc MIOS_IIC_PORT_SDA, MIOS_IIC_PIN_SDA
bsf MIOS_IIC_BUFFER, 0, BANKED
bcf MIOS_IIC_LAT_SCL, MIOS_IIC_PIN_SCL ; SCL -> 0
; (wait > 1.3 us)
rcall MIOS_IIC_Delay_600ns
decfsz MIOS_IIC_CTR, F, BANKED ; loop
rgoto MIOS_IIC_ByteReceiveLoop
movf MIOS_IIC_BUFFER, W, BANKED ; now copy the received value into W
return
;; --------------------------------------------------------------------------
;; FUNCTION: MIOS_IIC_CtrlSet
;; C_DECLARATION: void MIOS_IIC_CtrlSet(unsigned char ctrl)
;; DESCRIPTION: enables the "clock stretching" like specified in
;; the IIC specification http://www.semiconductors.philips.com/buses/i2c/
;; which is required for some IIC slaves which cannot service the bus
;; immediately on a request.
;; NOTE: if enabled, you have to add a 1k pull-up resistor to the SCL line (Pin #22 of the PIC)
;; IN: WREG = 0x00: clock stretching disabled
;; WREG = 0x01: clock stretching enabled
;; C_IN: <ctrl> = 0x00: clock stretching disabled
;; <ctrl> = 0x01: clock stretching enabled
;; OUT: -
;; USES: -
;; EXAMPLE:
;; ;; enable clock stretching
;; movlw 0x01
;; call MIOS_IIC_CtrlSet
;; C_EXAMPLE:
;; // enable clock stretching
;; MIOS_IIC_CtrlSet(0x01);
;; --------------------------------------------------------------------------
MIOS_IIC_CtrlSet
bcf MIOS_BOX_CFG1, MIOS_BOX_CFG1_IIC_STRETCH_CLK
btfsc WREG, 0
bsf MIOS_BOX_CFG1, MIOS_BOX_CFG1_IIC_STRETCH_CLK
return
;; --------------------------------------------------------------------------
;; FUNCTION: MIOS_IIC_CtrlGet
;; C_DECLARATION: unsigned char MIOS_IIC_CtrlGet(void)
;; DESCRIPTION: returns the IIC control status
;; IN: -
;; C_IN: -
;; OUT: WREG[0]: clock stretching enabled
;; C_OUT: bit 0 if return value: clock stretching enabled
;; USES: -
;; --------------------------------------------------------------------------
MIOS_IIC_CtrlGet
movlw 0x00
btfsc MIOS_BOX_CFG1, MIOS_BOX_CFG1_IIC_STRETCH_CLK
movlw 0x01
andlw 0xff ; fix STATUS
return