Skip to content

Commit

Permalink
Fix i2c interface to vexRiscUartHello
Browse files Browse the repository at this point in the history
Co-authored-by: Lucas Bollen <[email protected]>
  • Loading branch information
hiddemoll and lmbollen committed Dec 4, 2023
1 parent 7212ea1 commit d53a4be
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ module Bittide.Instances.Pnr.ProcessingElement where
import Clash.Prelude

import Clash.Annotations.TH
import Clash.Cores.Xilinx.Ila (Depth(D4096))
import Clash.Explicit.Prelude(orReset, noReset)
import Clash.Xilinx.ClockGen
import Language.Haskell.TH
Expand Down Expand Up @@ -47,9 +48,10 @@ vexRiscUartHello diffClk rst_in (uartIn, sclBs, sdaIn) =
peFunction =
toSignals $ withClockResetEnable clk200 rst200 enableGen $
circuit $ \(uartRx, i2cIn) -> do
[uartBus, i2cBus] <- processingElement @Basic200 peConfig -< ()
[uartBus, i2cBus0] <- processingElement @Basic200 peConfig -< ()
(uartTx, _uartStatus) <- uartWb d16 d16 (SNat @921600) -< (uartBus, uartRx)
i2cOut <- i2cWb -< (i2cBus, i2cIn)
i2cBus1 <- ilaWb 0 D4096 -< i2cBus0
i2cOut <- i2cWb -< (i2cBus1, i2cIn)
idC -< (uartTx, i2cOut)

(_,(uartOut, i2cO)) =
Expand Down
63 changes: 49 additions & 14 deletions bittide/src/Bittide/Wishbone.hs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import Bittide.SharedTypes

import Clash.Cores.UART (uart, ValidBaud)
import Clash.Cores.I2C
import Clash.Cores.Xilinx.Ila (ila, ilaConfig, IlaConfig(..), Depth)
import Clash.Cores.Xilinx.Ila hiding (Data)
import Clash.Util.Interpolate

import Bittide.Extra.Maybe
Expand All @@ -25,7 +25,7 @@ import Data.Bool(bool)
import Data.Constraint.Nat.Extra
import Data.Maybe

import Protocols.Df hiding (zipWith, pure, bimap, first, second, route, zip)
import Protocols.Df hiding (zipWith, pure, bimap, first, second, route, zip, snd)
import Protocols.Internal
import Protocols.Wishbone

Expand Down Expand Up @@ -440,17 +440,17 @@ wbToVec ::
( Vec nRegisters (Maybe (Bytes nBytes))
, Maybe (Index nRegisters)
, WishboneS2M (Bytes nBytes))
wbToVec readableData readAck WishboneM2S{..} = (writtenData, readRequest, wbS2M)
wbToVec readableData ack WishboneM2S{..} = (writtenData, transAddr, wbS2M)
where
(alignedAddress, alignment) = split @_ @(addrW - 2) @2 addr
addressRange = maxBound :: Index nRegisters
invalidAddress = (alignedAddress > resize (pack addressRange)) || alignment /= 0
masterActive = strobe && busCycle
err = masterActive && invalidAddress
acknowledge = masterActive && not err && (writeEnable || readAck)
wbWriting = writeEnable && acknowledge
acknowledge = masterActive && not err && ack
wbWriting = writeEnable && masterActive && not err
wbAddr = unpack $ resize alignedAddress :: Index nRegisters
readRequest = orNothing (masterActive && not err && not writeEnable) wbAddr
transAddr = orNothing (masterActive && not err) wbAddr
readData = readableData !! wbAddr
writtenData
| wbWriting = replace wbAddr (Just writeData) (repeat Nothing)
Expand All @@ -470,13 +470,13 @@ i2cWb ::
i2cWb = case (cancelMulDiv @nBytes @8) of
Dict -> Circuit go
where
go ((wbM2S, CSignal i2cIn), _) = ((wbS2M, CSignal $ pure ()), CSignal i2cOut)
go ((wbM2S, CSignal i2cIn), _) = hwSeqX ilaInstance ((wbS2M, CSignal $ pure ()), CSignal i2cOut)
where
-- Wishbone interface consists of:
-- 0. i2c data Read-Write
-- 1. clock divider Read-Write
-- 3. flags: MSBs are Read-Only flags, LSBs are Read-Write flags.
(vecOut, readRequest, wbS2M) = unbundle $ wbToVec <$> bundle vecIn <*> readAck <*> wbM2S
(vecOut, transAddr, wbS2M) = unbundle $ wbToVec <$> bundle vecIn <*> wbAck <*> wbM2S
vecIn = fmap resize dOut :> fmap (resize . pack) clkDiv :> flagsRead :> Nil
(i2cWrite :> clkDivWrite :> flagsWrite :> Nil) = unbundle vecOut

Expand All @@ -488,23 +488,58 @@ i2cWb = case (cancelMulDiv @nBytes @8) of
rwFlagsReg = regMaybe
(False :> False :> False :> False :> True :> Nil)
rwFlagsRegNext
(_ :> _ :> ackIn :> claimBus :> smReset :> Nil) = unbundle rwFlagsReg
(_ :> ackOutReg :> ackIn :> claimBus :> smReset :> Nil) = unbundle rwFlagsReg

-- ReadWrite flags
rwFlagsRegSetters = bundle $ al :> ackOut :> ackIn :> claimBus :> smReset :> Nil
rwFlagsRegSetters = bundle $ al :> (mux hostAck (fmap not ackOut) ackOutReg) :> ackIn :> claimBus :> smReset :> Nil

-- Alternative of wishbone write and updated i2c status signals.
rwFlagsRegNext = (<|>) <$> rwFlagsWrite <*>
(orNothing <$> (al .||. ackOut) <*> (zipWith (||) <$> rwFlagsReg <*> rwFlagsRegSetters))
(orNothing <$> (al .||. hostAck) <*> (zipWith (||) <$> rwFlagsReg <*> rwFlagsRegSetters))

clkDiv = regMaybe maxBound (unpack . resize <<$>> clkDivWrite)

-- Alternative based on i2cWrite and readRequest
-- Alternative based on i2cWrite and transAddr
i2cOp = (<|>)
<$> ((I2C.WriteData . resize) <<$>> i2cWrite)
<*> (flip orNothing I2C.ReadData <$> (readRequest .==. pure (Just 0)))
<*> (flip orNothing I2C.ReadData <$> (transAddr .==. pure (Just 0)))

-- If the wishbone interface targets the i2c core, wait for acknowledgement.
readAck = (pure (Just 0) ./=. readRequest) .||. hostAck
wbAck = (pure (Just 0) ./=. transAddr) .||. hostAck
(dOut,hostAck,busy,al,ackOut,i2cOut) =
i2c hasClock hasReset smReset (fromEnable hasEnable) clkDiv claimBus i2cOp ackIn i2cIn

(sclMaybe, sdaMaybe) = unbundle i2cOut
ilaInstance :: Signal dom ()
ilaInstance =
ila
( ilaConfig $
"probe_sdaIn"
:> "probe_sclOut"
:> "probe_sdaOut"
:> "probe_i2c_dout"
:> "probe_i2c_hostAck"
:> "probe_i2c_busy"
:> "probe_i2c_al"
:> "probe_i2c_ackOut"
:> "probe_i2c_op"
:> "probe_rwFlagsReg"
:> "probe_clkDiv"
:> "probe_i2cWrite"
:> "probe_transAddr"
:> Nil
) {stages = 2, depth = D32768, advancedTriggers = True }
hasClock
(dflipflop $ snd <$> i2cIn)
(dflipflop $ fmap isNothing sclMaybe)
(dflipflop $ fmap isNothing sdaMaybe)
(dflipflop dOut)
(dflipflop hostAck)
(dflipflop busy)
(dflipflop al)
(dflipflop $ fmap not ackOut)
(dflipflop i2cOp)
(dflipflop rwFlagsReg)
(dflipflop clkDiv)
(dflipflop i2cWrite)
(dflipflop transAddr)
28 changes: 23 additions & 5 deletions firmware-binaries/examples/hello/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,24 +23,42 @@ fn main() -> ! {
uwriteln!(uart, "Hello from {}!", name).unwrap();
}
uwriteln!(uart, "This can also do {} {:#x}", "debug prints", 42).unwrap();
_ = uart.receive();
uwriteln!(uart, "i2c device:\n{:?}", i2c).unwrap();
let mut flags = i2c.read_flags();
uwriteln!(uart, "i2c flags:\n{:?}", flags).unwrap();

// Deasserting i2c reset
uwriteln!(uart, "Deasserting i2c statemachine reset").unwrap();
let mut flags = i2c.read_flags();
flags.statemachine_reset = false;
i2c.write_flags(flags);
uwriteln!(uart, "i2c flags:\n{:?}", flags).unwrap();

// Getting and setting clock divider
let mut clk_div = i2c.get_clock_divider();
uwriteln!(uart, "i2c clk div:\n{:?}", clk_div).unwrap();
clk_div = 300;
uwriteln!(uart, "Changing i2c clk div to {}", clk_div).unwrap();
i2c.set_clock_divider(clk_div);
clk_div = i2c.get_clock_divider();
uwriteln!(uart, "i2c clk div:\n{:?}", clk_div).unwrap();

// Initiating i2c communication
uwriteln!(uart, "Claiming i2c bus").unwrap();
i2c.claim_bus().unwrap();
uwriteln!(uart, "i2c bus claimed, status:\n{:?}", i2c.read_flags()).unwrap();
uwriteln!(uart, "Checking for success").unwrap();
let flags = i2c.read_flags();
uwriteln!(uart, "i2c bus claimed, status:\n{:?}", flags).unwrap();

let a = 0x69;
i2c.write_byte((a << 1) + 1).unwrap();
uwriteln!(uart, "Writing address").unwrap();
i2c.write_byte(a << 1).unwrap();
uwriteln!(uart, "Reading data").unwrap();
let d = i2c.read_byte().unwrap();
uwriteln!(uart, "Read {:X} from {:X}", d, a).unwrap();

i2c.release_bus();
uwriteln!(uart, "i2c bus released, status: {:?}", i2c.read_flags()).unwrap();
let flags = i2c.read_flags();
uwriteln!(uart, "i2c bus released, status: {:?}", flags).unwrap();
uwriteln!(uart, "Going in echo mode!").unwrap();
loop {
let c = uart.receive();
Expand Down

0 comments on commit d53a4be

Please sign in to comment.