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
10 include morse+auto.inc
12 ;======================================================================
17 ; m_... routines used by master only
18 ; s_... routines used by slave only
19 ; <any other name> routines used by both
21 ; [ms]_event_... event handler, branched to from interrupt
22 ; handler; conditions are as in the name;
23 ; should `return' at end which will return
24 ; from i2c[ms]_interrupt
26 ; [sm]_event_bad[_...] event handler which panics; called when i2c
27 ; controller did something unexpected
29 ; m_improper_... panics; called when main program
30 ; does something wrong
32 ; [ms]_<anything else> routines or labels of some other kind
34 ; Whenever flow does not pass past the end of some code, we
35 ; have a boundary `;----------', and when flow passes past
36 ; an important label we sometimes mark it specially with `;...',
41 ; bt_f_if0 st, st_something
45 ; m_event_several_including_spong
46 ; bs_f st, st_sponging
47 ; bra metasyntacticing
52 ;============================================================
53 ; COMMON ADMINISTRATIVE ROUTINES and VARIABLES
59 sspcon2 res 1 ; master only
60 slave res 1 ; master only
65 ; st is a bitmask, bit set in visible states:
67 st_starting equ 7 ; Writing-Setup?,Reading-Busy?
68 st_addressing equ 6 ; Writing-Setup?,Reading-Busy?
69 st_writing equ 5 ; Writing-* [Idle-going-]Receiving
70 st_subsequent equ 4 ; Writing? Receiving
71 st_reading equ 3 ; Reading-* Transmitting
72 st_awaiting equ 2 ; Reading-Wait
73 st_acking equ 1 ; Reading-Busy?,Stopping(from read)
74 st_stopping equ 0 ; Stopping
75 ; ...? means not always set in that state
81 ; computes slave address in form suitable for use in i2c controller
82 ; actual i2c slave address is (slave number) + 0b0001000
83 ; W slave number i2c address * 2
88 ;======================================================================
93 mov_lw 100-1 ; baud rate = Fosc/(4*(SSPADD+1))
94 mov_wf SSPADD ; Fosc=20MHz, so SSPADD==99 means 50kbit/s
96 mov_lw 0x08 ; !SSPEN, Master mode
98 clr_f SSPCON2 ; nothing going
99 mov_lw 0x80 ; SMP(noslew), !CKE(!smbus)
107 ; We have an interrupt:
109 mov_ff SSPSTAT, sspstat
110 mov_ff SSPCON1, sspcon1
111 mov_ff SSPCON2, sspcon2
115 mov_lw (1<<WCOL) | (1<<SSPOV)
119 ; No ? Well, then the I2C should be idle now:
121 and_lw ~((1<<ACKSTAT) | (1<<ACKDT)) ; those two are ok if set
125 bt_f_if1 sspstat, R_W
128 bt_f_if1 st, st_stopping
129 bra m_event_done_stopping
131 bt_f_if1 st, st_starting
132 bra m_event_done_starting
135 bt_f_if1 st, st_addressing
136 bra m_event_done_addressing
138 bt_f_if1 st, st_writing
139 bra m_event_done_writing
141 bt_f_if1 st, st_acking
142 bra m_event_done_acking
144 bt_f_if1 st, st_reading
145 bra m_event_done_reading
150 ;========================================
151 ; MASTER - STARTING, ADDRESSING, STOPPING
155 ; st checked for busyness correct
156 ; st_reading/writing set unchanged
157 ; st_starting clear set
159 ; slave any slave_number
160 ; expects to return directly to main program (caller)
162 bra_z m_improper_slave
164 bra_nz m_improper_slave
170 m_event_done_starting
174 bt_f_if1 st, st_reading
175 bs_w 0 ; address bottom bit means read
179 bs_f st, st_addressing
183 m_event_done_addressing
184 bt_f_if1 sspcon2, ACKSTAT
185 bra m_bad_address_ack
188 bc_f st, st_addressing
189 bt_f_if1 st, st_reading
190 bra m_event_done_addressing_read
191 bra m_event_done_addressing_write
195 ; st_stopping clear set
196 ; st_reading/acking/writing any unchanged
197 ; expects to return directly to main program or to end interrupt handler
203 m_event_done_stopping
216 ;========================================
222 ; State Idle Writing-Setup
225 bra m_improper_write_start
232 ; Did slave ack our byte ? It had better have done !
233 bt_f_if1 sspcon2, ACKSTAT
236 bs_f st, st_subsequent
239 m_event_done_addressing_write
241 ; st_addressing cleared
242 call i2cmu_write_next_byte
243 bra_z m_event_write_mustfinish
244 ; OK, we have the next byte:
250 m_event_write_mustfinish
251 bt_f_if0 st, st_subsequent
252 bra m_improper_write_finish
257 m_improper_write_start
261 m_improper_write_finish
264 ;========================================
270 ; State Idle Reading-Busy
273 bra m_improper_read_start
279 m_event_done_addressing_read
280 m_event_done_acking_readmore
282 ; st_addressing/acking cleared
294 goto i2cmu_read_got_byte
298 ; State Reading-Wait Reading-Busy
299 bt_f_if0 st, st_awaiting
300 bra m_improper_read_another
301 ; OK, we're fine to read another:
305 ; st_reading 1 iff not done unchanged
306 ; st_awaiting still set cleared
307 ; st_acking clear set
308 ; expects to return directly to main program or to end interrupt handler
311 bc_f SSPCON2, ACKDT ; ACKDT=0 means to acknowledge
312 bt_f_if0 st, st_reading
313 bs_f SSPCON2, ACKDT ; don't ack last byte
319 ; State Reading-Wait Stopping
322 bt_f_if0 st, st_awaiting
323 bra m_improper_read_done
332 bt_f_if1 st, st_reading
333 bra m_event_done_acking_readmore
338 m_improper_read_start
342 m_improper_read_another
349 ;======================================================================
354 ; W slave number undefined
358 mov_lw 0x16 ; !SSPEN, CKP(release), I2C 7-bit slave no-SP-int
360 mov_lw 0x01 ; !GCEN, SEN
362 mov_lw 0x80 ; SMP(noslew), !CKE(!smbus)
365 ; Actually engages the I2C controller, which must already have
366 ; been set up (all but SSPEN):
367 ; SSPADD,SSPCON1,SSPCON2 configured correctly unchanged
368 ; SSPSTAT configured correctly unchanged, except:
369 ; SSPSTAT<SSPEN> 0 (disabled) 1 (enabled)
370 ; SSPIE 0 (disabled) 1 (enabled)
371 ; TRISB<1,0> any configured for I2C
372 ; SSPIP any configured correctly
373 ; GIEL 0 (disabled) 0 (disabled)
374 ; ssp* shadows any all bits set
386 ;========================================
387 ; SLAVE - INTERRUPT HANDLING
389 ; In general, we figure out our state and then see what kind of events
390 ; we were expecting. Bits we want to check:
391 ; 80 60 20 10 08 04 02 01
392 ; SMP CKE D_A P S R_W UA BF
393 ; set clr data? stop start read? clr full?
394 ; (we don't usually mention SMP, CKE and UA below)
398 chkvals_start_sspstat macro
402 chkval macro lastval, value, label
403 xor_lw value ^ lastval
407 chkvals_addrrecv macro lastval
408 chkval lastval, 0x8c, s_event_idle_addrrecvread ; A,!P, S,R,!BF
409 chkval 0x8c, 0x89, s_event_idle_addrrecvwrite ; A,!P, S,W,BF
411 chkvals_addrrecv_lastval equ 0x89
417 ; We have an interrupt:
419 ; Firstly, clear the interrupt flag so that if something else happens
420 ; while we faff, the interrupt will be regenerated:
423 mov_ff SSPSTAT, sspstat
424 mov_ff SSPCON1, sspcon1
427 mov_lw (1<<WCOL) | (1<<SSPOV)
431 bt_f_if1 st, st_reading
434 bt_f_if1 st, st_writing
438 chkvals_start_sspstat
441 panic morse_SS ; slave, interrupt, controller in bad state
443 ;========================================
447 s_event_idle_addrrecvread
449 call i2csu_read_begin
450 bra s_events_reading_datasend
454 chkvals_start_sspstat
455 chkval 0, 0xac, s_event_reading_datasent ; D,!P, S,R,!BF
462 ; Whatever is happening, we're done reading now !
466 chkvals_start_sspstat
467 chkval 0, 0xa8, s_event_reading_datanack ; D,!P, S,!R,!BF
468 ; Or, maybe it was nack and then we were reselected:
469 chkvals_addrrecv 0xa8
474 s_event_reading_datasent
475 call i2csu_read_another
476 s_events_reading_datasend
479 s_event_reading_datanack
482 ;========================================
486 s_event_idle_addrrecvwrite
487 bs_f SSPCON1, 3 ; we'll need the Stop interrupt
489 ; well, this is all fine so far, so do carry on:
492 ; W any byte from master
493 ; i2c controller waiting due to SEN etc continuing with next byte
500 chkvals_start_sspstat
501 chkval 0, 0xa9, s_event_writing_datarecv ; D,!P, S,W,BF
503 ; Well, we're done writing now in any case
505 bc_f SSPCON1, 3 ; no Start and Stop interrupts any more
506 call i2csu_write_done
508 ; Who knows what might have happened. We may have
509 ; missed a number of S and P due to delay between
510 ; clearing SSPIF and SSPM3(s&p-intrs) so we can't be
513 ; First, the nice cases:
514 chkvals_start_sspstat
519 and_lw 0xc7 ; ?D_A, ?P; ?S
520 xor_lw 0x80 ; SMP, !CKE, !R_W, !UA, !BF
528 s_event_writing_datarecv
529 rcall s_write_slurpbyte
531 bt_f_if1 st, st_subsequent
532 goto i2csu_write_another
533 ; not subsequent (yet):
535 bs_f st, st_subsequent
536 goto i2csu_write_begin
538 ;======================================================================