diff options
Diffstat (limited to 'fpga/src/I2C.bs')
-rw-r--r-- | fpga/src/I2C.bs | 93 |
1 files changed, 93 insertions, 0 deletions
diff --git a/fpga/src/I2C.bs b/fpga/src/I2C.bs index f3cd760..a8553a8 100644 --- a/fpga/src/I2C.bs +++ b/fpga/src/I2C.bs @@ -1,3 +1,96 @@ +-- | An I²C controller with support for 7-bit addresses, with a 16-element FIFO +-- buffer. package I2C where +import Clocks +import GetPut + +-- | An I²C controller. +interface I2C = + -- | The TX side of the SCL pin. High corresponds to high-impedance. + txSCL :: Bit 1 + -- | The TX side of the SDA pin. High corresponds to high-impedance. + txSDA :: Bit 1 + -- | Reads a byte from the I²C controller's receive buffer. + recv :: Get (Maybe (Bit 8)) + -- | Writes a command to the I²C controller's command buffer. + send :: Put I2CCommand + +data I2CCommand + = -- | A read from the given address. If the read succeeds with the byte `b`, + -- `Just b` is written to the receive buffer. If the read fails, `Nothing` + -- is written to the receive buffer. + Read (Bit 7) + | -- | A write to the given address. If the write succeeds, `Just 0` is + -- written to the receive buffer. If the write fails, `Nothing` is written + -- to the receive buffer. + Write (Bit 7) (Bit 8) + deriving (Bits) + +data State + = -- | The initial state. + Idle + | -- | TODO + TODO + deriving (Bits) + +-- | Returns an I²C interface that does _not_ have FIFOs. +mkI2C' :: Bit 1 -> Bit 1 -> Module I2C +mkI2C' rxSCL rxSDA = module + recvFIFO :: Wire (Maybe (Bit 8)) <- mkWire + sendFIFO :: Wire I2CCommand <- mkWire + state :: Reg State <- mkReg Idle + txSCL :: Wire (Bit 1) <- mkWire + txSDA :: Wire (Bit 1) <- mkWire + + rules + when Idle <- state ==> do + txSCL._write 1 + txSDA._write 1 + + interface I2C + txSCL = txSCL + txSDA = txSDA + recv = toGet recvFIFO._read + send = toPut sendFIFO._write + +-- | Returns an I²C interface with FIFOs that runs on a divided clock. Note +-- that the clock rate should be twice the bus speed -- to run the bus at +-- 100kbit/s (normal mode), the clock should run at 200kHz. +mkDividedI2C :: Integer -> Bit 1 -> Bit 1 -> Module I2C +mkDividedI2C divisor rxSCL rxSDA = module + clock <- mkClockDivider divisor + reset <- mkAsyncResetFromCR divisor clock.slowClock + + rxSCLSync :: SyncBitIfc (Bit 1) <- mkSyncBitFromCC clock.slowClock + rxSDASync :: SyncBitIfc (Bit 1) <- mkSyncBitFromCC clock.slowClock + txSCLSync :: Reg (Bit 1) <- mkSyncRegToCC 1 clock.slowClock reset + txSDASync :: Reg (Bit 1) <- mkSyncRegToCC 1 clock.slowClock reset + recvFIFO :: SyncFIFOIfc (Maybe (Bit 8)) <- mkSyncFIFOToCC 16 clock.slowClock reset + sendFIFO :: SyncFIFOIfc I2CCommand <- mkSyncFIFOFromCC 16 clock.slowClock + rules + when True ==> do + rxSCLSync.send rxSCL + rxSDASync.send rxSDA + + changeSpecialWires (Just clock.slowClock) (Just reset) Nothing $ module + i2c <- mkI2C' rxSCLSync.read rxSDASync.read + rules + when True ==> do + txSCLSync._write i2c.txSCL + txSDASync._write i2c.txSDA + when True ==> do + byte <- i2c.recv.get + recvFIFO.enq byte + when True ==> do + i2c.send.put sendFIFO.first + sendFIFO.deq + return () + + interface I2C + txSCL = txSCLSync + txSDA = txSDASync + recv = toGet recvFIFO + send = toPut sendFIFO + -- vim: set ft=haskell : |