Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions embassy-stm32/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- change: add error messages to can timing calculations ([#4961](https://github.com/embassy-rs/embassy/pull/4961))
- feat: stm32/spi bidirectional mode
- fix: stm32/i2c v2: add stop flag on stop received
- stm32: Add blocking_listen for blocking I2C driver
- fix: stm32l47*/stm32l48* adc analog pin setup
- fix: keep stm32/sai: make NODIV independent of MCKDIV

Expand Down
93 changes: 63 additions & 30 deletions embassy-stm32/src/i2c/v2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1680,43 +1680,50 @@ impl<'d, M: Mode> I2c<'d, M, MultiMaster> {

/// Listen for incoming I2C messages.
///
/// The listen method is an asynchronous method but it does not require DMA to be asynchronous.
pub async fn listen(&mut self) -> Result<SlaveCommand, Error> {
let _scoped_block_stop = self.info.rcc.block_stop();
let state = self.state;
/// This method blocks until the slave address is matched by a master.
pub fn blocking_listen(&mut self) -> Result<SlaveCommand, Error> {
let timeout = self.timeout();

self.info.regs.cr1().modify(|reg| {
reg.set_addrie(true);
trace!("Enable ADDRIE");
});

poll_fn(|cx| {
state.waker.register(cx.waker());
loop {
let isr = self.info.regs.isr().read();
if !isr.addr() {
Poll::Pending
} else {
trace!("ADDR triggered (address match)");
// we do not clear the address flag here as it will be cleared by the dma read/write
// if we clear it here the clock stretching will stop and the master will read in data before the slave is ready to send it
match isr.dir() {
i2c::vals::Dir::WRITE => {
trace!("DIR: write");
Poll::Ready(Ok(SlaveCommand {
kind: SlaveCommandKind::Write,
address: self.determine_matched_address()?,
}))
}
i2c::vals::Dir::READ => {
trace!("DIR: read");
Poll::Ready(Ok(SlaveCommand {
kind: SlaveCommandKind::Read,
address: self.determine_matched_address()?,
}))
}
}
if isr.addr() {
break;
}
})
.await
timeout.check()?;
}

trace!("ADDR triggered (address match)");

// we do not clear the address flag here as it will be cleared by the dma read/write
// if we clear it here the clock stretching will stop and the master will read in data before the slave is ready to send it
self.slave_command()
}

/// Determine the received slave command.
fn slave_command(&self) -> Result<SlaveCommand, Error> {
let isr = self.info.regs.isr().read();

match isr.dir() {
i2c::vals::Dir::WRITE => {
trace!("DIR: write");
Ok(SlaveCommand {
kind: SlaveCommandKind::Write,
address: self.determine_matched_address()?,
})
}
i2c::vals::Dir::READ => {
trace!("DIR: read");
Ok(SlaveCommand {
kind: SlaveCommandKind::Read,
address: self.determine_matched_address()?,
})
}
}
}

/// Respond to a write command.
Expand All @@ -1735,6 +1742,32 @@ impl<'d, M: Mode> I2c<'d, M, MultiMaster> {
}

impl<'d> I2c<'d, Async, MultiMaster> {
/// Listen for incoming I2C messages.
///
/// The listen method is an asynchronous method but it does not require DMA to be asynchronous.
pub async fn listen(&mut self) -> Result<SlaveCommand, Error> {
let _scoped_block_stop = self.info.rcc.block_stop();
let state = self.state;
self.info.regs.cr1().modify(|reg| {
reg.set_addrie(true);
trace!("Enable ADDRIE");
});

poll_fn(|cx| {
state.waker.register(cx.waker());
let isr = self.info.regs.isr().read();
if !isr.addr() {
Poll::Pending
} else {
trace!("ADDR triggered (address match)");
// we do not clear the address flag here as it will be cleared by the dma read/write
// if we clear it here the clock stretching will stop and the master will read in data before the slave is ready to send it
Poll::Ready(self.slave_command())
}
})
.await
}

/// Respond to a write command.
///
/// Returns the total number of bytes received.
Expand Down