diff options
| author | Jeremy Fitzhardinge <[email protected]> | 2022-10-02 15:08:58 -0700 |
|---|---|---|
| committer | Jeremy Fitzhardinge <[email protected]> | 2022-10-02 15:09:14 -0700 |
| commit | e8bb8faa23c1e8b78285646ca7e711bafe990e20 (patch) | |
| tree | 2e506e2500aeec609732057089b62b485c2e3693 | |
| parent | 09afece93d0dccb750a0dbc9c63282d3dca55e48 (diff) | |
rp i2c: allow blocking ops on async contexts
| -rw-r--r-- | embassy-rp/src/i2c.rs | 210 |
1 files changed, 105 insertions, 105 deletions
diff --git a/embassy-rp/src/i2c.rs b/embassy-rp/src/i2c.rs index f62cf0b86..e01692dc1 100644 --- a/embassy-rp/src/i2c.rs +++ b/embassy-rp/src/i2c.rs | |||
| @@ -68,106 +68,6 @@ impl<'d, T: Instance> I2c<'d, T, Blocking> { | |||
| 68 | into_ref!(scl, sda); | 68 | into_ref!(scl, sda); |
| 69 | Self::new_inner(peri, scl.map_into(), sda.map_into(), config) | 69 | Self::new_inner(peri, scl.map_into(), sda.map_into(), config) |
| 70 | } | 70 | } |
| 71 | |||
| 72 | fn read_blocking_internal(&mut self, buffer: &mut [u8], restart: bool, send_stop: bool) -> Result<(), Error> { | ||
| 73 | if buffer.is_empty() { | ||
| 74 | return Err(Error::InvalidReadBufferLength); | ||
| 75 | } | ||
| 76 | |||
| 77 | let p = T::regs(); | ||
| 78 | let lastindex = buffer.len() - 1; | ||
| 79 | for (i, byte) in buffer.iter_mut().enumerate() { | ||
| 80 | let first = i == 0; | ||
| 81 | let last = i == lastindex; | ||
| 82 | |||
| 83 | // NOTE(unsafe) We have &mut self | ||
| 84 | unsafe { | ||
| 85 | // wait until there is space in the FIFO to write the next byte | ||
| 86 | while Self::tx_fifo_full() {} | ||
| 87 | |||
| 88 | p.ic_data_cmd().write(|w| { | ||
| 89 | w.set_restart(restart && first); | ||
| 90 | w.set_stop(send_stop && last); | ||
| 91 | |||
| 92 | w.set_cmd(true); | ||
| 93 | }); | ||
| 94 | |||
| 95 | while Self::rx_fifo_len() == 0 { | ||
| 96 | self.read_and_clear_abort_reason()?; | ||
| 97 | } | ||
| 98 | |||
| 99 | *byte = p.ic_data_cmd().read().dat(); | ||
| 100 | } | ||
| 101 | } | ||
| 102 | |||
| 103 | Ok(()) | ||
| 104 | } | ||
| 105 | |||
| 106 | fn write_blocking_internal(&mut self, bytes: &[u8], send_stop: bool) -> Result<(), Error> { | ||
| 107 | if bytes.is_empty() { | ||
| 108 | return Err(Error::InvalidWriteBufferLength); | ||
| 109 | } | ||
| 110 | |||
| 111 | let p = T::regs(); | ||
| 112 | |||
| 113 | for (i, byte) in bytes.iter().enumerate() { | ||
| 114 | let last = i == bytes.len() - 1; | ||
| 115 | |||
| 116 | // NOTE(unsafe) We have &mut self | ||
| 117 | unsafe { | ||
| 118 | p.ic_data_cmd().write(|w| { | ||
| 119 | w.set_stop(send_stop && last); | ||
| 120 | w.set_dat(*byte); | ||
| 121 | }); | ||
| 122 | |||
| 123 | // Wait until the transmission of the address/data from the | ||
| 124 | // internal shift register has completed. For this to function | ||
| 125 | // correctly, the TX_EMPTY_CTRL flag in IC_CON must be set. The | ||
| 126 | // TX_EMPTY_CTRL flag was set in i2c_init. | ||
| 127 | while !p.ic_raw_intr_stat().read().tx_empty() {} | ||
| 128 | |||
| 129 | let abort_reason = self.read_and_clear_abort_reason(); | ||
| 130 | |||
| 131 | if abort_reason.is_err() || (send_stop && last) { | ||
| 132 | // If the transaction was aborted or if it completed | ||
| 133 | // successfully wait until the STOP condition has occured. | ||
| 134 | |||
| 135 | while !p.ic_raw_intr_stat().read().stop_det() {} | ||
| 136 | |||
| 137 | p.ic_clr_stop_det().read().clr_stop_det(); | ||
| 138 | } | ||
| 139 | |||
| 140 | // Note the hardware issues a STOP automatically on an abort | ||
| 141 | // condition. Note also the hardware clears RX FIFO as well as | ||
| 142 | // TX on abort, ecause we set hwparam | ||
| 143 | // IC_AVOID_RX_FIFO_FLUSH_ON_TX_ABRT to 0. | ||
| 144 | abort_reason?; | ||
| 145 | } | ||
| 146 | } | ||
| 147 | Ok(()) | ||
| 148 | } | ||
| 149 | |||
| 150 | // ========================= | ||
| 151 | // Blocking public API | ||
| 152 | // ========================= | ||
| 153 | |||
| 154 | pub fn blocking_read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> { | ||
| 155 | Self::setup(address.into())?; | ||
| 156 | self.read_blocking_internal(buffer, true, true) | ||
| 157 | // Automatic Stop | ||
| 158 | } | ||
| 159 | |||
| 160 | pub fn blocking_write(&mut self, address: u8, bytes: &[u8]) -> Result<(), Error> { | ||
| 161 | Self::setup(address.into())?; | ||
| 162 | self.write_blocking_internal(bytes, true) | ||
| 163 | } | ||
| 164 | |||
| 165 | pub fn blocking_write_read(&mut self, address: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Error> { | ||
| 166 | Self::setup(address.into())?; | ||
| 167 | self.write_blocking_internal(bytes, false)?; | ||
| 168 | self.read_blocking_internal(buffer, true, true) | ||
| 169 | // Automatic Stop | ||
| 170 | } | ||
| 171 | } | 71 | } |
| 172 | 72 | ||
| 173 | static I2C_WAKER: AtomicWaker = AtomicWaker::new(); | 73 | static I2C_WAKER: AtomicWaker = AtomicWaker::new(); |
| @@ -406,7 +306,7 @@ impl<'d, T: Instance> I2c<'d, T, Async> { | |||
| 406 | self.read_async_internal(buffer, false, true).await | 306 | self.read_async_internal(buffer, false, true).await |
| 407 | } | 307 | } |
| 408 | 308 | ||
| 409 | pub async fn write_async(&mut self, addr: u16, bytes : impl IntoIterator<Item = u8>) -> Result<(), Error> { | 309 | pub async fn write_async(&mut self, addr: u16, bytes: impl IntoIterator<Item = u8>) -> Result<(), Error> { |
| 410 | Self::setup(addr)?; | 310 | Self::setup(addr)?; |
| 411 | self.write_async_internal(bytes, true).await | 311 | self.write_async_internal(bytes, true).await |
| 412 | } | 312 | } |
| @@ -581,12 +481,112 @@ impl<'d, T: Instance + 'd, M: Mode> I2c<'d, T, M> { | |||
| 581 | } | 481 | } |
| 582 | } | 482 | } |
| 583 | } | 483 | } |
| 484 | |||
| 485 | fn read_blocking_internal(&mut self, buffer: &mut [u8], restart: bool, send_stop: bool) -> Result<(), Error> { | ||
| 486 | if buffer.is_empty() { | ||
| 487 | return Err(Error::InvalidReadBufferLength); | ||
| 488 | } | ||
| 489 | |||
| 490 | let p = T::regs(); | ||
| 491 | let lastindex = buffer.len() - 1; | ||
| 492 | for (i, byte) in buffer.iter_mut().enumerate() { | ||
| 493 | let first = i == 0; | ||
| 494 | let last = i == lastindex; | ||
| 495 | |||
| 496 | // NOTE(unsafe) We have &mut self | ||
| 497 | unsafe { | ||
| 498 | // wait until there is space in the FIFO to write the next byte | ||
| 499 | while Self::tx_fifo_full() {} | ||
| 500 | |||
| 501 | p.ic_data_cmd().write(|w| { | ||
| 502 | w.set_restart(restart && first); | ||
| 503 | w.set_stop(send_stop && last); | ||
| 504 | |||
| 505 | w.set_cmd(true); | ||
| 506 | }); | ||
| 507 | |||
| 508 | while Self::rx_fifo_len() == 0 { | ||
| 509 | self.read_and_clear_abort_reason()?; | ||
| 510 | } | ||
| 511 | |||
| 512 | *byte = p.ic_data_cmd().read().dat(); | ||
| 513 | } | ||
| 514 | } | ||
| 515 | |||
| 516 | Ok(()) | ||
| 517 | } | ||
| 518 | |||
| 519 | fn write_blocking_internal(&mut self, bytes: &[u8], send_stop: bool) -> Result<(), Error> { | ||
| 520 | if bytes.is_empty() { | ||
| 521 | return Err(Error::InvalidWriteBufferLength); | ||
| 522 | } | ||
| 523 | |||
| 524 | let p = T::regs(); | ||
| 525 | |||
| 526 | for (i, byte) in bytes.iter().enumerate() { | ||
| 527 | let last = i == bytes.len() - 1; | ||
| 528 | |||
| 529 | // NOTE(unsafe) We have &mut self | ||
| 530 | unsafe { | ||
| 531 | p.ic_data_cmd().write(|w| { | ||
| 532 | w.set_stop(send_stop && last); | ||
| 533 | w.set_dat(*byte); | ||
| 534 | }); | ||
| 535 | |||
| 536 | // Wait until the transmission of the address/data from the | ||
| 537 | // internal shift register has completed. For this to function | ||
| 538 | // correctly, the TX_EMPTY_CTRL flag in IC_CON must be set. The | ||
| 539 | // TX_EMPTY_CTRL flag was set in i2c_init. | ||
| 540 | while !p.ic_raw_intr_stat().read().tx_empty() {} | ||
| 541 | |||
| 542 | let abort_reason = self.read_and_clear_abort_reason(); | ||
| 543 | |||
| 544 | if abort_reason.is_err() || (send_stop && last) { | ||
| 545 | // If the transaction was aborted or if it completed | ||
| 546 | // successfully wait until the STOP condition has occured. | ||
| 547 | |||
| 548 | while !p.ic_raw_intr_stat().read().stop_det() {} | ||
| 549 | |||
| 550 | p.ic_clr_stop_det().read().clr_stop_det(); | ||
| 551 | } | ||
| 552 | |||
| 553 | // Note the hardware issues a STOP automatically on an abort | ||
| 554 | // condition. Note also the hardware clears RX FIFO as well as | ||
| 555 | // TX on abort, ecause we set hwparam | ||
| 556 | // IC_AVOID_RX_FIFO_FLUSH_ON_TX_ABRT to 0. | ||
| 557 | abort_reason?; | ||
| 558 | } | ||
| 559 | } | ||
| 560 | Ok(()) | ||
| 561 | } | ||
| 562 | |||
| 563 | // ========================= | ||
| 564 | // Blocking public API | ||
| 565 | // ========================= | ||
| 566 | |||
| 567 | pub fn blocking_read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> { | ||
| 568 | Self::setup(address.into())?; | ||
| 569 | self.read_blocking_internal(buffer, true, true) | ||
| 570 | // Automatic Stop | ||
| 571 | } | ||
| 572 | |||
| 573 | pub fn blocking_write(&mut self, address: u8, bytes: &[u8]) -> Result<(), Error> { | ||
| 574 | Self::setup(address.into())?; | ||
| 575 | self.write_blocking_internal(bytes, true) | ||
| 576 | } | ||
| 577 | |||
| 578 | pub fn blocking_write_read(&mut self, address: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Error> { | ||
| 579 | Self::setup(address.into())?; | ||
| 580 | self.write_blocking_internal(bytes, false)?; | ||
| 581 | self.read_blocking_internal(buffer, true, true) | ||
| 582 | // Automatic Stop | ||
| 583 | } | ||
| 584 | } | 584 | } |
| 585 | 585 | ||
| 586 | mod eh02 { | 586 | mod eh02 { |
| 587 | use super::*; | 587 | use super::*; |
| 588 | 588 | ||
| 589 | impl<'d, T: Instance> embedded_hal_02::blocking::i2c::Read for I2c<'d, T, Blocking> { | 589 | impl<'d, T: Instance, M: Mode> embedded_hal_02::blocking::i2c::Read for I2c<'d, T, M> { |
| 590 | type Error = Error; | 590 | type Error = Error; |
| 591 | 591 | ||
| 592 | fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error> { | 592 | fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error> { |
| @@ -594,7 +594,7 @@ mod eh02 { | |||
| 594 | } | 594 | } |
| 595 | } | 595 | } |
| 596 | 596 | ||
| 597 | impl<'d, T: Instance> embedded_hal_02::blocking::i2c::Write for I2c<'d, T, Blocking> { | 597 | impl<'d, T: Instance, M: Mode> embedded_hal_02::blocking::i2c::Write for I2c<'d, T, M> { |
| 598 | type Error = Error; | 598 | type Error = Error; |
| 599 | 599 | ||
| 600 | fn write(&mut self, address: u8, bytes: &[u8]) -> Result<(), Self::Error> { | 600 | fn write(&mut self, address: u8, bytes: &[u8]) -> Result<(), Self::Error> { |
| @@ -602,7 +602,7 @@ mod eh02 { | |||
| 602 | } | 602 | } |
| 603 | } | 603 | } |
| 604 | 604 | ||
| 605 | impl<'d, T: Instance> embedded_hal_02::blocking::i2c::WriteRead for I2c<'d, T, Blocking> { | 605 | impl<'d, T: Instance, M: Mode> embedded_hal_02::blocking::i2c::WriteRead for I2c<'d, T, M> { |
| 606 | type Error = Error; | 606 | type Error = Error; |
| 607 | 607 | ||
| 608 | fn write_read(&mut self, address: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Self::Error> { | 608 | fn write_read(&mut self, address: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Self::Error> { |
| @@ -635,7 +635,7 @@ mod eh1 { | |||
| 635 | type Error = Error; | 635 | type Error = Error; |
| 636 | } | 636 | } |
| 637 | 637 | ||
| 638 | impl<'d, T: Instance> embedded_hal_1::i2c::I2c for I2c<'d, T, Blocking> { | 638 | impl<'d, T: Instance, M: Mode> embedded_hal_1::i2c::I2c for I2c<'d, T, M> { |
| 639 | fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error> { | 639 | fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error> { |
| 640 | self.blocking_read(address, buffer) | 640 | self.blocking_read(address, buffer) |
| 641 | } | 641 | } |
