diff options
author | Nathan Ringo <nathan@remexre.com> | 2024-10-24 19:31:34 -0500 |
---|---|---|
committer | Nathan Ringo <nathan@remexre.com> | 2024-10-24 19:31:34 -0500 |
commit | 97723bb6471ce74a8e69e79fda4410b0c53329a2 (patch) | |
tree | c133552b70375f885893585b3e7f93eefd033319 /fpga/src/I2C.bs | |
parent | 2d7d2d10a98f3773db6428235d86408ddb48a33d (diff) |
Completed read?
Diffstat (limited to 'fpga/src/I2C.bs')
-rw-r--r-- | fpga/src/I2C.bs | 43 |
1 files changed, 27 insertions, 16 deletions
diff --git a/fpga/src/I2C.bs b/fpga/src/I2C.bs index 292691b..2752acd 100644 --- a/fpga/src/I2C.bs +++ b/fpga/src/I2C.bs @@ -8,7 +8,8 @@ struct I2CStatus = { -- | This bit is low when a message is being sent, and gets raised after: -- -- - We finished sending an address, but a NACK was received. - -- - We finished reading a byte, including sending an ACK or NACK bit. + -- - We finished reading a byte, including starting to send an ACK or NACK + -- bit. -- - We finished writing a byte, including reading an ACK or NACK bit. -- -- When this bit is `True`, writing to it will cause a new read or write, @@ -23,10 +24,10 @@ struct I2CStatus = busIdle :: Bool ; -- | The last ACK bit we received from sending an address. Writing to this -- bit does not affect the internal state of the I²C controller. - addrAck :: Bool + addrAckBit :: Bool ; -- | The last ACK bit we received during a write, or the next ACK bit we'll -- send during a read. - dataAck :: Bool + dataAckBit :: Bool ; -- | A flag set if we detect during a START condition that we've lost -- arbitration. If this occurs, no read or write will occur, and the read -- or write should be retried later. Writing to this bit does not affect @@ -69,7 +70,7 @@ data I2CBusState SendAddrBitWait (Bit 3) (Bit 1) | -- | We're sending an address, and about to lower SCL. SendAddrBitLowerSCL (Bit 3) (Bit 1) - | -- | We're lowering SDA as part of getting the ACK bit after sending an + | -- | We're raising SDA as part of getting the ACK bit after sending an -- address. GetAddrAckSDA | -- | We're raising SCL to start the clock cycle in which we'll get the ACK @@ -105,13 +106,15 @@ mkI2C' :: Bit 1 -> Bit 1 -> Wire (Bit 1) -> Wire (Bit 1) -> Reg (Bit 8) -> Reg (Bit 8) -> Reg I2CStatus -> Module () mkI2C' rxSCL rxSDA txSCL txSDA addrReg dataReg statusReg = module state :: Reg I2CBusState <- mkReg Idle + savedAddr :: Reg (Bit 8) <- mkReg 0 + savedData :: Reg (Bit 8) <- mkReg 0 rules "debug": when True ==> $display (fshow state) - "remain Idle": when Idle <- state, statusReg.notBusy ==> do + "remain Idle": when Idle <- state, statusReg.ready ==> do state := Idle txSCL := 1 txSDA := 1 - "triggered from Idle": when Idle <- state, not statusReg.notBusy ==> + "triggered from Idle": when Idle <- state, not statusReg.ready ==> if rxSDA == 0 then do statusReg := statusReg { ready = True; busIdle = True; arbitrationLost = True } state := Idle @@ -123,10 +126,14 @@ mkI2C' rxSCL rxSDA txSCL txSDA addrReg dataReg statusReg = module txSDA := 0 "StartSDA": when StartSDA <- state ==> do state := SendAddrBitSDA 7 + savedAddr := addrReg + savedData := if savedAddr[0:0] == 1 -- R/!W + then 0 -- R + else dataReg -- !W txSCL := 0 txSDA := 0 "SendAddrBitSDA": when SendAddrBitSDA n <- state ==> do - let bit = addrReg[n:n] + let bit = savedAddr[n:n] state := SendAddrBitRaiseSCL n bit txSCL := 0 txSDA := bit @@ -147,16 +154,16 @@ mkI2C' rxSCL rxSDA txSCL txSDA addrReg dataReg statusReg = module "GetAddrAckSDA": when GetAddrAckSDA <- state ==> do state := GetAddrAckRaiseSCL txSCL := 0 - txSDA := 0 + txSDA := 1 "GetAddrAckRaiseSCL": when GetAddrAckRaiseSCL <- state ==> do state := GetAddrAckReadSDA txSCL := 1 txSDA := 1 "GetAddrAckReadSDA": when GetAddrAckReadSDA <- state ==> do - statusReg := statusReg { addrAck = unpack rxSDA } + statusReg := statusReg { addrAckBit = unpack rxSDA } state := if rxSDA == 1 -- NACK then TODO - else if addrReg[0:0] == 0 -- R/!W + else if savedAddr[0:0] == 0 -- R/!W then TODO -- !W else ReadLowerSCL 7 1 txSCL := 1 @@ -172,7 +179,7 @@ mkI2C' rxSCL rxSDA txSCL txSDA addrReg dataReg statusReg = module txSCL := 1 txSDA := 1 "ReadReadSDA": when ReadReadSDA n <- state ==> do - dataReg := dataReg [6:0] ++ rxSDA + savedData := savedData [6:0] ++ rxSDA state := if n == 0 then ReadAckLowerSCL else ReadLowerSCL (n - 1) 1 @@ -183,14 +190,18 @@ mkI2C' rxSCL rxSDA txSCL txSDA addrReg dataReg statusReg = module txSCL := 0 txSDA := 1 "ReadAckWriteSDA": when ReadAckWriteSDA <- state ==> do - let bit = pack statusReg.dataAck + let bit = pack statusReg.dataAckBit + statusReg := statusReg { ready = True } + dataReg := savedData state := ReadAckRaiseSCL bit 1 txSCL := 0 txSDA := bit "ReadAckRaiseSCL": when ReadAckRaiseSCL bit time <- state ==> do state := if time == 1 then ReadAckRaiseSCL bit (time - 1) - else TODO + else if bit == 0 + then ReadLowerSCL 7 1 -- ACK + else TODO -- NACK txSCL := 1 txSDA := bit return () @@ -204,10 +215,10 @@ mkI2C rxSCL rxSDA = module addrReg <- mkReg 0 dataReg <- mkReg 0 statusReg <- mkReg (I2CStatus - { notBusy = False + { ready = True ; busIdle = False - ; addrAck = False - ; dataAck = False + ; addrAckBit = False + ; dataAckBit = False ; arbitrationLost = False ; rsvd = 0 }) |