add drop guard, clear interrupts, fix len return

This commit is contained in:
jrmoulton 2024-06-18 19:05:07 -06:00
parent 8b50f2a58b
commit c7b4a076cc
No known key found for this signature in database
2 changed files with 28 additions and 16 deletions

View File

@ -162,19 +162,32 @@ pub enum SendStatus {
LeftoverBytes(usize),
}
struct I2CDropGuard<'d> {
info: &'static Info,
scl: Option<PeripheralRef<'d, AnyPin>>,
sda: Option<PeripheralRef<'d, AnyPin>>,
}
impl<'d> Drop for I2CDropGuard<'d> {
fn drop(&mut self) {
self.scl.as_ref().map(|x| x.set_as_disconnected());
self.sda.as_ref().map(|x| x.set_as_disconnected());
self.info.rcc.disable();
}
}
/// I2C driver.
pub struct I2c<'d, M: Mode, IM: MasterMode> {
info: &'static Info,
state: &'static State,
kernel_clock: Hertz,
scl: Option<PeripheralRef<'d, AnyPin>>,
sda: Option<PeripheralRef<'d, AnyPin>>,
tx_dma: Option<ChannelAndRequest<'d>>,
rx_dma: Option<ChannelAndRequest<'d>>,
#[cfg(feature = "time")]
timeout: Duration,
_phantom: PhantomData<M>,
_phantom2: PhantomData<IM>,
drop_guard: I2CDropGuard<'d>,
}
impl<'d> I2c<'d, Async, Master> {
@ -242,14 +255,17 @@ impl<'d, M: Mode> I2c<'d, M, Master> {
info: T::info(),
state: T::state(),
kernel_clock: T::frequency(),
scl,
sda,
tx_dma,
rx_dma,
#[cfg(feature = "time")]
timeout: config.timeout,
_phantom: PhantomData,
_phantom2: PhantomData,
drop_guard: I2CDropGuard {
info: T::info(),
scl,
sda,
},
};
this.enable_and_init(freq, config);
@ -271,15 +287,6 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> {
}
}
impl<'d, M: Mode, IM: MasterMode> Drop for I2c<'d, M, IM> {
fn drop(&mut self) {
self.scl.as_ref().map(|x| x.set_as_disconnected());
self.sda.as_ref().map(|x| x.set_as_disconnected());
self.info.rcc.disable()
}
}
#[derive(Copy, Clone)]
struct Timeout {
#[cfg(feature = "time")]

View File

@ -47,6 +47,8 @@ pub(crate) unsafe fn on_interrupt<T: Instance>() {
critical_section::with(|_| {
regs.cr1().modify(|w| {
w.set_addrie(false);
w.set_stopie(false);
w.set_tcie(false);
// The flag can only be cleared by writting to nbytes, we won't do that here, so disable
// the interrupt
w.set_tcie(false);
@ -725,14 +727,13 @@ impl<'d, M: Mode> I2c<'d, M, Master> {
info: self.info,
state: self.state,
kernel_clock: self.kernel_clock,
scl: self.scl.take(),
sda: self.sda.take(),
tx_dma: self.tx_dma.take(),
rx_dma: self.rx_dma.take(),
#[cfg(feature = "time")]
timeout: self.timeout,
_phantom: PhantomData,
_phantom2: PhantomData,
drop_guard: self.drop_guard,
};
slave.init_slave(slave_addr_config);
slave
@ -930,6 +931,8 @@ impl<'d, M: Mode> I2c<'d, M, MultiMaster> {
impl<'d> I2c<'d, Async, MultiMaster> {
/// Respond to a receive command.
///
/// Returns the total number of bytes received.
pub async fn respond_to_receive(&mut self, buffer: &mut [u8]) -> Result<usize, Error> {
let timeout = self.timeout();
timeout.with(self.read_dma_internal_slave(buffer, timeout)).await
@ -942,6 +945,8 @@ impl<'d> I2c<'d, Async, MultiMaster> {
}
// for data reception in slave mode
//
// returns the total number of bytes received
async fn read_dma_internal_slave(&mut self, buffer: &mut [u8], timeout: Timeout) -> Result<usize, Error> {
let total_len = buffer.len();
let mut remaining_len = total_len;
@ -988,7 +993,7 @@ impl<'d> I2c<'d, Async, MultiMaster> {
Poll::Pending
} else if isr.stopf() {
regs.icr().write(|reg| reg.set_stopcf(true));
let poll = Poll::Ready(Ok(remaining_len));
let poll = Poll::Ready(Ok(total_len - remaining_len));
poll
} else {
Poll::Pending