chiark / gitweb /
before copies of ssp*
[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 ;============================================================
11 ; COMMON ADMINISTRATIVE ROUTINES and VARIABLES
12
13                 udata_acs
14
15 sspstat         res     1
16 sspcon1         res     1
17 sspcon2         res     1
18
19 st      res     1 ; bitmask, bit set in visible states:
20                   ;    master                          slave
21 st_reading      equ 0 ; Reading-*                       Transmitting
22 st_writing      equ 1 ; Writing-*                       [Idle-going-]Receiving
23 st_subsequent   equ 2 ;                                 Receiving
24 st_working      equ 3 ; Writing-*,Reading-Busy,Stopping
25 st_starting     equ 4 ; Writing-Setup,Reading-Busy
26
27                 code
28
29 ;----------
30 slave2addr
31 ; computes slave address in form suitable for use in i2c controller
32 ; actual i2c slave address is (slave number) + 0b0001000
33 ;       W               slave number            i2c address * 2
34                 add_lw  0b0001000
35                 rlc_w
36                 return
37
38 ;----------
39 check_wcolsspov
40                 mov_fw  SSPCON1
41                 mov_wf  ssp
42                 and_lw  0xc0 ; WCOL,SSPOV
43                 bra_z   intr_wcolsspov
44                 return
45
46 ;----------
47 intr_wcolsspov
48                 panic   morse_SV
49
50 ;======================================================================
51 ; MASTER
52
53 ;----------
54 i2cm_init
55                 mov_lw  100-1   ; baud rate = Fosc/(4*(SSPADD+1))
56                 mov_wf  SSPADD  ; Fosc=20MHz, so SSPADD==99 means 50kbit/s
57                 mov_lw  0x08    ; !SSPEN, Master mode
58                 mov_wf  SSPCON1
59                 clr_f   SSPCON2 ; nothing going
60                 mov_lw  0x80    ; SMP(noslew), !CKE(!smbus)
61                 bra     init_enable
62
63 ;----------
64 i2cm_write_start
65 ;                               At call         On return
66 ;   State                       Idle            Writing-Setup
67 ;   W                           slave number    any
68                 tst_f_ifnz st
69                 bra     m_bad_write_start
70                 bs_f    st, st_writing
71 m_start
72                 bs_f    st, st_starting
73                 bs_f    SSPCON2, SEN
74                 return
75
76 ;----------
77 m_bad_write_start
78                 panic   morse_SPW
79
80 ;----------
81 i2cm_interrupt
82                 ; Do we have a doomy clash ?
83                 bsr     check_wcolsspov
84
85                 ; No ?  Well, then the I2C should be idle now:
86                 mov_fw  SSPCON2
87                 mov_wf  ssp
88                 and_lw  ~0x60 ; ACKSTAT,ACKDT
89                 bra_nz  m_bad_sspcon2
90                 ; OK, what's happening;
91
92                 bt_f_if0 PIR1, SSPIF
93                 return
94                 ; We have an interrupt:
95
96                 bt_f_if1 st, st_starting
97                 bra     m_event_starting
98                 ; not just done SEN
99
100                 fixme
101
102 ;----------
103 m_bad_sspcon2
104                 panic   morse_SM
105
106
107 ;----------
108 m_event_starting
109                 mov_lw  0x88
110                 bsr     m_check_sspstat
111
112
113 m_check_sspstat
114 ;       W       expected bit values             any
115 ; Panics if  (SSPSTAT ^ W) & mask  != 0
116                 mov_ff  SSPSTAT, ssp
117                 
118
119 ;======================================================================
120 ; SLAVE
121
122 ;----------
123 i2cs_init
124 ;       W               slave number            undefined
125                 rcall   slave2addr2
126                 mov_wf  SSPADD
127                 clr_f   st
128                 mov_lw  0x16 ; !SSPEN, CKP(release), I2C 7-bit slave no-SP-int
129                 mov_wf  SSPCON1
130                 mov_lw  0x01 ; !GCEN, SEN
131                 mov_wf  SSPCON2
132                 mov_lw  0x8 ; SMP(noslew), !CKE(!smbus)
133                 mov_wf  SSPSTAT
134 ms_init_enable
135 ; Actually engages the I2C controller, which must already have
136 ; been set up (all but SSPEN):
137 ;  SSPADD,SSPCON1,SSPCON2       configured correctly    unchanged
138 ;       SSPSTAT                 configured correctly    unchanged, except:
139 ;       SSPSTAT<SSPEN>          0 (disabled)            1 (enabled)
140 ;       SSPIE                   0 (disabled)            1 (enabled)
141 ;       TRISB<1,0>              any                     configured for I2C
142 ;       SSPIP                   any                     configured correctly
143 ;       GIEL                    0 (disabled)            0 (disabled)
144                 bs_f    TRISB, 0
145                 bs_f    TRISB, 1
146                 bc_f    IPR1, SSPIP
147                 bs_f    SSPCON1, SSPEN
148                 bs_f    PIE1, SSPIE
149                 return
150
151 ;========================================
152 ; SLAVE - INTERRUPT HANDLING
153
154 ; In general, we figure out our state and then see what kind of events
155 ; we were expecting.  Bits we want to check:
156 ;       80    60    20    10            08    04    02    01
157 ;       SMP   CKE   D_A   P             S     R_W   UA    BF
158 ;       set   clr   data? stop          start read? clr   full?
159 ; (we don't usually mention SMP, CKE and UA below)
160
161 ; Some macros:
162
163 chkvals_start macro
164                 mov_fw  ssp
165 chkval_lastvalue equ 0
166                 endm
167
168 chkval macro value, label
169                 xor_lw  value ^ chkval_lastvalue
170  chkval_lastvalue equ value
171                 bra_z   label
172                 endm
173
174 chkvals_addrrecv macro
175                 chkval  0x8c, s_event_idle_addrrecvread ; A,!P, S,R,!BF
176                 chkval  0x89, s_event_idle_addrrecvwrite ; A,!P, S,W,BF
177                 endm
178
179 ;----------
180 i2cs_interrupt
181                 bt_f_if0 PIR1, SSPIF
182                 return
183                 ; We have an interrupt:
184
185 ; Firstly, clear the interrupt flag so that if something else happens
186 ; while we faff, the interrupt will be regenerated:
187                 bc_f    PIR1, SSPIF
188
189 ; Check that nothing obvious is wrong:
190                 bsr     check_wcolsspov
191
192                 bt_f_if0 st, st_reading
193                 bra     s_event_reading
194
195                 bt_f_if0 st, st_writing
196                 bra     s_event_writing
197
198 s_event_idle
199                 chkvals_start
200                 chkvals_addrrecv
201
202                 panic   morse_SI
203
204 ;========================================
205 ; SLAVE - READING
206
207 ;----------
208 s_event_idle_addrrecvread
209                 bs_f    st, st_reading
210                 call    i2csu_read_begin
211                 bra     s_events_read_datasend
212
213 ;----------
214 s_event_reading
215                 chkvals_start
216                 chkval  0xac, s_event_reading_datasent ; D,!P, S,R,!BF
217
218                 ; Whatever is happening, we're done reading now !
219                 clr_f   st
220                 call    i2csu_read_done
221
222                 chkval  0xa8, s_event_reading_datanack ; D,!P, S,!R,!BF
223                 ; Or, maybe it was nack and then we were reselected:
224                 chkvals_addrrecv
225
226                 panic   morse_SR
227
228 ;----------
229 s_event_reading_datasent
230                 call    i2csu_read_another
231 s_events_reading_datasend
232                 mov_wf  SSPBUF
233                 bs_f    SSPCON1, CKP
234 s_event_reading_datanack
235                 return
236
237 ;========================================
238 ; SLAVE - WRITING
239
240 ;----------
241 s_event_idle_addrrecvwrite
242                 bs_f    SSPCON, 3 ; we'll need the Stop interrupt
243                 bs_f    st, st_writing
244                 ; well, this is all fine so far, so do carry on:
245
246 s_write_slurpbyte
247 ;       W               any                     byte from master
248 ;       i2c controller  waiting due to SEN etc  continuing with next byte
249                 mov_fw  SSPBUF
250                 bs_f    SSPCON1, CKP
251                 return
252
253 ;----------
254 s_event_writing
255                 chkvals_start
256                 chkval  0xa9, s_event_writing_datarecv ; D,!P, S,W,BF
257
258                 ; Well, we're done writing now in any case
259                 clr_f   st
260                 bc_f    SSPCON1, 3 ; no Start and Stop interrupts any more
261                 call    i2csu_write_done
262
263                 ; Who knows what might have happened.  We may have
264                 ; missed a number of S and P due to delay between
265                 ; clearing SSPIF and SSPM3(s&p-intrs) so we can't be
266                 ; too picky.
267
268                 ; First, the nice cases:
269                 chkvals_start
270                 chkvals_addrrecv
271
272                 ; Then random junk:
273                 mov_fw  ssp
274                 and_lw  0xc7 ; ?D_A, ?P; ?S
275                 xor_lw  0x80 ; SMP, !CKE, !R_W, !UA, !BF
276                 bt_f_if1 STATUS, Z
277                 return
278
279                 panic   morse_SW
280
281 ;----------
282 s_event_writing_datarecv
283                 rcall   s_write_slurpbyte
284
285                 bt_f_if1 st, st_subsequent
286                 goto    i2csu_write_another
287                 ; not subsequent (yet):
288
289                 bs_f    st, st_subsequent
290                 goto    i2csu_write_begin
291
292 ;======================================================================
293
294  include i2clib.inc
295  end