chiark / gitweb /
giant diffs of clock speed change
[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  include ../iwjpictest/clockvaries.inc
10  include panic.inc
11  include morse+auto.inc
12
13 ;======================================================================
14 ; NOTATION
15
16 ; Naming conventions
17 ;
18 ;  m_...                        routines used by master only
19 ;  s_...                        routines used by slave only
20 ;  <any other name>             routines used by both
21 ;
22 ;  [ms]_event_...               event handler, branched to from interrupt
23 ;                                handler; conditions are as in the name;
24 ;                                should `return' at end which will return
25 ;                                from i2c[ms]_interrupt
26 ;
27 ;  [sm]_event_bad[_...]         event handler which panics; called when i2c
28 ;                                controller did something unexpected
29 ;
30 ;  m_improper_...               panics; called when main program
31 ;                                does something wrong
32 ;
33 ;  [ms]_<anything else>         routines or labels of some other kind
34
35 ; Whenever flow does not pass past the end of some code, we
36 ; have a boundary `;----------', and when flow passes past
37 ; an important label we sometimes mark it specially with `;...',
38 ; like this:
39 ;
40 ;               ;----------
41 ;               m_event_spong
42 ;                               bt_f_if0 st, st_something
43 ;                               bra     m_event_bad
44 ;               ;...
45 ;
46 ;               m_event_several_including_spong
47 ;                               bs_f    st, st_sponging
48 ;                               bra     metasyntacticing
49 ;
50 ;               ;----------
51 ;               m_event_wombat
52
53 ;============================================================
54 ; COMMON ADMINISTRATIVE ROUTINES and VARIABLES
55
56                 udata_acs
57
58 sspstat         res     1
59 sspcon1         res     1
60 sspcon2         res     1       ; master only
61 slave           res     1       ; master only
62
63 st              res     1
64 st_orig         res     1
65
66 ; st is a bitmask, bit set in visible states:
67                   ;    master                          slave
68 st_starting     equ 7 ; Writing-Setup?,Reading-Busy?
69 st_addressing   equ 6 ; Writing-Setup?,Reading-Busy?
70 st_writing      equ 5 ; Writing-*                       [Idle-going-]Receiving
71 st_subsequent   equ 4 ; Writing?                        Receiving
72 st_reading      equ 3 ; Reading-*                       Transmitting
73 st_awaiting     equ 2 ; Reading-Wait
74 st_acking       equ 1 ; Reading-Busy?,Stopping(from read)
75 st_stopping     equ 0 ; Stopping
76                   ; ...? means not always set in that state
77
78                 code
79
80 ;----------
81 slave2addr
82 ; computes slave address in form suitable for use in i2c controller
83 ; actual i2c slave address is (slave number) + 0b0001000
84 ;       W               slave number            i2c address * 2
85                 add_lw  b'0001000'
86                 rlc_w
87                 return
88
89 ;======================================================================
90 ; MASTER
91
92 ;----------
93 i2cm_init
94                 mov_lw  i2c_sspadd
95                 mov_wf  SSPADD
96                 clr_f   st
97                 mov_lw  0x08    ; !SSPEN, Master mode
98                 mov_wf  SSPCON1
99                 clr_f   SSPCON2 ; nothing going
100                 mov_lw  0x80    ; SMP(noslew), !CKE(!smbus)
101                 mov_wf  SSPSTAT
102                 bra     init_enable
103
104 ;----------
105 i2cm_interrupt
106                 bt_f_if0 PIR1, SSPIF
107                 return
108                 ; We have an interrupt:
109
110                 mov_ff  SSPSTAT, sspstat
111                 mov_ff  SSPCON1, sspcon1
112                 mov_ff  SSPCON2, sspcon2
113
114                 bc_f    PIR1, SSPIF
115
116                 mov_lw  (1<<WCOL) | (1<<SSPOV)
117                 and_wfw sspcon1
118                 bra_nz  m_event_bad
119
120                 ; No ?  Well, then the I2C should be idle now:
121                 mov_fw  sspcon2
122                 and_lw  ~((1<<ACKSTAT) | (1<<ACKDT)) ; those two are ok if set
123                 bra_nz  m_event_bad
124                 ; OK...
125
126                 bt_f_if1 sspstat, R_W
127                 bra_nz  m_event_bad
128
129                 bt_f_if1 st, st_stopping
130                 bra     m_event_done_stopping
131
132                 bt_f_if1 st, st_starting
133                 bra     m_event_done_starting
134                 ; not just done SEN
135
136                 bt_f_if1 st, st_addressing
137                 bra     m_event_done_addressing
138
139                 bt_f_if1 st, st_writing
140                 bra     m_event_done_writing
141
142                 bt_f_if1 st, st_acking
143                 bra     m_event_done_acking
144
145                 bt_f_if1 st, st_reading
146                 bra     m_event_done_reading
147
148 m_event_bad
149                 panic   morse_SM
150
151 ;========================================
152 ; MASTER - STARTING, ADDRESSING, STOPPING
153
154 ;----------
155 m_start
156 ;       st                      checked for busyness    correct
157 ;       st_reading/writing      set                     unchanged
158 ;       st_starting             clear                   set
159 ;       W                       slave number            any
160 ;       slave                   any                     slave_number
161 ; expects to return directly to main program (caller)
162                 mov_wf  slave
163                 bra_z   m_improper_slave
164                 and_lw  ~31
165                 bra_nz  m_improper_slave
166                 bs_f    st, st_starting
167                 bs_f    SSPCON2, SEN
168                 return
169
170 ;----------
171 m_event_done_starting
172                 mov_fw  slave
173                 rcall   slave2addr
174
175                 bt_f_if1 st, st_reading
176                 bs_w    0       ; address bottom bit means read
177
178                 mov_wf  SSPBUF
179                 bc_f    st, st_starting
180                 bs_f    st, st_addressing
181                 return
182
183 ;----------
184 m_event_done_addressing
185                 bt_f_if1 sspcon2, ACKSTAT
186                 bra     m_bad_address_ack
187                 ; OK, we got ack.
188
189                 bc_f    st, st_addressing
190                 bt_f_if1 st, st_reading
191                 bra     m_event_done_addressing_read
192                 bra     m_event_done_addressing_write
193
194 ;----------
195 m_stop
196 ;       st_stopping                     clear           set
197 ;       st_reading/acking/writing       any             unchanged
198 ; expects to return directly to main program or to end interrupt handler
199                 bs_f    st, st_stopping
200                 bs_f    SSPCON2, PEN
201                 return
202
203 ;----------
204 m_event_done_stopping
205                 clr_f   st
206                 goto    i2cmu_done
207
208 ;----------
209 m_bad_address_ack
210                 panic   morse_SK
211
212 ;----------
213 m_improper_slave
214 ;       slave                   slave number
215                 panic   morse_SN
216
217 ;========================================
218 ; MASTER - WRITING
219
220 ;----------
221 i2cm_write_start
222 ;                               At call         On return
223 ;   State                       Idle            Writing-Setup
224 ;   W                           slave number    any
225                 tst_f_ifnz st
226                 bra     m_improper_write_start
227
228                 bs_f    st, st_writing
229                 bra     m_start
230
231 ;----------
232 m_event_done_writing
233                 ; Did slave ack our byte ?  It had better have done !
234                 bt_f_if1 sspcon2, ACKSTAT
235                 bra     m_event_bad
236
237                 bs_f    st, st_subsequent
238 ;...
239
240 m_event_done_addressing_write
241 ;       ACKSTAT         checked
242 ;       st_addressing   cleared
243                 call    i2cmu_write_next_byte
244                 bra_z   m_event_write_mustfinish
245                 ; OK, we have the next byte:
246
247                 mov_wf  SSPBUF
248                 return
249
250 ;----------
251 m_event_write_mustfinish
252                 bt_f_if0 st, st_subsequent
253                 bra     m_improper_write_finish
254
255                 bra     m_stop
256
257 ;----------
258 m_improper_write_start
259                 panic   morse_SW
260
261 ;----------
262 m_improper_write_finish
263                 panic   morse_SF
264
265 ;========================================
266 ; MASTER - READING
267
268 ;----------
269 i2cm_read_start
270 ;                               At call         On return
271 ;       State                   Idle            Reading-Busy
272 ;       W                       slave number    any
273                 tst_f_ifnz st
274                 bra     m_improper_read_start
275
276                 bs_f    st, st_reading
277                 bra     m_start
278
279 ;----------
280 m_event_done_addressing_read
281 m_event_done_acking_readmore
282 ;       ACKSTAT                 checked
283 ;       st_addressing/acking    cleared
284                 bs_f    SSPCON2, RCEN
285                 return
286
287 ;----------
288 m_event_done_reading
289                 bt_f_if0 sspstat, BF
290                 bra     m_event_bad
291
292                 mov_fw  SSPBUF
293
294                 bs_f    st, st_awaiting
295                 goto    i2cmu_read_got_byte
296
297 ;----------
298 i2cm_read_another
299 ;   State                       Reading-Wait    Reading-Busy
300                 bt_f_if0 st, st_awaiting
301                 bra     m_improper_read_another
302                 ; OK, we're fine to read another:
303 ;...
304
305 m_read_ack
306 ;       st_reading              1 iff not done          unchanged
307 ;       st_awaiting             still set               cleared
308 ;       st_acking               clear                   set
309 ; expects to return directly to main program or to end interrupt handler
310                 bc_f    st, st_awaiting
311                 bs_f    st, st_acking
312                 bc_f    SSPCON2, ACKDT ; ACKDT=0 means to acknowledge
313                 bt_f_if0 st, st_reading
314                 bs_f    SSPCON2, ACKDT ; don't ack last byte
315                 bs_f    SSPCON2, ACKEN
316                 return
317
318 ;----------
319 i2cm_read_done
320 ;   State                       Reading-Wait    Stopping
321                 bc_f    st, st_reading
322                 
323                 bt_f_if0 st, st_awaiting
324                 bra     m_improper_read_done
325                 ; OK:
326
327                 bra     m_read_ack
328
329 ;----------
330 m_event_done_acking
331                 bc_f    st, st_acking
332
333                 bt_f_if1 st, st_reading
334                 bra     m_event_done_acking_readmore
335
336                 bra     m_stop
337
338 ;----------
339 m_improper_read_start
340                 panic   morse_SR
341
342 ;----------
343 m_improper_read_another
344                 panic   morse_SA
345
346 ;----------
347 m_improper_read_done
348                 panic   morse_SD
349
350 ;======================================================================
351 ; SLAVE
352
353 ;----------
354 i2cs_init
355 ;       W               slave number            undefined
356                 rcall   slave2addr
357                 mov_wf  SSPADD
358                 clr_f   st
359                 mov_lw  0x16 ; !SSPEN, CKP(release), I2C 7-bit slave no-SP-int
360                 mov_wf  SSPCON1
361                 mov_lw  0x01 ; !GCEN, SEN
362                 mov_wf  SSPCON2
363                 mov_lw  0x80 ; SMP(noslew), !CKE(!smbus)
364                 mov_wf  SSPSTAT
365 init_enable
366 ; Actually engages the I2C controller, which must already have
367 ; been set up (all but SSPEN):
368 ;  SSPADD,SSPCON1,SSPCON2       configured correctly    unchanged
369 ;       SSPSTAT                 configured correctly    unchanged, except:
370 ;       SSPSTAT<SSPEN>          0 (disabled)            1 (enabled)
371 ;       SSPIE                   0 (disabled)            1 (enabled)
372 ;       TRISB<1,0>              any                     configured for I2C
373 ;       SSPIP                   any                     configured correctly
374 ;       GIEL                    0 (disabled)            0 (disabled)
375 ;       ssp* shadows            any                     all bits set
376                 set_f   sspstat
377                 set_f   sspcon1
378                 set_f   sspcon2
379                 set_f   st_orig
380                 bs_f    TRISB, 0
381                 bs_f    TRISB, 1
382                 bc_f    IPR1, SSPIP
383                 bs_f    SSPCON1, SSPEN
384                 bs_f    PIE1, SSPIE
385                 return
386
387 ;========================================
388 ; SLAVE - INTERRUPT HANDLING
389
390 ; In general, we figure out our state and then see what kind of events
391 ; we were expecting.  Bits we want to check:
392 ;       80    60    20    10            08    04    02    01
393 ;       SMP   CKE   D_A   P             S     R_W   UA    BF
394 ;       set   clr   data? stop          start read? clr   full?
395 ; (we don't usually mention SMP, CKE and UA below)
396
397 ; Some macros:
398
399 chkvals_start_sspstat macro
400                 mov_fw  sspstat
401                 endm
402
403 chkval macro lastval, value, label
404                 xor_lw  value ^ lastval
405                 bra_z   label
406                 endm
407
408 chkvals_addrrecv macro lastval
409         chkval  lastval, 0x8c, s_event_idle_addrrecvread ; A,!P, S,R,!BF
410         chkval  0x8c,    0x89, s_event_idle_addrrecvwrite ; A,!P, S,W,BF
411         endm
412 chkvals_addrrecv_lastval equ 0x89
413
414 ;----------
415 i2cs_interrupt
416                 bt_f_if0 PIR1, SSPIF
417                 return
418                 ; We have an interrupt:
419
420 ; Firstly, clear the interrupt flag so that if something else happens
421 ; while we faff, the interrupt will be regenerated:
422                 bc_f    PIR1, SSPIF
423
424                 mov_ff  SSPSTAT, sspstat
425                 mov_ff  SSPCON1, sspcon1
426                 mov_ff  st, st_orig
427
428                 mov_lw  (1<<WCOL) | (1<<SSPOV)
429                 and_wfw sspcon1
430                 bra_nz  s_event_bad
431
432                 bt_f_if1 st, st_reading
433                 bra     s_event_reading
434
435                 bt_f_if1 st, st_writing
436                 bra     s_event_writing
437
438 s_event_idle
439                 chkvals_start_sspstat
440                 chkvals_addrrecv 0
441 s_event_bad
442                 panic   morse_SS ; slave, interrupt, controller in bad state
443
444 ;========================================
445 ; SLAVE - READING
446
447 ;----------
448 s_event_idle_addrrecvread
449                 bs_f    st, st_reading
450                 call    i2csu_read_begin
451                 bra     s_events_reading_datasend
452
453 ;----------
454 s_event_reading
455                 chkvals_start_sspstat
456                 chkval  0, 0xac, s_event_reading_datasent ; D,!P, S,R,!BF
457
458 ; mov_fw st
459 ; bra_z nopanic
460 ; panic morse_Z
461 ;nopanic
462
463                 ; Whatever is happening, we're done reading now !
464                 clr_f   st
465                 call    i2csu_read_done
466
467                 chkvals_start_sspstat
468                 chkval  0, 0xa8, s_event_reading_datanack ; D,!P, S,!R,!BF
469                 ; Or, maybe it was nack and then we were reselected:
470                 chkvals_addrrecv 0xa8
471
472                 bra     s_event_bad
473
474 ;----------
475 s_event_reading_datasent
476                 call    i2csu_read_another
477 s_events_reading_datasend
478                 mov_wf  SSPBUF
479                 bs_f    SSPCON1, CKP
480 s_event_reading_datanack
481                 return
482
483 ;========================================
484 ; SLAVE - WRITING
485
486 ;----------
487 s_event_idle_addrrecvwrite
488                 bs_f    SSPCON1, 3 ; we'll need the Stop interrupt
489                 bs_f    st, st_writing
490                 ; well, this is all fine so far, so do carry on:
491
492 s_write_slurpbyte
493 ;       W               any                     byte from master
494 ;       i2c controller  waiting due to SEN etc  continuing with next byte
495                 mov_fw  SSPBUF
496                 bs_f    SSPCON1, CKP
497                 return
498
499 ;----------
500 s_event_writing
501                 chkvals_start_sspstat
502                 chkval  0, 0xa9, s_event_writing_datarecv ; D,!P, S,W,BF
503
504                 ; Well, we're done writing now in any case
505                 clr_f   st
506                 bc_f    SSPCON1, 3 ; no Start and Stop interrupts any more
507                 call    i2csu_write_done
508
509                 ; Who knows what might have happened.  We may have
510                 ; missed a number of S and P due to delay between
511                 ; clearing SSPIF and SSPM3(s&p-intrs) so we can't be
512                 ; too picky.
513
514                 ; First, the nice cases:
515                 chkvals_start_sspstat
516                 chkvals_addrrecv 0
517
518                 ; Then random junk:
519                 mov_fw  sspstat
520                 and_lw  0xc7 ; ?D_A, ?P; ?S
521                 xor_lw  0x80 ; SMP, !CKE, !R_W, !UA, !BF
522                 bt_f_if1 STATUS, Z
523                 return
524                 ; no good
525
526                 bra     s_event_bad
527
528 ;----------
529 s_event_writing_datarecv
530                 rcall   s_write_slurpbyte
531
532                 bt_f_if1 st, st_subsequent
533                 goto    i2csu_write_another
534                 ; not subsequent (yet):
535
536                 bs_f    st, st_subsequent
537                 goto    i2csu_write_begin
538
539 ;======================================================================
540
541  include panic.fin
542  include i2clib.inc
543
544  end