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), 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. /// I2C driver.
pub struct I2c<'d, M: Mode, IM: MasterMode> { pub struct I2c<'d, M: Mode, IM: MasterMode> {
info: &'static Info, info: &'static Info,
state: &'static State, state: &'static State,
kernel_clock: Hertz, kernel_clock: Hertz,
scl: Option<PeripheralRef<'d, AnyPin>>,
sda: Option<PeripheralRef<'d, AnyPin>>,
tx_dma: Option<ChannelAndRequest<'d>>, tx_dma: Option<ChannelAndRequest<'d>>,
rx_dma: Option<ChannelAndRequest<'d>>, rx_dma: Option<ChannelAndRequest<'d>>,
#[cfg(feature = "time")] #[cfg(feature = "time")]
timeout: Duration, timeout: Duration,
_phantom: PhantomData<M>, _phantom: PhantomData<M>,
_phantom2: PhantomData<IM>, _phantom2: PhantomData<IM>,
drop_guard: I2CDropGuard<'d>,
} }
impl<'d> I2c<'d, Async, Master> { impl<'d> I2c<'d, Async, Master> {
@ -242,14 +255,17 @@ impl<'d, M: Mode> I2c<'d, M, Master> {
info: T::info(), info: T::info(),
state: T::state(), state: T::state(),
kernel_clock: T::frequency(), kernel_clock: T::frequency(),
scl,
sda,
tx_dma, tx_dma,
rx_dma, rx_dma,
#[cfg(feature = "time")] #[cfg(feature = "time")]
timeout: config.timeout, timeout: config.timeout,
_phantom: PhantomData, _phantom: PhantomData,
_phantom2: PhantomData, _phantom2: PhantomData,
drop_guard: I2CDropGuard {
info: T::info(),
scl,
sda,
},
}; };
this.enable_and_init(freq, config); 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)] #[derive(Copy, Clone)]
struct Timeout { struct Timeout {
#[cfg(feature = "time")] #[cfg(feature = "time")]

View File

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