aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeremy Fitzhardinge <[email protected]>2022-10-03 01:00:03 -0700
committerJeremy Fitzhardinge <[email protected]>2022-10-03 01:18:26 -0700
commitcae84991790976387aa4d4b7afae90094a876b25 (patch)
tree832713e2d75e87a5d6ac06ef0fa93a02d108c16f
parente8bb8faa23c1e8b78285646ca7e711bafe990e20 (diff)
rp i2c: clean up tx_abrt handling
Make sure we always wait for the stop bit if there's a reason to - either because we sent one, or because there was a hardware tx abort.
-rw-r--r--embassy-rp/src/i2c.rs134
1 files changed, 69 insertions, 65 deletions
diff --git a/embassy-rp/src/i2c.rs b/embassy-rp/src/i2c.rs
index e01692dc1..f004c522c 100644
--- a/embassy-rp/src/i2c.rs
+++ b/embassy-rp/src/i2c.rs
@@ -135,7 +135,7 @@ impl<'d, T: Instance> I2c<'d, T, Async> {
135 let mut remaining = buffer.len(); 135 let mut remaining = buffer.len();
136 let mut remaining_queue = buffer.len(); 136 let mut remaining_queue = buffer.len();
137 137
138 let mut abort_reason = None; 138 let mut abort_reason = Ok(());
139 139
140 while remaining > 0 { 140 while remaining > 0 {
141 // Waggle SCK - basically the same as write 141 // Waggle SCK - basically the same as write
@@ -190,8 +190,7 @@ impl<'d, T: Instance> I2c<'d, T, Async> {
190 190
191 match res { 191 match res {
192 Err(reason) => { 192 Err(reason) => {
193 abort_reason = Some(reason); 193 abort_reason = Err(reason);
194 // XXX keep going anyway?
195 break; 194 break;
196 } 195 }
197 Ok(rxfifo) => { 196 Ok(rxfifo) => {
@@ -207,29 +206,7 @@ impl<'d, T: Instance> I2c<'d, T, Async> {
207 }; 206 };
208 } 207 }
209 208
210 // wait for stop condition to be emitted. 209 self.wait_stop_det(abort_reason, send_stop).await
211 self.wait_on(
212 |_me| unsafe {
213 if !p.ic_raw_intr_stat().read().stop_det() && send_stop {
214 Poll::Pending
215 } else {
216 Poll::Ready(())
217 }
218 },
219 |_me| unsafe {
220 p.ic_intr_mask().modify(|w| {
221 w.set_m_stop_det(true);
222 w.set_m_tx_abrt(true);
223 });
224 },
225 )
226 .await;
227 unsafe { p.ic_clr_stop_det().read() };
228
229 if let Some(abort_reason) = abort_reason {
230 return Err(abort_reason);
231 }
232 Ok(())
233 } 210 }
234 211
235 async fn write_async_internal( 212 async fn write_async_internal(
@@ -241,7 +218,7 @@ impl<'d, T: Instance> I2c<'d, T, Async> {
241 218
242 let mut bytes = bytes.into_iter().peekable(); 219 let mut bytes = bytes.into_iter().peekable();
243 220
244 'xmit: loop { 221 let res = 'xmit: loop {
245 let tx_fifo_space = Self::tx_fifo_capacity(); 222 let tx_fifo_space = Self::tx_fifo_capacity();
246 223
247 for _ in 0..tx_fifo_space { 224 for _ in 0..tx_fifo_space {
@@ -256,49 +233,76 @@ impl<'d, T: Instance> I2c<'d, T, Async> {
256 }); 233 });
257 } 234 }
258 } else { 235 } else {
259 break 'xmit; 236 break 'xmit Ok(());
260 } 237 }
261 } 238 }
262 239
263 self.wait_on( 240 let res = self
264 |me| { 241 .wait_on(
265 if let Err(abort_reason) = me.read_and_clear_abort_reason() { 242 |me| {
266 Poll::Ready(Err(abort_reason)) 243 if let abort_reason @ Err(_) = me.read_and_clear_abort_reason() {
267 } else if !Self::tx_fifo_full() { 244 Poll::Ready(abort_reason)
268 Poll::Ready(Ok(())) 245 } else if !Self::tx_fifo_full() {
269 } else { 246 Poll::Ready(Ok(()))
270 Poll::Pending 247 } else {
271 } 248 Poll::Pending
272 }, 249 }
273 |_me| unsafe { 250 },
274 p.ic_intr_mask().modify(|w| { 251 |_me| unsafe {
275 w.set_m_tx_empty(true); 252 p.ic_intr_mask().modify(|w| {
276 w.set_m_tx_abrt(true); 253 w.set_m_tx_empty(true);
277 }) 254 w.set_m_tx_abrt(true);
278 }, 255 })
279 ) 256 },
280 .await?; 257 )
281 } 258 .await;
259 if res.is_err() {
260 break res;
261 }
262 };
282 263
283 // wait for fifo to drain 264 self.wait_stop_det(res, send_stop).await
284 self.wait_on( 265 }
285 |_me| unsafe {
286 if p.ic_raw_intr_stat().read().tx_empty() {
287 Poll::Ready(())
288 } else {
289 Poll::Pending
290 }
291 },
292 |_me| unsafe {
293 p.ic_intr_mask().modify(|w| {
294 w.set_m_tx_empty(true);
295 w.set_m_tx_abrt(true);
296 });
297 },
298 )
299 .await;
300 266
301 Ok(()) 267 /// Helper to wait for a stop bit, for both tx and rx. If we had an abort,
268 /// then we'll get a hardware-generated stop, otherwise wait for a stop if
269 /// we're expecting it.
270 ///
271 /// Also handles an abort which arises while processing the tx fifo.
272 async fn wait_stop_det(&mut self, had_abort: Result<(), Error>, do_stop: bool) -> Result<(), Error> {
273 if had_abort.is_err() || do_stop {
274 let p = T::regs();
275
276 let had_abort2 = self
277 .wait_on(
278 |me| unsafe {
279 // We could see an abort while processing fifo backlog,
280 // so handle it here.
281 let abort = me.read_and_clear_abort_reason();
282 if had_abort.is_ok() && abort.is_err() {
283 Poll::Ready(abort)
284 } else if p.ic_raw_intr_stat().read().stop_det() {
285 Poll::Ready(Ok(()))
286 } else {
287 Poll::Pending
288 }
289 },
290 |_me| unsafe {
291 p.ic_intr_mask().modify(|w| {
292 w.set_m_stop_det(true);
293 w.set_m_tx_abrt(true);
294 });
295 },
296 )
297 .await;
298 unsafe {
299 p.ic_clr_stop_det().read();
300 }
301
302 had_abort.and(had_abort2)
303 } else {
304 had_abort
305 }
302 } 306 }
303 307
304 pub async fn read_async(&mut self, addr: u16, buffer: &mut [u8]) -> Result<(), Error> { 308 pub async fn read_async(&mut self, addr: u16, buffer: &mut [u8]) -> Result<(), Error> {