Fix i2c peripheral mode state machine

The start_det flag is set as soon as a start condition occurs
whereas rd_req flag is only set once the address byte is received.
This commit is contained in:
Wilfried Chauveau 2022-01-25 12:15:04 +00:00 committed by 9names
parent d6bb177fd7
commit d08bfac989

View file

@ -24,9 +24,10 @@ pub enum I2CEvent {
Stop, Stop,
} }
#[derive(Debug)] #[derive(Debug, Clone, Copy)]
enum State { enum State {
Idle, Idle,
Active,
Read, Read,
Write, Write,
} }
@ -98,7 +99,7 @@ where
} }
impl<T: Deref<Target = I2CBlock>, PINS> I2CPeripheralEventIterator<T, PINS> { impl<T: Deref<Target = I2CBlock>, PINS> I2CPeripheralEventIterator<T, PINS> {
/// Pushs up to `usize::min(TX_FIFO_SIZE, buf.len())` bytes to the TX FIFO. /// Push up to `usize::min(TX_FIFO_SIZE, buf.len())` bytes to the TX FIFO.
/// Returns the number of bytes pushed to the FIFO. Note this does *not* reflect how many bytes /// Returns the number of bytes pushed to the FIFO. Note this does *not* reflect how many bytes
/// are effectively received by the controller. /// are effectively received by the controller.
pub fn write(&mut self, buf: &[u8]) -> usize { pub fn write(&mut self, buf: &[u8]) -> usize {
@ -122,7 +123,7 @@ impl<T: Deref<Target = I2CBlock>, PINS> I2CPeripheralEventIterator<T, PINS> {
sent sent
} }
/// Pulls up to `usize::min(RX_FIFO_SIZE, buf.len())` bytes from the RX FIFO. /// Pull up to `usize::min(RX_FIFO_SIZE, buf.len())` bytes from the RX FIFO.
pub fn read(&mut self, buf: &mut [u8]) -> usize { pub fn read(&mut self, buf: &mut [u8]) -> usize {
let mut read = 0; let mut read = 0;
@ -147,29 +148,30 @@ impl<T: Deref<Target = I2CBlock>, PINS> Iterator for I2CPeripheralEventIterator<
match self.state { match self.state {
State::Idle if stat.start_det().bit_is_set() => { State::Idle if stat.start_det().bit_is_set() => {
self.i2c.i2c.ic_clr_start_det.read(); self.i2c.i2c.ic_clr_start_det.read();
self.state = if stat.rd_req().bit_is_set() { self.state = State::Active;
State::Read
} else {
State::Write
};
Some(I2CEvent::Start) Some(I2CEvent::Start)
} }
State::Read if stat.rd_req().bit_is_set() => { State::Active if !self.i2c.rx_fifo_empty() => {
// `rd_req` is used by the hardware to detect when the I2C block can stop stretching self.state = State::Write;
// the clock and start process the data pushed to the FIFO (if any). Some(I2CEvent::TransferWrite)
}
State::Active if stat.rd_req().bit_is_set() => {
// Clearing `rd_req` is used by the hardware to detect when the I2C block can stop
// stretching the clock and start process the data pushed to the FIFO (if any).
// This is done in `Self::write`. // This is done in `Self::write`.
self.state = State::Read;
Some(I2CEvent::TransferRead) Some(I2CEvent::TransferRead)
} }
State::Read if stat.rd_req().bit_is_set() => Some(I2CEvent::TransferRead),
State::Read if stat.restart_det().bit_is_set() => { State::Read if stat.restart_det().bit_is_set() => {
self.i2c.i2c.ic_clr_restart_det.read(); self.i2c.i2c.ic_clr_restart_det.read();
self.state = State::Write; self.state = State::Active;
Some(I2CEvent::Restart) Some(I2CEvent::Restart)
} }
State::Write if !self.i2c.rx_fifo_empty() => Some(I2CEvent::TransferWrite), State::Write if !self.i2c.rx_fifo_empty() => Some(I2CEvent::TransferWrite),
State::Write if stat.restart_det().bit_is_set() => { State::Write if stat.restart_det().bit_is_set() => {
self.i2c.i2c.ic_clr_restart_det.read(); self.i2c.i2c.ic_clr_restart_det.read();
self.state = State::Read; self.state = State::Active;
Some(I2CEvent::Restart) Some(I2CEvent::Restart)
} }
_ if stat.stop_det().bit_is_set() => { _ if stat.stop_det().bit_is_set() => {