@@ -12,11 +12,13 @@ module Clash.Cores.SPI
12
12
, SpiMasterIn (.. )
13
13
, SpiMasterOut (.. )
14
14
, spiMaster
15
+ , spiMaster1
15
16
-- * SPI slave
16
17
, SpiSlaveIn (.. )
17
18
, SpiSlaveOut (.. )
18
19
, SPISlaveConfig (.. )
19
20
, spiSlave
21
+ , spiSlave1
20
22
-- ** Vendor configured SPI slaves
21
23
, spiSlaveLatticeSBIO
22
24
, spiSlaveLatticeBB
@@ -125,7 +127,7 @@ sampleOnLeading _ = False
125
127
sampleOnTrailing :: SPIMode -> Bool
126
128
sampleOnTrailing = not . sampleOnLeading
127
129
128
- data SPISlaveConfig ds dom
130
+ data SPISlaveConfig ds dom ( misoW :: Nat ) ( mosiW :: Nat )
129
131
= SPISlaveConfig
130
132
{ spiSlaveConfigMode :: SPIMode
131
133
-- ^ SPI mode
@@ -139,30 +141,34 @@ data SPISlaveConfig ds dom
139
141
--
140
142
-- * Set to /False/ when core clock is twice as fast, or as fast, as the SCK
141
143
, spiSlaveConfigBuffer
142
- :: BiSignalIn ds dom 1
144
+ :: BiSignalIn ds dom misoW
143
145
-> Signal dom Bool
144
- -> Signal dom Bit
145
- -> BiSignalOut ds dom 1
146
+ -> Signal dom ( BitVector misoW )
147
+ -> BiSignalOut ds dom misoW
146
148
-- ^ Tri-state buffer: first argument is the inout pin, second
147
149
-- argument is the output enable, third argument is the value to
148
150
-- output when the enable is high
149
151
}
150
152
151
153
-- | SPI capture and shift logic that is shared between slave and master
152
154
spiCommon
153
- :: forall n dom
154
- . (HiddenClockResetEnable dom , KnownNat n , 1 <= n )
155
+ :: forall n dom inW outW
156
+ . ( HiddenClockResetEnable dom
157
+ , KnownNat inW
158
+ , KnownNat outW
159
+ , KnownNat n
160
+ , 1 <= n )
155
161
=> SPIMode
156
162
-> Signal dom Bool
157
163
-- ^ Slave select
158
- -> Signal dom Bit
164
+ -> Signal dom ( BitVector inW )
159
165
-- ^ Slave: MOSI; Master: MISO
160
166
-> Signal dom Bool
161
167
-- ^ SCK
162
- -> Signal dom (BitVector n )
163
- -> ( Signal dom Bit -- Slave: MISO; Master: MOSI
164
- , Signal dom Bool -- Acknowledge start of transfer
165
- , Signal dom (Maybe (BitVector n ))
168
+ -> Signal dom (Vec outW ( BitVector n ) )
169
+ -> ( Signal dom ( BitVector outW ) -- Slave: MISO; Master: MOSI
170
+ , Signal dom Bool -- Acknowledge start of transfer
171
+ , Signal dom (Maybe (Vec inW ( BitVector n ) ))
166
172
)
167
173
spiCommon mode ssI msI sckI dinI =
168
174
mooreB go cvt ( 0 :: Index n -- cntR
@@ -176,13 +182,16 @@ spiCommon mode ssI msI sckI dinI =
176
182
(ssI,msI,sckI,dinI)
177
183
where
178
184
cvt (_,_,_,dataInQ,dataOutQ,ackQ,doneQ) =
179
- ( head dataOutQ
185
+ ( v2bv $ map head dataOutQ
180
186
, ackQ
181
187
, if doneQ
182
- then Just (pack dataInQ)
188
+ then Just (map v2bv dataInQ)
183
189
else Nothing
184
190
)
185
191
192
+ go :: (Index n , Bool , Bool , Vec inW (Vec n Bit ), Vec outW (Vec n Bit ), Bool , Bool )
193
+ -> (Bool , BitVector inW , Bool , Vec outW (BitVector n ))
194
+ -> (Index n , Bool , Bool , Vec inW (Vec n Bit ), Vec outW (Vec n Bit ), Bool , Bool )
186
195
go (cntQ,cntOldQ,sckOldQ,dataInQ,dataOutQ,_,_) (ss,ms,sck,din) =
187
196
(cntD,cntOldD,sck,dataInD,dataOutD,ackD,doneD)
188
197
where
@@ -191,16 +200,18 @@ spiCommon mode ssI msI sckI dinI =
191
200
| sampleSck = if cntQ == maxBound then 0 else cntQ + 1
192
201
| otherwise = cntQ
193
202
203
+ dataInD :: Vec inW (Vec n Bit )
194
204
dataInD
195
205
| ss = unpack undefined #
196
- | sampleSck = tail @ (n - 1 ) dataInQ :< ms
206
+ | sampleSck = zipWith ( \ d m -> tail @ (n - 1 ) d :< m) dataInQ (bv2v ms)
197
207
| otherwise = dataInQ
198
208
209
+ dataOutD :: Vec outW (Vec n Bit )
199
210
dataOutD
200
- | ss || (sampleOnTrailing mode && sampleSck && cntQ == maxBound ) = unpack din
211
+ | ss || (sampleOnTrailing mode && sampleSck && cntQ == maxBound ) = fmap bv2v din
201
212
| shiftSck = if sampleOnTrailing mode && cntQ == 0
202
213
then dataOutQ
203
- else tail @ (n - 1 ) dataOutQ :< unpack undefined #
214
+ else map ( \ d -> tail @ (n - 1 ) d :< unpack undefined # ) dataOutQ
204
215
| otherwise = dataOutQ
205
216
206
217
-- The counter is updated during the capture moment
@@ -222,19 +233,23 @@ spiCommon mode ssI msI sckI dinI =
222
233
223
234
-- | SPI slave configurable SPI mode and tri-state buffer
224
235
spiSlave
225
- :: forall n ds dom
226
- . (HiddenClockResetEnable dom , KnownNat n , 1 <= n )
227
- => SPISlaveConfig ds dom
236
+ :: forall n ds dom misoW mosiW
237
+ . ( HiddenClockResetEnable dom
238
+ , KnownNat n
239
+ , 1 <= n
240
+ , KnownNat misoW
241
+ , KnownNat mosiW )
242
+ => SPISlaveConfig ds dom misoW mosiW
228
243
-- ^ Configure SPI mode and tri-state buffer
229
- -> SpiSlaveIn ds dom 1 1
244
+ -> SpiSlaveIn ds dom misoW mosiW
230
245
-- ^ SPI interface
231
- -> Signal dom (BitVector n )
246
+ -> Signal dom (Vec misoW ( BitVector n ) )
232
247
-- ^ Data to send from slave to master.
233
248
--
234
249
-- Input is latched the moment slave select goes low
235
- -> ( SpiSlaveOut ds dom 1 1
250
+ -> ( SpiSlaveOut ds dom misoW mosiW
236
251
, Signal dom Bool
237
- , Signal dom (Maybe (BitVector n )))
252
+ , Signal dom (Maybe (Vec mosiW ( BitVector n ))) )
238
253
-- ^ Parts of the tuple:
239
254
--
240
255
-- 1. The "out" part of the inout port of the MISO; used only for simulation.
@@ -246,17 +261,46 @@ spiSlave (SPISlaveConfig mode latch buf) (SpiSlaveIn mosi bin sclk ss) din =
246
261
let ssL = if latch then delay undefined ss else ss
247
262
mosiL = if latch then delay undefined mosi else mosi
248
263
sclkL = if latch then delay undefined sclk else sclk
249
- (miso, ack, dout) = spiCommon mode (bitToBool <$> ssL) ( head . bv2v <$> mosiL) (bitToBool <$> sclkL) din
264
+ (miso, ack, dout) = spiCommon mode (bitToBool <$> ssL) mosiL (bitToBool <$> sclkL) din
250
265
bout = buf bin (not . bitToBool <$> ssL) miso
251
266
in (SpiSlaveOut bout, ack, dout)
252
267
268
+ spiSlave1
269
+ :: forall n ds dom
270
+ . ( HiddenClockResetEnable dom
271
+ , KnownNat n
272
+ , 1 <= n )
273
+ => SPISlaveConfig ds dom 1 1
274
+ -- ^ Configure SPI mode and tri-state buffer
275
+ -> SpiSlaveIn ds dom 1 1
276
+ -- ^ SPI interface
277
+ -> Signal dom (BitVector n )
278
+ -- ^ Data to send from slave to master.
279
+ --
280
+ -- Input is latched the moment slave select goes low
281
+ -> ( SpiSlaveOut ds dom 1 1
282
+ , Signal dom Bool
283
+ , Signal dom (Maybe (BitVector n )) )
284
+ -- ^ Parts of the tuple:
285
+ --
286
+ -- 1. The "out" part of the inout port of the MISO; used only for simulation.
287
+ --
288
+ -- 2. the acknowledgement for the data sent from the master to the slave.
289
+ --
290
+ -- 2. (Maybe) the word sent by the master
291
+ spiSlave1 config spiIn dout =
292
+ let (spiOut, ack, din) = spiSlave config spiIn (singleton <$> dout)
293
+ in (spiOut, ack, fmap head <$> din)
294
+
253
295
-- | SPI master configurable in the SPI mode and clock divider
254
296
--
255
297
-- Adds latch to MISO line if the (half period) clock divider is
256
298
-- set to 2 or higher.
257
299
spiMaster
258
- :: forall n halfPeriod waitTime dom
300
+ :: forall n halfPeriod waitTime dom misoW mosiW
259
301
. ( HiddenClockResetEnable dom
302
+ , KnownNat misoW
303
+ , KnownNat mosiW
260
304
, KnownNat n
261
305
, 1 <= n
262
306
, 1 <= halfPeriod
@@ -270,14 +314,14 @@ spiMaster
270
314
-> SNat waitTime
271
315
-- ^ (core clock) cycles between de-asserting slave-select and start of
272
316
-- the SPI clock
273
- -> Signal dom (Maybe (BitVector n ))
317
+ -> Signal dom (Maybe (Vec mosiW ( BitVector n ) ))
274
318
-- ^ Data to send from master to slave, transmission starts when receiving
275
319
-- /Just/ a value
276
- -> SpiMasterIn dom 1 1
277
- -> ( SpiMasterOut dom 1 1
320
+ -> SpiMasterIn dom misoW mosiW
321
+ -> ( SpiMasterOut dom misoW mosiW
278
322
, Signal dom Bool -- Busy
279
323
, Signal dom Bool -- Acknowledge
280
- , Signal dom (Maybe (BitVector n )) -- Data: Slave -> Master
324
+ , Signal dom (Maybe (Vec misoW ( BitVector n ) )) -- Data: Slave -> Master
281
325
)
282
326
-- ^ Parts of the tuple:
283
327
--
@@ -288,27 +332,59 @@ spiMaster
288
332
-- the data line will be ignored when /True/
289
333
-- 5. (Maybe) the word send from the slave to the master
290
334
spiMaster mode fN fW din (SpiMasterIn miso) =
291
- let (mosi, ack, dout) = spiCommon mode ssL ( head . bv2v <$> misoL) sclkL
292
- (fromMaybe undefined # <$> din)
335
+ let (mosi, ack, dout) = spiCommon mode ssL misoL sclkL
336
+ (fromMaybe ( repeat undefined # ) <$> din)
293
337
latch = snatToInteger fN /= 1
294
338
ssL = if latch then delay undefined ss else ss
295
339
misoL = if latch then delay undefined miso else miso
296
340
sclkL = if latch then delay undefined sclk else sclk
297
341
(ss, sclk, busy) = spiGen mode fN fW din
298
- in (SpiMasterOut (v2bv . singleton <$> mosi) (boolToBit <$> sclk) (boolToBit <$> ss), busy, ack, dout)
342
+ in (SpiMasterOut mosi (boolToBit <$> sclk) (boolToBit <$> ss), busy, ack, dout)
343
+
344
+ -- | SPI master with single-bit MISO and MOSI width.
345
+ spiMaster1
346
+ :: forall n halfPeriod waitTime dom
347
+ . ( HiddenClockResetEnable dom
348
+ , KnownNat n
349
+ , 1 <= n
350
+ , 1 <= halfPeriod
351
+ , 1 <= waitTime )
352
+ => SPIMode
353
+ -- ^ SPI Mode
354
+ -> SNat halfPeriod
355
+ -- ^ Clock divider (half period)
356
+ --
357
+ -- If set to two or higher, the MISO line will be latched
358
+ -> SNat waitTime
359
+ -- ^ (core clock) cycles between de-asserting slave-select and start of
360
+ -- the SPI clock
361
+ -> Signal dom (Maybe (BitVector n ))
362
+ -- ^ Data to send from master to slave, transmission starts when receiving
363
+ -- /Just/ a value
364
+ -> SpiMasterIn dom 1 1
365
+ -> ( SpiMasterOut dom 1 1
366
+ , Signal dom Bool -- Busy
367
+ , Signal dom Bool -- Acknowledge
368
+ , Signal dom (Maybe (BitVector n )) -- Data: Slave -> Master
369
+ )
370
+ spiMaster1 mode halfPeriod waitTime dout spiIn =
371
+ let (spiOut, busy, ack, din) =
372
+ spiMaster mode halfPeriod waitTime (fmap singleton <$> dout) spiIn
373
+ in (spiOut, busy, ack, fmap head <$> din)
299
374
300
375
-- | Generate slave select and SCK
301
376
spiGen
302
- :: forall n halfPeriod waitTime dom
377
+ :: forall n halfPeriod waitTime dom outW
303
378
. ( HiddenClockResetEnable dom
304
379
, KnownNat n
380
+ , KnownNat outW
305
381
, 1 <= n
306
382
, 1 <= halfPeriod
307
383
, 1 <= waitTime )
308
384
=> SPIMode
309
385
-> SNat halfPeriod
310
386
-> SNat waitTime
311
- -> Signal dom (Maybe (BitVector n ))
387
+ -> Signal dom (Maybe (Vec outW ( BitVector n ) ))
312
388
-> ( Signal dom Bool
313
389
, Signal dom Bool
314
390
, Signal dom Bool
@@ -386,11 +462,11 @@ spiSlaveLatticeSBIO
386
462
--
387
463
-- 2. (Maybe) the word send by the master
388
464
spiSlaveLatticeSBIO mode latchSPI =
389
- spiSlave (SPISlaveConfig mode latchSPI sbioX)
465
+ spiSlave1 (SPISlaveConfig mode latchSPI sbioX)
390
466
where
391
467
sbioX bin en dout = bout
392
468
where
393
- (bout,_,_) = sbio 0b101001 bin (pure 0 ) dout (pure undefined ) en
469
+ (bout,_,_) = sbio 0b101001 bin (pure 0 ) ( head . bv2v <$> dout) (pure undefined ) en
394
470
395
471
396
472
-- | SPI slave configurable SPI mode, using the BB tri-state buffer
@@ -423,8 +499,8 @@ spiSlaveLatticeBB
423
499
--
424
500
-- 2. (Maybe) the word send by the master
425
501
spiSlaveLatticeBB mode latchSPI =
426
- spiSlave (SPISlaveConfig mode latchSPI bbX)
502
+ spiSlave1 (SPISlaveConfig mode latchSPI bbX)
427
503
where
428
504
bbX bin en dout = bout
429
505
where
430
- (bout,_) = bidirectionalBuffer (toEnable en) bin dout
506
+ (bout,_) = bidirectionalBuffer (toEnable en) bin ( head . bv2v <$> dout)
0 commit comments