Merge pull request #3878 from showier-drastic/i2c-v2-add-nack

stm32: i2c-v2: Add error handling
This commit is contained in:
Dario Nieuwenhuis 2025-02-17 19:52:41 +01:00 committed by GitHub
commit 1780f8479e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -13,13 +13,17 @@ pub(crate) unsafe fn on_interrupt<T: Instance>() {
let regs = T::info().regs;
let isr = regs.isr().read();
if isr.tcr() || isr.tc() {
if isr.tcr() || isr.tc() || isr.nackf() || isr.berr() || isr.arlo() || isr.ovr() {
T::state().waker.wake();
}
// The flag can only be cleared by writting to nbytes, we won't do that here, so disable
// the interrupt
critical_section::with(|_| {
regs.cr1().modify(|w| w.set_tcie(false));
regs.cr1().modify(|w| {
// The flag can only be cleared by writting to nbytes, we won't do that here
w.set_tcie(false);
// Error flags are to be read in the routines, so we also don't clear them here
w.set_nackie(false);
w.set_errie(false);
});
});
}
@ -450,6 +454,8 @@ impl<'d> I2c<'d, Async> {
if first_slice {
w.set_tcie(true);
}
w.set_nackie(true);
w.set_errie(true);
});
let dst = regs.txdr().as_ptr() as *mut u8;
@ -460,18 +466,41 @@ impl<'d> I2c<'d, Async> {
let on_drop = OnDrop::new(|| {
let regs = self.info.regs;
let isr = regs.isr().read();
regs.cr1().modify(|w| {
if last_slice {
if last_slice || isr.nackf() || isr.arlo() || isr.berr() || isr.ovr() {
w.set_txdmaen(false);
}
w.set_tcie(false);
})
w.set_nackie(false);
w.set_errie(false);
});
regs.icr().write(|w| {
w.set_nackcf(true);
w.set_berrcf(true);
w.set_arlocf(true);
w.set_ovrcf(true);
});
});
poll_fn(|cx| {
self.state.waker.register(cx.waker());
let isr = self.info.regs.isr().read();
if isr.nackf() {
return Poll::Ready(Err(Error::Nack));
}
if isr.arlo() {
return Poll::Ready(Err(Error::Arbitration));
}
if isr.berr() {
return Poll::Ready(Err(Error::Bus));
}
if isr.ovr() {
return Poll::Ready(Err(Error::Overrun));
}
if remaining_len == total_len {
if first_slice {
Self::master_write(
@ -534,6 +563,8 @@ impl<'d> I2c<'d, Async> {
regs.cr1().modify(|w| {
w.set_rxdmaen(true);
w.set_tcie(true);
w.set_nackie(true);
w.set_errie(true);
});
let src = regs.rxdr().as_ptr() as *mut u8;
@ -547,13 +578,35 @@ impl<'d> I2c<'d, Async> {
regs.cr1().modify(|w| {
w.set_rxdmaen(false);
w.set_tcie(false);
})
w.set_nackie(false);
w.set_errie(false);
});
regs.icr().write(|w| {
w.set_nackcf(true);
w.set_berrcf(true);
w.set_arlocf(true);
w.set_ovrcf(true);
});
});
poll_fn(|cx| {
self.state.waker.register(cx.waker());
let isr = self.info.regs.isr().read();
if isr.nackf() {
return Poll::Ready(Err(Error::Nack));
}
if isr.arlo() {
return Poll::Ready(Err(Error::Arbitration));
}
if isr.berr() {
return Poll::Ready(Err(Error::Bus));
}
if isr.ovr() {
return Poll::Ready(Err(Error::Overrun));
}
if remaining_len == total_len {
Self::master_read(
self.info,