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 ;======================================================================
15 ; m_... routines used by master only
16 ; s_... routines used by slave only
17 ; <any other name> routines used by both
19 ; [ms]_event_... event handler, branched to from interrupt
20 ; handler; conditions are as in the name;
21 ; should `return' at end which will return
22 ; from i2c[ms]_interrupt
24 ; [sm]_event_bad[_...] event handler which panics; called when i2c
25 ; controller did something unexpected
27 ; m_improper_... panics; called when main program
28 ; does something wrong
30 ; [ms]_<anything else> routines or labels of some other kind
32 ; Whenever flow does not pass past the end of some code, we
33 ; have a boundary `;----------', and when flow passes past
34 ; an important label we sometimes mark it specially with `;...',
39 ; bt_f_if0 i2c_st, st_something
43 ; m_event_several_including_spong
44 ; bs_f i2c_st, st_sponging
45 ; bra metasyntacticing
50 ;============================================================
51 ; COMMON ADMINISTRATIVE ROUTINES and VARIABLES
57 i2c_sspcon2 res 1 ; master only
58 i2c_slave res 1 ; master only
62 ; i2c_st is a bitmask, bit set in visible states:
64 st_starting equ 7 ; Writing-Setup?,Reading-Busy?
65 st_addressing equ 6 ; Writing-Setup?,Reading-Busy?
66 st_writing equ 5 ; Writing-* [Idle-going-]Receiving
67 st_subsequent equ 4 ; Writing? Receiving
68 st_reading equ 3 ; Reading-* Transmitting
69 st_awaiting equ 2 ; Reading-Wait
70 st_acking equ 1 ; Reading-Busy?,Stopping(from read)
71 st_stopping equ 0 ; Stopping
72 ; ...? means not always set in that state
78 ; computes slave address in form suitable for use in i2c controller
79 ; actual i2c slave address is (slave number) + 0b0001000
80 ; W slave number i2c address * 2
85 ;======================================================================
90 mov_lw 100-1 ; baud rate = Fosc/(4*(SSPADD+1))
91 mov_wf SSPADD ; Fosc=20MHz, so SSPADD==99 means 50kbit/s
92 mov_lw 0x08 ; !SSPEN, Master mode
94 clr_f SSPCON2 ; nothing going
95 mov_lw 0x80 ; SMP(noslew), !CKE(!smbus)
102 ; We have an interrupt:
104 mov_ff SSPSTAT, i2c_sspstat
105 mov_ff SSPCON1, i2c_sspcon1
106 mov_ff SSPCON2, i2c_sspcon2
108 bt_f_if1 i2c_sspcon1, WCOL
110 bt_f_if1 i2c_sspcon1, SSPOV
113 ; No ? Well, then the I2C should be idle now:
115 and_lw ~0x60 ; ACKSTAT,ACKDT
119 bt_f_if1 i2c_sspstat, R_W
122 bt_f_if1 i2c_st, st_stopping
123 bra m_event_done_stopping
125 bt_f_if1 i2c_st, st_starting
126 bra m_event_done_starting
129 bt_f_if1 i2c_st, st_addressing
130 bra m_event_done_addressing
132 bt_f_if1 i2c_st, st_writing
133 bra m_event_done_writing
135 bt_f_if1 i2c_st, st_acking
136 bra m_event_done_acking
138 bt_f_if1 i2c_st, st_reading
139 bra m_event_done_reading
142 panic morse_SM ; master, interrupt, controller in bad state
144 ;========================================
145 ; MASTER - STARTING, ADDRESSING, STOPPING
149 ; i2c_st checked for busyness correct
150 ; st_reading/writing set unchanged
151 ; st_starting clear set
153 ; i2c_slave any slave_number
154 ; expects to return directly to main program (caller)
157 bra_nz m_improper_slave
158 bs_f i2c_st, st_starting
159 bs_f i2c_st, st_working
164 m_event_done_starting
168 bt_f_if1 i2c_st, st_reading
169 bs_w 0 ; address bottom bit means read
172 bc_f i2c_st, st_starting
173 bs_f i2c_st, st_addressing
177 m_event_done_addressing
178 bt_f_if1 i2c_sspcon2, ACKSTAT
179 bra m_bad_address_ack
182 bc_f i2c_st, st_addressing
183 bt_f_if1 i2c_st, st_reading
184 bra m_event_done_addressing_read
185 bra m_event_done_addressing_write
189 ; st_stopping clear set
190 ; st_reading/acking/writing any unchanged
191 ; expects to return directly to main program or to end interrupt handler
192 bs_f i2c_st, st_stopping
197 m_event_done_stopping
207 ; i2c_slave slave number
210 ;========================================
216 ; State Idle Writing-Setup
219 bra m_improper_write_start
221 bs_f i2c_st, st_writing
226 ; Did slave ack our byte ? It had better have done !
227 bt_f_if1 i2c_sspcon2, ACKSTAT
230 bs_f i2c_st, st_subsequent
233 m_event_done_addressing_write
235 ; st_addressing cleared
236 call i2cmu_write_next_byte
237 bra_z m_event_write_mustfinish
238 ; OK, we have the next byte:
244 m_event_write_mustfinish
245 bt_f_if0 i2c_st, st_subsequent
246 bra m_improper_write_finish
251 m_improper_write_start
255 m_improper_write_finish
258 ;========================================
264 ; State Idle Reading-Busy
267 bra m_improper_read_start
269 bs_f i2c_st, st_reading
273 m_event_done_addressing_read
274 m_event_done_acking_readmore
276 ; st_addressing/acking cleared
282 bt_f_if0 i2c_sspstat, BF
287 bs_f i2c_st, st_awaiting
288 goto i2cmu_read_got_byte
292 ; State Reading-Wait Reading-Busy
293 bt_f_if0 i2c_st, st_awaiting
294 bra m_improper_read_another
295 ; OK, we're fine to read another:
299 ; st_reading 1 iff not done unchanged
300 ; st_awaiting still set cleared
301 ; st_acking clear set
302 ; expects to return directly to main program or to end interrupt handler
303 bc_f i2c_st, st_awaiting
304 bs_f i2c_st, st_acking
305 bc_f SSPCON2, ACKDT ; ACKDT=0 means to acknowledge
311 ; State Reading-Wait Stopping
312 bc_f i2c_st, st_reading
314 bt_f_if0 i2c_st, st_awaiting
315 bra m_improper_read_done
322 bc_f i2c_st, st_acking
324 bt_f_if1 i2c_st, st_reading
325 bra m_event_done_acking_readmore
330 m_improper_read_start
334 m_improper_read_another
341 ;======================================================================
346 ; W slave number undefined
350 mov_lw 0x16 ; !SSPEN, CKP(release), I2C 7-bit slave no-SP-int
352 mov_lw 0x01 ; !GCEN, SEN
354 mov_lw 0x8 ; SMP(noslew), !CKE(!smbus)
357 ; Actually engages the I2C controller, which must already have
358 ; been set up (all but SSPEN):
359 ; SSPADD,SSPCON1,SSPCON2 configured correctly unchanged
360 ; SSPSTAT configured correctly unchanged, except:
361 ; SSPSTAT<SSPEN> 0 (disabled) 1 (enabled)
362 ; SSPIE 0 (disabled) 1 (enabled)
363 ; TRISB<1,0> any configured for I2C
364 ; SSPIP any configured correctly
365 ; GIEL 0 (disabled) 0 (disabled)
366 ; ssp* shadows any all bits set
377 ;========================================
378 ; SLAVE - INTERRUPT HANDLING
380 ; In general, we figure out our state and then see what kind of events
381 ; we were expecting. Bits we want to check:
382 ; 80 60 20 10 08 04 02 01
383 ; SMP CKE D_A P S R_W UA BF
384 ; set clr data? stop start read? clr full?
385 ; (we don't usually mention SMP, CKE and UA below)
389 chkvals_start_sspstat macro
391 chkval_lastvalue equ 0
394 chkval macro value, label
395 xor_lw value ^ chkval_lastvalue
396 chkval_lastvalue equ value
400 chkvals_addrrecv macro
401 chkval 0x8c, s_event_idle_addrrecvread ; A,!P, S,R,!BF
402 chkval 0x89, s_event_idle_addrrecvwrite ; A,!P, S,W,BF
409 ; We have an interrupt:
411 bt_f_if1 i2c_sspcon1, WCOL
413 bt_f_if1 i2c_sspcon1, SSPOV
416 ; Firstly, clear the interrupt flag so that if something else happens
417 ; while we faff, the interrupt will be regenerated:
420 mov_ff SSPSTAT, i2c_sspstat
421 mov_ff SSPCON1, i2c_sspcon1
422 ; Check that nothing obvious is wrong:
425 bt_f_if0 i2c_st, st_reading
428 bt_f_if0 i2c_st, st_writing
435 panic morse_SS ; slave, interrupt, controller in bad state
437 ;========================================
441 s_event_idle_addrrecvread
442 bs_f i2c_st, st_reading
443 call i2csu_read_begin
444 bra s_events_read_datasend
448 chkvals_start_sspstat
449 chkval 0xac, s_event_reading_datasent ; D,!P, S,R,!BF
451 ; Whatever is happening, we're done reading now !
455 chkval 0xa8, s_event_reading_datanack ; D,!P, S,!R,!BF
456 ; Or, maybe it was nack and then we were reselected:
462 s_event_reading_datasent
463 call i2csu_read_another
464 s_events_reading_datasend
467 s_event_reading_datanack
470 ;========================================
474 s_event_idle_addrrecvwrite
475 bs_f SSPCON, 3 ; we'll need the Stop interrupt
476 bs_f i2c_st, st_writing
477 ; well, this is all fine so far, so do carry on:
480 ; W any byte from master
481 ; i2c controller waiting due to SEN etc continuing with next byte
488 chkvals_start_sspstat
489 chkval 0xa9, s_event_writing_datarecv ; D,!P, S,W,BF
491 ; Well, we're done writing now in any case
493 bc_f SSPCON1, 3 ; no Start and Stop interrupts any more
494 call i2csu_write_done
496 ; Who knows what might have happened. We may have
497 ; missed a number of S and P due to delay between
498 ; clearing SSPIF and SSPM3(s&p-intrs) so we can't be
501 ; First, the nice cases:
502 chkvals_start_sspstat
507 and_lw 0xc7 ; ?D_A, ?P; ?S
508 xor_lw 0x80 ; SMP, !CKE, !R_W, !UA, !BF
516 s_event_writing_datarecv
517 rcall s_write_slurpbyte
519 bt_f_if1 i2c_st, st_subsequent
520 goto i2csu_write_another
521 ; not subsequent (yet):
523 bs_f i2c_st, st_subsequent
524 goto i2csu_write_begin
526 ;======================================================================