chiark / gitweb /
get rid of spurious clock equ 0
[trains.git] / detpic / i2clib.asm
1 ;######################################################################
2 ; i2clib.inc - I2C LIBRARY - IMPLEMENTATION
3 ;
4 ; See i2clib.asm for documentation of the interface to this file.
5
6  include /usr/share/gputils/header/p18f458.inc
7  radix dec
8  include ../iwjpictest/insn-aliases.inc
9
10  include ../iwjpictest/clockvaries.inc
11  include panic.inc
12  include morse+auto.inc
13  include i2clib.incm
14
15 ;======================================================================
16 ; NOTATION
17
18 ; Naming conventions
19 ;
20 ;  m_...                        routines used by master only
21 ;  s_...                        routines used by slave only
22 ;  <any other name>             routines used by both
23 ;
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
28 ;
29 ;  [sm]_event_bad[_...]         event handler which panics; called when i2c
30 ;                                controller did something unexpected
31 ;
32 ;  m_improper_...               panics; called when main program
33 ;                                does something wrong
34 ;
35 ;  [ms]_<anything else>         routines or labels of some other kind
36
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 `;...',
40 ; like this:
41 ;
42 ;               ;----------
43 ;               m_event_spong
44 ;                               bt_f_if0 st, st_something
45 ;                               bra     m_event_bad
46 ;               ;...
47 ;
48 ;               m_event_several_including_spong
49 ;                               bs_f    st, st_sponging
50 ;                               bra     metasyntacticing
51 ;
52 ;               ;----------
53 ;               m_event_wombat
54
55 ;============================================================
56 ; COMMON ADMINISTRATIVE ROUTINES and VARIABLES
57
58                 udata_acs
59
60 sspstat         res     1
61 sspcon1         res     1
62 sspcon2         res     1       ; master only
63 slave           res     1       ; master only
64 slave_next      res     1       ; master only
65
66 st              res     1
67 st_orig         res     1
68
69 ; st is a bitmask, bit set in visible states:
70                   ;    master
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
80
81                 code
82
83 ;----------
84 i2cpanic macro morse_addr
85 ; Like panic but turns off the I2C controller
86         bc_f    SSPCON1, SSPEN
87         panic   morse_addr
88         endm
89
90 ;----------
91 slave2addr
92 ; computes slave address in form suitable for use in i2c controller
93 ; actual i2c slave address is (slave number) + 0b0001000
94 ;       W               slave number            i2c address * 2
95                 add_lw  b'0001000'
96                 rlc_w
97                 return
98
99 ;----------
100 improper_read_done_data
101                 i2cpanic morse_SD
102
103 ;======================================================================
104 ; MASTER
105
106 ;----------
107 i2cm_init
108                 mov_lw  i2c_sspadd
109                 mov_wf  SSPADD
110                 clr_f   st
111                 clr_f   slave_next
112                 mov_lw  0x08    ; !SSPEN, Master mode
113                 mov_wf  SSPCON1
114                 clr_f   SSPCON2 ; nothing going
115                 mov_lw  0x80    ; SMP(noslew), !CKE(!smbus)
116                 mov_wf  SSPSTAT
117                 bc_f    IPR1, SSPIP ; low priority
118                 bra     init_enable
119
120 ;----------
121 i2cm_interrupt
122                 bt_f_if0 PIR1, SSPIF
123                 return
124                 ; We have an interrupt:
125 ;...
126 i2cm_interrupt_definite
127                 mov_ff  SSPSTAT, sspstat
128                 mov_ff  SSPCON1, sspcon1
129                 mov_ff  SSPCON2, sspcon2
130
131                 bc_f    PIR1, SSPIF
132
133                 mov_lw  (1<<WCOL) | (1<<SSPOV)
134                 and_wfw sspcon1
135                 bra_nz  m_event_bad
136
137                 ; No ?  Well, then the I2C should be idle now:
138                 mov_fw  sspcon2
139                 and_lw  ~((1<<ACKSTAT) | (1<<ACKDT)) ; those two are ok if set
140                 bra_nz  m_event_bad
141                 ; OK...
142
143                 bt_f_if1 sspstat, R_W
144                 bra_nz  m_event_bad
145
146                 bt_f_if1 st, st_stopping
147                 bra     m_event_done_stopping
148
149                 bt_f_if1 st, st_starting
150                 bra     m_event_done_starting
151                 ; not just done SEN
152
153                 bt_f_if1 st, st_addressing
154                 bra     m_event_done_addressing
155
156                 bt_f_if1 st, st_acking
157                 bra     m_event_done_acking
158
159                 bt_f_if1 st, st_writing
160                 bra     m_event_done_writing
161
162                 bt_f_if1 st, st_reading
163                 bra     m_event_done_reading
164
165 m_event_bad
166                 i2cpanic morse_SM
167
168 ;========================================
169 ; MASTER - STARTING, ADDRESSING, STOPPING
170
171 ;----------
172 m_start
173 ;       st                      checked for busyness    correct
174 ;       st_reading/writing      one set, one clear      unchanged
175 ;       st_starting             clear                   set
176 ;       W                       slave number            any
177 ;       slave                   any                     slave_number
178 ; expects to return directly to main program (caller)
179                 mov_wf  slave
180                 bra_z   m_improper_slave
181                 bs_f    SSPCON2, SEN
182 m_start_or_restart
183                 and_lw  ~31
184                 bra_nz  m_improper_slave
185                 bs_f    st, st_starting
186                 return
187
188 ;----------
189 m_event_done_starting
190                 mov_fw  slave
191                 rcall   slave2addr
192
193                 bt_f_if1 st, st_reading
194                 bs_w    0       ; address bottom bit means read
195
196                 mov_wf  SSPBUF
197                 bc_f    st, st_starting
198                 bs_f    st, st_addressing
199                 return
200
201 ;----------
202 m_event_done_addressing
203                 bt_f_if1 sspcon2, ACKSTAT
204                 bra     m_bad_address_ack
205                 ; OK, we got ack.
206
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
211
212 ;----------
213 m_stop
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
217                 bs_f    st, st_stopping
218                 bs_f    SSPCON2, PEN
219                 return
220
221 ;----------
222 m_event_done_stopping
223                 clr_f   st
224                 goto    i2cmu_done
225
226 ;----------
227 m_bad_address_ack
228                 i2cpanic morse_SK
229
230 ;----------
231 m_improper_slave
232 ;       slave                   slave number
233                 i2cpanic morse_SN
234
235 ;========================================
236 ; MASTER - WRITING
237
238 ;----------
239 i2cm_write_start
240 ;                               At call         On return
241 ;   State                   Idle/Reading-Wait   Writing-Setup
242 ;   W                           slave number    any
243                 tst_f_ifnz st
244                 bra     m_write_start_busy
245
246                 bs_f    st, st_writing
247                 bra     m_start
248
249 ;----------
250 m_event_done_writing
251                 ; Did slave ack our byte ?  It had better have done !
252                 bt_f_if1 sspcon2, ACKSTAT
253                 bra     m_event_bad
254
255                 bs_f    st, st_subsequent
256 ;...
257
258 m_event_done_addressing_write
259 ;       ACKSTAT         checked
260 ;       st_addressing   cleared
261                 call    i2cmu_write_next_byte
262                 bra_z   m_event_write_mustfinish
263                 ; OK, we have the next byte:
264
265                 mov_wf  SSPBUF
266                 return
267
268 ;----------
269 m_event_write_mustfinish
270                 bt_f_if0 st, st_subsequent
271                 bra     m_improper_write_finish
272
273                 bra     m_stop
274
275 ;----------
276 m_improper_write_finish
277                 i2cpanic morse_SF
278
279 ;========================================
280 ; MASTER - READING
281
282 ;----------
283 i2cm_read_start
284 ;                               At call         On return
285 ;       State                   Idle            Reading-Busy
286 ;       W                       slave number    any
287                 tst_f_ifnz st
288                 bra     m_read_start_busy
289
290                 bs_f    st, st_reading
291                 bra     m_start
292
293 ;----------
294 m_write_start_busy
295                 bs_f    st, st_writing
296 m_read_start_busy
297                 bt_f_if1 st, st_awaiting
298                 bra     m_address_different
299                 i2cpanic morse_SB
300
301 ;----------
302 m_address_different
303 ; Main program would like to address another slave for reading.
304                 mov_wf  slave_next
305                 bra_z   m_improper_slave
306                 bra     i2cm_read_done
307
308 ;----------
309 m_event_done_addressing_read
310 m_event_done_acking_readmore
311 ;       ACKSTAT                 checked
312 ;       st_addressing/acking    cleared
313                 bs_f    SSPCON2, RCEN
314                 return
315
316 ;----------
317 m_event_done_reading
318                 bt_f_if0 sspstat, BF
319                 bra     m_event_bad
320
321                 mov_fw  SSPBUF
322
323                 bs_f    st, st_awaiting
324                 goto    i2cmu_read_got_byte
325
326 ;----------
327 i2cm_read_another
328 ;   State                       Reading-Wait    Reading-Busy
329                 bt_f_if0 st, st_awaiting
330                 bra     m_improper_read_another
331                 ; OK, we're fine to read another:
332 ;...
333
334 m_read_ack
335 ;       st_reading              1 iff not done          unchanged
336 ;       st_awaiting             still set               cleared
337 ;       st_acking               clear                   set
338 ; expects to return directly to main program or to end interrupt handler
339                 bc_f    st, st_awaiting
340                 bs_f    st, st_acking
341                 bc_f    SSPCON2, ACKDT ; ACKDT=0 means to acknowledge
342                 bt_f_if0 st, st_reading
343                 bs_f    SSPCON2, ACKDT ; don't ack last byte
344                 bs_f    SSPCON2, ACKEN
345                 return
346
347 ;----------
348 i2cm_read_done
349 ;   State                       Reading-Wait    Stopping
350                 bc_f    st, st_reading
351                 
352                 bt_f_if0 st, st_awaiting
353                 bra     improper_read_done_data
354                 ; OK:
355
356                 bra     m_read_ack
357
358 ;----------
359 m_event_done_acking
360                 bc_f    st, st_acking
361
362                 bt_f_if1 st, st_reading
363                 bra     m_event_done_acking_readmore
364
365                 mov_fw  slave_next
366                 bra_z   m_stop
367 ; ok, we want to read another:
368                 mov_wf  slave
369                 clr_f   slave_next
370                 bt_f_if0 st, st_writing ; because of i2cm_write_start ?
371                 bs_f    st, st_reading ; no, then we will want to read
372                 bs_f    SSPCON2, RSEN
373                 bra     m_start_or_restart
374
375 ;----------
376 m_improper_read_another
377                 i2cpanic morse_SA
378
379 ;======================================================================
380 ; SLAVE
381
382 ;----------
383 i2cs_init
384 ;       W               slave number            undefined
385                 rcall   slave2addr
386                 mov_wf  SSPADD
387                 clr_f   st
388                 mov_lw  0x16 ; !SSPEN, CKP(release), I2C 7-bit slave no-SP-int
389                 mov_wf  SSPCON1
390                 mov_lw  0x01 ; !GCEN, SEN
391                 mov_wf  SSPCON2
392                 mov_lw  0x80 ; SMP(noslew), !CKE(!smbus)
393                 mov_wf  SSPSTAT
394                 bs_f    IPR1, SSPIP ; high priority
395 init_enable
396 ; Actually engages the I2C controller, which must already have
397 ; been set up (all but SSPEN):
398 ;  SSPADD,SSPCON1,SSPCON2       configured correctly    unchanged
399 ;       SSPSTAT                 configured correctly    unchanged, except:
400 ;       SSPSTAT<SSPEN>          0 (disabled)            1 (enabled)
401 ;       SSPIE                   0 (disabled)            1 (enabled)
402 ;       SSPIF                   configured correctly    unchanged
403 ;       TRISB<1,0>              any                     configured for I2C
404 ;       SSPIP                   any                     configured correctly
405 ;       GIEL                    0 (disabled)            0 (disabled)
406 ;       ssp* shadows            any                     all bits set
407                 set_f   sspstat
408                 set_f   sspcon1
409                 set_f   sspcon2
410                 set_f   st_orig
411                 bs_f    TRISB, 0
412                 bs_f    TRISB, 1
413                 bs_f    SSPCON1, SSPEN
414                 bs_f    PIE1, SSPIE
415                 return
416
417 ;========================================
418 ; SLAVE
419 ;
420 ; In general, we figure out our state and then see what kind of events
421 ; we were expecting.  Bits we want to check:
422 ;       80    40    20    10            08    04    02    01
423 ;       SMP   CKE   D_A   P             S     R_W   UA    BF
424 ;       set   clr   data? stop          start read? clr   full?
425 ; (we don't usually mention SMP, CKE and UA below)
426 ;
427 ; Labels of the form s_event_* are branches of the interrupt
428 ; handler and are supposed to finish with return.
429
430 ;----------
431 ; Macros: chkvals_start and chkval
432
433 chkvals_start macro what
434                 mov_fw  what
435                 endm
436
437 chkval macro lastval, value, label
438                 xor_lw  value ^ lastval
439                 bra_z   label
440                 endm
441
442 near_i2csu code
443
444 ;----------
445 s_write_slurpbyte macro
446 ;       W               any                     byte from master
447 ;       i2c controller  waiting due to SEN etc  continuing with next byte
448                 mov_fw  SSPBUF
449                 bs_f    SSPCON1, CKP
450                 endm
451
452 ;----------------------------------------
453 i2cs_read_data
454                 i2cs_read_data_macro
455                 return
456
457 ;----------------------------------------
458 ; branches from the ISR
459
460 ;----------
461 s_event_addrrecvwrite
462                 s_write_slurpbyte
463                 goto    i2csu_write_begin
464
465 ;----------
466 s_event_reading_datanack
467                 return
468
469 ;----------
470 s_event_writing_datarecv
471                 s_write_slurpbyte
472                 goto    i2csu_write_data
473
474 ;----------
475 s_event_bad_intr
476                 i2cpanic morse_IH ; unknown high-priority interrupt
477
478 ;----------------------------------------
479 i2cs_interrupt  ; 4cy interrupt latency + 3cy until branch to here
480                 bt_f_if0 PIR1, SSPIF
481                 bra     s_event_bad_intr
482                 ; We have an interrupt:
483
484                 mov_lw  (1<<WCOL) | (1<<SSPOV)
485                 and_wfw SSPCON1
486                 bra_nz  s_event_bad
487
488 ; Firstly, clear the interrupt flag so that if something else happens
489 ; while we faff, the interrupt will be regenerated:
490                 bc_f    PIR1, SSPIF
491
492                 chkvals_start SSPSTAT
493                 chkval  0,   0x8c, i2csu_read_begin             ;A,!P, S,R,!BF
494                 chkval  0x8c,0xac, i2csu_read_another           ;D,!P, S,R,!BF
495                 chkval  0xac,0x89, s_event_addrrecvwrite        ;A,!P, S,W,BF
496                 chkval  0x89,0xa9, s_event_writing_datarecv     ;D,!P, S,W,BF
497                 chkval  0xa9,0xa8, s_event_reading_datanack     ;D,!P, S,!R,!BF
498 s_event_bad
499                 i2cpanic morse_SS
500
501 ;======================================================================
502
503  include panic.fin
504  include i2clib.inc
505
506  end