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 ;============================================================
11 ; COMMON ADMINISTRATIVE ROUTINES and VARIABLES
19 st res 1 ; bitmask, bit set in visible states:
21 st_reading equ 0 ; Reading-* Transmitting
22 st_writing equ 1 ; Writing-* [Idle-going-]Receiving
23 st_subsequent equ 2 ; Receiving
24 st_working equ 3 ; Writing-*,Reading-Busy,Stopping
25 st_starting equ 4 ; Writing-Setup,Reading-Busy
31 ; computes slave address in form suitable for use in i2c controller
32 ; actual i2c slave address is (slave number) + 0b0001000
33 ; W slave number i2c address * 2
42 and_lw 0xc0 ; WCOL,SSPOV
50 ;======================================================================
55 mov_lw 100-1 ; baud rate = Fosc/(4*(SSPADD+1))
56 mov_wf SSPADD ; Fosc=20MHz, so SSPADD==99 means 50kbit/s
57 mov_lw 0x08 ; !SSPEN, Master mode
59 clr_f SSPCON2 ; nothing going
60 mov_lw 0x80 ; SMP(noslew), !CKE(!smbus)
66 ; State Idle Writing-Setup
82 ; Do we have a doomy clash ?
85 ; No ? Well, then the I2C should be idle now:
88 and_lw ~0x60 ; ACKSTAT,ACKDT
90 ; OK, what's happening;
94 ; We have an interrupt:
96 bt_f_if1 st, st_starting
114 ; W expected bit values any
115 ; Panics if (SSPSTAT ^ W) & mask != 0
119 ;======================================================================
124 ; W slave number undefined
128 mov_lw 0x16 ; !SSPEN, CKP(release), I2C 7-bit slave no-SP-int
130 mov_lw 0x01 ; !GCEN, SEN
132 mov_lw 0x8 ; SMP(noslew), !CKE(!smbus)
135 ; Actually engages the I2C controller, which must already have
136 ; been set up (all but SSPEN):
137 ; SSPADD,SSPCON1,SSPCON2 configured correctly unchanged
138 ; SSPSTAT configured correctly unchanged, except:
139 ; SSPSTAT<SSPEN> 0 (disabled) 1 (enabled)
140 ; SSPIE 0 (disabled) 1 (enabled)
141 ; TRISB<1,0> any configured for I2C
142 ; SSPIP any configured correctly
143 ; GIEL 0 (disabled) 0 (disabled)
151 ;========================================
152 ; SLAVE - INTERRUPT HANDLING
154 ; In general, we figure out our state and then see what kind of events
155 ; we were expecting. Bits we want to check:
156 ; 80 60 20 10 08 04 02 01
157 ; SMP CKE D_A P S R_W UA BF
158 ; set clr data? stop start read? clr full?
159 ; (we don't usually mention SMP, CKE and UA below)
165 chkval_lastvalue equ 0
168 chkval macro value, label
169 xor_lw value ^ chkval_lastvalue
170 chkval_lastvalue equ value
174 chkvals_addrrecv macro
175 chkval 0x8c, s_event_idle_addrrecvread ; A,!P, S,R,!BF
176 chkval 0x89, s_event_idle_addrrecvwrite ; A,!P, S,W,BF
183 ; We have an interrupt:
185 ; Firstly, clear the interrupt flag so that if something else happens
186 ; while we faff, the interrupt will be regenerated:
189 ; Check that nothing obvious is wrong:
192 bt_f_if0 st, st_reading
195 bt_f_if0 st, st_writing
204 ;========================================
208 s_event_idle_addrrecvread
210 call i2csu_read_begin
211 bra s_events_read_datasend
216 chkval 0xac, s_event_reading_datasent ; D,!P, S,R,!BF
218 ; Whatever is happening, we're done reading now !
222 chkval 0xa8, s_event_reading_datanack ; D,!P, S,!R,!BF
223 ; Or, maybe it was nack and then we were reselected:
229 s_event_reading_datasent
230 call i2csu_read_another
231 s_events_reading_datasend
234 s_event_reading_datanack
237 ;========================================
241 s_event_idle_addrrecvwrite
242 bs_f SSPCON, 3 ; we'll need the Stop interrupt
244 ; well, this is all fine so far, so do carry on:
247 ; W any byte from master
248 ; i2c controller waiting due to SEN etc continuing with next byte
256 chkval 0xa9, s_event_writing_datarecv ; D,!P, S,W,BF
258 ; Well, we're done writing now in any case
260 bc_f SSPCON1, 3 ; no Start and Stop interrupts any more
261 call i2csu_write_done
263 ; Who knows what might have happened. We may have
264 ; missed a number of S and P due to delay between
265 ; clearing SSPIF and SSPM3(s&p-intrs) so we can't be
268 ; First, the nice cases:
274 and_lw 0xc7 ; ?D_A, ?P; ?S
275 xor_lw 0x80 ; SMP, !CKE, !R_W, !UA, !BF
282 s_event_writing_datarecv
283 rcall s_write_slurpbyte
285 bt_f_if1 st, st_subsequent
286 goto i2csu_write_another
287 ; not subsequent (yet):
289 bs_f st, st_subsequent
290 goto i2csu_write_begin
292 ;======================================================================