-- | 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 :