chiark / gitweb /
panic crash dump seems to work on slave and test-sofar master end is probably good...
[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 clock equ 0
11  include ../iwjpictest/clockvaries.inc
12  include panic.inc
13  include morse+auto.inc
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                          slave
71 st_starting     equ 7 ; Writing-Setup?,Reading-Busy?
72 st_addressing   equ 6 ; Writing-Setup?,Reading-Busy?
73 st_writing      equ 5 ; Writing-*                       [Idle-going-]Receiving
74 st_subsequent   equ 4 ; Writing?                        Receiving
75 st_reading      equ 3 ; Reading-*                       Transmit-*
76 st_awaiting     equ 2 ; Reading-Wait                    Transmit-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                 mov_ff  SSPSTAT, sspstat
127                 mov_ff  SSPCON1, sspcon1
128                 mov_ff  SSPCON2, sspcon2
129
130                 bc_f    PIR1, SSPIF
131
132                 mov_lw  (1<<WCOL) | (1<<SSPOV)
133                 and_wfw sspcon1
134                 bra_nz  m_event_bad
135
136                 ; No ?  Well, then the I2C should be idle now:
137                 mov_fw  sspcon2
138                 and_lw  ~((1<<ACKSTAT) | (1<<ACKDT)) ; those two are ok if set
139                 bra_nz  m_event_bad
140                 ; OK...
141
142                 bt_f_if1 sspstat, R_W
143                 bra_nz  m_event_bad
144
145                 bt_f_if1 st, st_stopping
146                 bra     m_event_done_stopping
147
148                 bt_f_if1 st, st_starting
149                 bra     m_event_done_starting
150                 ; not just done SEN
151
152                 bt_f_if1 st, st_addressing
153                 bra     m_event_done_addressing
154
155                 bt_f_if1 st, st_writing
156                 bra     m_event_done_writing
157
158                 bt_f_if1 st, st_acking
159                 bra     m_event_done_acking
160
161                 bt_f_if1 st, st_reading
162                 bra     m_event_done_reading
163
164 m_event_bad
165                 i2cpanic morse_SM
166
167 ;========================================
168 ; MASTER - STARTING, ADDRESSING, STOPPING
169
170 ;----------
171 m_start
172 ;       st                      checked for busyness    correct
173 ;       st_reading/writing      set                     unchanged
174 ;       st_starting             clear                   set
175 ;       W                       slave number            any
176 ;       slave                   any                     slave_number
177 ; expects to return directly to main program (caller)
178                 mov_wf  slave
179                 bra_z   m_improper_slave
180                 bs_f    SSPCON2, SEN
181 m_start_or_restart
182                 and_lw  ~31
183                 bra_nz  m_improper_slave
184                 bs_f    st, st_starting
185                 return
186
187 ;----------
188 m_event_done_starting
189                 mov_fw  slave
190                 rcall   slave2addr
191
192                 bt_f_if1 st, st_reading
193                 bs_w    0       ; address bottom bit means read
194
195                 mov_wf  SSPBUF
196                 bc_f    st, st_starting
197                 bs_f    st, st_addressing
198                 return
199
200 ;----------
201 m_event_done_addressing
202                 bt_f_if1 sspcon2, ACKSTAT
203                 bra     m_bad_address_ack
204                 ; OK, we got ack.
205
206                 bc_f    st, st_addressing
207                 bt_f_if1 st, st_reading
208                 bra     m_event_done_addressing_read
209                 bra     m_event_done_addressing_write
210
211 ;----------
212 m_stop
213 ;       st_stopping                     clear           set
214 ;       st_reading/acking/writing       any             unchanged
215 ; expects to return directly to main program or to end interrupt handler
216                 bs_f    st, st_stopping
217                 bs_f    SSPCON2, PEN
218                 return
219
220 ;----------
221 m_event_done_stopping
222                 clr_f   st
223                 goto    i2cmu_done
224
225 ;----------
226 m_bad_address_ack
227                 i2cpanic morse_SK
228
229 ;----------
230 m_improper_slave
231 ;       slave                   slave number
232                 i2cpanic morse_SN
233
234 ;========================================
235 ; MASTER - WRITING
236
237 ;----------
238 i2cm_write_start
239 ;                               At call         On return
240 ;   State                       Idle            Writing-Setup
241 ;   W                           slave number    any
242                 tst_f_ifnz st
243                 bra     m_improper_write_start
244
245                 bs_f    st, st_writing
246                 bra     m_start
247
248 ;----------
249 m_event_done_writing
250                 ; Did slave ack our byte ?  It had better have done !
251                 bt_f_if1 sspcon2, ACKSTAT
252                 bra     m_event_bad
253
254                 bs_f    st, st_subsequent
255 ;...
256
257 m_event_done_addressing_write
258 ;       ACKSTAT         checked
259 ;       st_addressing   cleared
260                 call    i2cmu_write_next_byte
261                 bra_z   m_event_write_mustfinish
262                 ; OK, we have the next byte:
263
264                 mov_wf  SSPBUF
265                 return
266
267 ;----------
268 m_event_write_mustfinish
269                 bt_f_if0 st, st_subsequent
270                 bra     m_improper_write_finish
271
272                 bra     m_stop
273
274 ;----------
275 m_improper_write_start
276                 i2cpanic morse_SW
277
278 ;----------
279 m_improper_write_finish
280                 i2cpanic morse_SF
281
282 ;========================================
283 ; MASTER - READING
284
285 ;----------
286 i2cm_read_start
287 ;                               At call         On return
288 ;       State                   Idle            Reading-Busy
289 ;       W                       slave number    any
290                 tst_f_ifnz st
291                 bra     m_read_start_busy
292
293                 bs_f    st, st_reading
294                 bra     m_start
295
296 ;----------
297 m_read_start_busy
298                 bt_f_if1 st, st_awaiting
299                 bra     m_read_different
300                 i2cpanic morse_SR
301
302 ;----------
303 m_read_different
304 ; Main program would like to address another slave.
305                 mov_wf  slave_next
306                 bra_z   m_improper_slave
307                 bra     i2cm_read_done
308
309 ;----------
310 m_event_done_addressing_read
311 m_event_done_acking_readmore
312 ;       ACKSTAT                 checked
313 ;       st_addressing/acking    cleared
314                 bs_f    SSPCON2, RCEN
315                 return
316
317 ;----------
318 m_event_done_reading
319                 bt_f_if0 sspstat, BF
320                 bra     m_event_bad
321
322                 mov_fw  SSPBUF
323
324                 bs_f    st, st_awaiting
325                 goto    i2cmu_read_got_byte
326
327 ;----------
328 i2cm_read_another
329 ;   State                       Reading-Wait    Reading-Busy
330                 bt_f_if0 st, st_awaiting
331                 bra     m_improper_read_another
332                 ; OK, we're fine to read another:
333 ;...
334
335 m_read_ack
336 ;       st_reading              1 iff not done          unchanged
337 ;       st_awaiting             still set               cleared
338 ;       st_acking               clear                   set
339 ; expects to return directly to main program or to end interrupt handler
340                 bc_f    st, st_awaiting
341                 bs_f    st, st_acking
342                 bc_f    SSPCON2, ACKDT ; ACKDT=0 means to acknowledge
343                 bt_f_if0 st, st_reading
344                 bs_f    SSPCON2, ACKDT ; don't ack last byte
345                 bs_f    SSPCON2, ACKEN
346                 return
347
348 ;----------
349 i2cm_read_done
350 ;   State                       Reading-Wait    Stopping
351                 bc_f    st, st_reading
352                 
353                 bt_f_if0 st, st_awaiting
354                 bra     improper_read_done_data
355                 ; OK:
356
357                 bra     m_read_ack
358
359 ;----------
360 m_event_done_acking
361                 bc_f    st, st_acking
362
363                 bt_f_if1 st, st_reading
364                 bra     m_event_done_acking_readmore
365
366                 mov_fw  slave_next
367                 bra_z   m_stop
368 ; ok, we want to read another:
369                 mov_wf  slave
370                 clr_f   slave_next
371                 bs_f    st, st_reading
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 - INTERRUPT HANDLING
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    60    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 ; Some macros:
431
432 chkvals_start macro what
433                 mov_fw  what
434                 endm
435
436 chkval macro lastval, value, label
437                 xor_lw  value ^ lastval
438                 bra_z   label
439                 endm
440
441 chkvals_addrrecv macro lastval
442         chkval  lastval, 0x8c, s_event_idle_addrrecvread ; A,!P, S,R,!BF
443         chkval  0x8c,    0x89, s_event_idle_addrrecvwrite ; A,!P, S,W,BF
444         endm
445 chkvals_addrrecv_lastval equ 0x89
446
447 ;----------
448 i2cs_interrupt  ; 4cy interrupt latency + 3cy until branch to here
449                 bt_f_if0 PIR1, SSPIF
450                 bra     s_event_bad_intr
451                 ; We have an interrupt:
452
453 ; Firstly, clear the interrupt flag so that if something else happens
454 ; while we faff, the interrupt will be regenerated:
455                 bc_f    PIR1, SSPIF
456
457                 mov_ff  st, st_orig
458
459                 mov_lw  (1<<WCOL) | (1<<SSPOV)
460                 and_wfw SSPCON1
461                 bra_nz  s_event_bad
462
463                 ; 8cy from entry to here, so total of 15cy
464                 bt_f_if1 st, st_reading
465                 bra     s_event_reading ; 18cy to 1st insn of event_reading
466
467                 bt_f_if1 st, st_writing
468                 bra     s_event_writing
469
470 s_event_idle
471                 chkvals_start SSPSTAT
472                 chkvals_addrrecv 0 ; 23cy to 1st insn of addrrecvread
473 s_event_bad
474                 i2cpanic morse_SS ; slave, interrupt, controller in bad state
475
476 s_event_bad_intr
477                 i2cpanic morse_IH ; unknown high-priority interrupt
478
479 ;========================================
480 ; SLAVE - READING
481
482 ;----------
483 s_event_idle_addrrecvread
484                 bs_f    st, st_awaiting
485                 goto    i2csu_read_begin ; 26cy until 1st insn of read_begin
486
487 ;----------
488 s_event_reading
489                 bs_f    st, st_awaiting ; (probably)
490
491                 mov_fw  SSPSTAT
492                 xor_lw  0xac ; D,!P, S,R,!BF
493                 bra_nz  s_event_reading_not_another
494                 goto    i2csu_read_another
495                                 ; 24cy until 1st insn of i2csu_read_another
496
497 ;----------
498 s_event_reading_datanack
499                 return
500
501 ;----------
502 s_event_reading_not_another
503                 ; Whatever is happening, we're done reading now !
504                 clr_f   st
505                 call    i2csu_read_done
506
507                 chkvals_start SSPSTAT
508                 chkval  0, 0xa8, s_event_reading_datanack ; D,!P, S,!R,!BF
509                 ; Or, maybe it was nack and then we were reselected:
510                 chkvals_addrrecv 0xa8
511
512                 bra     s_event_bad
513
514 ;----------
515 i2cs_read_data
516 ;       W               byte for master         any
517 ;       State           Transmit-Wait           Transmit-Busy
518                 mov_wf  SSPBUF
519                 bs_f    SSPCON1, CKP
520                 
521                 bt_f_if0 st, st_awaiting
522                 bra     improper_read_done_data
523                 bc_f    st, st_awaiting
524                 bs_f    st, st_reading
525                 return
526
527 ;========================================
528 ; SLAVE - WRITING
529
530 ;----------
531 s_event_idle_addrrecvwrite
532                 bs_f    SSPCON1, 3 ; we'll need the Stop interrupt
533                 bs_f    st, st_writing
534                 ; well, this is all fine so far, so do carry on:
535
536 s_write_slurpbyte
537 ;       W               any                     byte from master
538 ;       i2c controller  waiting due to SEN etc  continuing with next byte
539                 mov_fw  SSPBUF
540                 bs_f    SSPCON1, CKP
541                 return
542
543 ;----------
544 s_event_writing
545                 chkvals_start SSPSTAT
546                 chkval  0, 0xa9, s_event_writing_datarecv ; D,!P, S,W,BF
547
548                 ; Well, we're done writing now in any case
549                 clr_f   st
550                 bc_f    SSPCON1, 3 ; no Start and Stop interrupts any more
551                 call    i2csu_write_done
552
553                 ; Who knows what might have happened.  We may have
554                 ; missed a number of S and P due to delay between
555                 ; clearing SSPIF and SSPM3(s&p-intrs) so we can't be
556                 ; too picky.
557
558                 ; First, the nice cases:
559                 chkvals_start SSPSTAT
560                 chkvals_addrrecv 0
561
562                 ; Then random junk:
563                 mov_fw  SSPSTAT
564                 and_lw  0xc7 ; ?D_A, ?P; ?S
565                 xor_lw  0x80 ; SMP, !CKE, !R_W, !UA, !BF
566                 bra_nz  s_event_bad
567                 return
568
569 ;----------
570 s_event_writing_datarecv
571                 rcall   s_write_slurpbyte
572
573                 bt_f_if1 st, st_subsequent
574                 goto    i2csu_write_another
575
576                 bs_f    st, st_subsequent
577                 goto    i2csu_write_begin
578
579
580 ;======================================================================
581
582  include panic.fin
583  include i2clib.inc
584
585  end