aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embassy-stm32/src/i2c/mod.rs95
-rw-r--r--embassy-stm32/src/i2c/v2.rs292
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
3use 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")]
5mod _version; 7mod _version;
6use crate::peripherals; 8use crate::{dma, peripherals};
7pub use _version::*; 9pub 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
20pub(crate) mod sealed { 22pub(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
37pub trait Instance: sealed::Instance + 'static {} 50pub trait Instance: sealed::Instance + 'static {
51 type Interrupt: Interrupt;
52}
38 53
39pub trait SclPin<T: Instance>: sealed::SclPin<T> + 'static {} 54pub trait SclPin<T: Instance>: sealed::SclPin<T> + 'static {}
40 55
41pub trait SdaPin<T: Instance>: sealed::SdaPin<T> + 'static {} 56pub trait SdaPin<T: Instance>: sealed::SdaPin<T> + 'static {}
42 57
43crate::pac::peripherals!( 58pub trait RxDma<T: Instance>: sealed::RxDma<T> + dma::Channel {}
44 (i2c, $inst:ident) => { 59
60pub trait TxDma<T: Instance>: sealed::TxDma<T> + dma::Channel {}
61
62macro_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
80crate::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
121macro_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
148crate::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 @@
1use core::cmp; 1use core::cmp;
2use core::marker::PhantomData; 2use core::marker::PhantomData;
3use embassy::util::Unborrow; 3use core::task::Poll;
4
5use atomic_polyfill::{AtomicUsize, Ordering};
6use embassy::interrupt::InterruptExt;
7use embassy::util::{AtomicWaker, OnDrop, Unborrow};
4use embassy_hal_common::unborrow; 8use embassy_hal_common::unborrow;
5use embedded_hal::blocking::i2c::Read; 9use embedded_hal::blocking::i2c::Read;
6use embedded_hal::blocking::i2c::Write; 10use embedded_hal::blocking::i2c::Write;
7use embedded_hal::blocking::i2c::WriteRead; 11use embedded_hal::blocking::i2c::WriteRead;
12use futures::future::poll_fn;
8 13
14use crate::dma::NoDma;
9use crate::i2c::{Error, Instance, SclPin, SdaPin}; 15use crate::i2c::{Error, Instance, SclPin, SdaPin};
16use crate::pac;
10use crate::pac::gpio::vals::{Afr, Moder, Ot}; 17use crate::pac::gpio::vals::{Afr, Moder, Ot};
11use crate::pac::gpio::Gpio; 18use crate::pac::gpio::Gpio;
12use crate::pac::i2c; 19use crate::pac::i2c;
13use crate::time::Hertz; 20use crate::time::Hertz;
14 21
15pub struct I2c<'d, T: Instance> { 22const I2C_COUNT: usize = pac::peripheral_count!(i2c);
23
24pub struct State {
25 waker: [AtomicWaker; I2C_COUNT],
26 chunks_transferred: [AtomicUsize; I2C_COUNT],
27}
28
29impl 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
41static STATE: State = State::new();
42
43pub 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
19impl<'d, T: Instance> I2c<'d, T> { 50impl<'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 {