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