add drop guard, clear interrupts, fix len return
This commit is contained in:
parent
8b50f2a58b
commit
c7b4a076cc
@ -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")]
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user