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