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