aboutsummaryrefslogtreecommitdiff
path: root/fpga/src/I2C.bs
diff options
context:
space:
mode:
Diffstat (limited to 'fpga/src/I2C.bs')
-rw-r--r--fpga/src/I2C.bs43
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
})