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
11 include ../iwjpictest/clockvaries.inc
13 include morse+auto.inc
15 ;======================================================================
20 ; m_... routines used by master only
21 ; s_... routines used by slave only
22 ; <any other name> routines used by both
24 ; [ms]_event_... event handler, branched to from interrupt
25 ; handler; conditions are as in the name;
26 ; should `return' at end which will return
27 ; from i2c[ms]_interrupt
29 ; [sm]_event_bad[_...] event handler which panics; called when i2c
30 ; controller did something unexpected
32 ; m_improper_... panics; called when main program
33 ; does something wrong
35 ; [ms]_<anything else> routines or labels of some other kind
37 ; Whenever flow does not pass past the end of some code, we
38 ; have a boundary `;----------', and when flow passes past
39 ; an important label we sometimes mark it specially with `;...',
44 ; bt_f_if0 st, st_something
48 ; m_event_several_including_spong
49 ; bs_f st, st_sponging
50 ; bra metasyntacticing
55 ;============================================================
56 ; COMMON ADMINISTRATIVE ROUTINES and VARIABLES
62 sspcon2 res 1 ; master only
63 slave res 1 ; master only
68 ; st is a bitmask, bit set in visible states:
70 st_starting equ 7 ; Writing-Setup?,Reading-Busy?
71 st_addressing equ 6 ; Writing-Setup?,Reading-Busy?
72 st_writing equ 5 ; Writing-* [Idle-going-]Receiving
73 st_subsequent equ 4 ; Writing? Receiving
74 st_reading equ 3 ; Reading-* Transmitting
75 st_awaiting equ 2 ; Reading-Wait
76 st_acking equ 1 ; Reading-Busy?,Stopping(from read)
77 st_stopping equ 0 ; Stopping
78 ; ...? means not always set in that state
84 ; computes slave address in form suitable for use in i2c controller
85 ; actual i2c slave address is (slave number) + 0b0001000
86 ; W slave number i2c address * 2
91 ;======================================================================
99 mov_lw 0x08 ; !SSPEN, Master mode
101 clr_f SSPCON2 ; nothing going
102 mov_lw 0x80 ; SMP(noslew), !CKE(!smbus)
110 ; We have an interrupt:
112 mov_ff SSPSTAT, sspstat
113 mov_ff SSPCON1, sspcon1
114 mov_ff SSPCON2, sspcon2
118 mov_lw (1<<WCOL) | (1<<SSPOV)
122 ; No ? Well, then the I2C should be idle now:
124 and_lw ~((1<<ACKSTAT) | (1<<ACKDT)) ; those two are ok if set
128 bt_f_if1 sspstat, R_W
131 bt_f_if1 st, st_stopping
132 bra m_event_done_stopping
134 bt_f_if1 st, st_starting
135 bra m_event_done_starting
138 bt_f_if1 st, st_addressing
139 bra m_event_done_addressing
141 bt_f_if1 st, st_writing
142 bra m_event_done_writing
144 bt_f_if1 st, st_acking
145 bra m_event_done_acking
147 bt_f_if1 st, st_reading
148 bra m_event_done_reading
153 ;========================================
154 ; MASTER - STARTING, ADDRESSING, STOPPING
158 ; st checked for busyness correct
159 ; st_reading/writing set unchanged
160 ; st_starting clear set
162 ; slave any slave_number
163 ; expects to return directly to main program (caller)
165 bra_z m_improper_slave
167 bra_nz m_improper_slave
173 m_event_done_starting
177 bt_f_if1 st, st_reading
178 bs_w 0 ; address bottom bit means read
182 bs_f st, st_addressing
186 m_event_done_addressing
187 bt_f_if1 sspcon2, ACKSTAT
188 bra m_bad_address_ack
191 bc_f st, st_addressing
192 bt_f_if1 st, st_reading
193 bra m_event_done_addressing_read
194 bra m_event_done_addressing_write
198 ; st_stopping clear set
199 ; st_reading/acking/writing any unchanged
200 ; expects to return directly to main program or to end interrupt handler
206 m_event_done_stopping
219 ;========================================
225 ; State Idle Writing-Setup
228 bra m_improper_write_start
235 ; Did slave ack our byte ? It had better have done !
236 bt_f_if1 sspcon2, ACKSTAT
239 bs_f st, st_subsequent
242 m_event_done_addressing_write
244 ; st_addressing cleared
245 call i2cmu_write_next_byte
246 bra_z m_event_write_mustfinish
247 ; OK, we have the next byte:
253 m_event_write_mustfinish
254 bt_f_if0 st, st_subsequent
255 bra m_improper_write_finish
260 m_improper_write_start
264 m_improper_write_finish
267 ;========================================
273 ; State Idle Reading-Busy
276 bra m_improper_read_start
282 m_event_done_addressing_read
283 m_event_done_acking_readmore
285 ; st_addressing/acking cleared
297 goto i2cmu_read_got_byte
301 ; State Reading-Wait Reading-Busy
302 bt_f_if0 st, st_awaiting
303 bra m_improper_read_another
304 ; OK, we're fine to read another:
308 ; st_reading 1 iff not done unchanged
309 ; st_awaiting still set cleared
310 ; st_acking clear set
311 ; expects to return directly to main program or to end interrupt handler
314 bc_f SSPCON2, ACKDT ; ACKDT=0 means to acknowledge
315 bt_f_if0 st, st_reading
316 bs_f SSPCON2, ACKDT ; don't ack last byte
322 ; State Reading-Wait Stopping
325 bt_f_if0 st, st_awaiting
326 bra m_improper_read_done
335 bt_f_if1 st, st_reading
336 bra m_event_done_acking_readmore
341 m_improper_read_start
345 m_improper_read_another
352 ;======================================================================
357 ; W slave number undefined
361 mov_lw 0x16 ; !SSPEN, CKP(release), I2C 7-bit slave no-SP-int
363 mov_lw 0x01 ; !GCEN, SEN
365 mov_lw 0x80 ; SMP(noslew), !CKE(!smbus)
368 ; Actually engages the I2C controller, which must already have
369 ; been set up (all but SSPEN):
370 ; SSPADD,SSPCON1,SSPCON2 configured correctly unchanged
371 ; SSPSTAT configured correctly unchanged, except:
372 ; SSPSTAT<SSPEN> 0 (disabled) 1 (enabled)
373 ; SSPIE 0 (disabled) 1 (enabled)
374 ; TRISB<1,0> any configured for I2C
375 ; SSPIP any configured correctly
376 ; GIEL 0 (disabled) 0 (disabled)
377 ; ssp* shadows any all bits set
389 ;========================================
390 ; SLAVE - INTERRUPT HANDLING
392 ; In general, we figure out our state and then see what kind of events
393 ; we were expecting. Bits we want to check:
394 ; 80 60 20 10 08 04 02 01
395 ; SMP CKE D_A P S R_W UA BF
396 ; set clr data? stop start read? clr full?
397 ; (we don't usually mention SMP, CKE and UA below)
401 chkvals_start_sspstat macro
405 chkval macro lastval, value, label
406 xor_lw value ^ lastval
410 chkvals_addrrecv macro lastval
411 chkval lastval, 0x8c, s_event_idle_addrrecvread ; A,!P, S,R,!BF
412 chkval 0x8c, 0x89, s_event_idle_addrrecvwrite ; A,!P, S,W,BF
414 chkvals_addrrecv_lastval equ 0x89
420 ; We have an interrupt:
422 ; Firstly, clear the interrupt flag so that if something else happens
423 ; while we faff, the interrupt will be regenerated:
426 mov_ff SSPSTAT, sspstat
427 mov_ff SSPCON1, sspcon1
430 mov_lw (1<<WCOL) | (1<<SSPOV)
434 bt_f_if1 st, st_reading
437 bt_f_if1 st, st_writing
441 chkvals_start_sspstat
444 panic morse_SS ; slave, interrupt, controller in bad state
446 ;========================================
450 s_event_idle_addrrecvread
452 call i2csu_read_begin
453 bra s_events_reading_datasend
457 chkvals_start_sspstat
458 chkval 0, 0xac, s_event_reading_datasent ; D,!P, S,R,!BF
465 ; Whatever is happening, we're done reading now !
469 chkvals_start_sspstat
470 chkval 0, 0xa8, s_event_reading_datanack ; D,!P, S,!R,!BF
471 ; Or, maybe it was nack and then we were reselected:
472 chkvals_addrrecv 0xa8
477 s_event_reading_datasent
478 call i2csu_read_another
479 s_events_reading_datasend
482 s_event_reading_datanack
485 ;========================================
489 s_event_idle_addrrecvwrite
490 bs_f SSPCON1, 3 ; we'll need the Stop interrupt
492 ; well, this is all fine so far, so do carry on:
495 ; W any byte from master
496 ; i2c controller waiting due to SEN etc continuing with next byte
503 chkvals_start_sspstat
504 chkval 0, 0xa9, s_event_writing_datarecv ; D,!P, S,W,BF
506 ; Well, we're done writing now in any case
508 bc_f SSPCON1, 3 ; no Start and Stop interrupts any more
509 call i2csu_write_done
511 ; Who knows what might have happened. We may have
512 ; missed a number of S and P due to delay between
513 ; clearing SSPIF and SSPM3(s&p-intrs) so we can't be
516 ; First, the nice cases:
517 chkvals_start_sspstat
522 and_lw 0xc7 ; ?D_A, ?P; ?S
523 xor_lw 0x80 ; SMP, !CKE, !R_W, !UA, !BF
531 s_event_writing_datarecv
532 rcall s_write_slurpbyte
534 bt_f_if1 st, st_subsequent
535 goto i2csu_write_another
536 ; not subsequent (yet):
538 bs_f st, st_subsequent
539 goto i2csu_write_begin
541 ;======================================================================