1 ;######################################################################
2 ; i2clib.inc - I2C LIBRARY - IMPLEMENTATION
4 ; See i2clib.asm for documentation of the interface to this file.
6 include /usr/share/gputils/header/p18f458.inc
8 include ../iwjpictest/insn-aliases.inc
9 include ../iwjpictest/clockvaries.inc
11 include morse+auto.inc
13 ;======================================================================
18 ; m_... routines used by master only
19 ; s_... routines used by slave only
20 ; <any other name> routines used by both
22 ; [ms]_event_... event handler, branched to from interrupt
23 ; handler; conditions are as in the name;
24 ; should `return' at end which will return
25 ; from i2c[ms]_interrupt
27 ; [sm]_event_bad[_...] event handler which panics; called when i2c
28 ; controller did something unexpected
30 ; m_improper_... panics; called when main program
31 ; does something wrong
33 ; [ms]_<anything else> routines or labels of some other kind
35 ; Whenever flow does not pass past the end of some code, we
36 ; have a boundary `;----------', and when flow passes past
37 ; an important label we sometimes mark it specially with `;...',
42 ; bt_f_if0 st, st_something
46 ; m_event_several_including_spong
47 ; bs_f st, st_sponging
48 ; bra metasyntacticing
53 ;============================================================
54 ; COMMON ADMINISTRATIVE ROUTINES and VARIABLES
60 sspcon2 res 1 ; master only
61 slave res 1 ; master only
66 ; st is a bitmask, bit set in visible states:
68 st_starting equ 7 ; Writing-Setup?,Reading-Busy?
69 st_addressing equ 6 ; Writing-Setup?,Reading-Busy?
70 st_writing equ 5 ; Writing-* [Idle-going-]Receiving
71 st_subsequent equ 4 ; Writing? Receiving
72 st_reading equ 3 ; Reading-* Transmitting
73 st_awaiting equ 2 ; Reading-Wait
74 st_acking equ 1 ; Reading-Busy?,Stopping(from read)
75 st_stopping equ 0 ; Stopping
76 ; ...? means not always set in that state
82 ; computes slave address in form suitable for use in i2c controller
83 ; actual i2c slave address is (slave number) + 0b0001000
84 ; W slave number i2c address * 2
89 ;======================================================================
97 mov_lw 0x08 ; !SSPEN, Master mode
99 clr_f SSPCON2 ; nothing going
100 mov_lw 0x80 ; SMP(noslew), !CKE(!smbus)
108 ; We have an interrupt:
110 mov_ff SSPSTAT, sspstat
111 mov_ff SSPCON1, sspcon1
112 mov_ff SSPCON2, sspcon2
116 mov_lw (1<<WCOL) | (1<<SSPOV)
120 ; No ? Well, then the I2C should be idle now:
122 and_lw ~((1<<ACKSTAT) | (1<<ACKDT)) ; those two are ok if set
126 bt_f_if1 sspstat, R_W
129 bt_f_if1 st, st_stopping
130 bra m_event_done_stopping
132 bt_f_if1 st, st_starting
133 bra m_event_done_starting
136 bt_f_if1 st, st_addressing
137 bra m_event_done_addressing
139 bt_f_if1 st, st_writing
140 bra m_event_done_writing
142 bt_f_if1 st, st_acking
143 bra m_event_done_acking
145 bt_f_if1 st, st_reading
146 bra m_event_done_reading
151 ;========================================
152 ; MASTER - STARTING, ADDRESSING, STOPPING
156 ; st checked for busyness correct
157 ; st_reading/writing set unchanged
158 ; st_starting clear set
160 ; slave any slave_number
161 ; expects to return directly to main program (caller)
163 bra_z m_improper_slave
165 bra_nz m_improper_slave
171 m_event_done_starting
175 bt_f_if1 st, st_reading
176 bs_w 0 ; address bottom bit means read
180 bs_f st, st_addressing
184 m_event_done_addressing
185 bt_f_if1 sspcon2, ACKSTAT
186 bra m_bad_address_ack
189 bc_f st, st_addressing
190 bt_f_if1 st, st_reading
191 bra m_event_done_addressing_read
192 bra m_event_done_addressing_write
196 ; st_stopping clear set
197 ; st_reading/acking/writing any unchanged
198 ; expects to return directly to main program or to end interrupt handler
204 m_event_done_stopping
217 ;========================================
223 ; State Idle Writing-Setup
226 bra m_improper_write_start
233 ; Did slave ack our byte ? It had better have done !
234 bt_f_if1 sspcon2, ACKSTAT
237 bs_f st, st_subsequent
240 m_event_done_addressing_write
242 ; st_addressing cleared
243 call i2cmu_write_next_byte
244 bra_z m_event_write_mustfinish
245 ; OK, we have the next byte:
251 m_event_write_mustfinish
252 bt_f_if0 st, st_subsequent
253 bra m_improper_write_finish
258 m_improper_write_start
262 m_improper_write_finish
265 ;========================================
271 ; State Idle Reading-Busy
274 bra m_improper_read_start
280 m_event_done_addressing_read
281 m_event_done_acking_readmore
283 ; st_addressing/acking cleared
295 goto i2cmu_read_got_byte
299 ; State Reading-Wait Reading-Busy
300 bt_f_if0 st, st_awaiting
301 bra m_improper_read_another
302 ; OK, we're fine to read another:
306 ; st_reading 1 iff not done unchanged
307 ; st_awaiting still set cleared
308 ; st_acking clear set
309 ; expects to return directly to main program or to end interrupt handler
312 bc_f SSPCON2, ACKDT ; ACKDT=0 means to acknowledge
313 bt_f_if0 st, st_reading
314 bs_f SSPCON2, ACKDT ; don't ack last byte
320 ; State Reading-Wait Stopping
323 bt_f_if0 st, st_awaiting
324 bra m_improper_read_done
333 bt_f_if1 st, st_reading
334 bra m_event_done_acking_readmore
339 m_improper_read_start
343 m_improper_read_another
350 ;======================================================================
355 ; W slave number undefined
359 mov_lw 0x16 ; !SSPEN, CKP(release), I2C 7-bit slave no-SP-int
361 mov_lw 0x01 ; !GCEN, SEN
363 mov_lw 0x80 ; SMP(noslew), !CKE(!smbus)
366 ; Actually engages the I2C controller, which must already have
367 ; been set up (all but SSPEN):
368 ; SSPADD,SSPCON1,SSPCON2 configured correctly unchanged
369 ; SSPSTAT configured correctly unchanged, except:
370 ; SSPSTAT<SSPEN> 0 (disabled) 1 (enabled)
371 ; SSPIE 0 (disabled) 1 (enabled)
372 ; TRISB<1,0> any configured for I2C
373 ; SSPIP any configured correctly
374 ; GIEL 0 (disabled) 0 (disabled)
375 ; ssp* shadows any all bits set
387 ;========================================
388 ; SLAVE - INTERRUPT HANDLING
390 ; In general, we figure out our state and then see what kind of events
391 ; we were expecting. Bits we want to check:
392 ; 80 60 20 10 08 04 02 01
393 ; SMP CKE D_A P S R_W UA BF
394 ; set clr data? stop start read? clr full?
395 ; (we don't usually mention SMP, CKE and UA below)
399 chkvals_start_sspstat macro
403 chkval macro lastval, value, label
404 xor_lw value ^ lastval
408 chkvals_addrrecv macro lastval
409 chkval lastval, 0x8c, s_event_idle_addrrecvread ; A,!P, S,R,!BF
410 chkval 0x8c, 0x89, s_event_idle_addrrecvwrite ; A,!P, S,W,BF
412 chkvals_addrrecv_lastval equ 0x89
418 ; We have an interrupt:
420 ; Firstly, clear the interrupt flag so that if something else happens
421 ; while we faff, the interrupt will be regenerated:
424 mov_ff SSPSTAT, sspstat
425 mov_ff SSPCON1, sspcon1
428 mov_lw (1<<WCOL) | (1<<SSPOV)
432 bt_f_if1 st, st_reading
435 bt_f_if1 st, st_writing
439 chkvals_start_sspstat
442 panic morse_SS ; slave, interrupt, controller in bad state
444 ;========================================
448 s_event_idle_addrrecvread
450 call i2csu_read_begin
451 bra s_events_reading_datasend
455 chkvals_start_sspstat
456 chkval 0, 0xac, s_event_reading_datasent ; D,!P, S,R,!BF
463 ; Whatever is happening, we're done reading now !
467 chkvals_start_sspstat
468 chkval 0, 0xa8, s_event_reading_datanack ; D,!P, S,!R,!BF
469 ; Or, maybe it was nack and then we were reselected:
470 chkvals_addrrecv 0xa8
475 s_event_reading_datasent
476 call i2csu_read_another
477 s_events_reading_datasend
480 s_event_reading_datanack
483 ;========================================
487 s_event_idle_addrrecvwrite
488 bs_f SSPCON1, 3 ; we'll need the Stop interrupt
490 ; well, this is all fine so far, so do carry on:
493 ; W any byte from master
494 ; i2c controller waiting due to SEN etc continuing with next byte
501 chkvals_start_sspstat
502 chkval 0, 0xa9, s_event_writing_datarecv ; D,!P, S,W,BF
504 ; Well, we're done writing now in any case
506 bc_f SSPCON1, 3 ; no Start and Stop interrupts any more
507 call i2csu_write_done
509 ; Who knows what might have happened. We may have
510 ; missed a number of S and P due to delay between
511 ; clearing SSPIF and SSPM3(s&p-intrs) so we can't be
514 ; First, the nice cases:
515 chkvals_start_sspstat
520 and_lw 0xc7 ; ?D_A, ?P; ?S
521 xor_lw 0x80 ; SMP, !CKE, !R_W, !UA, !BF
529 s_event_writing_datarecv
530 rcall s_write_slurpbyte
532 bt_f_if1 st, st_subsequent
533 goto i2csu_write_another
534 ; not subsequent (yet):
536 bs_f st, st_subsequent
537 goto i2csu_write_begin
539 ;======================================================================