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
16 ;======================================================================
21 ; m_... routines used by master only
22 ; s_... routines used by slave only
23 ; <any other name> routines used by both
25 ; [ms]_event_... event handler, branched to from interrupt
26 ; handler; conditions are as in the name;
27 ; should `return' at end which will return
28 ; from i2c[ms]_interrupt
30 ; [sm]_event_bad[_...] event handler which panics; called when i2c
31 ; controller did something unexpected
33 ; m_improper_... panics; called when main program
34 ; does something wrong
36 ; [ms]_<anything else> routines or labels of some other kind
38 ; Whenever flow does not pass past the end of some code, we
39 ; have a boundary `;----------', and when flow passes past
40 ; an important label we sometimes mark it specially with `;...',
45 ; bt_f_if0 st, st_something
49 ; m_event_several_including_spong
50 ; bs_f st, st_sponging
51 ; bra metasyntacticing
56 ;============================================================
57 ; COMMON ADMINISTRATIVE ROUTINES and VARIABLES
63 sspcon2 res 1 ; master only
64 slave res 1 ; master only
65 slave_next res 1 ; master only
70 ; st is a bitmask, bit set in visible states:
72 st_starting equ 7 ; Writing-Setup?,Reading-Busy?
73 st_addressing equ 6 ; Writing-Setup?,Reading-Busy?
74 st_writing equ 5 ; Writing-* [Idle-going-]Receiving
75 st_subsequent equ 4 ; Writing? Receiving
76 st_reading equ 3 ; Reading-* Transmit-*
77 st_awaiting equ 2 ; Reading-Wait Transmit-Wait
78 st_acking equ 1 ; Reading-Busy?,Stopping(from read)
79 st_stopping equ 0 ; Stopping
80 ; ...? means not always set in that state
85 i2cpanic macro morse_addr
86 ; Like panic but turns off the I2C controller
93 ; computes slave address in form suitable for use in i2c controller
94 ; actual i2c slave address is (slave number) + 0b0001000
95 ; W slave number i2c address * 2
101 improper_read_done_data
104 ;======================================================================
113 mov_lw 0x08 ; !SSPEN, Master mode
115 clr_f SSPCON2 ; nothing going
116 mov_lw 0x80 ; SMP(noslew), !CKE(!smbus)
118 bc_f IPR1, SSPIP ; low priority
125 ; We have an interrupt:
127 i2cm_interrupt_definite
128 mov_ff SSPSTAT, sspstat
129 mov_ff SSPCON1, sspcon1
130 mov_ff SSPCON2, sspcon2
134 mov_lw (1<<WCOL) | (1<<SSPOV)
138 ; No ? Well, then the I2C should be idle now:
140 and_lw ~((1<<ACKSTAT) | (1<<ACKDT)) ; those two are ok if set
144 bt_f_if1 sspstat, R_W
147 bt_f_if1 st, st_stopping
148 bra m_event_done_stopping
150 bt_f_if1 st, st_starting
151 bra m_event_done_starting
154 bt_f_if1 st, st_addressing
155 bra m_event_done_addressing
157 bt_f_if1 st, st_writing
158 bra m_event_done_writing
160 bt_f_if1 st, st_acking
161 bra m_event_done_acking
163 bt_f_if1 st, st_reading
164 bra m_event_done_reading
169 ;========================================
170 ; MASTER - STARTING, ADDRESSING, STOPPING
174 ; st checked for busyness correct
175 ; st_reading/writing set unchanged
176 ; st_starting clear set
178 ; slave any slave_number
179 ; expects to return directly to main program (caller)
181 bra_z m_improper_slave
185 bra_nz m_improper_slave
190 m_event_done_starting
194 bt_f_if1 st, st_reading
195 bs_w 0 ; address bottom bit means read
199 bs_f st, st_addressing
203 m_event_done_addressing
204 bt_f_if1 sspcon2, ACKSTAT
205 bra m_bad_address_ack
208 bc_f st, st_addressing
209 bt_f_if1 st, st_reading
210 bra m_event_done_addressing_read
211 bra m_event_done_addressing_write
215 ; st_stopping clear set
216 ; st_reading/acking/writing any unchanged
217 ; expects to return directly to main program or to end interrupt handler
223 m_event_done_stopping
236 ;========================================
242 ; State Idle Writing-Setup
245 bra m_improper_write_start
252 ; Did slave ack our byte ? It had better have done !
253 bt_f_if1 sspcon2, ACKSTAT
256 bs_f st, st_subsequent
259 m_event_done_addressing_write
261 ; st_addressing cleared
262 call i2cmu_write_next_byte
263 bra_z m_event_write_mustfinish
264 ; OK, we have the next byte:
270 m_event_write_mustfinish
271 bt_f_if0 st, st_subsequent
272 bra m_improper_write_finish
277 m_improper_write_start
281 m_improper_write_finish
284 ;========================================
290 ; State Idle Reading-Busy
293 bra m_read_start_busy
300 bt_f_if1 st, st_awaiting
306 ; Main program would like to address another slave.
308 bra_z m_improper_slave
312 m_event_done_addressing_read
313 m_event_done_acking_readmore
315 ; st_addressing/acking cleared
327 goto i2cmu_read_got_byte
331 ; State Reading-Wait Reading-Busy
332 bt_f_if0 st, st_awaiting
333 bra m_improper_read_another
334 ; OK, we're fine to read another:
338 ; st_reading 1 iff not done unchanged
339 ; st_awaiting still set cleared
340 ; st_acking clear set
341 ; expects to return directly to main program or to end interrupt handler
344 bc_f SSPCON2, ACKDT ; ACKDT=0 means to acknowledge
345 bt_f_if0 st, st_reading
346 bs_f SSPCON2, ACKDT ; don't ack last byte
352 ; State Reading-Wait Stopping
355 bt_f_if0 st, st_awaiting
356 bra improper_read_done_data
365 bt_f_if1 st, st_reading
366 bra m_event_done_acking_readmore
370 ; ok, we want to read another:
375 bra m_start_or_restart
378 m_improper_read_another
381 ;======================================================================
386 ; W slave number undefined
390 mov_lw 0x16 ; !SSPEN, CKP(release), I2C 7-bit slave no-SP-int
392 mov_lw 0x01 ; !GCEN, SEN
394 mov_lw 0x80 ; SMP(noslew), !CKE(!smbus)
396 bs_f IPR1, SSPIP ; high priority
398 ; Actually engages the I2C controller, which must already have
399 ; been set up (all but SSPEN):
400 ; SSPADD,SSPCON1,SSPCON2 configured correctly unchanged
401 ; SSPSTAT configured correctly unchanged, except:
402 ; SSPSTAT<SSPEN> 0 (disabled) 1 (enabled)
403 ; SSPIE 0 (disabled) 1 (enabled)
404 ; SSPIF configured correctly unchanged
405 ; TRISB<1,0> any configured for I2C
406 ; SSPIP any configured correctly
407 ; GIEL 0 (disabled) 0 (disabled)
408 ; ssp* shadows any all bits set
419 ;========================================
422 ; In general, we figure out our state and then see what kind of events
423 ; we were expecting. Bits we want to check:
424 ; 80 40 20 10 08 04 02 01
425 ; SMP CKE D_A P S R_W UA BF
426 ; set clr data? stop start read? clr full?
427 ; (we don't usually mention SMP, CKE and UA below)
429 ; Labels of the form s_event_* are branches of the interrupt
430 ; handler and are supposed to finish with return.
433 ; Macros: chkvals_start and chkval
435 chkvals_start macro what
439 chkval macro lastval, value, label
440 xor_lw value ^ lastval
444 near_i2csu_section code
447 s_write_slurpbyte macro
448 ; W any byte from master
449 ; i2c controller waiting due to SEN etc continuing with next byte
454 ;----------------------------------------
459 ;----------------------------------------
460 ; branches from the ISR
463 s_event_addrrecvwrite
465 goto i2csu_write_begin
468 s_event_reading_datanack
472 s_event_writing_datarecv
474 goto i2csu_write_data
478 i2cpanic morse_IH ; unknown high-priority interrupt
480 ;----------------------------------------
481 i2cs_interrupt ; 4cy interrupt latency + 3cy until branch to here
484 ; We have an interrupt:
486 mov_lw (1<<WCOL) | (1<<SSPOV)
490 ; Firstly, clear the interrupt flag so that if something else happens
491 ; while we faff, the interrupt will be regenerated:
494 chkvals_start SSPSTAT
495 chkval 0, 0x8c, i2csu_read_begin ;A,!P, S,R,!BF
496 chkval 0x8c,0xac, i2csu_read_another ;D,!P, S,R,!BF
497 chkval 0xac,0x89, s_event_addrrecvwrite ;A,!P, S,W,BF
498 chkval 0x89,0xa9, s_event_writing_datarecv ;D,!P, S,W,BF
499 chkval 0xa9,0xa8, s_event_reading_datanack ;D,!P, S,!R,!BF
503 ;======================================================================