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