aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2023-11-24 23:08:47 +0000
committerGitHub <[email protected]>2023-11-24 23:08:47 +0000
commitf5c9e3baa6615928f948cf9ae4c03123d2d84cbc (patch)
treed753f3aa382534b952c23d39ece6821146439105
parent47bac9df70492cd9c1b1f8617c1abc1209ee3338 (diff)
parent3efc3eee5700d2a39e397f1b1b821885301c0862 (diff)
Merge pull request #2200 from barnabywalters/asynci2cv1
Implemented async I2C for v1
-rw-r--r--embassy-stm32/Cargo.toml4
-rw-r--r--embassy-stm32/build.rs20
-rw-r--r--embassy-stm32/src/i2c/mod.rs157
-rw-r--r--embassy-stm32/src/i2c/v1.rs484
-rw-r--r--embassy-stm32/src/i2c/v2.rs157
-rw-r--r--examples/stm32f4/src/bin/i2c.rs3
-rw-r--r--examples/stm32f4/src/bin/i2c_async.rs62
-rw-r--r--examples/stm32f4/src/bin/i2c_comparison.rs135
-rw-r--r--examples/stm32h5/src/bin/i2c.rs3
-rw-r--r--examples/stm32h7/src/bin/camera.rs3
-rw-r--r--examples/stm32h7/src/bin/i2c.rs3
-rw-r--r--examples/stm32l4/src/bin/i2c.rs3
-rw-r--r--examples/stm32l4/src/bin/i2c_blocking_async.rs3
-rw-r--r--examples/stm32l4/src/bin/i2c_dma.rs3
-rw-r--r--examples/stm32l4/src/bin/spe_adin1110_http_server.rs3
15 files changed, 796 insertions, 247 deletions
diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml
index 65434ceca..d04000a1d 100644
--- a/embassy-stm32/Cargo.toml
+++ b/embassy-stm32/Cargo.toml
@@ -58,7 +58,7 @@ rand_core = "0.6.3"
58sdio-host = "0.5.0" 58sdio-host = "0.5.0"
59embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true } 59embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true }
60critical-section = "1.1" 60critical-section = "1.1"
61stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-fbb8f77326dd066aa6c0d66b3b46e76a569dda8b" } 61stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-f6d1ffc1a25f208b5cd6b1024bff246592da1949" }
62vcell = "0.1.3" 62vcell = "0.1.3"
63bxcan = "0.7.0" 63bxcan = "0.7.0"
64nb = "1.0.0" 64nb = "1.0.0"
@@ -76,7 +76,7 @@ critical-section = { version = "1.1", features = ["std"] }
76[build-dependencies] 76[build-dependencies]
77proc-macro2 = "1.0.36" 77proc-macro2 = "1.0.36"
78quote = "1.0.15" 78quote = "1.0.15"
79stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-fbb8f77326dd066aa6c0d66b3b46e76a569dda8b", default-features = false, features = ["metadata"]} 79stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-f6d1ffc1a25f208b5cd6b1024bff246592da1949", default-features = false, features = ["metadata"]}
80 80
81 81
82[features] 82[features]
diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs
index a7dac5f9d..4aae58229 100644
--- a/embassy-stm32/build.rs
+++ b/embassy-stm32/build.rs
@@ -1139,6 +1139,23 @@ fn main() {
1139 } 1139 }
1140 1140
1141 // ======== 1141 // ========
1142 // Write peripheral_interrupts module.
1143 let mut mt = TokenStream::new();
1144 for p in METADATA.peripherals {
1145 let mut pt = TokenStream::new();
1146
1147 for irq in p.interrupts {
1148 let iname = format_ident!("{}", irq.interrupt);
1149 let sname = format_ident!("{}", irq.signal);
1150 pt.extend(quote!(pub type #sname = crate::interrupt::typelevel::#iname;));
1151 }
1152
1153 let pname = format_ident!("{}", p.name);
1154 mt.extend(quote!(pub mod #pname { #pt }));
1155 }
1156 g.extend(quote!(#[allow(non_camel_case_types)] pub mod peripheral_interrupts { #mt }));
1157
1158 // ========
1142 // Write foreach_foo! macrotables 1159 // Write foreach_foo! macrotables
1143 1160
1144 let mut flash_regions_table: Vec<Vec<String>> = Vec::new(); 1161 let mut flash_regions_table: Vec<Vec<String>> = Vec::new();
@@ -1296,6 +1313,9 @@ fn main() {
1296 1313
1297 let mut m = String::new(); 1314 let mut m = String::new();
1298 1315
1316 // DO NOT ADD more macros like these.
1317 // These turned to be a bad idea!
1318 // Instead, make build.rs generate the final code.
1299 make_table(&mut m, "foreach_flash_region", &flash_regions_table); 1319 make_table(&mut m, "foreach_flash_region", &flash_regions_table);
1300 make_table(&mut m, "foreach_interrupt", &interrupts_table); 1320 make_table(&mut m, "foreach_interrupt", &interrupts_table);
1301 make_table(&mut m, "foreach_peripheral", &peripherals_table); 1321 make_table(&mut m, "foreach_peripheral", &peripherals_table);
diff --git a/embassy-stm32/src/i2c/mod.rs b/embassy-stm32/src/i2c/mod.rs
index dde1a5040..19346d707 100644
--- a/embassy-stm32/src/i2c/mod.rs
+++ b/embassy-stm32/src/i2c/mod.rs
@@ -1,11 +1,14 @@
1#![macro_use] 1#![macro_use]
2 2
3use core::marker::PhantomData;
4
3use crate::interrupt; 5use crate::interrupt;
4 6
5#[cfg_attr(i2c_v1, path = "v1.rs")] 7#[cfg_attr(i2c_v1, path = "v1.rs")]
6#[cfg_attr(i2c_v2, path = "v2.rs")] 8#[cfg_attr(i2c_v2, path = "v2.rs")]
7mod _version; 9mod _version;
8pub use _version::*; 10pub use _version::*;
11use embassy_sync::waitqueue::AtomicWaker;
9 12
10use crate::peripherals; 13use crate::peripherals;
11 14
@@ -23,6 +26,20 @@ pub enum Error {
23 26
24pub(crate) mod sealed { 27pub(crate) mod sealed {
25 use super::*; 28 use super::*;
29
30 pub struct State {
31 #[allow(unused)]
32 pub waker: AtomicWaker,
33 }
34
35 impl State {
36 pub const fn new() -> Self {
37 Self {
38 waker: AtomicWaker::new(),
39 }
40 }
41 }
42
26 pub trait Instance: crate::rcc::RccPeripheral { 43 pub trait Instance: crate::rcc::RccPeripheral {
27 fn regs() -> crate::pac::i2c::I2c; 44 fn regs() -> crate::pac::i2c::I2c;
28 fn state() -> &'static State; 45 fn state() -> &'static State;
@@ -30,7 +47,8 @@ pub(crate) mod sealed {
30} 47}
31 48
32pub trait Instance: sealed::Instance + 'static { 49pub trait Instance: sealed::Instance + 'static {
33 type Interrupt: interrupt::typelevel::Interrupt; 50 type EventInterrupt: interrupt::typelevel::Interrupt;
51 type ErrorInterrupt: interrupt::typelevel::Interrupt;
34} 52}
35 53
36pin_trait!(SclPin, Instance); 54pin_trait!(SclPin, Instance);
@@ -38,21 +56,148 @@ pin_trait!(SdaPin, Instance);
38dma_trait!(RxDma, Instance); 56dma_trait!(RxDma, Instance);
39dma_trait!(TxDma, Instance); 57dma_trait!(TxDma, Instance);
40 58
41foreach_interrupt!( 59/// Interrupt handler.
42 ($inst:ident, i2c, $block:ident, EV, $irq:ident) => { 60pub struct EventInterruptHandler<T: Instance> {
61 _phantom: PhantomData<T>,
62}
63
64impl<T: Instance> interrupt::typelevel::Handler<T::EventInterrupt> for EventInterruptHandler<T> {
65 unsafe fn on_interrupt() {
66 _version::on_interrupt::<T>()
67 }
68}
69
70pub struct ErrorInterruptHandler<T: Instance> {
71 _phantom: PhantomData<T>,
72}
73
74impl<T: Instance> interrupt::typelevel::Handler<T::ErrorInterrupt> for ErrorInterruptHandler<T> {
75 unsafe fn on_interrupt() {
76 _version::on_interrupt::<T>()
77 }
78}
79
80foreach_peripheral!(
81 (i2c, $inst:ident) => {
43 impl sealed::Instance for peripherals::$inst { 82 impl sealed::Instance for peripherals::$inst {
44 fn regs() -> crate::pac::i2c::I2c { 83 fn regs() -> crate::pac::i2c::I2c {
45 crate::pac::$inst 84 crate::pac::$inst
46 } 85 }
47 86
48 fn state() -> &'static State { 87 fn state() -> &'static sealed::State {
49 static STATE: State = State::new(); 88 static STATE: sealed::State = sealed::State::new();
50 &STATE 89 &STATE
51 } 90 }
52 } 91 }
53 92
54 impl Instance for peripherals::$inst { 93 impl Instance for peripherals::$inst {
55 type Interrupt = crate::interrupt::typelevel::$irq; 94 type EventInterrupt = crate::_generated::peripheral_interrupts::$inst::EV;
95 type ErrorInterrupt = crate::_generated::peripheral_interrupts::$inst::ER;
56 } 96 }
57 }; 97 };
58); 98);
99
100mod eh02 {
101 use super::*;
102
103 impl<'d, T: Instance> embedded_hal_02::blocking::i2c::Read for I2c<'d, T> {
104 type Error = Error;
105
106 fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error> {
107 self.blocking_read(address, buffer)
108 }
109 }
110
111 impl<'d, T: Instance> embedded_hal_02::blocking::i2c::Write for I2c<'d, T> {
112 type Error = Error;
113
114 fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Self::Error> {
115 self.blocking_write(address, write)
116 }
117 }
118
119 impl<'d, T: Instance> embedded_hal_02::blocking::i2c::WriteRead for I2c<'d, T> {
120 type Error = Error;
121
122 fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Self::Error> {
123 self.blocking_write_read(address, write, read)
124 }
125 }
126}
127
128#[cfg(feature = "unstable-traits")]
129mod eh1 {
130 use super::*;
131 use crate::dma::NoDma;
132
133 impl embedded_hal_1::i2c::Error for Error {
134 fn kind(&self) -> embedded_hal_1::i2c::ErrorKind {
135 match *self {
136 Self::Bus => embedded_hal_1::i2c::ErrorKind::Bus,
137 Self::Arbitration => embedded_hal_1::i2c::ErrorKind::ArbitrationLoss,
138 Self::Nack => {
139 embedded_hal_1::i2c::ErrorKind::NoAcknowledge(embedded_hal_1::i2c::NoAcknowledgeSource::Unknown)
140 }
141 Self::Timeout => embedded_hal_1::i2c::ErrorKind::Other,
142 Self::Crc => embedded_hal_1::i2c::ErrorKind::Other,
143 Self::Overrun => embedded_hal_1::i2c::ErrorKind::Overrun,
144 Self::ZeroLengthTransfer => embedded_hal_1::i2c::ErrorKind::Other,
145 }
146 }
147 }
148
149 impl<'d, T: Instance, TXDMA, RXDMA> embedded_hal_1::i2c::ErrorType for I2c<'d, T, TXDMA, RXDMA> {
150 type Error = Error;
151 }
152
153 impl<'d, T: Instance> embedded_hal_1::i2c::I2c for I2c<'d, T, NoDma, NoDma> {
154 fn read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Self::Error> {
155 self.blocking_read(address, read)
156 }
157
158 fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Self::Error> {
159 self.blocking_write(address, write)
160 }
161
162 fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Self::Error> {
163 self.blocking_write_read(address, write, read)
164 }
165
166 fn transaction(
167 &mut self,
168 _address: u8,
169 _operations: &mut [embedded_hal_1::i2c::Operation<'_>],
170 ) -> Result<(), Self::Error> {
171 todo!();
172 }
173 }
174}
175
176#[cfg(all(feature = "unstable-traits", feature = "nightly"))]
177mod eha {
178 use super::*;
179
180 impl<'d, T: Instance, TXDMA: TxDma<T>, RXDMA: RxDma<T>> embedded_hal_async::i2c::I2c for I2c<'d, T, TXDMA, RXDMA> {
181 async fn read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Self::Error> {
182 self.read(address, read).await
183 }
184
185 async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Self::Error> {
186 self.write(address, write).await
187 }
188
189 async fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Self::Error> {
190 self.write_read(address, write, read).await
191 }
192
193 async fn transaction(
194 &mut self,
195 address: u8,
196 operations: &mut [embedded_hal_1::i2c::Operation<'_>],
197 ) -> Result<(), Self::Error> {
198 let _ = address;
199 let _ = operations;
200 todo!()
201 }
202 }
203}
diff --git a/embassy-stm32/src/i2c/v1.rs b/embassy-stm32/src/i2c/v1.rs
index ab59f5ab9..b62ee8246 100644
--- a/embassy-stm32/src/i2c/v1.rs
+++ b/embassy-stm32/src/i2c/v1.rs
@@ -1,23 +1,33 @@
1use core::future::poll_fn;
1use core::marker::PhantomData; 2use core::marker::PhantomData;
3use core::task::Poll;
2 4
3use embassy_embedded_hal::SetConfig; 5use embassy_embedded_hal::SetConfig;
6use embassy_futures::select::{select, Either};
7use embassy_hal_internal::drop::OnDrop;
4use embassy_hal_internal::{into_ref, PeripheralRef}; 8use embassy_hal_internal::{into_ref, PeripheralRef};
5 9
6use crate::dma::NoDma; 10use super::*;
11use crate::dma::{NoDma, Transfer};
7use crate::gpio::sealed::AFType; 12use crate::gpio::sealed::AFType;
8use crate::gpio::Pull; 13use crate::gpio::Pull;
9use crate::i2c::{Error, Instance, SclPin, SdaPin}; 14use crate::interrupt::typelevel::Interrupt;
10use crate::pac::i2c; 15use crate::pac::i2c;
11use crate::time::Hertz; 16use crate::time::Hertz;
12use crate::{interrupt, Peripheral}; 17use crate::{interrupt, Peripheral};
13 18
14/// Interrupt handler. 19pub unsafe fn on_interrupt<T: Instance>() {
15pub struct InterruptHandler<T: Instance> { 20 let regs = T::regs();
16 _phantom: PhantomData<T>, 21 // i2c v2 only woke the task on transfer complete interrupts. v1 uses interrupts for a bunch of
17} 22 // other stuff, so we wake the task on every interrupt.
18 23 T::state().waker.wake();
19impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> { 24 critical_section::with(|_| {
20 unsafe fn on_interrupt() {} 25 // Clear event interrupt flag.
26 regs.cr2().modify(|w| {
27 w.set_itevten(false);
28 w.set_iterren(false);
29 });
30 });
21} 31}
22 32
23#[non_exhaustive] 33#[non_exhaustive]
@@ -27,14 +37,6 @@ pub struct Config {
27 pub scl_pullup: bool, 37 pub scl_pullup: bool,
28} 38}
29 39
30pub struct State {}
31
32impl State {
33 pub(crate) const fn new() -> Self {
34 Self {}
35 }
36}
37
38pub struct I2c<'d, T: Instance, TXDMA = NoDma, RXDMA = NoDma> { 40pub struct I2c<'d, T: Instance, TXDMA = NoDma, RXDMA = NoDma> {
39 phantom: PhantomData<&'d mut T>, 41 phantom: PhantomData<&'d mut T>,
40 #[allow(dead_code)] 42 #[allow(dead_code)]
@@ -48,7 +50,9 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
48 _peri: impl Peripheral<P = T> + 'd, 50 _peri: impl Peripheral<P = T> + 'd,
49 scl: impl Peripheral<P = impl SclPin<T>> + 'd, 51 scl: impl Peripheral<P = impl SclPin<T>> + 'd,
50 sda: impl Peripheral<P = impl SdaPin<T>> + 'd, 52 sda: impl Peripheral<P = impl SdaPin<T>> + 'd,
51 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 53 _irq: impl interrupt::typelevel::Binding<T::EventInterrupt, EventInterruptHandler<T>>
54 + interrupt::typelevel::Binding<T::ErrorInterrupt, ErrorInterruptHandler<T>>
55 + 'd,
52 tx_dma: impl Peripheral<P = TXDMA> + 'd, 56 tx_dma: impl Peripheral<P = TXDMA> + 'd,
53 rx_dma: impl Peripheral<P = RXDMA> + 'd, 57 rx_dma: impl Peripheral<P = RXDMA> + 'd,
54 freq: Hertz, 58 freq: Hertz,
@@ -98,6 +102,9 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
98 reg.set_pe(true); 102 reg.set_pe(true);
99 }); 103 });
100 104
105 unsafe { T::EventInterrupt::enable() };
106 unsafe { T::ErrorInterrupt::enable() };
107
101 Self { 108 Self {
102 phantom: PhantomData, 109 phantom: PhantomData,
103 tx_dma, 110 tx_dma,
@@ -105,40 +112,58 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
105 } 112 }
106 } 113 }
107 114
108 fn check_and_clear_error_flags(&self) -> Result<i2c::regs::Sr1, Error> { 115 fn check_and_clear_error_flags() -> Result<i2c::regs::Sr1, Error> {
109 // Note that flags should only be cleared once they have been registered. If flags are 116 // Note that flags should only be cleared once they have been registered. If flags are
110 // cleared otherwise, there may be an inherent race condition and flags may be missed. 117 // cleared otherwise, there may be an inherent race condition and flags may be missed.
111 let sr1 = T::regs().sr1().read(); 118 let sr1 = T::regs().sr1().read();
112 119
113 if sr1.timeout() { 120 if sr1.timeout() {
114 T::regs().sr1().modify(|reg| reg.set_timeout(false)); 121 T::regs().sr1().write(|reg| {
122 reg.0 = !0;
123 reg.set_timeout(false);
124 });
115 return Err(Error::Timeout); 125 return Err(Error::Timeout);
116 } 126 }
117 127
118 if sr1.pecerr() { 128 if sr1.pecerr() {
119 T::regs().sr1().modify(|reg| reg.set_pecerr(false)); 129 T::regs().sr1().write(|reg| {
130 reg.0 = !0;
131 reg.set_pecerr(false);
132 });
120 return Err(Error::Crc); 133 return Err(Error::Crc);
121 } 134 }
122 135
123 if sr1.ovr() { 136 if sr1.ovr() {
124 T::regs().sr1().modify(|reg| reg.set_ovr(false)); 137 T::regs().sr1().write(|reg| {
138 reg.0 = !0;
139 reg.set_ovr(false);
140 });
125 return Err(Error::Overrun); 141 return Err(Error::Overrun);
126 } 142 }
127 143
128 if sr1.af() { 144 if sr1.af() {
129 T::regs().sr1().modify(|reg| reg.set_af(false)); 145 T::regs().sr1().write(|reg| {
146 reg.0 = !0;
147 reg.set_af(false);
148 });
130 return Err(Error::Nack); 149 return Err(Error::Nack);
131 } 150 }
132 151
133 if sr1.arlo() { 152 if sr1.arlo() {
134 T::regs().sr1().modify(|reg| reg.set_arlo(false)); 153 T::regs().sr1().write(|reg| {
154 reg.0 = !0;
155 reg.set_arlo(false);
156 });
135 return Err(Error::Arbitration); 157 return Err(Error::Arbitration);
136 } 158 }
137 159
138 // The errata indicates that BERR may be incorrectly detected. It recommends ignoring and 160 // The errata indicates that BERR may be incorrectly detected. It recommends ignoring and
139 // clearing the BERR bit instead. 161 // clearing the BERR bit instead.
140 if sr1.berr() { 162 if sr1.berr() {
141 T::regs().sr1().modify(|reg| reg.set_berr(false)); 163 T::regs().sr1().write(|reg| {
164 reg.0 = !0;
165 reg.set_berr(false);
166 });
142 } 167 }
143 168
144 Ok(sr1) 169 Ok(sr1)
@@ -157,13 +182,13 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
157 }); 182 });
158 183
159 // Wait until START condition was generated 184 // Wait until START condition was generated
160 while !self.check_and_clear_error_flags()?.start() { 185 while !Self::check_and_clear_error_flags()?.start() {
161 check_timeout()?; 186 check_timeout()?;
162 } 187 }
163 188
164 // Also wait until signalled we're master and everything is waiting for us 189 // Also wait until signalled we're master and everything is waiting for us
165 while { 190 while {
166 self.check_and_clear_error_flags()?; 191 Self::check_and_clear_error_flags()?;
167 192
168 let sr2 = T::regs().sr2().read(); 193 let sr2 = T::regs().sr2().read();
169 !sr2.msl() && !sr2.busy() 194 !sr2.msl() && !sr2.busy()
@@ -177,7 +202,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
177 // Wait until address was sent 202 // Wait until address was sent
178 // Wait for the address to be acknowledged 203 // Wait for the address to be acknowledged
179 // Check for any I2C errors. If a NACK occurs, the ADDR bit will never be set. 204 // Check for any I2C errors. If a NACK occurs, the ADDR bit will never be set.
180 while !self.check_and_clear_error_flags()?.addr() { 205 while !Self::check_and_clear_error_flags()?.addr() {
181 check_timeout()?; 206 check_timeout()?;
182 } 207 }
183 208
@@ -197,7 +222,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
197 // Wait until we're ready for sending 222 // Wait until we're ready for sending
198 while { 223 while {
199 // Check for any I2C errors. If a NACK occurs, the ADDR bit will never be set. 224 // Check for any I2C errors. If a NACK occurs, the ADDR bit will never be set.
200 !self.check_and_clear_error_flags()?.txe() 225 !Self::check_and_clear_error_flags()?.txe()
201 } { 226 } {
202 check_timeout()?; 227 check_timeout()?;
203 } 228 }
@@ -208,7 +233,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
208 // Wait until byte is transferred 233 // Wait until byte is transferred
209 while { 234 while {
210 // Check for any potential error conditions. 235 // Check for any potential error conditions.
211 !self.check_and_clear_error_flags()?.btf() 236 !Self::check_and_clear_error_flags()?.btf()
212 } { 237 } {
213 check_timeout()?; 238 check_timeout()?;
214 } 239 }
@@ -219,7 +244,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
219 fn recv_byte(&self, check_timeout: impl Fn() -> Result<(), Error>) -> Result<u8, Error> { 244 fn recv_byte(&self, check_timeout: impl Fn() -> Result<(), Error>) -> Result<u8, Error> {
220 while { 245 while {
221 // Check for any potential error conditions. 246 // Check for any potential error conditions.
222 self.check_and_clear_error_flags()?; 247 Self::check_and_clear_error_flags()?;
223 248
224 !T::regs().sr1().read().rxne() 249 !T::regs().sr1().read().rxne()
225 } { 250 } {
@@ -244,7 +269,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
244 }); 269 });
245 270
246 // Wait until START condition was generated 271 // Wait until START condition was generated
247 while !self.check_and_clear_error_flags()?.start() { 272 while !Self::check_and_clear_error_flags()?.start() {
248 check_timeout()?; 273 check_timeout()?;
249 } 274 }
250 275
@@ -261,7 +286,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
261 286
262 // Wait until address was sent 287 // Wait until address was sent
263 // Wait for the address to be acknowledged 288 // Wait for the address to be acknowledged
264 while !self.check_and_clear_error_flags()?.addr() { 289 while !Self::check_and_clear_error_flags()?.addr() {
265 check_timeout()?; 290 check_timeout()?;
266 } 291 }
267 292
@@ -336,82 +361,361 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
336 pub fn blocking_write_read(&mut self, addr: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> { 361 pub fn blocking_write_read(&mut self, addr: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> {
337 self.blocking_write_read_timeout(addr, write, read, || Ok(())) 362 self.blocking_write_read_timeout(addr, write, read, || Ok(()))
338 } 363 }
339}
340 364
341impl<'d, T: Instance, TXDMA, RXDMA> Drop for I2c<'d, T, TXDMA, RXDMA> { 365 // Async
342 fn drop(&mut self) { 366
343 T::disable(); 367 #[inline] // pretty sure this should always be inlined
368 fn enable_interrupts() -> () {
369 T::regs().cr2().modify(|w| {
370 w.set_iterren(true);
371 w.set_itevten(true);
372 });
344 } 373 }
345}
346 374
347impl<'d, T: Instance> embedded_hal_02::blocking::i2c::Read for I2c<'d, T> { 375 async fn write_with_stop(&mut self, address: u8, write: &[u8], send_stop: bool) -> Result<(), Error>
348 type Error = Error; 376 where
377 TXDMA: crate::i2c::TxDma<T>,
378 {
379 let dma_transfer = unsafe {
380 let regs = T::regs();
381 regs.cr2().modify(|w| {
382 // DMA mode can be enabled for transmission by setting the DMAEN bit in the I2C_CR2 register.
383 w.set_dmaen(true);
384 w.set_itbufen(false);
385 });
386 // Set the I2C_DR register address in the DMA_SxPAR register. The data will be moved to this address from the memory after each TxE event.
387 let dst = regs.dr().as_ptr() as *mut u8;
349 388
350 fn read(&mut self, addr: u8, read: &mut [u8]) -> Result<(), Self::Error> { 389 let ch = &mut self.tx_dma;
351 self.blocking_read(addr, read) 390 let request = ch.request();
352 } 391 Transfer::new_write(ch, request, write, dst, Default::default())
353} 392 };
354 393
355impl<'d, T: Instance> embedded_hal_02::blocking::i2c::Write for I2c<'d, T> { 394 let on_drop = OnDrop::new(|| {
356 type Error = Error; 395 let regs = T::regs();
396 regs.cr2().modify(|w| {
397 w.set_dmaen(false);
398 w.set_iterren(false);
399 w.set_itevten(false);
400 })
401 });
357 402
358 fn write(&mut self, addr: u8, write: &[u8]) -> Result<(), Self::Error> { 403 Self::enable_interrupts();
359 self.blocking_write(addr, write)
360 }
361}
362 404
363impl<'d, T: Instance> embedded_hal_02::blocking::i2c::WriteRead for I2c<'d, T> { 405 // Send a START condition
364 type Error = Error; 406 T::regs().cr1().modify(|reg| {
407 reg.set_start(true);
408 });
365 409
366 fn write_read(&mut self, addr: u8, write: &[u8], read: &mut [u8]) -> Result<(), Self::Error> { 410 let state = T::state();
367 self.blocking_write_read(addr, write, read) 411
368 } 412 // Wait until START condition was generated
369} 413 poll_fn(|cx| {
414 state.waker.register(cx.waker());
415
416 match Self::check_and_clear_error_flags() {
417 Err(e) => Poll::Ready(Err(e)),
418 Ok(sr1) => {
419 if sr1.start() {
420 Poll::Ready(Ok(()))
421 } else {
422 Poll::Pending
423 }
424 }
425 }
426 })
427 .await?;
370 428
371#[cfg(feature = "unstable-traits")] 429 // Also wait until signalled we're master and everything is waiting for us
372mod eh1 { 430 Self::enable_interrupts();
373 use super::*; 431 poll_fn(|cx| {
374 432 state.waker.register(cx.waker());
375 impl embedded_hal_1::i2c::Error for Error { 433
376 fn kind(&self) -> embedded_hal_1::i2c::ErrorKind { 434 match Self::check_and_clear_error_flags() {
377 match *self { 435 Err(e) => Poll::Ready(Err(e)),
378 Self::Bus => embedded_hal_1::i2c::ErrorKind::Bus, 436 Ok(_) => {
379 Self::Arbitration => embedded_hal_1::i2c::ErrorKind::ArbitrationLoss, 437 let sr2 = T::regs().sr2().read();
380 Self::Nack => { 438 if !sr2.msl() && !sr2.busy() {
381 embedded_hal_1::i2c::ErrorKind::NoAcknowledge(embedded_hal_1::i2c::NoAcknowledgeSource::Unknown) 439 Poll::Pending
440 } else {
441 Poll::Ready(Ok(()))
442 }
382 } 443 }
383 Self::Timeout => embedded_hal_1::i2c::ErrorKind::Other,
384 Self::Crc => embedded_hal_1::i2c::ErrorKind::Other,
385 Self::Overrun => embedded_hal_1::i2c::ErrorKind::Overrun,
386 Self::ZeroLengthTransfer => embedded_hal_1::i2c::ErrorKind::Other,
387 } 444 }
388 } 445 })
446 .await?;
447
448 // Set up current address, we're trying to talk to
449 Self::enable_interrupts();
450 T::regs().dr().write(|reg| reg.set_dr(address << 1));
451
452 poll_fn(|cx| {
453 state.waker.register(cx.waker());
454 match Self::check_and_clear_error_flags() {
455 Err(e) => Poll::Ready(Err(e)),
456 Ok(sr1) => {
457 if sr1.addr() {
458 // Clear the ADDR condition by reading SR2.
459 T::regs().sr2().read();
460 Poll::Ready(Ok(()))
461 } else {
462 Poll::Pending
463 }
464 }
465 }
466 })
467 .await?;
468 Self::enable_interrupts();
469 let poll_error = poll_fn(|cx| {
470 state.waker.register(cx.waker());
471
472 match Self::check_and_clear_error_flags() {
473 // Unclear why the Err turbofish is necessary here? The compiler didn’t require it in the other
474 // identical poll_fn check_and_clear matches.
475 Err(e) => Poll::Ready(Err::<T, Error>(e)),
476 Ok(_) => Poll::Pending,
477 }
478 });
479
480 // Wait for either the DMA transfer to successfully finish, or an I2C error to occur.
481 match select(dma_transfer, poll_error).await {
482 Either::Second(Err(e)) => Err(e),
483 _ => Ok(()),
484 }?;
485
486 // The I2C transfer itself will take longer than the DMA transfer, so wait for that to finish too.
487
488 // 18.3.8 “Master transmitter: In the interrupt routine after the EOT interrupt, disable DMA
489 // requests then wait for a BTF event before programming the Stop condition.”
490
491 // TODO: If this has to be done “in the interrupt routine after the EOT interrupt”, where to put it?
492 T::regs().cr2().modify(|w| {
493 w.set_dmaen(false);
494 });
495
496 Self::enable_interrupts();
497 poll_fn(|cx| {
498 state.waker.register(cx.waker());
499
500 match Self::check_and_clear_error_flags() {
501 Err(e) => Poll::Ready(Err(e)),
502 Ok(sr1) => {
503 if sr1.btf() {
504 if send_stop {
505 T::regs().cr1().modify(|w| {
506 w.set_stop(true);
507 });
508 }
509
510 Poll::Ready(Ok(()))
511 } else {
512 Poll::Pending
513 }
514 }
515 }
516 })
517 .await?;
518
519 drop(on_drop);
520
521 // Fallthrough is success
522 Ok(())
389 } 523 }
390 524
391 impl<'d, T: Instance> embedded_hal_1::i2c::ErrorType for I2c<'d, T> { 525 pub async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Error>
392 type Error = Error; 526 where
527 TXDMA: crate::i2c::TxDma<T>,
528 {
529 self.write_with_stop(address, write, true).await?;
530
531 // Wait for STOP condition to transmit.
532 Self::enable_interrupts();
533 poll_fn(|cx| {
534 T::state().waker.register(cx.waker());
535 // TODO: error interrupts are enabled here, should we additional check for and return errors?
536 if T::regs().cr1().read().stop() {
537 Poll::Pending
538 } else {
539 Poll::Ready(Ok(()))
540 }
541 })
542 .await?;
543
544 Ok(())
393 } 545 }
394 546
395 impl<'d, T: Instance> embedded_hal_1::i2c::I2c for I2c<'d, T> { 547 pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error>
396 fn read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Self::Error> { 548 where
397 self.blocking_read(address, read) 549 RXDMA: crate::i2c::RxDma<T>,
398 } 550 {
551 let state = T::state();
552 let buffer_len = buffer.len();
553
554 let dma_transfer = unsafe {
555 let regs = T::regs();
556 regs.cr2().modify(|w| {
557 // DMA mode can be enabled for transmission by setting the DMAEN bit in the I2C_CR2 register.
558 w.set_itbufen(false);
559 w.set_dmaen(true);
560 });
561 // Set the I2C_DR register address in the DMA_SxPAR register. The data will be moved to this address from the memory after each TxE event.
562 let src = regs.dr().as_ptr() as *mut u8;
399 563
400 fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Self::Error> { 564 let ch = &mut self.rx_dma;
401 self.blocking_write(address, write) 565 let request = ch.request();
402 } 566 Transfer::new_read(ch, request, src, buffer, Default::default())
567 };
403 568
404 fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Self::Error> { 569 let on_drop = OnDrop::new(|| {
405 self.blocking_write_read(address, write, read) 570 let regs = T::regs();
406 } 571 regs.cr2().modify(|w| {
572 w.set_dmaen(false);
573 w.set_iterren(false);
574 w.set_itevten(false);
575 })
576 });
577
578 Self::enable_interrupts();
579
580 // Send a START condition and set ACK bit
581 T::regs().cr1().modify(|reg| {
582 reg.set_start(true);
583 reg.set_ack(true);
584 });
585
586 // Wait until START condition was generated
587 poll_fn(|cx| {
588 state.waker.register(cx.waker());
589
590 match Self::check_and_clear_error_flags() {
591 Err(e) => Poll::Ready(Err(e)),
592 Ok(sr1) => {
593 if sr1.start() {
594 Poll::Ready(Ok(()))
595 } else {
596 Poll::Pending
597 }
598 }
599 }
600 })
601 .await?;
602
603 // Also wait until signalled we're master and everything is waiting for us
604 Self::enable_interrupts();
605 poll_fn(|cx| {
606 state.waker.register(cx.waker());
607
608 // blocking read didn’t have a check_and_clear call here, but blocking write did so
609 // I’m adding it here in case that was an oversight.
610 match Self::check_and_clear_error_flags() {
611 Err(e) => Poll::Ready(Err(e)),
612 Ok(_) => {
613 let sr2 = T::regs().sr2().read();
614 if !sr2.msl() && !sr2.busy() {
615 Poll::Pending
616 } else {
617 Poll::Ready(Ok(()))
618 }
619 }
620 }
621 })
622 .await?;
623
624 // Set up current address, we're trying to talk to
625 T::regs().dr().write(|reg| reg.set_dr((address << 1) + 1));
407 626
408 fn transaction( 627 // Wait for the address to be acknowledged
409 &mut self, 628
410 _address: u8, 629 Self::enable_interrupts();
411 _operations: &mut [embedded_hal_1::i2c::Operation<'_>], 630 poll_fn(|cx| {
412 ) -> Result<(), Self::Error> { 631 state.waker.register(cx.waker());
413 todo!(); 632
633 match Self::check_and_clear_error_flags() {
634 Err(e) => Poll::Ready(Err(e)),
635 Ok(sr1) => {
636 if sr1.addr() {
637 // 18.3.8: When a single byte must be received: the NACK must be programmed during EV6
638 // event, i.e. program ACK=0 when ADDR=1, before clearing ADDR flag.
639 if buffer_len == 1 {
640 T::regs().cr1().modify(|w| {
641 w.set_ack(false);
642 });
643 }
644 Poll::Ready(Ok(()))
645 } else {
646 Poll::Pending
647 }
648 }
649 }
650 })
651 .await?;
652
653 // Clear ADDR condition by reading SR2
654 T::regs().sr2().read();
655
656 // 18.3.8: When a single byte must be received: [snip] Then the
657 // user can program the STOP condition either after clearing ADDR flag, or in the
658 // DMA Transfer Complete interrupt routine.
659 if buffer_len == 1 {
660 T::regs().cr1().modify(|w| {
661 w.set_stop(true);
662 });
663 } else {
664 // If, in the I2C_CR2 register, the LAST bit is set, I2C
665 // automatically sends a NACK after the next byte following EOT_1. The user can
666 // generate a Stop condition in the DMA Transfer Complete interrupt routine if enabled.
667 T::regs().cr2().modify(|w| {
668 w.set_last(true);
669 })
414 } 670 }
671
672 // Wait for bytes to be received, or an error to occur.
673 Self::enable_interrupts();
674 let poll_error = poll_fn(|cx| {
675 state.waker.register(cx.waker());
676
677 match Self::check_and_clear_error_flags() {
678 Err(e) => Poll::Ready(Err::<T, Error>(e)),
679 _ => Poll::Pending,
680 }
681 });
682
683 match select(dma_transfer, poll_error).await {
684 Either::Second(Err(e)) => Err(e),
685 _ => Ok(()),
686 }?;
687
688 // Wait for the STOP to be sent (STOP bit cleared).
689 Self::enable_interrupts();
690 poll_fn(|cx| {
691 state.waker.register(cx.waker());
692 // TODO: error interrupts are enabled here, should we additional check for and return errors?
693 if T::regs().cr1().read().stop() {
694 Poll::Pending
695 } else {
696 Poll::Ready(Ok(()))
697 }
698 })
699 .await?;
700 drop(on_drop);
701
702 // Fallthrough is success
703 Ok(())
704 }
705
706 pub async fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error>
707 where
708 RXDMA: crate::i2c::RxDma<T>,
709 TXDMA: crate::i2c::TxDma<T>,
710 {
711 self.write_with_stop(address, write, false).await?;
712 self.read(address, read).await
713 }
714}
715
716impl<'d, T: Instance, TXDMA, RXDMA> Drop for I2c<'d, T, TXDMA, RXDMA> {
717 fn drop(&mut self) {
718 T::disable();
415 } 719 }
416} 720}
417 721
diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs
index 40bcaa9bc..8c20e1c54 100644
--- a/embassy-stm32/src/i2c/v2.rs
+++ b/embassy-stm32/src/i2c/v2.rs
@@ -1,19 +1,17 @@
1use core::cmp; 1use core::cmp;
2use core::future::poll_fn; 2use core::future::poll_fn;
3use core::marker::PhantomData;
4use core::task::Poll; 3use core::task::Poll;
5 4
6use embassy_embedded_hal::SetConfig; 5use embassy_embedded_hal::SetConfig;
7use embassy_hal_internal::drop::OnDrop; 6use embassy_hal_internal::drop::OnDrop;
8use embassy_hal_internal::{into_ref, PeripheralRef}; 7use embassy_hal_internal::{into_ref, PeripheralRef};
9use embassy_sync::waitqueue::AtomicWaker;
10#[cfg(feature = "time")] 8#[cfg(feature = "time")]
11use embassy_time::{Duration, Instant}; 9use embassy_time::{Duration, Instant};
12 10
11use super::*;
13use crate::dma::{NoDma, Transfer}; 12use crate::dma::{NoDma, Transfer};
14use crate::gpio::sealed::AFType; 13use crate::gpio::sealed::AFType;
15use crate::gpio::Pull; 14use crate::gpio::Pull;
16use crate::i2c::{Error, Instance, SclPin, SdaPin};
17use crate::interrupt::typelevel::Interrupt; 15use crate::interrupt::typelevel::Interrupt;
18use crate::pac::i2c; 16use crate::pac::i2c;
19use crate::time::Hertz; 17use crate::time::Hertz;
@@ -36,25 +34,18 @@ pub fn no_timeout_fn() -> impl Fn() -> Result<(), Error> {
36 move || Ok(()) 34 move || Ok(())
37} 35}
38 36
39/// Interrupt handler. 37pub unsafe fn on_interrupt<T: Instance>() {
40pub struct InterruptHandler<T: Instance> { 38 let regs = T::regs();
41 _phantom: PhantomData<T>, 39 let isr = regs.isr().read();
42}
43
44impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
45 unsafe fn on_interrupt() {
46 let regs = T::regs();
47 let isr = regs.isr().read();
48 40
49 if isr.tcr() || isr.tc() { 41 if isr.tcr() || isr.tc() {
50 T::state().waker.wake(); 42 T::state().waker.wake();
51 }
52 // The flag can only be cleared by writting to nbytes, we won't do that here, so disable
53 // the interrupt
54 critical_section::with(|_| {
55 regs.cr1().modify(|w| w.set_tcie(false));
56 });
57 } 43 }
44 // The flag can only be cleared by writting to nbytes, we won't do that here, so disable
45 // the interrupt
46 critical_section::with(|_| {
47 regs.cr1().modify(|w| w.set_tcie(false));
48 });
58} 49}
59 50
60#[non_exhaustive] 51#[non_exhaustive]
@@ -77,18 +68,6 @@ impl Default for Config {
77 } 68 }
78} 69}
79 70
80pub struct State {
81 waker: AtomicWaker,
82}
83
84impl State {
85 pub(crate) const fn new() -> Self {
86 Self {
87 waker: AtomicWaker::new(),
88 }
89 }
90}
91
92pub struct I2c<'d, T: Instance, TXDMA = NoDma, RXDMA = NoDma> { 71pub struct I2c<'d, T: Instance, TXDMA = NoDma, RXDMA = NoDma> {
93 _peri: PeripheralRef<'d, T>, 72 _peri: PeripheralRef<'d, T>,
94 #[allow(dead_code)] 73 #[allow(dead_code)]
@@ -104,7 +83,9 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
104 peri: impl Peripheral<P = T> + 'd, 83 peri: impl Peripheral<P = T> + 'd,
105 scl: impl Peripheral<P = impl SclPin<T>> + 'd, 84 scl: impl Peripheral<P = impl SclPin<T>> + 'd,
106 sda: impl Peripheral<P = impl SdaPin<T>> + 'd, 85 sda: impl Peripheral<P = impl SdaPin<T>> + 'd,
107 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 86 _irq: impl interrupt::typelevel::Binding<T::EventInterrupt, EventInterruptHandler<T>>
87 + interrupt::typelevel::Binding<T::ErrorInterrupt, ErrorInterruptHandler<T>>
88 + 'd,
108 tx_dma: impl Peripheral<P = TXDMA> + 'd, 89 tx_dma: impl Peripheral<P = TXDMA> + 'd,
109 rx_dma: impl Peripheral<P = RXDMA> + 'd, 90 rx_dma: impl Peripheral<P = RXDMA> + 'd,
110 freq: Hertz, 91 freq: Hertz,
@@ -150,8 +131,8 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
150 reg.set_pe(true); 131 reg.set_pe(true);
151 }); 132 });
152 133
153 T::Interrupt::unpend(); 134 unsafe { T::EventInterrupt::enable() };
154 unsafe { T::Interrupt::enable() }; 135 unsafe { T::ErrorInterrupt::enable() };
155 136
156 Self { 137 Self {
157 _peri: peri, 138 _peri: peri,
@@ -987,35 +968,6 @@ impl<'d, T: Instance, TXDMA, RXDMA> Drop for I2c<'d, T, TXDMA, RXDMA> {
987 } 968 }
988} 969}
989 970
990#[cfg(feature = "time")]
991mod eh02 {
992 use super::*;
993
994 impl<'d, T: Instance> embedded_hal_02::blocking::i2c::Read for I2c<'d, T> {
995 type Error = Error;
996
997 fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error> {
998 self.blocking_read(address, buffer)
999 }
1000 }
1001
1002 impl<'d, T: Instance> embedded_hal_02::blocking::i2c::Write for I2c<'d, T> {
1003 type Error = Error;
1004
1005 fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Self::Error> {
1006 self.blocking_write(address, write)
1007 }
1008 }
1009
1010 impl<'d, T: Instance> embedded_hal_02::blocking::i2c::WriteRead for I2c<'d, T> {
1011 type Error = Error;
1012
1013 fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Self::Error> {
1014 self.blocking_write_read(address, write, read)
1015 }
1016 }
1017}
1018
1019/// I2C Stop Configuration 971/// I2C Stop Configuration
1020/// 972///
1021/// Peripheral options for generating the STOP condition 973/// Peripheral options for generating the STOP condition
@@ -1140,83 +1092,6 @@ impl Timings {
1140 } 1092 }
1141} 1093}
1142 1094
1143#[cfg(feature = "unstable-traits")]
1144mod eh1 {
1145 use super::*;
1146
1147 impl embedded_hal_1::i2c::Error for Error {
1148 fn kind(&self) -> embedded_hal_1::i2c::ErrorKind {
1149 match *self {
1150 Self::Bus => embedded_hal_1::i2c::ErrorKind::Bus,
1151 Self::Arbitration => embedded_hal_1::i2c::ErrorKind::ArbitrationLoss,
1152 Self::Nack => {
1153 embedded_hal_1::i2c::ErrorKind::NoAcknowledge(embedded_hal_1::i2c::NoAcknowledgeSource::Unknown)
1154 }
1155 Self::Timeout => embedded_hal_1::i2c::ErrorKind::Other,
1156 Self::Crc => embedded_hal_1::i2c::ErrorKind::Other,
1157 Self::Overrun => embedded_hal_1::i2c::ErrorKind::Overrun,
1158 Self::ZeroLengthTransfer => embedded_hal_1::i2c::ErrorKind::Other,
1159 }
1160 }
1161 }
1162
1163 impl<'d, T: Instance, TXDMA, RXDMA> embedded_hal_1::i2c::ErrorType for I2c<'d, T, TXDMA, RXDMA> {
1164 type Error = Error;
1165 }
1166
1167 impl<'d, T: Instance> embedded_hal_1::i2c::I2c for I2c<'d, T, NoDma, NoDma> {
1168 fn read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Self::Error> {
1169 self.blocking_read(address, read)
1170 }
1171
1172 fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Self::Error> {
1173 self.blocking_write(address, write)
1174 }
1175
1176 fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Self::Error> {
1177 self.blocking_write_read(address, write, read)
1178 }
1179
1180 fn transaction(
1181 &mut self,
1182 _address: u8,
1183 _operations: &mut [embedded_hal_1::i2c::Operation<'_>],
1184 ) -> Result<(), Self::Error> {
1185 todo!();
1186 }
1187 }
1188}
1189
1190#[cfg(all(feature = "unstable-traits", feature = "nightly"))]
1191mod eha {
1192 use super::super::{RxDma, TxDma};
1193 use super::*;
1194
1195 impl<'d, T: Instance, TXDMA: TxDma<T>, RXDMA: RxDma<T>> embedded_hal_async::i2c::I2c for I2c<'d, T, TXDMA, RXDMA> {
1196 async fn read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Self::Error> {
1197 self.read(address, read).await
1198 }
1199
1200 async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Self::Error> {
1201 self.write(address, write).await
1202 }
1203
1204 async fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Self::Error> {
1205 self.write_read(address, write, read).await
1206 }
1207
1208 async fn transaction(
1209 &mut self,
1210 address: u8,
1211 operations: &mut [embedded_hal_1::i2c::Operation<'_>],
1212 ) -> Result<(), Self::Error> {
1213 let _ = address;
1214 let _ = operations;
1215 todo!()
1216 }
1217 }
1218}
1219
1220impl<'d, T: Instance> SetConfig for I2c<'d, T> { 1095impl<'d, T: Instance> SetConfig for I2c<'d, T> {
1221 type Config = Hertz; 1096 type Config = Hertz;
1222 type ConfigError = (); 1097 type ConfigError = ();
diff --git a/examples/stm32f4/src/bin/i2c.rs b/examples/stm32f4/src/bin/i2c.rs
index 032bd97ee..4f4adde28 100644
--- a/examples/stm32f4/src/bin/i2c.rs
+++ b/examples/stm32f4/src/bin/i2c.rs
@@ -14,7 +14,8 @@ const ADDRESS: u8 = 0x5F;
14const WHOAMI: u8 = 0x0F; 14const WHOAMI: u8 = 0x0F;
15 15
16bind_interrupts!(struct Irqs { 16bind_interrupts!(struct Irqs {
17 I2C2_EV => i2c::InterruptHandler<peripherals::I2C2>; 17 I2C2_EV => i2c::EventInterruptHandler<peripherals::I2C2>;
18 I2C2_ER => i2c::ErrorInterruptHandler<peripherals::I2C2>;
18}); 19});
19 20
20#[embassy_executor::main] 21#[embassy_executor::main]
diff --git a/examples/stm32f4/src/bin/i2c_async.rs b/examples/stm32f4/src/bin/i2c_async.rs
new file mode 100644
index 000000000..9f59e4d41
--- /dev/null
+++ b/examples/stm32f4/src/bin/i2c_async.rs
@@ -0,0 +1,62 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5// Example originally designed for stm32f411ceu6 reading an A1454 hall effect sensor on I2C1
6// DMA peripherals changed to compile for stm32f429zi, for the CI.
7
8use defmt::*;
9use embassy_executor::Spawner;
10use embassy_stm32::i2c::I2c;
11use embassy_stm32::time::Hertz;
12use embassy_stm32::{bind_interrupts, i2c, peripherals};
13use {defmt_rtt as _, panic_probe as _};
14
15const ADDRESS: u8 = 96;
16
17bind_interrupts!(struct Irqs {
18 I2C1_EV => i2c::EventInterruptHandler<peripherals::I2C1>;
19 I2C1_ER => i2c::ErrorInterruptHandler<peripherals::I2C1>;
20});
21
22#[embassy_executor::main]
23async fn main(_spawner: Spawner) {
24 info!("Hello world!");
25 let p = embassy_stm32::init(Default::default());
26
27 let mut i2c = I2c::new(
28 p.I2C1,
29 p.PB8,
30 p.PB7,
31 Irqs,
32 p.DMA1_CH6,
33 p.DMA1_CH0,
34 Hertz(100_000),
35 Default::default(),
36 );
37
38 loop {
39 let a1454_read_sensor_command = [0x1F];
40 let mut sensor_data_buffer: [u8; 4] = [0, 0, 0, 0];
41
42 match i2c
43 .write_read(ADDRESS, &a1454_read_sensor_command, &mut sensor_data_buffer)
44 .await
45 {
46 Ok(()) => {
47 // Convert 12-bit signed integer into 16-bit signed integer.
48 // Is the 12 bit number negative?
49 if (sensor_data_buffer[2] & 0b00001000) == 0b0001000 {
50 sensor_data_buffer[2] = sensor_data_buffer[2] | 0b11110000;
51 }
52
53 let mut sensor_value_raw: u16 = sensor_data_buffer[3].into();
54 sensor_value_raw |= (sensor_data_buffer[2] as u16) << 8;
55 let sensor_value: u16 = sensor_value_raw.into();
56 let sensor_value = sensor_value as i16;
57 info!("Data: {}", sensor_value);
58 }
59 Err(e) => error!("I2C Error during read: {:?}", e),
60 }
61 }
62}
diff --git a/examples/stm32f4/src/bin/i2c_comparison.rs b/examples/stm32f4/src/bin/i2c_comparison.rs
new file mode 100644
index 000000000..6d23c0ed8
--- /dev/null
+++ b/examples/stm32f4/src/bin/i2c_comparison.rs
@@ -0,0 +1,135 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5// Example originally designed for stm32f411ceu6 with three A1454 hall effect sensors, connected to I2C1, 2 and 3
6// on the pins referenced in the peripheral definitions.
7// Pins and DMA peripherals changed to compile for stm32f429zi, to work with the CI.
8// MUST be compiled in release mode to see actual performance, otherwise the async transactions take 2x
9// as long to complete as the blocking ones!
10
11use defmt::*;
12use embassy_executor::Spawner;
13use embassy_stm32::i2c::I2c;
14use embassy_stm32::time::Hertz;
15use embassy_stm32::{bind_interrupts, i2c, peripherals};
16use embassy_time::Instant;
17use futures::future::try_join3;
18use {defmt_rtt as _, panic_probe as _};
19
20const ADDRESS: u8 = 96;
21
22bind_interrupts!(struct Irqs {
23 I2C1_EV => i2c::EventInterruptHandler<peripherals::I2C1>;
24 I2C1_ER => i2c::ErrorInterruptHandler<peripherals::I2C1>;
25 I2C2_EV => i2c::EventInterruptHandler<peripherals::I2C2>;
26 I2C2_ER => i2c::ErrorInterruptHandler<peripherals::I2C2>;
27 I2C3_EV => i2c::EventInterruptHandler<peripherals::I2C3>;
28 I2C3_ER => i2c::ErrorInterruptHandler<peripherals::I2C3>;
29});
30
31/// Convert 12-bit signed integer within a 4 byte long buffer into 16-bit signed integer.
32fn a1454_buf_to_i16(buffer: &[u8; 4]) -> i16 {
33 let lower = buffer[3];
34 let mut upper = buffer[2];
35 // Fill in additional 1s if the 12 bit number is negative.
36 if (upper & 0b00001000) == 0b0001000 {
37 upper = upper | 0b11110000;
38 }
39
40 let mut sensor_value_raw: u16 = lower.into();
41 sensor_value_raw |= (upper as u16) << 8;
42 let sensor_value: u16 = sensor_value_raw.into();
43 let sensor_value = sensor_value as i16;
44 sensor_value
45}
46
47#[embassy_executor::main]
48async fn main(_spawner: Spawner) {
49 info!("Setting up peripherals.");
50 let p = embassy_stm32::init(Default::default());
51
52 let mut i2c1 = I2c::new(
53 p.I2C1,
54 p.PB8,
55 p.PB7,
56 Irqs,
57 p.DMA1_CH6,
58 p.DMA1_CH0,
59 Hertz(100_000),
60 Default::default(),
61 );
62
63 let mut i2c2 = I2c::new(
64 p.I2C2,
65 p.PB10,
66 p.PB11,
67 Irqs,
68 p.DMA1_CH7,
69 p.DMA1_CH3,
70 Hertz(100_000),
71 Default::default(),
72 );
73
74 let mut i2c3 = I2c::new(
75 p.I2C3,
76 p.PA8,
77 p.PC9,
78 Irqs,
79 p.DMA1_CH4,
80 p.DMA1_CH2,
81 Hertz(100_000),
82 Default::default(),
83 );
84
85 let a1454_read_sensor_command = [0x1F];
86 let mut i2c1_buffer: [u8; 4] = [0, 0, 0, 0];
87 let mut i2c2_buffer: [u8; 4] = [0, 0, 0, 0];
88 let mut i2c3_buffer: [u8; 4] = [0, 0, 0, 0];
89 loop {
90 // Blocking reads one after the other. Completes in about 2000us.
91 let blocking_read_start_us = Instant::now().as_micros();
92 match i2c1.blocking_write_read(ADDRESS, &a1454_read_sensor_command, &mut i2c1_buffer) {
93 Ok(()) => {}
94 Err(e) => error!("I2C Error: {:?}", e),
95 }
96 match i2c2.blocking_write_read(ADDRESS, &a1454_read_sensor_command, &mut i2c2_buffer) {
97 Ok(()) => {}
98 Err(e) => error!("I2C Error: {:?}", e),
99 }
100 match i2c3.blocking_write_read(ADDRESS, &a1454_read_sensor_command, &mut i2c3_buffer) {
101 Ok(()) => {}
102 Err(e) => error!("I2C Error: {:?}", e),
103 }
104 let blocking_read_total_us = Instant::now().as_micros() - blocking_read_start_us;
105 info!(
106 "Blocking reads completed in {}us: i2c1: {} i2c2: {} i2c3: {}",
107 blocking_read_total_us,
108 a1454_buf_to_i16(&i2c1_buffer),
109 a1454_buf_to_i16(&i2c2_buffer),
110 a1454_buf_to_i16(&i2c3_buffer)
111 );
112
113 // Async reads overlapping. Completes in about 1000us.
114 let async_read_start_us = Instant::now().as_micros();
115
116 let i2c1_result = i2c1.write_read(ADDRESS, &a1454_read_sensor_command, &mut i2c1_buffer);
117 let i2c2_result = i2c2.write_read(ADDRESS, &a1454_read_sensor_command, &mut i2c2_buffer);
118 let i2c3_result = i2c3.write_read(ADDRESS, &a1454_read_sensor_command, &mut i2c3_buffer);
119
120 // Wait for all three transactions to finish, or any one of them to fail.
121 match try_join3(i2c1_result, i2c2_result, i2c3_result).await {
122 Ok(_) => {
123 let async_read_total_us = Instant::now().as_micros() - async_read_start_us;
124 info!(
125 "Async reads completed in {}us: i2c1: {} i2c2: {} i2c3: {}",
126 async_read_total_us,
127 a1454_buf_to_i16(&i2c1_buffer),
128 a1454_buf_to_i16(&i2c2_buffer),
129 a1454_buf_to_i16(&i2c3_buffer)
130 );
131 }
132 Err(e) => error!("I2C Error during async write-read: {}", e),
133 };
134 }
135}
diff --git a/examples/stm32h5/src/bin/i2c.rs b/examples/stm32h5/src/bin/i2c.rs
index 8b1662f39..31783a2bf 100644
--- a/examples/stm32h5/src/bin/i2c.rs
+++ b/examples/stm32h5/src/bin/i2c.rs
@@ -13,7 +13,8 @@ const ADDRESS: u8 = 0x5F;
13const WHOAMI: u8 = 0x0F; 13const WHOAMI: u8 = 0x0F;
14 14
15bind_interrupts!(struct Irqs { 15bind_interrupts!(struct Irqs {
16 I2C2_EV => i2c::InterruptHandler<peripherals::I2C2>; 16 I2C2_EV => i2c::EventInterruptHandler<peripherals::I2C2>;
17 I2C2_ER => i2c::ErrorInterruptHandler<peripherals::I2C2>;
17}); 18});
18 19
19#[embassy_executor::main] 20#[embassy_executor::main]
diff --git a/examples/stm32h7/src/bin/camera.rs b/examples/stm32h7/src/bin/camera.rs
index 23ece1c38..489fb03dd 100644
--- a/examples/stm32h7/src/bin/camera.rs
+++ b/examples/stm32h7/src/bin/camera.rs
@@ -19,7 +19,8 @@ const HEIGHT: usize = 100;
19static mut FRAME: [u32; WIDTH * HEIGHT / 2] = [0u32; WIDTH * HEIGHT / 2]; 19static mut FRAME: [u32; WIDTH * HEIGHT / 2] = [0u32; WIDTH * HEIGHT / 2];
20 20
21bind_interrupts!(struct Irqs { 21bind_interrupts!(struct Irqs {
22 I2C1_EV => i2c::InterruptHandler<peripherals::I2C1>; 22 I2C1_EV => i2c::EventInterruptHandler<peripherals::I2C1>;
23 I2C1_ER => i2c::ErrorInterruptHandler<peripherals::I2C1>;
23 DCMI => dcmi::InterruptHandler<peripherals::DCMI>; 24 DCMI => dcmi::InterruptHandler<peripherals::DCMI>;
24}); 25});
25 26
diff --git a/examples/stm32h7/src/bin/i2c.rs b/examples/stm32h7/src/bin/i2c.rs
index 9aa0ca08b..aea21ec6f 100644
--- a/examples/stm32h7/src/bin/i2c.rs
+++ b/examples/stm32h7/src/bin/i2c.rs
@@ -13,7 +13,8 @@ const ADDRESS: u8 = 0x5F;
13const WHOAMI: u8 = 0x0F; 13const WHOAMI: u8 = 0x0F;
14 14
15bind_interrupts!(struct Irqs { 15bind_interrupts!(struct Irqs {
16 I2C2_EV => i2c::InterruptHandler<peripherals::I2C2>; 16 I2C2_EV => i2c::EventInterruptHandler<peripherals::I2C2>;
17 I2C2_ER => i2c::ErrorInterruptHandler<peripherals::I2C2>;
17}); 18});
18 19
19#[embassy_executor::main] 20#[embassy_executor::main]
diff --git a/examples/stm32l4/src/bin/i2c.rs b/examples/stm32l4/src/bin/i2c.rs
index d0060d20c..07dc12e8c 100644
--- a/examples/stm32l4/src/bin/i2c.rs
+++ b/examples/stm32l4/src/bin/i2c.rs
@@ -14,7 +14,8 @@ const ADDRESS: u8 = 0x5F;
14const WHOAMI: u8 = 0x0F; 14const WHOAMI: u8 = 0x0F;
15 15
16bind_interrupts!(struct Irqs { 16bind_interrupts!(struct Irqs {
17 I2C2_EV => i2c::InterruptHandler<peripherals::I2C2>; 17 I2C2_EV => i2c::EventInterruptHandler<peripherals::I2C2>;
18 I2C2_ER => i2c::ErrorInterruptHandler<peripherals::I2C2>;
18}); 19});
19 20
20#[embassy_executor::main] 21#[embassy_executor::main]
diff --git a/examples/stm32l4/src/bin/i2c_blocking_async.rs b/examples/stm32l4/src/bin/i2c_blocking_async.rs
index eca59087b..60a4e2eb3 100644
--- a/examples/stm32l4/src/bin/i2c_blocking_async.rs
+++ b/examples/stm32l4/src/bin/i2c_blocking_async.rs
@@ -16,7 +16,8 @@ const ADDRESS: u8 = 0x5F;
16const WHOAMI: u8 = 0x0F; 16const WHOAMI: u8 = 0x0F;
17 17
18bind_interrupts!(struct Irqs { 18bind_interrupts!(struct Irqs {
19 I2C2_EV => i2c::InterruptHandler<peripherals::I2C2>; 19 I2C2_EV => i2c::EventInterruptHandler<peripherals::I2C2>;
20 I2C2_ER => i2c::ErrorInterruptHandler<peripherals::I2C2>;
20}); 21});
21 22
22#[embassy_executor::main] 23#[embassy_executor::main]
diff --git a/examples/stm32l4/src/bin/i2c_dma.rs b/examples/stm32l4/src/bin/i2c_dma.rs
index cf6f3da67..4c2c224a6 100644
--- a/examples/stm32l4/src/bin/i2c_dma.rs
+++ b/examples/stm32l4/src/bin/i2c_dma.rs
@@ -13,7 +13,8 @@ const ADDRESS: u8 = 0x5F;
13const WHOAMI: u8 = 0x0F; 13const WHOAMI: u8 = 0x0F;
14 14
15bind_interrupts!(struct Irqs { 15bind_interrupts!(struct Irqs {
16 I2C2_EV => i2c::InterruptHandler<peripherals::I2C2>; 16 I2C2_EV => i2c::EventInterruptHandler<peripherals::I2C2>;
17 I2C2_ER => i2c::ErrorInterruptHandler<peripherals::I2C2>;
17}); 18});
18 19
19#[embassy_executor::main] 20#[embassy_executor::main]
diff --git a/examples/stm32l4/src/bin/spe_adin1110_http_server.rs b/examples/stm32l4/src/bin/spe_adin1110_http_server.rs
index 3a7e5370c..4826e0bed 100644
--- a/examples/stm32l4/src/bin/spe_adin1110_http_server.rs
+++ b/examples/stm32l4/src/bin/spe_adin1110_http_server.rs
@@ -40,7 +40,8 @@ use static_cell::make_static;
40use {embassy_stm32 as hal, panic_probe as _}; 40use {embassy_stm32 as hal, panic_probe as _};
41 41
42bind_interrupts!(struct Irqs { 42bind_interrupts!(struct Irqs {
43 I2C3_EV => i2c::InterruptHandler<peripherals::I2C3>; 43 I2C3_EV => i2c::EventInterruptHandler<peripherals::I2C3>;
44 I2C3_ER => i2c::ErrorInterruptHandler<peripherals::I2C3>;
44 RNG => rng::InterruptHandler<peripherals::RNG>; 45 RNG => rng::InterruptHandler<peripherals::RNG>;
45}); 46});
46 47