diff options
| author | Dario Nieuwenhuis <[email protected]> | 2022-01-13 20:47:28 +0100 |
|---|---|---|
| committer | Dario Nieuwenhuis <[email protected]> | 2022-01-13 23:56:39 +0100 |
| commit | ecb4f8fb00e8e1c220cfb24252e562b80f8de457 (patch) | |
| tree | 70141a84992050e37ac42b1149ff1d479b08a5c8 | |
| parent | a287fef687b47edc57e17131e3d663cd860ad471 (diff) | |
nrf/twim: expose all functionality as inherent methods.
| -rw-r--r-- | embassy-nrf/src/twim.rs | 420 | ||||
| -rw-r--r-- | examples/nrf/src/bin/twim.rs | 2 | ||||
| -rw-r--r-- | examples/nrf/src/bin/twim_lowpower.rs | 2 |
3 files changed, 157 insertions, 267 deletions
diff --git a/embassy-nrf/src/twim.rs b/embassy-nrf/src/twim.rs index 3cc79227e..ab649c470 100644 --- a/embassy-nrf/src/twim.rs +++ b/embassy-nrf/src/twim.rs | |||
| @@ -201,7 +201,7 @@ impl<'d, T: Instance> Twim<'d, T> { | |||
| 201 | } | 201 | } |
| 202 | 202 | ||
| 203 | /// Get Error instance, if any occurred. | 203 | /// Get Error instance, if any occurred. |
| 204 | fn read_errorsrc(&self) -> Result<(), Error> { | 204 | fn check_errorsrc(&self) -> Result<(), Error> { |
| 205 | let r = T::regs(); | 205 | let r = T::regs(); |
| 206 | 206 | ||
| 207 | let err = r.errorsrc.read(); | 207 | let err = r.errorsrc.read(); |
| @@ -217,8 +217,26 @@ impl<'d, T: Instance> Twim<'d, T> { | |||
| 217 | Ok(()) | 217 | Ok(()) |
| 218 | } | 218 | } |
| 219 | 219 | ||
| 220 | fn check_rx(&self, len: usize) -> Result<(), Error> { | ||
| 221 | let r = T::regs(); | ||
| 222 | if r.rxd.amount.read().bits() != len as u32 { | ||
| 223 | Err(Error::Receive) | ||
| 224 | } else { | ||
| 225 | Ok(()) | ||
| 226 | } | ||
| 227 | } | ||
| 228 | |||
| 229 | fn check_tx(&self, len: usize) -> Result<(), Error> { | ||
| 230 | let r = T::regs(); | ||
| 231 | if r.txd.amount.read().bits() != len as u32 { | ||
| 232 | Err(Error::Transmit) | ||
| 233 | } else { | ||
| 234 | Ok(()) | ||
| 235 | } | ||
| 236 | } | ||
| 237 | |||
| 220 | /// Wait for stop or error | 238 | /// Wait for stop or error |
| 221 | fn wait(&mut self) { | 239 | fn blocking_wait(&mut self) { |
| 222 | let r = T::regs(); | 240 | let r = T::regs(); |
| 223 | loop { | 241 | loop { |
| 224 | if r.events_stopped.read().bits() != 0 { | 242 | if r.events_stopped.read().bits() != 0 { |
| @@ -232,16 +250,32 @@ impl<'d, T: Instance> Twim<'d, T> { | |||
| 232 | } | 250 | } |
| 233 | } | 251 | } |
| 234 | 252 | ||
| 235 | /// Write to an I2C slave. | 253 | /// Wait for stop or error |
| 236 | /// | 254 | fn async_wait(&mut self) -> impl Future<Output = ()> { |
| 237 | /// The buffer must have a length of at most 255 bytes on the nRF52832 | 255 | poll_fn(move |cx| { |
| 238 | /// and at most 65535 bytes on the nRF52840. | 256 | let r = T::regs(); |
| 239 | pub fn write(&mut self, address: u8, buffer: &[u8]) -> Result<(), Error> { | 257 | let s = T::state(); |
| 258 | |||
| 259 | s.end_waker.register(cx.waker()); | ||
| 260 | if r.events_stopped.read().bits() != 0 { | ||
| 261 | r.events_stopped.reset(); | ||
| 262 | |||
| 263 | return Poll::Ready(()); | ||
| 264 | } | ||
| 265 | |||
| 266 | // stop if an error occured | ||
| 267 | if r.events_error.read().bits() != 0 { | ||
| 268 | r.events_error.reset(); | ||
| 269 | r.tasks_stop.write(|w| unsafe { w.bits(1) }); | ||
| 270 | } | ||
| 271 | |||
| 272 | Poll::Pending | ||
| 273 | }) | ||
| 274 | } | ||
| 275 | |||
| 276 | fn setup_write(&mut self, address: u8, buffer: &[u8], inten: bool) -> Result<(), Error> { | ||
| 240 | let r = T::regs(); | 277 | let r = T::regs(); |
| 241 | 278 | ||
| 242 | // Conservative compiler fence to prevent optimizations that do not | ||
| 243 | // take in to account actions by DMA. The fence has been placed here, | ||
| 244 | // before any DMA action has started. | ||
| 245 | compiler_fence(SeqCst); | 279 | compiler_fence(SeqCst); |
| 246 | 280 | ||
| 247 | r.address.write(|w| unsafe { w.address().bits(address) }); | 281 | r.address.write(|w| unsafe { w.address().bits(address) }); |
| @@ -255,38 +289,21 @@ impl<'d, T: Instance> Twim<'d, T> { | |||
| 255 | r.events_lasttx.reset(); | 289 | r.events_lasttx.reset(); |
| 256 | self.clear_errorsrc(); | 290 | self.clear_errorsrc(); |
| 257 | 291 | ||
| 258 | // Start write operation. | 292 | if inten { |
| 259 | r.shorts.write(|w| w.lasttx_stop().enabled()); | 293 | r.intenset.write(|w| w.stopped().set().error().set()); |
| 260 | r.tasks_starttx.write(|w| | 294 | } else { |
| 261 | // `1` is a valid value to write to task registers. | 295 | r.intenclr.write(|w| w.stopped().clear().error().clear()); |
| 262 | unsafe { w.bits(1) }); | ||
| 263 | |||
| 264 | self.wait(); | ||
| 265 | |||
| 266 | // Conservative compiler fence to prevent optimizations that do not | ||
| 267 | // take in to account actions by DMA. The fence has been placed here, | ||
| 268 | // after all possible DMA actions have completed. | ||
| 269 | compiler_fence(SeqCst); | ||
| 270 | |||
| 271 | self.read_errorsrc()?; | ||
| 272 | |||
| 273 | if r.txd.amount.read().bits() != buffer.len() as u32 { | ||
| 274 | return Err(Error::Transmit); | ||
| 275 | } | 296 | } |
| 276 | 297 | ||
| 298 | // Start write operation. | ||
| 299 | r.shorts.write(|w| w.lasttx_stop().enabled()); | ||
| 300 | r.tasks_starttx.write(|w| unsafe { w.bits(1) }); | ||
| 277 | Ok(()) | 301 | Ok(()) |
| 278 | } | 302 | } |
| 279 | 303 | ||
| 280 | /// Read from an I2C slave. | 304 | fn setup_read(&mut self, address: u8, buffer: &mut [u8], inten: bool) -> Result<(), Error> { |
| 281 | /// | ||
| 282 | /// The buffer must have a length of at most 255 bytes on the nRF52832 | ||
| 283 | /// and at most 65535 bytes on the nRF52840. | ||
| 284 | pub fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> { | ||
| 285 | let r = T::regs(); | 305 | let r = T::regs(); |
| 286 | 306 | ||
| 287 | // Conservative compiler fence to prevent optimizations that do not | ||
| 288 | // take in to account actions by DMA. The fence has been placed here, | ||
| 289 | // before any DMA action has started. | ||
| 290 | compiler_fence(SeqCst); | 307 | compiler_fence(SeqCst); |
| 291 | 308 | ||
| 292 | r.address.write(|w| unsafe { w.address().bits(address) }); | 309 | r.address.write(|w| unsafe { w.address().bits(address) }); |
| @@ -299,44 +316,27 @@ impl<'d, T: Instance> Twim<'d, T> { | |||
| 299 | r.events_error.reset(); | 316 | r.events_error.reset(); |
| 300 | self.clear_errorsrc(); | 317 | self.clear_errorsrc(); |
| 301 | 318 | ||
| 302 | // Start read operation. | 319 | if inten { |
| 303 | r.shorts.write(|w| w.lastrx_stop().enabled()); | 320 | r.intenset.write(|w| w.stopped().set().error().set()); |
| 304 | r.tasks_startrx.write(|w| | 321 | } else { |
| 305 | // `1` is a valid value to write to task registers. | 322 | r.intenclr.write(|w| w.stopped().clear().error().clear()); |
| 306 | unsafe { w.bits(1) }); | ||
| 307 | |||
| 308 | self.wait(); | ||
| 309 | |||
| 310 | // Conservative compiler fence to prevent optimizations that do not | ||
| 311 | // take in to account actions by DMA. The fence has been placed here, | ||
| 312 | // after all possible DMA actions have completed. | ||
| 313 | compiler_fence(SeqCst); | ||
| 314 | |||
| 315 | self.read_errorsrc()?; | ||
| 316 | |||
| 317 | if r.rxd.amount.read().bits() != buffer.len() as u32 { | ||
| 318 | return Err(Error::Receive); | ||
| 319 | } | 323 | } |
| 320 | 324 | ||
| 325 | // Start read operation. | ||
| 326 | r.shorts.write(|w| w.lastrx_stop().enabled()); | ||
| 327 | r.tasks_startrx.write(|w| unsafe { w.bits(1) }); | ||
| 321 | Ok(()) | 328 | Ok(()) |
| 322 | } | 329 | } |
| 323 | 330 | ||
| 324 | /// Write data to an I2C slave, then read data from the slave without | 331 | fn setup_write_read( |
| 325 | /// triggering a stop condition between the two. | ||
| 326 | /// | ||
| 327 | /// The buffers must have a length of at most 255 bytes on the nRF52832 | ||
| 328 | /// and at most 65535 bytes on the nRF52840. | ||
| 329 | pub fn write_then_read( | ||
| 330 | &mut self, | 332 | &mut self, |
| 331 | address: u8, | 333 | address: u8, |
| 332 | wr_buffer: &[u8], | 334 | wr_buffer: &[u8], |
| 333 | rd_buffer: &mut [u8], | 335 | rd_buffer: &mut [u8], |
| 336 | inten: bool, | ||
| 334 | ) -> Result<(), Error> { | 337 | ) -> Result<(), Error> { |
| 335 | let r = T::regs(); | 338 | let r = T::regs(); |
| 336 | 339 | ||
| 337 | // Conservative compiler fence to prevent optimizations that do not | ||
| 338 | // take in to account actions by DMA. The fence has been placed here, | ||
| 339 | // before any DMA action has started. | ||
| 340 | compiler_fence(SeqCst); | 340 | compiler_fence(SeqCst); |
| 341 | 341 | ||
| 342 | r.address.write(|w| unsafe { w.address().bits(address) }); | 342 | r.address.write(|w| unsafe { w.address().bits(address) }); |
| @@ -352,35 +352,65 @@ impl<'d, T: Instance> Twim<'d, T> { | |||
| 352 | r.events_error.reset(); | 352 | r.events_error.reset(); |
| 353 | self.clear_errorsrc(); | 353 | self.clear_errorsrc(); |
| 354 | 354 | ||
| 355 | if inten { | ||
| 356 | r.intenset.write(|w| w.stopped().set().error().set()); | ||
| 357 | } else { | ||
| 358 | r.intenclr.write(|w| w.stopped().clear().error().clear()); | ||
| 359 | } | ||
| 360 | |||
| 355 | // Start write+read operation. | 361 | // Start write+read operation. |
| 356 | r.shorts.write(|w| { | 362 | r.shorts.write(|w| { |
| 357 | w.lasttx_startrx().enabled(); | 363 | w.lasttx_startrx().enabled(); |
| 358 | w.lastrx_stop().enabled(); | 364 | w.lastrx_stop().enabled(); |
| 359 | w | 365 | w |
| 360 | }); | 366 | }); |
| 361 | // `1` is a valid value to write to task registers. | ||
| 362 | r.tasks_starttx.write(|w| unsafe { w.bits(1) }); | 367 | r.tasks_starttx.write(|w| unsafe { w.bits(1) }); |
| 368 | Ok(()) | ||
| 369 | } | ||
| 363 | 370 | ||
| 364 | self.wait(); | 371 | /// Write to an I2C slave. |
| 365 | 372 | /// | |
| 366 | // Conservative compiler fence to prevent optimizations that do not | 373 | /// The buffer must have a length of at most 255 bytes on the nRF52832 |
| 367 | // take in to account actions by DMA. The fence has been placed here, | 374 | /// and at most 65535 bytes on the nRF52840. |
| 368 | // after all possible DMA actions have completed. | 375 | pub fn blocking_write(&mut self, address: u8, buffer: &[u8]) -> Result<(), Error> { |
| 376 | self.setup_write(address, buffer, false)?; | ||
| 377 | self.blocking_wait(); | ||
| 369 | compiler_fence(SeqCst); | 378 | compiler_fence(SeqCst); |
| 379 | self.check_errorsrc()?; | ||
| 380 | self.check_tx(buffer.len())?; | ||
| 381 | Ok(()) | ||
| 382 | } | ||
| 370 | 383 | ||
| 371 | self.read_errorsrc()?; | 384 | /// Read from an I2C slave. |
| 372 | 385 | /// | |
| 373 | let bad_write = r.txd.amount.read().bits() != wr_buffer.len() as u32; | 386 | /// The buffer must have a length of at most 255 bytes on the nRF52832 |
| 374 | let bad_read = r.rxd.amount.read().bits() != rd_buffer.len() as u32; | 387 | /// and at most 65535 bytes on the nRF52840. |
| 375 | 388 | pub fn blocking_read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> { | |
| 376 | if bad_write { | 389 | self.setup_read(address, buffer, false)?; |
| 377 | return Err(Error::Transmit); | 390 | self.blocking_wait(); |
| 378 | } | 391 | compiler_fence(SeqCst); |
| 379 | 392 | self.check_errorsrc()?; | |
| 380 | if bad_read { | 393 | self.check_rx(buffer.len())?; |
| 381 | return Err(Error::Receive); | 394 | Ok(()) |
| 382 | } | 395 | } |
| 383 | 396 | ||
| 397 | /// Write data to an I2C slave, then read data from the slave without | ||
| 398 | /// triggering a stop condition between the two. | ||
| 399 | /// | ||
| 400 | /// The buffers must have a length of at most 255 bytes on the nRF52832 | ||
| 401 | /// and at most 65535 bytes on the nRF52840. | ||
| 402 | pub fn blocking_write_read( | ||
| 403 | &mut self, | ||
| 404 | address: u8, | ||
| 405 | wr_buffer: &[u8], | ||
| 406 | rd_buffer: &mut [u8], | ||
| 407 | ) -> Result<(), Error> { | ||
| 408 | self.setup_write_read(address, wr_buffer, rd_buffer, false)?; | ||
| 409 | self.blocking_wait(); | ||
| 410 | compiler_fence(SeqCst); | ||
| 411 | self.check_errorsrc()?; | ||
| 412 | self.check_tx(wr_buffer.len())?; | ||
| 413 | self.check_rx(rd_buffer.len())?; | ||
| 384 | Ok(()) | 414 | Ok(()) |
| 385 | } | 415 | } |
| 386 | 416 | ||
| @@ -388,7 +418,7 @@ impl<'d, T: Instance> Twim<'d, T> { | |||
| 388 | /// | 418 | /// |
| 389 | /// The write buffer must have a length of at most 255 bytes on the nRF52832 | 419 | /// The write buffer must have a length of at most 255 bytes on the nRF52832 |
| 390 | /// and at most 1024 bytes on the nRF52840. | 420 | /// and at most 1024 bytes on the nRF52840. |
| 391 | pub fn copy_write(&mut self, address: u8, wr_buffer: &[u8]) -> Result<(), Error> { | 421 | pub fn blocking_copy_write(&mut self, address: u8, wr_buffer: &[u8]) -> Result<(), Error> { |
| 392 | if wr_buffer.len() > FORCE_COPY_BUFFER_SIZE { | 422 | if wr_buffer.len() > FORCE_COPY_BUFFER_SIZE { |
| 393 | return Err(Error::TxBufferTooLong); | 423 | return Err(Error::TxBufferTooLong); |
| 394 | } | 424 | } |
| @@ -397,7 +427,7 @@ impl<'d, T: Instance> Twim<'d, T> { | |||
| 397 | let wr_ram_buffer = &mut [0; FORCE_COPY_BUFFER_SIZE][..wr_buffer.len()]; | 427 | let wr_ram_buffer = &mut [0; FORCE_COPY_BUFFER_SIZE][..wr_buffer.len()]; |
| 398 | wr_ram_buffer.copy_from_slice(wr_buffer); | 428 | wr_ram_buffer.copy_from_slice(wr_buffer); |
| 399 | 429 | ||
| 400 | self.write(address, wr_ram_buffer) | 430 | self.blocking_write(address, wr_ram_buffer) |
| 401 | } | 431 | } |
| 402 | 432 | ||
| 403 | /// Copy data into RAM and write to an I2C slave, then read data from the slave without | 433 | /// Copy data into RAM and write to an I2C slave, then read data from the slave without |
| @@ -408,7 +438,7 @@ impl<'d, T: Instance> Twim<'d, T> { | |||
| 408 | /// | 438 | /// |
| 409 | /// The read buffer must have a length of at most 255 bytes on the nRF52832 | 439 | /// The read buffer must have a length of at most 255 bytes on the nRF52832 |
| 410 | /// and at most 65535 bytes on the nRF52840. | 440 | /// and at most 65535 bytes on the nRF52840. |
| 411 | pub fn copy_write_then_read( | 441 | pub fn blocking_copy_write_read( |
| 412 | &mut self, | 442 | &mut self, |
| 413 | address: u8, | 443 | address: u8, |
| 414 | wr_buffer: &[u8], | 444 | wr_buffer: &[u8], |
| @@ -422,27 +452,40 @@ impl<'d, T: Instance> Twim<'d, T> { | |||
| 422 | let wr_ram_buffer = &mut [0; FORCE_COPY_BUFFER_SIZE][..wr_buffer.len()]; | 452 | let wr_ram_buffer = &mut [0; FORCE_COPY_BUFFER_SIZE][..wr_buffer.len()]; |
| 423 | wr_ram_buffer.copy_from_slice(wr_buffer); | 453 | wr_ram_buffer.copy_from_slice(wr_buffer); |
| 424 | 454 | ||
| 425 | self.write_then_read(address, wr_ram_buffer, rd_buffer) | 455 | self.blocking_write_read(address, wr_ram_buffer, rd_buffer) |
| 426 | } | 456 | } |
| 427 | 457 | ||
| 428 | fn wait_for_stopped_event(cx: &mut core::task::Context) -> Poll<()> { | 458 | pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> { |
| 429 | let r = T::regs(); | 459 | self.setup_read(address, buffer, true)?; |
| 430 | let s = T::state(); | 460 | self.async_wait().await; |
| 431 | 461 | compiler_fence(SeqCst); | |
| 432 | s.end_waker.register(cx.waker()); | 462 | self.check_errorsrc()?; |
| 433 | if r.events_stopped.read().bits() != 0 { | 463 | self.check_rx(buffer.len())?; |
| 434 | r.events_stopped.reset(); | 464 | Ok(()) |
| 435 | 465 | } | |
| 436 | return Poll::Ready(()); | ||
| 437 | } | ||
| 438 | 466 | ||
| 439 | // stop if an error occured | 467 | pub async fn write(&mut self, address: u8, buffer: &[u8]) -> Result<(), Error> { |
| 440 | if r.events_error.read().bits() != 0 { | 468 | self.setup_write(address, buffer, true)?; |
| 441 | r.events_error.reset(); | 469 | self.async_wait().await; |
| 442 | r.tasks_stop.write(|w| unsafe { w.bits(1) }); | 470 | compiler_fence(SeqCst); |
| 443 | } | 471 | self.check_errorsrc()?; |
| 472 | self.check_tx(buffer.len())?; | ||
| 473 | Ok(()) | ||
| 474 | } | ||
| 444 | 475 | ||
| 445 | Poll::Pending | 476 | pub async fn write_read( |
| 477 | &mut self, | ||
| 478 | address: u8, | ||
| 479 | wr_buffer: &[u8], | ||
| 480 | rd_buffer: &mut [u8], | ||
| 481 | ) -> Result<(), Error> { | ||
| 482 | self.setup_write_read(address, wr_buffer, rd_buffer, true)?; | ||
| 483 | self.async_wait().await; | ||
| 484 | compiler_fence(SeqCst); | ||
| 485 | self.check_errorsrc()?; | ||
| 486 | self.check_tx(wr_buffer.len())?; | ||
| 487 | self.check_rx(rd_buffer.len())?; | ||
| 488 | Ok(()) | ||
| 446 | } | 489 | } |
| 447 | } | 490 | } |
| 448 | 491 | ||
| @@ -450,7 +493,7 @@ impl<'a, T: Instance> Drop for Twim<'a, T> { | |||
| 450 | fn drop(&mut self) { | 493 | fn drop(&mut self) { |
| 451 | trace!("twim drop"); | 494 | trace!("twim drop"); |
| 452 | 495 | ||
| 453 | // TODO when implementing async here, check for abort | 496 | // TODO: check for abort |
| 454 | 497 | ||
| 455 | // disable! | 498 | // disable! |
| 456 | let r = T::regs(); | 499 | let r = T::regs(); |
| @@ -483,174 +526,20 @@ where | |||
| 483 | = impl Future<Output = Result<(), Self::Error>> + 'a; | 526 | = impl Future<Output = Result<(), Self::Error>> + 'a; |
| 484 | 527 | ||
| 485 | fn read<'a>(&'a mut self, address: u8, buffer: &'a mut [u8]) -> Self::ReadFuture<'a> { | 528 | fn read<'a>(&'a mut self, address: u8, buffer: &'a mut [u8]) -> Self::ReadFuture<'a> { |
| 486 | async move { | 529 | self.read(address, buffer) |
| 487 | // NOTE: RAM slice check for buffer is not necessary, as a mutable | ||
| 488 | // slice can only be built from data located in RAM. | ||
| 489 | |||
| 490 | let r = T::regs(); | ||
| 491 | |||
| 492 | // Conservative compiler fence to prevent optimizations that do not | ||
| 493 | // take in to account actions by DMA. The fence has been placed here, | ||
| 494 | // before any DMA action has started. | ||
| 495 | compiler_fence(SeqCst); | ||
| 496 | |||
| 497 | r.address.write(|w| unsafe { w.address().bits(address) }); | ||
| 498 | |||
| 499 | // Set up the DMA read. | ||
| 500 | unsafe { self.set_rx_buffer(buffer)? }; | ||
| 501 | |||
| 502 | // Reset events | ||
| 503 | r.events_stopped.reset(); | ||
| 504 | r.events_error.reset(); | ||
| 505 | self.clear_errorsrc(); | ||
| 506 | |||
| 507 | // Enable events | ||
| 508 | r.intenset.write(|w| w.stopped().set().error().set()); | ||
| 509 | |||
| 510 | // Start read operation. | ||
| 511 | r.shorts.write(|w| w.lastrx_stop().enabled()); | ||
| 512 | r.tasks_startrx.write(|w| | ||
| 513 | // `1` is a valid value to write to task registers. | ||
| 514 | unsafe { w.bits(1) }); | ||
| 515 | |||
| 516 | // Conservative compiler fence to prevent optimizations that do not | ||
| 517 | // take in to account actions by DMA. The fence has been placed here, | ||
| 518 | // after all possible DMA actions have completed. | ||
| 519 | compiler_fence(SeqCst); | ||
| 520 | |||
| 521 | // Wait for 'stopped' event. | ||
| 522 | poll_fn(Self::wait_for_stopped_event).await; | ||
| 523 | |||
| 524 | self.read_errorsrc()?; | ||
| 525 | |||
| 526 | if r.rxd.amount.read().bits() != buffer.len() as u32 { | ||
| 527 | return Err(Error::Receive); | ||
| 528 | } | ||
| 529 | |||
| 530 | Ok(()) | ||
| 531 | } | ||
| 532 | } | 530 | } |
| 533 | 531 | ||
| 534 | fn write<'a>(&'a mut self, address: u8, bytes: &'a [u8]) -> Self::WriteFuture<'a> { | 532 | fn write<'a>(&'a mut self, address: u8, buffer: &'a [u8]) -> Self::WriteFuture<'a> { |
| 535 | async move { | 533 | self.write(address, buffer) |
| 536 | slice_in_ram_or(bytes, Error::DMABufferNotInDataMemory)?; | ||
| 537 | |||
| 538 | // Conservative compiler fence to prevent optimizations that do not | ||
| 539 | // take in to account actions by DMA. The fence has been placed here, | ||
| 540 | // before any DMA action has started. | ||
| 541 | compiler_fence(SeqCst); | ||
| 542 | |||
| 543 | let r = T::regs(); | ||
| 544 | |||
| 545 | // Set up current address we're trying to talk to | ||
| 546 | r.address.write(|w| unsafe { w.address().bits(address) }); | ||
| 547 | |||
| 548 | // Set up DMA write. | ||
| 549 | unsafe { | ||
| 550 | self.set_tx_buffer(bytes)?; | ||
| 551 | } | ||
| 552 | |||
| 553 | // Reset events | ||
| 554 | r.events_stopped.reset(); | ||
| 555 | r.events_error.reset(); | ||
| 556 | r.events_lasttx.reset(); | ||
| 557 | self.clear_errorsrc(); | ||
| 558 | |||
| 559 | // Enable events | ||
| 560 | r.intenset.write(|w| w.stopped().set().error().set()); | ||
| 561 | |||
| 562 | // Start write operation. | ||
| 563 | r.shorts.write(|w| w.lasttx_stop().enabled()); | ||
| 564 | r.tasks_starttx.write(|w| | ||
| 565 | // `1` is a valid value to write to task registers. | ||
| 566 | unsafe { w.bits(1) }); | ||
| 567 | |||
| 568 | // Conservative compiler fence to prevent optimizations that do not | ||
| 569 | // take in to account actions by DMA. The fence has been placed here, | ||
| 570 | // after all possible DMA actions have completed. | ||
| 571 | compiler_fence(SeqCst); | ||
| 572 | |||
| 573 | // Wait for 'stopped' event. | ||
| 574 | poll_fn(Self::wait_for_stopped_event).await; | ||
| 575 | |||
| 576 | self.read_errorsrc()?; | ||
| 577 | |||
| 578 | if r.txd.amount.read().bits() != bytes.len() as u32 { | ||
| 579 | return Err(Error::Transmit); | ||
| 580 | } | ||
| 581 | |||
| 582 | Ok(()) | ||
| 583 | } | ||
| 584 | } | 534 | } |
| 585 | 535 | ||
| 586 | fn write_read<'a>( | 536 | fn write_read<'a>( |
| 587 | &'a mut self, | 537 | &'a mut self, |
| 588 | address: u8, | 538 | address: u8, |
| 589 | bytes: &'a [u8], | 539 | wr_buffer: &'a [u8], |
| 590 | buffer: &'a mut [u8], | 540 | rd_buffer: &'a mut [u8], |
| 591 | ) -> Self::WriteReadFuture<'a> { | 541 | ) -> Self::WriteReadFuture<'a> { |
| 592 | async move { | 542 | self.write_read(address, wr_buffer, rd_buffer) |
| 593 | slice_in_ram_or(bytes, Error::DMABufferNotInDataMemory)?; | ||
| 594 | // NOTE: RAM slice check for buffer is not necessary, as a mutable | ||
| 595 | // slice can only be built from data located in RAM. | ||
| 596 | |||
| 597 | // Conservative compiler fence to prevent optimizations that do not | ||
| 598 | // take in to account actions by DMA. The fence has been placed here, | ||
| 599 | // before any DMA action has started. | ||
| 600 | compiler_fence(SeqCst); | ||
| 601 | |||
| 602 | let r = T::regs(); | ||
| 603 | |||
| 604 | // Set up current address we're trying to talk to | ||
| 605 | r.address.write(|w| unsafe { w.address().bits(address) }); | ||
| 606 | |||
| 607 | // Set up DMA buffers. | ||
| 608 | unsafe { | ||
| 609 | self.set_tx_buffer(bytes)?; | ||
| 610 | self.set_rx_buffer(buffer)?; | ||
| 611 | } | ||
| 612 | |||
| 613 | // Reset events | ||
| 614 | r.events_stopped.reset(); | ||
| 615 | r.events_error.reset(); | ||
| 616 | r.events_lasttx.reset(); | ||
| 617 | self.clear_errorsrc(); | ||
| 618 | |||
| 619 | // Enable events | ||
| 620 | r.intenset.write(|w| w.stopped().set().error().set()); | ||
| 621 | |||
| 622 | // Start write+read operation. | ||
| 623 | r.shorts.write(|w| { | ||
| 624 | w.lasttx_startrx().enabled(); | ||
| 625 | w.lastrx_stop().enabled(); | ||
| 626 | w | ||
| 627 | }); | ||
| 628 | // `1` is a valid value to write to task registers. | ||
| 629 | r.tasks_starttx.write(|w| unsafe { w.bits(1) }); | ||
| 630 | |||
| 631 | // Conservative compiler fence to prevent optimizations that do not | ||
| 632 | // take in to account actions by DMA. The fence has been placed here, | ||
| 633 | // after all possible DMA actions have completed. | ||
| 634 | compiler_fence(SeqCst); | ||
| 635 | |||
| 636 | // Wait for 'stopped' event. | ||
| 637 | poll_fn(Self::wait_for_stopped_event).await; | ||
| 638 | |||
| 639 | self.read_errorsrc()?; | ||
| 640 | |||
| 641 | let bad_write = r.txd.amount.read().bits() != bytes.len() as u32; | ||
| 642 | let bad_read = r.rxd.amount.read().bits() != buffer.len() as u32; | ||
| 643 | |||
| 644 | if bad_write { | ||
| 645 | return Err(Error::Transmit); | ||
| 646 | } | ||
| 647 | |||
| 648 | if bad_read { | ||
| 649 | return Err(Error::Receive); | ||
| 650 | } | ||
| 651 | |||
| 652 | Ok(()) | ||
| 653 | } | ||
| 654 | } | 543 | } |
| 655 | } | 544 | } |
| 656 | 545 | ||
| @@ -659,12 +548,12 @@ impl<'a, T: Instance> embedded_hal::blocking::i2c::Write for Twim<'a, T> { | |||
| 659 | 548 | ||
| 660 | fn write<'w>(&mut self, addr: u8, bytes: &'w [u8]) -> Result<(), Error> { | 549 | fn write<'w>(&mut self, addr: u8, bytes: &'w [u8]) -> Result<(), Error> { |
| 661 | if slice_in_ram(bytes) { | 550 | if slice_in_ram(bytes) { |
| 662 | self.write(addr, bytes) | 551 | self.blocking_write(addr, bytes) |
| 663 | } else { | 552 | } else { |
| 664 | let buf = &mut [0; FORCE_COPY_BUFFER_SIZE][..]; | 553 | let buf = &mut [0; FORCE_COPY_BUFFER_SIZE][..]; |
| 665 | for chunk in bytes.chunks(FORCE_COPY_BUFFER_SIZE) { | 554 | for chunk in bytes.chunks(FORCE_COPY_BUFFER_SIZE) { |
| 666 | buf[..chunk.len()].copy_from_slice(chunk); | 555 | buf[..chunk.len()].copy_from_slice(chunk); |
| 667 | self.write(addr, &buf[..chunk.len()])?; | 556 | self.blocking_write(addr, &buf[..chunk.len()])?; |
| 668 | } | 557 | } |
| 669 | Ok(()) | 558 | Ok(()) |
| 670 | } | 559 | } |
| @@ -675,7 +564,7 @@ impl<'a, T: Instance> embedded_hal::blocking::i2c::Read for Twim<'a, T> { | |||
| 675 | type Error = Error; | 564 | type Error = Error; |
| 676 | 565 | ||
| 677 | fn read<'w>(&mut self, addr: u8, bytes: &'w mut [u8]) -> Result<(), Error> { | 566 | fn read<'w>(&mut self, addr: u8, bytes: &'w mut [u8]) -> Result<(), Error> { |
| 678 | self.read(addr, bytes) | 567 | self.blocking_read(addr, bytes) |
| 679 | } | 568 | } |
| 680 | } | 569 | } |
| 681 | 570 | ||
| @@ -689,15 +578,16 @@ impl<'a, T: Instance> embedded_hal::blocking::i2c::WriteRead for Twim<'a, T> { | |||
| 689 | buffer: &'w mut [u8], | 578 | buffer: &'w mut [u8], |
| 690 | ) -> Result<(), Error> { | 579 | ) -> Result<(), Error> { |
| 691 | if slice_in_ram(bytes) { | 580 | if slice_in_ram(bytes) { |
| 692 | self.write_then_read(addr, bytes, buffer) | 581 | self.blocking_write_read(addr, bytes, buffer) |
| 693 | } else { | 582 | } else { |
| 694 | self.copy_write_then_read(addr, bytes, buffer) | 583 | self.blocking_copy_write_read(addr, bytes, buffer) |
| 695 | } | 584 | } |
| 696 | } | 585 | } |
| 697 | } | 586 | } |
| 698 | 587 | ||
| 699 | #[derive(Debug, Copy, Clone, Eq, PartialEq)] | 588 | #[derive(Debug, Copy, Clone, Eq, PartialEq)] |
| 700 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | 589 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
| 590 | #[non_exhaustive] | ||
| 701 | pub enum Error { | 591 | pub enum Error { |
| 702 | TxBufferTooLong, | 592 | TxBufferTooLong, |
| 703 | RxBufferTooLong, | 593 | RxBufferTooLong, |
diff --git a/examples/nrf/src/bin/twim.rs b/examples/nrf/src/bin/twim.rs index 4c2f2bf2e..1ac3a3945 100644 --- a/examples/nrf/src/bin/twim.rs +++ b/examples/nrf/src/bin/twim.rs | |||
| @@ -26,7 +26,7 @@ async fn main(_spawner: Spawner, p: Peripherals) { | |||
| 26 | info!("Reading..."); | 26 | info!("Reading..."); |
| 27 | 27 | ||
| 28 | let mut buf = [0u8; 16]; | 28 | let mut buf = [0u8; 16]; |
| 29 | unwrap!(twi.write_then_read(ADDRESS, &mut [0x00], &mut buf)); | 29 | unwrap!(twi.blocking_write_read(ADDRESS, &mut [0x00], &mut buf)); |
| 30 | 30 | ||
| 31 | info!("Read: {=[u8]:x}", buf); | 31 | info!("Read: {=[u8]:x}", buf); |
| 32 | } | 32 | } |
diff --git a/examples/nrf/src/bin/twim_lowpower.rs b/examples/nrf/src/bin/twim_lowpower.rs index 62a5f0c94..4a0596437 100644 --- a/examples/nrf/src/bin/twim_lowpower.rs +++ b/examples/nrf/src/bin/twim_lowpower.rs | |||
| @@ -36,7 +36,7 @@ async fn main(_spawner: Spawner, mut p: Peripherals) { | |||
| 36 | info!("Reading..."); | 36 | info!("Reading..."); |
| 37 | 37 | ||
| 38 | let mut buf = [0u8; 16]; | 38 | let mut buf = [0u8; 16]; |
| 39 | unwrap!(twi.write_then_read(ADDRESS, &mut [0x00], &mut buf)); | 39 | unwrap!(twi.blocking_write_read(ADDRESS, &mut [0x00], &mut buf)); |
| 40 | 40 | ||
| 41 | info!("Read: {=[u8]:x}", buf); | 41 | info!("Read: {=[u8]:x}", buf); |
| 42 | 42 | ||
