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 ../iwjpictest/clockvaries.inc
12 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
60 sspstat res 1 ; master only
61 sspcon1 res 1 ; master only
62 sspcon2 res 1 ; master only
63 slave res 1 ; master only
64 slave_next res 1 ; master only
69 ; st is a bitmask, bit set in visible states:
71 st_starting equ 7 ; Writing-Setup?, Reading-Busy?
72 st_addressing equ 6 ; Writing-Setup?, Reading-Busy?
73 st_writing equ 5 ; Writing-*, Stopping(after Reading-Wait:write_start)
74 st_subsequent equ 4 ; Writing?
75 st_reading equ 3 ; Reading-*
76 st_awaiting equ 2 ; Reading-Wait
77 st_acking equ 1 ; Reading-Busy?, Stopping(from read)
78 st_stopping equ 0 ; Stopping
79 ; ...? means not always set in that state
85 ; computes slave address in form suitable for use in i2c controller
86 ; actual i2c slave address is (slave number) + 0b0001000
87 ; W slave number i2c address * 2
93 improper_read_done_data
96 ;======================================================================
105 mov_lw 0x08 ; !SSPEN, Master mode
107 clr_f SSPCON2 ; nothing going
108 mov_lw 0x80 ; SMP(noslew), !CKE(!smbus)
110 bc_f IPR1, SSPIP ; low priority
117 ; We have an interrupt:
119 i2cm_interrupt_definite
120 mov_ff SSPSTAT, sspstat
121 mov_ff SSPCON1, sspcon1
122 mov_ff SSPCON2, sspcon2
126 mov_lw (1<<WCOL) | (1<<SSPOV)
130 ; No ? Well, then the I2C should be idle now:
132 and_lw ~((1<<ACKSTAT) | (1<<ACKDT)) ; those two are ok if set
136 bt_f_if1 sspstat, R_W
139 bt_f_if1 st, st_stopping
140 bra m_event_done_stopping
142 bt_f_if1 st, st_starting
143 bra m_event_done_starting
146 bt_f_if1 st, st_addressing
147 bra m_event_done_addressing
149 bt_f_if1 st, st_acking
150 bra m_event_done_acking
152 bt_f_if1 st, st_writing
153 bra m_event_done_writing
155 bt_f_if1 st, st_reading
156 bra m_event_done_reading
161 ;========================================
162 ; MASTER - STARTING, ADDRESSING, STOPPING
166 ; st checked for busyness correct
167 ; st_reading/writing one set, one clear unchanged
168 ; st_starting clear set
170 ; slave any slave_number
171 ; expects to return directly to main program (caller)
176 bra_nz m_improper_slave
189 m_event_done_starting
193 bt_f_if1 st, st_reading
194 bs_w 0 ; address bottom bit means read
198 bs_f st, st_addressing
202 m_event_done_addressing
203 bt_f_if1 sspcon2, ACKSTAT
204 bra m_bad_address_ack
207 bc_f st, st_addressing
208 bt_f_if1 st, st_reading
209 bra m_event_done_addressing_read
210 bra m_event_done_addressing_write
214 ; st_stopping clear set
215 ; st_reading/acking/writing any unchanged
216 ; expects to return directly to main program or to end interrupt handler
222 m_event_done_stopping
230 ;========================================
236 ; State Idle/Reading-Wait Writing-Setup
239 bra m_write_start_busy
246 ; Did slave ack our byte ? It had better have done !
247 bt_f_if1 sspcon2, ACKSTAT
250 bs_f st, st_subsequent
253 m_event_done_addressing_write
255 ; st_addressing cleared
256 call i2cmu_write_next_byte
257 bra_z m_event_write_mustfinish
258 ; OK, we have the next byte:
264 m_event_write_mustfinish
265 bt_f_if0 st, st_subsequent
266 bra m_improper_write_finish
271 m_improper_write_finish
274 ;========================================
280 ; State Idle Reading-Busy
283 bra m_read_start_busy
292 bt_f_if1 st, st_awaiting
293 bra m_address_different
298 ; Main program would like to address another slave for reading.
300 tst_f_ifnz slave_next
305 m_event_done_addressing_read
306 m_event_done_acking_readmore
308 ; st_addressing/acking cleared
320 goto i2cmu_read_got_byte
324 ; State Reading-Wait Reading-Busy
325 bt_f_if0 st, st_awaiting
326 bra m_improper_read_another
327 ; OK, we're fine to read another:
331 ; st_reading 1 iff not done unchanged
332 ; st_awaiting still set cleared
333 ; st_acking clear set
334 ; expects to return directly to main program or to end interrupt handler
337 bc_f SSPCON2, ACKDT ; ACKDT=0 means to acknowledge
338 bt_f_if0 st, st_reading
339 bs_f SSPCON2, ACKDT ; don't ack last byte
345 ; State Reading-Wait Stopping
348 bt_f_if0 st, st_awaiting
349 bra improper_read_done_data
358 bt_f_if1 st, st_reading
359 bra m_event_done_acking_readmore
363 ; ok, we want to read another:
366 bt_f_if0 st, st_writing ; because of i2cm_write_start ?
367 bs_f st, st_reading ; no, then we will want to read
369 bra m_start_or_restart
372 m_improper_read_another
375 ;======================================================================
380 ; W slave number undefined
384 mov_lw 0x16 ; !SSPEN, CKP(release), I2C 7-bit slave no-SP-int
386 mov_lw 0x01 ; !GCEN, SEN
388 mov_lw 0x80 ; SMP(noslew), !CKE(!smbus)
390 bs_f IPR1, SSPIP ; high priority
392 ; Actually engages the I2C controller, which must already have
393 ; been set up (all but SSPEN):
394 ; SSPADD,SSPCON1,SSPCON2 configured correctly unchanged
395 ; SSPSTAT configured correctly unchanged, except:
396 ; SSPSTAT<SSPEN> 0 (disabled) 1 (enabled)
397 ; SSPIE 0 (disabled) 1 (enabled)
398 ; SSPIF configured correctly unchanged
399 ; TRISB<1,0> any configured for I2C
400 ; SSPIP any configured correctly
401 ; GIEL 0 (disabled) 0 (disabled)
402 ; ssp* shadows any all bits set
413 ;========================================
416 ; In general, we figure out our state and then see what kind of events
417 ; we were expecting. Bits we want to check:
418 ; 80 40 20 10 08 04 02 01
419 ; SMP CKE D_A P S R_W UA BF
420 ; set clr data? stop start read? clr full?
421 ; (we don't usually mention SMP, CKE and UA below)
423 ; Labels of the form s_event_* are branches of the interrupt
424 ; handler and are supposed to finish with return.
427 ; Macros: chkvals_start and chkval
429 chkvals_start macro chvals_what
433 chkval macro chkval_lastval, chkval_value, chkval_label
434 xor_lw chkval_value ^ chkval_lastval
441 s_write_slurpbyte macro
442 ; W any byte from master
443 ; i2c controller waiting due to SEN etc continuing with next byte
448 ;----------------------------------------
453 ;----------------------------------------
454 ; branches from the ISR
457 s_event_addrrecvwrite
459 goto i2csu_write_begin
462 s_event_reading_datanack
466 s_event_writing_datarecv
468 goto i2csu_write_data
472 i2cpanic morse_IH ; unknown high-priority interrupt
474 ;----------------------------------------
475 i2cs_interrupt ; 4cy interrupt latency + 3cy until branch to here
478 ; We have an interrupt:
480 mov_lw (1<<WCOL) | (1<<SSPOV)
484 ; Firstly, clear the interrupt flag so that if something else happens
485 ; while we faff, the interrupt will be regenerated:
488 chkvals_start SSPSTAT
489 chkval 0, 0x8c, i2csu_read_begin ;A,!P, S,R,!BF
490 chkval 0x8c,0xac, i2csu_read_another ;D,!P, S,R,!BF
491 chkval 0xac,0x89, s_event_addrrecvwrite ;A,!P, S,W,BF
492 chkval 0x89,0xa9, s_event_writing_datarecv ;D,!P, S,W,BF
493 chkval 0xa9,0xa8, s_event_reading_datanack ;D,!P, S,!R,!BF
497 ;======================================================================
499 include program+externs.fin