diff options
| -rw-r--r-- | embassy-stm32/src/i2c/mod.rs | 95 | ||||
| -rw-r--r-- | embassy-stm32/src/i2c/v2.rs | 292 |
2 files changed, 330 insertions, 57 deletions
diff --git a/embassy-stm32/src/i2c/mod.rs b/embassy-stm32/src/i2c/mod.rs index daf7e31e8..523a0b83a 100644 --- a/embassy-stm32/src/i2c/mod.rs +++ b/embassy-stm32/src/i2c/mod.rs | |||
| @@ -1,9 +1,11 @@ | |||
| 1 | #![macro_use] | 1 | #![macro_use] |
| 2 | 2 | ||
| 3 | use embassy::interrupt::Interrupt; | ||
| 4 | |||
| 3 | #[cfg_attr(i2c_v1, path = "v1.rs")] | 5 | #[cfg_attr(i2c_v1, path = "v1.rs")] |
| 4 | #[cfg_attr(i2c_v2, path = "v2.rs")] | 6 | #[cfg_attr(i2c_v2, path = "v2.rs")] |
| 5 | mod _version; | 7 | mod _version; |
| 6 | use crate::peripherals; | 8 | use crate::{dma, peripherals}; |
| 7 | pub use _version::*; | 9 | pub use _version::*; |
| 8 | 10 | ||
| 9 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | 11 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
| @@ -18,11 +20,14 @@ pub enum Error { | |||
| 18 | } | 20 | } |
| 19 | 21 | ||
| 20 | pub(crate) mod sealed { | 22 | pub(crate) mod sealed { |
| 23 | use super::dma; | ||
| 21 | use crate::gpio::Pin; | 24 | use crate::gpio::Pin; |
| 22 | use crate::rcc::RccPeripheral; | 25 | use crate::rcc::RccPeripheral; |
| 23 | 26 | ||
| 24 | pub trait Instance: RccPeripheral { | 27 | pub trait Instance: RccPeripheral { |
| 25 | fn regs() -> &'static crate::pac::i2c::I2c; | 28 | fn regs() -> crate::pac::i2c::I2c; |
| 29 | |||
| 30 | fn state_number() -> usize; | ||
| 26 | } | 31 | } |
| 27 | 32 | ||
| 28 | pub trait SclPin<T: Instance>: Pin { | 33 | pub trait SclPin<T: Instance>: Pin { |
| @@ -32,23 +37,61 @@ pub(crate) mod sealed { | |||
| 32 | pub trait SdaPin<T: Instance>: Pin { | 37 | pub trait SdaPin<T: Instance>: Pin { |
| 33 | fn af_num(&self) -> u8; | 38 | fn af_num(&self) -> u8; |
| 34 | } | 39 | } |
| 40 | |||
| 41 | pub trait RxDma<T: Instance> { | ||
| 42 | fn request(&self) -> dma::Request; | ||
| 43 | } | ||
| 44 | |||
| 45 | pub trait TxDma<T: Instance> { | ||
| 46 | fn request(&self) -> dma::Request; | ||
| 47 | } | ||
| 35 | } | 48 | } |
| 36 | 49 | ||
| 37 | pub trait Instance: sealed::Instance + 'static {} | 50 | pub trait Instance: sealed::Instance + 'static { |
| 51 | type Interrupt: Interrupt; | ||
| 52 | } | ||
| 38 | 53 | ||
| 39 | pub trait SclPin<T: Instance>: sealed::SclPin<T> + 'static {} | 54 | pub trait SclPin<T: Instance>: sealed::SclPin<T> + 'static {} |
| 40 | 55 | ||
| 41 | pub trait SdaPin<T: Instance>: sealed::SdaPin<T> + 'static {} | 56 | pub trait SdaPin<T: Instance>: sealed::SdaPin<T> + 'static {} |
| 42 | 57 | ||
| 43 | crate::pac::peripherals!( | 58 | pub trait RxDma<T: Instance>: sealed::RxDma<T> + dma::Channel {} |
| 44 | (i2c, $inst:ident) => { | 59 | |
| 60 | pub trait TxDma<T: Instance>: sealed::TxDma<T> + dma::Channel {} | ||
| 61 | |||
| 62 | macro_rules! i2c_state { | ||
| 63 | (I2C1) => { | ||
| 64 | 0 | ||
| 65 | }; | ||
| 66 | (I2C2) => { | ||
| 67 | 1 | ||
| 68 | }; | ||
| 69 | (I2C3) => { | ||
| 70 | 2 | ||
| 71 | }; | ||
| 72 | (I2C4) => { | ||
| 73 | 3 | ||
| 74 | }; | ||
| 75 | (I2C5) => { | ||
| 76 | 4 | ||
| 77 | }; | ||
| 78 | } | ||
| 79 | |||
| 80 | crate::pac::interrupts!( | ||
| 81 | ($inst:ident, i2c, $block:ident, EV, $irq:ident) => { | ||
| 45 | impl sealed::Instance for peripherals::$inst { | 82 | impl sealed::Instance for peripherals::$inst { |
| 46 | fn regs() -> &'static crate::pac::i2c::I2c { | 83 | fn regs() -> crate::pac::i2c::I2c { |
| 47 | &crate::pac::$inst | 84 | crate::pac::$inst |
| 85 | } | ||
| 86 | |||
| 87 | fn state_number() -> usize { | ||
| 88 | i2c_state!($inst) | ||
| 48 | } | 89 | } |
| 49 | } | 90 | } |
| 50 | 91 | ||
| 51 | impl Instance for peripherals::$inst {} | 92 | impl Instance for peripherals::$inst { |
| 93 | type Interrupt = crate::interrupt::$irq; | ||
| 94 | } | ||
| 52 | 95 | ||
| 53 | }; | 96 | }; |
| 54 | ); | 97 | ); |
| @@ -74,3 +117,39 @@ crate::pac::peripheral_pins!( | |||
| 74 | impl_pin!($inst, $pin, SclPin, $af); | 117 | impl_pin!($inst, $pin, SclPin, $af); |
| 75 | }; | 118 | }; |
| 76 | ); | 119 | ); |
| 120 | |||
| 121 | macro_rules! impl_dma { | ||
| 122 | ($inst:ident, {dmamux: $dmamux:ident}, $signal:ident, $request:expr) => { | ||
| 123 | impl<T> sealed::$signal<peripherals::$inst> for T | ||
| 124 | where | ||
| 125 | T: crate::dma::MuxChannel<Mux = crate::dma::$dmamux>, | ||
| 126 | { | ||
| 127 | fn request(&self) -> dma::Request { | ||
| 128 | $request | ||
| 129 | } | ||
| 130 | } | ||
| 131 | |||
| 132 | impl<T> $signal<peripherals::$inst> for T where | ||
| 133 | T: crate::dma::MuxChannel<Mux = crate::dma::$dmamux> | ||
| 134 | { | ||
| 135 | } | ||
| 136 | }; | ||
| 137 | ($inst:ident, {channel: $channel:ident}, $signal:ident, $request:expr) => { | ||
| 138 | impl sealed::$signal<peripherals::$inst> for peripherals::$channel { | ||
| 139 | fn request(&self) -> dma::Request { | ||
| 140 | $request | ||
| 141 | } | ||
| 142 | } | ||
| 143 | |||
| 144 | impl $signal<peripherals::$inst> for peripherals::$channel {} | ||
| 145 | }; | ||
| 146 | } | ||
| 147 | |||
| 148 | crate::pac::peripheral_dma_channels! { | ||
| 149 | ($peri:ident, i2c, $kind:ident, RX, $channel:tt, $request:expr) => { | ||
| 150 | impl_dma!($peri, $channel, RxDma, $request); | ||
| 151 | }; | ||
| 152 | ($peri:ident, i2c, $kind:ident, TX, $channel:tt, $request:expr) => { | ||
| 153 | impl_dma!($peri, $channel, TxDma, $request); | ||
| 154 | }; | ||
| 155 | } | ||
diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs index 9f7206107..fc4f52cf3 100644 --- a/embassy-stm32/src/i2c/v2.rs +++ b/embassy-stm32/src/i2c/v2.rs | |||
| @@ -1,32 +1,66 @@ | |||
| 1 | use core::cmp; | 1 | use core::cmp; |
| 2 | use core::marker::PhantomData; | 2 | use core::marker::PhantomData; |
| 3 | use embassy::util::Unborrow; | 3 | use core::task::Poll; |
| 4 | |||
| 5 | use atomic_polyfill::{AtomicUsize, Ordering}; | ||
| 6 | use embassy::interrupt::InterruptExt; | ||
| 7 | use embassy::util::{AtomicWaker, OnDrop, Unborrow}; | ||
| 4 | use embassy_hal_common::unborrow; | 8 | use embassy_hal_common::unborrow; |
| 5 | use embedded_hal::blocking::i2c::Read; | 9 | use embedded_hal::blocking::i2c::Read; |
| 6 | use embedded_hal::blocking::i2c::Write; | 10 | use embedded_hal::blocking::i2c::Write; |
| 7 | use embedded_hal::blocking::i2c::WriteRead; | 11 | use embedded_hal::blocking::i2c::WriteRead; |
| 12 | use futures::future::poll_fn; | ||
| 8 | 13 | ||
| 14 | use crate::dma::NoDma; | ||
| 9 | use crate::i2c::{Error, Instance, SclPin, SdaPin}; | 15 | use crate::i2c::{Error, Instance, SclPin, SdaPin}; |
| 16 | use crate::pac; | ||
| 10 | use crate::pac::gpio::vals::{Afr, Moder, Ot}; | 17 | use crate::pac::gpio::vals::{Afr, Moder, Ot}; |
| 11 | use crate::pac::gpio::Gpio; | 18 | use crate::pac::gpio::Gpio; |
| 12 | use crate::pac::i2c; | 19 | use crate::pac::i2c; |
| 13 | use crate::time::Hertz; | 20 | use crate::time::Hertz; |
| 14 | 21 | ||
| 15 | pub struct I2c<'d, T: Instance> { | 22 | const I2C_COUNT: usize = pac::peripheral_count!(i2c); |
| 23 | |||
| 24 | pub struct State { | ||
| 25 | waker: [AtomicWaker; I2C_COUNT], | ||
| 26 | chunks_transferred: [AtomicUsize; I2C_COUNT], | ||
| 27 | } | ||
| 28 | |||
| 29 | impl State { | ||
| 30 | const fn new() -> Self { | ||
| 31 | const AW: AtomicWaker = AtomicWaker::new(); | ||
| 32 | const CT: AtomicUsize = AtomicUsize::new(0); | ||
| 33 | |||
| 34 | Self { | ||
| 35 | waker: [AW; I2C_COUNT], | ||
| 36 | chunks_transferred: [CT; I2C_COUNT], | ||
| 37 | } | ||
| 38 | } | ||
| 39 | } | ||
| 40 | |||
| 41 | static STATE: State = State::new(); | ||
| 42 | |||
| 43 | pub struct I2c<'d, T: Instance, TXDMA = NoDma, RXDMA = NoDma> { | ||
| 16 | phantom: PhantomData<&'d mut T>, | 44 | phantom: PhantomData<&'d mut T>, |
| 45 | tx_dma: TXDMA, | ||
| 46 | #[allow(dead_code)] | ||
| 47 | rx_dma: RXDMA, | ||
| 17 | } | 48 | } |
| 18 | 49 | ||
| 19 | impl<'d, T: Instance> I2c<'d, T> { | 50 | impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { |
| 20 | pub fn new<F>( | 51 | pub fn new<F>( |
| 21 | _peri: impl Unborrow<Target = T> + 'd, | 52 | _peri: impl Unborrow<Target = T> + 'd, |
| 22 | scl: impl Unborrow<Target = impl SclPin<T>>, | 53 | scl: impl Unborrow<Target = impl SclPin<T>> + 'd, |
| 23 | sda: impl Unborrow<Target = impl SdaPin<T>>, | 54 | sda: impl Unborrow<Target = impl SdaPin<T>> + 'd, |
| 55 | irq: impl Unborrow<Target = T::Interrupt> + 'd, | ||
| 56 | tx_dma: impl Unborrow<Target = TXDMA> + 'd, | ||
| 57 | rx_dma: impl Unborrow<Target = RXDMA> + 'd, | ||
| 24 | freq: F, | 58 | freq: F, |
| 25 | ) -> Self | 59 | ) -> Self |
| 26 | where | 60 | where |
| 27 | F: Into<Hertz>, | 61 | F: Into<Hertz>, |
| 28 | { | 62 | { |
| 29 | unborrow!(scl, sda); | 63 | unborrow!(irq, scl, sda, tx_dma, rx_dma); |
| 30 | 64 | ||
| 31 | T::enable(); | 65 | T::enable(); |
| 32 | 66 | ||
| @@ -60,9 +94,31 @@ impl<'d, T: Instance> I2c<'d, T> { | |||
| 60 | }); | 94 | }); |
| 61 | } | 95 | } |
| 62 | 96 | ||
| 97 | irq.set_handler(Self::on_interrupt); | ||
| 98 | irq.unpend(); | ||
| 99 | irq.enable(); | ||
| 100 | |||
| 63 | Self { | 101 | Self { |
| 64 | phantom: PhantomData, | 102 | phantom: PhantomData, |
| 103 | tx_dma, | ||
| 104 | rx_dma, | ||
| 105 | } | ||
| 106 | } | ||
| 107 | |||
| 108 | unsafe fn on_interrupt(_: *mut ()) { | ||
| 109 | let regs = T::regs(); | ||
| 110 | let isr = regs.isr().read(); | ||
| 111 | |||
| 112 | if isr.tcr() || isr.tc() { | ||
| 113 | let n = T::state_number(); | ||
| 114 | STATE.chunks_transferred[n].fetch_add(1, Ordering::Relaxed); | ||
| 115 | STATE.waker[n].wake(); | ||
| 65 | } | 116 | } |
| 117 | // The flag can only be cleared by writting to nbytes, we won't do that here, so disable | ||
| 118 | // the interrupt | ||
| 119 | critical_section::with(|_| { | ||
| 120 | regs.cr1().modify(|w| w.set_tcie(false)); | ||
| 121 | }); | ||
| 66 | } | 122 | } |
| 67 | 123 | ||
| 68 | unsafe fn configure_pin(block: Gpio, pin: usize, af_num: u8) { | 124 | unsafe fn configure_pin(block: Gpio, pin: usize, af_num: u8) { |
| @@ -114,13 +170,13 @@ impl<'d, T: Instance> I2c<'d, T> { | |||
| 114 | } | 170 | } |
| 115 | } | 171 | } |
| 116 | 172 | ||
| 117 | fn master_write(&mut self, address: u8, length: usize, stop: Stop, reload: bool) { | 173 | unsafe fn master_write(address: u8, length: usize, stop: Stop, reload: bool) { |
| 118 | assert!(length < 256 && length > 0); | 174 | assert!(length < 256 && length > 0); |
| 119 | 175 | ||
| 120 | // Wait for any previous address sequence to end | 176 | // Wait for any previous address sequence to end |
| 121 | // automatically. This could be up to 50% of a bus | 177 | // automatically. This could be up to 50% of a bus |
| 122 | // cycle (ie. up to 0.5/freq) | 178 | // cycle (ie. up to 0.5/freq) |
| 123 | while unsafe { T::regs().cr2().read().start() == i2c::vals::Start::START } {} | 179 | while T::regs().cr2().read().start() == i2c::vals::Start::START {} |
| 124 | 180 | ||
| 125 | let reload = if reload { | 181 | let reload = if reload { |
| 126 | i2c::vals::Reload::NOTCOMPLETED | 182 | i2c::vals::Reload::NOTCOMPLETED |
| @@ -131,23 +187,21 @@ impl<'d, T: Instance> I2c<'d, T> { | |||
| 131 | // Set START and prepare to send `bytes`. The | 187 | // Set START and prepare to send `bytes`. The |
| 132 | // START bit can be set even if the bus is BUSY or | 188 | // START bit can be set even if the bus is BUSY or |
| 133 | // I2C is in slave mode. | 189 | // I2C is in slave mode. |
| 134 | unsafe { | 190 | T::regs().cr2().modify(|w| { |
| 135 | T::regs().cr2().modify(|w| { | 191 | w.set_sadd((address << 1 | 0) as u16); |
| 136 | w.set_sadd((address << 1 | 0) as u16); | 192 | w.set_add10(i2c::vals::Add::BIT7); |
| 137 | w.set_add10(i2c::vals::Add::BIT7); | 193 | w.set_rd_wrn(i2c::vals::RdWrn::WRITE); |
| 138 | w.set_rd_wrn(i2c::vals::RdWrn::WRITE); | 194 | w.set_nbytes(length as u8); |
| 139 | w.set_nbytes(length as u8); | 195 | w.set_start(i2c::vals::Start::START); |
| 140 | w.set_start(i2c::vals::Start::START); | 196 | w.set_autoend(stop.autoend()); |
| 141 | w.set_autoend(stop.autoend()); | 197 | w.set_reload(reload); |
| 142 | w.set_reload(reload); | 198 | }); |
| 143 | }); | ||
| 144 | } | ||
| 145 | } | 199 | } |
| 146 | 200 | ||
| 147 | fn master_continue(&mut self, length: usize, reload: bool) { | 201 | unsafe fn master_continue(length: usize, reload: bool) { |
| 148 | assert!(length < 256 && length > 0); | 202 | assert!(length < 256 && length > 0); |
| 149 | 203 | ||
| 150 | while unsafe { !T::regs().isr().read().tcr() } {} | 204 | while !T::regs().isr().read().tcr() {} |
| 151 | 205 | ||
| 152 | let reload = if reload { | 206 | let reload = if reload { |
| 153 | i2c::vals::Reload::NOTCOMPLETED | 207 | i2c::vals::Reload::NOTCOMPLETED |
| @@ -155,12 +209,10 @@ impl<'d, T: Instance> I2c<'d, T> { | |||
| 155 | i2c::vals::Reload::COMPLETED | 209 | i2c::vals::Reload::COMPLETED |
| 156 | }; | 210 | }; |
| 157 | 211 | ||
| 158 | unsafe { | 212 | T::regs().cr2().modify(|w| { |
| 159 | T::regs().cr2().modify(|w| { | 213 | w.set_nbytes(length as u8); |
| 160 | w.set_nbytes(length as u8); | 214 | w.set_reload(reload); |
| 161 | w.set_reload(reload); | 215 | }); |
| 162 | }); | ||
| 163 | } | ||
| 164 | } | 216 | } |
| 165 | 217 | ||
| 166 | fn flush_txdr(&self) { | 218 | fn flush_txdr(&self) { |
| @@ -265,7 +317,10 @@ impl<'d, T: Instance> I2c<'d, T> { | |||
| 265 | 317 | ||
| 266 | for (number, chunk) in buffer.chunks_mut(255).enumerate() { | 318 | for (number, chunk) in buffer.chunks_mut(255).enumerate() { |
| 267 | if number != 0 { | 319 | if number != 0 { |
| 268 | self.master_continue(chunk.len(), number != last_chunk_idx); | 320 | // NOTE(unsafe) We have &mut self |
| 321 | unsafe { | ||
| 322 | Self::master_continue(chunk.len(), number != last_chunk_idx); | ||
| 323 | } | ||
| 269 | } | 324 | } |
| 270 | 325 | ||
| 271 | for byte in chunk { | 326 | for byte in chunk { |
| @@ -292,16 +347,22 @@ impl<'d, T: Instance> I2c<'d, T> { | |||
| 292 | // I2C start | 347 | // I2C start |
| 293 | // | 348 | // |
| 294 | // ST SAD+W | 349 | // ST SAD+W |
| 295 | self.master_write( | 350 | // NOTE(unsafe) We have &mut self |
| 296 | address, | 351 | unsafe { |
| 297 | bytes.len().min(255), | 352 | Self::master_write( |
| 298 | Stop::Software, | 353 | address, |
| 299 | last_chunk_idx != 0, | 354 | bytes.len().min(255), |
| 300 | ); | 355 | Stop::Software, |
| 356 | last_chunk_idx != 0, | ||
| 357 | ); | ||
| 358 | } | ||
| 301 | 359 | ||
| 302 | for (number, chunk) in bytes.chunks(255).enumerate() { | 360 | for (number, chunk) in bytes.chunks(255).enumerate() { |
| 303 | if number != 0 { | 361 | if number != 0 { |
| 304 | self.master_continue(chunk.len(), number != last_chunk_idx); | 362 | // NOTE(unsafe) We have &mut self |
| 363 | unsafe { | ||
| 364 | Self::master_continue(chunk.len(), number != last_chunk_idx); | ||
| 365 | } | ||
| 305 | } | 366 | } |
| 306 | 367 | ||
| 307 | for byte in chunk { | 368 | for byte in chunk { |
| @@ -324,6 +385,130 @@ impl<'d, T: Instance> I2c<'d, T> { | |||
| 324 | Ok(()) | 385 | Ok(()) |
| 325 | } | 386 | } |
| 326 | 387 | ||
| 388 | async fn write_dma_internal( | ||
| 389 | &mut self, | ||
| 390 | address: u8, | ||
| 391 | bytes: &[u8], | ||
| 392 | first_slice: bool, | ||
| 393 | last_slice: bool, | ||
| 394 | ) -> Result<(), Error> | ||
| 395 | where | ||
| 396 | TXDMA: crate::i2c::TxDma<T>, | ||
| 397 | { | ||
| 398 | let total_len = bytes.len(); | ||
| 399 | let completed_chunks = total_len / 255; | ||
| 400 | let total_chunks = if completed_chunks * 255 == total_len { | ||
| 401 | completed_chunks | ||
| 402 | } else { | ||
| 403 | completed_chunks + 1 | ||
| 404 | }; | ||
| 405 | |||
| 406 | let dma_transfer = unsafe { | ||
| 407 | let regs = T::regs(); | ||
| 408 | regs.cr1().modify(|w| { | ||
| 409 | w.set_txdmaen(true); | ||
| 410 | if first_slice { | ||
| 411 | w.set_tcie(true); | ||
| 412 | } | ||
| 413 | }); | ||
| 414 | let dst = regs.txdr().ptr() as *mut u8; | ||
| 415 | |||
| 416 | let ch = &mut self.tx_dma; | ||
| 417 | ch.write(ch.request(), bytes, dst) | ||
| 418 | }; | ||
| 419 | |||
| 420 | let state_number = T::state_number(); | ||
| 421 | STATE.chunks_transferred[state_number].store(0, Ordering::Relaxed); | ||
| 422 | let mut remaining_len = total_len; | ||
| 423 | |||
| 424 | let _on_drop = OnDrop::new(|| { | ||
| 425 | let regs = T::regs(); | ||
| 426 | unsafe { | ||
| 427 | regs.cr1().modify(|w| { | ||
| 428 | if last_slice { | ||
| 429 | w.set_txdmaen(false); | ||
| 430 | } | ||
| 431 | w.set_tcie(false); | ||
| 432 | }) | ||
| 433 | } | ||
| 434 | }); | ||
| 435 | |||
| 436 | // NOTE(unsafe) self.tx_dma does not fiddle with the i2c registers | ||
| 437 | if first_slice { | ||
| 438 | unsafe { | ||
| 439 | Self::master_write( | ||
| 440 | address, | ||
| 441 | total_len.min(255), | ||
| 442 | Stop::Software, | ||
| 443 | (total_chunks != 1) || !last_slice, | ||
| 444 | ); | ||
| 445 | } | ||
| 446 | } else { | ||
| 447 | unsafe { | ||
| 448 | Self::master_continue(total_len.min(255), (total_chunks != 1) || !last_slice); | ||
| 449 | T::regs().cr1().modify(|w| w.set_tcie(true)); | ||
| 450 | } | ||
| 451 | } | ||
| 452 | |||
| 453 | poll_fn(|cx| { | ||
| 454 | STATE.waker[state_number].register(cx.waker()); | ||
| 455 | let chunks_transferred = STATE.chunks_transferred[state_number].load(Ordering::Relaxed); | ||
| 456 | |||
| 457 | if chunks_transferred == total_chunks { | ||
| 458 | return Poll::Ready(()); | ||
| 459 | } else if chunks_transferred != 0 { | ||
| 460 | remaining_len = remaining_len.saturating_sub(255); | ||
| 461 | let last_piece = (chunks_transferred + 1 == total_chunks) && last_slice; | ||
| 462 | |||
| 463 | // NOTE(unsafe) self.tx_dma does not fiddle with the i2c registers | ||
| 464 | unsafe { | ||
| 465 | Self::master_continue(remaining_len.min(255), !last_piece); | ||
| 466 | T::regs().cr1().modify(|w| w.set_tcie(true)); | ||
| 467 | } | ||
| 468 | } | ||
| 469 | Poll::Pending | ||
| 470 | }) | ||
| 471 | .await; | ||
| 472 | |||
| 473 | dma_transfer.await; | ||
| 474 | |||
| 475 | if last_slice { | ||
| 476 | // This should be done already | ||
| 477 | self.wait_tc()?; | ||
| 478 | self.master_stop(); | ||
| 479 | } | ||
| 480 | Ok(()) | ||
| 481 | } | ||
| 482 | |||
| 483 | pub async fn write_dma(&mut self, address: u8, bytes: &[u8]) -> Result<(), Error> | ||
| 484 | where | ||
| 485 | TXDMA: crate::i2c::TxDma<T>, | ||
| 486 | { | ||
| 487 | self.write_dma_internal(address, bytes, true, true).await | ||
| 488 | } | ||
| 489 | |||
| 490 | pub async fn write_dma_vectored(&mut self, address: u8, bytes: &[&[u8]]) -> Result<(), Error> | ||
| 491 | where | ||
| 492 | TXDMA: crate::i2c::TxDma<T>, | ||
| 493 | { | ||
| 494 | if bytes.is_empty() { | ||
| 495 | return Err(Error::ZeroLengthTransfer); | ||
| 496 | } | ||
| 497 | let mut iter = bytes.iter(); | ||
| 498 | |||
| 499 | let mut first = true; | ||
| 500 | let mut current = iter.next(); | ||
| 501 | while let Some(c) = current { | ||
| 502 | let next = iter.next(); | ||
| 503 | let is_last = next.is_none(); | ||
| 504 | |||
| 505 | self.write_dma_internal(address, c, first, is_last).await?; | ||
| 506 | first = false; | ||
| 507 | current = next; | ||
| 508 | } | ||
| 509 | Ok(()) | ||
| 510 | } | ||
| 511 | |||
| 327 | pub fn write_vectored(&mut self, address: u8, bytes: &[&[u8]]) -> Result<(), Error> { | 512 | pub fn write_vectored(&mut self, address: u8, bytes: &[&[u8]]) -> Result<(), Error> { |
| 328 | if bytes.is_empty() { | 513 | if bytes.is_empty() { |
| 329 | return Err(Error::ZeroLengthTransfer); | 514 | return Err(Error::ZeroLengthTransfer); |
| @@ -331,12 +516,15 @@ impl<'d, T: Instance> I2c<'d, T> { | |||
| 331 | let first_length = bytes[0].len(); | 516 | let first_length = bytes[0].len(); |
| 332 | let last_slice_index = bytes.len() - 1; | 517 | let last_slice_index = bytes.len() - 1; |
| 333 | 518 | ||
| 334 | self.master_write( | 519 | // NOTE(unsafe) We have &mut self |
| 335 | address, | 520 | unsafe { |
| 336 | first_length.min(255), | 521 | Self::master_write( |
| 337 | Stop::Software, | 522 | address, |
| 338 | (first_length > 255) || (last_slice_index != 0), | 523 | first_length.min(255), |
| 339 | ); | 524 | Stop::Software, |
| 525 | (first_length > 255) || (last_slice_index != 0), | ||
| 526 | ); | ||
| 527 | } | ||
| 340 | 528 | ||
| 341 | for (idx, slice) in bytes.iter().enumerate() { | 529 | for (idx, slice) in bytes.iter().enumerate() { |
| 342 | let slice_len = slice.len(); | 530 | let slice_len = slice.len(); |
| @@ -349,18 +537,24 @@ impl<'d, T: Instance> I2c<'d, T> { | |||
| 349 | let last_chunk_idx = total_chunks.saturating_sub(1); | 537 | let last_chunk_idx = total_chunks.saturating_sub(1); |
| 350 | 538 | ||
| 351 | if idx != 0 { | 539 | if idx != 0 { |
| 352 | self.master_continue( | 540 | // NOTE(unsafe) We have &mut self |
| 353 | slice_len.min(255), | 541 | unsafe { |
| 354 | (idx != last_slice_index) || (slice_len > 255), | 542 | Self::master_continue( |
| 355 | ); | 543 | slice_len.min(255), |
| 544 | (idx != last_slice_index) || (slice_len > 255), | ||
| 545 | ); | ||
| 546 | } | ||
| 356 | } | 547 | } |
| 357 | 548 | ||
| 358 | for (number, chunk) in slice.chunks(255).enumerate() { | 549 | for (number, chunk) in slice.chunks(255).enumerate() { |
| 359 | if number != 0 { | 550 | if number != 0 { |
| 360 | self.master_continue( | 551 | // NOTE(unsafe) We have &mut self |
| 361 | chunk.len(), | 552 | unsafe { |
| 362 | (number != last_chunk_idx) || (idx != last_slice_index), | 553 | Self::master_continue( |
| 363 | ); | 554 | chunk.len(), |
| 555 | (number != last_chunk_idx) || (idx != last_slice_index), | ||
| 556 | ); | ||
| 557 | } | ||
| 364 | } | 558 | } |
| 365 | 559 | ||
| 366 | for byte in chunk { | 560 | for byte in chunk { |
