diff options
| author | Dario Nieuwenhuis <[email protected]> | 2023-11-24 23:08:47 +0000 |
|---|---|---|
| committer | GitHub <[email protected]> | 2023-11-24 23:08:47 +0000 |
| commit | f5c9e3baa6615928f948cf9ae4c03123d2d84cbc (patch) | |
| tree | d753f3aa382534b952c23d39ece6821146439105 | |
| parent | 47bac9df70492cd9c1b1f8617c1abc1209ee3338 (diff) | |
| parent | 3efc3eee5700d2a39e397f1b1b821885301c0862 (diff) | |
Merge pull request #2200 from barnabywalters/asynci2cv1
Implemented async I2C for v1
| -rw-r--r-- | embassy-stm32/Cargo.toml | 4 | ||||
| -rw-r--r-- | embassy-stm32/build.rs | 20 | ||||
| -rw-r--r-- | embassy-stm32/src/i2c/mod.rs | 157 | ||||
| -rw-r--r-- | embassy-stm32/src/i2c/v1.rs | 484 | ||||
| -rw-r--r-- | embassy-stm32/src/i2c/v2.rs | 157 | ||||
| -rw-r--r-- | examples/stm32f4/src/bin/i2c.rs | 3 | ||||
| -rw-r--r-- | examples/stm32f4/src/bin/i2c_async.rs | 62 | ||||
| -rw-r--r-- | examples/stm32f4/src/bin/i2c_comparison.rs | 135 | ||||
| -rw-r--r-- | examples/stm32h5/src/bin/i2c.rs | 3 | ||||
| -rw-r--r-- | examples/stm32h7/src/bin/camera.rs | 3 | ||||
| -rw-r--r-- | examples/stm32h7/src/bin/i2c.rs | 3 | ||||
| -rw-r--r-- | examples/stm32l4/src/bin/i2c.rs | 3 | ||||
| -rw-r--r-- | examples/stm32l4/src/bin/i2c_blocking_async.rs | 3 | ||||
| -rw-r--r-- | examples/stm32l4/src/bin/i2c_dma.rs | 3 | ||||
| -rw-r--r-- | examples/stm32l4/src/bin/spe_adin1110_http_server.rs | 3 |
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" | |||
| 58 | sdio-host = "0.5.0" | 58 | sdio-host = "0.5.0" |
| 59 | embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true } | 59 | embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true } |
| 60 | critical-section = "1.1" | 60 | critical-section = "1.1" |
| 61 | stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-fbb8f77326dd066aa6c0d66b3b46e76a569dda8b" } | 61 | stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-f6d1ffc1a25f208b5cd6b1024bff246592da1949" } |
| 62 | vcell = "0.1.3" | 62 | vcell = "0.1.3" |
| 63 | bxcan = "0.7.0" | 63 | bxcan = "0.7.0" |
| 64 | nb = "1.0.0" | 64 | nb = "1.0.0" |
| @@ -76,7 +76,7 @@ critical-section = { version = "1.1", features = ["std"] } | |||
| 76 | [build-dependencies] | 76 | [build-dependencies] |
| 77 | proc-macro2 = "1.0.36" | 77 | proc-macro2 = "1.0.36" |
| 78 | quote = "1.0.15" | 78 | quote = "1.0.15" |
| 79 | stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-fbb8f77326dd066aa6c0d66b3b46e76a569dda8b", default-features = false, features = ["metadata"]} | 79 | stm32-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 | ||
| 3 | use core::marker::PhantomData; | ||
| 4 | |||
| 3 | use crate::interrupt; | 5 | use 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")] |
| 7 | mod _version; | 9 | mod _version; |
| 8 | pub use _version::*; | 10 | pub use _version::*; |
| 11 | use embassy_sync::waitqueue::AtomicWaker; | ||
| 9 | 12 | ||
| 10 | use crate::peripherals; | 13 | use crate::peripherals; |
| 11 | 14 | ||
| @@ -23,6 +26,20 @@ pub enum Error { | |||
| 23 | 26 | ||
| 24 | pub(crate) mod sealed { | 27 | pub(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 | ||
| 32 | pub trait Instance: sealed::Instance + 'static { | 49 | pub 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 | ||
| 36 | pin_trait!(SclPin, Instance); | 54 | pin_trait!(SclPin, Instance); |
| @@ -38,21 +56,148 @@ pin_trait!(SdaPin, Instance); | |||
| 38 | dma_trait!(RxDma, Instance); | 56 | dma_trait!(RxDma, Instance); |
| 39 | dma_trait!(TxDma, Instance); | 57 | dma_trait!(TxDma, Instance); |
| 40 | 58 | ||
| 41 | foreach_interrupt!( | 59 | /// Interrupt handler. |
| 42 | ($inst:ident, i2c, $block:ident, EV, $irq:ident) => { | 60 | pub struct EventInterruptHandler<T: Instance> { |
| 61 | _phantom: PhantomData<T>, | ||
| 62 | } | ||
| 63 | |||
| 64 | impl<T: Instance> interrupt::typelevel::Handler<T::EventInterrupt> for EventInterruptHandler<T> { | ||
| 65 | unsafe fn on_interrupt() { | ||
| 66 | _version::on_interrupt::<T>() | ||
| 67 | } | ||
| 68 | } | ||
| 69 | |||
| 70 | pub struct ErrorInterruptHandler<T: Instance> { | ||
| 71 | _phantom: PhantomData<T>, | ||
| 72 | } | ||
| 73 | |||
| 74 | impl<T: Instance> interrupt::typelevel::Handler<T::ErrorInterrupt> for ErrorInterruptHandler<T> { | ||
| 75 | unsafe fn on_interrupt() { | ||
| 76 | _version::on_interrupt::<T>() | ||
| 77 | } | ||
| 78 | } | ||
| 79 | |||
| 80 | foreach_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 | |||
| 100 | mod 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")] | ||
| 129 | mod 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"))] | ||
| 177 | mod 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 @@ | |||
| 1 | use core::future::poll_fn; | ||
| 1 | use core::marker::PhantomData; | 2 | use core::marker::PhantomData; |
| 3 | use core::task::Poll; | ||
| 2 | 4 | ||
| 3 | use embassy_embedded_hal::SetConfig; | 5 | use embassy_embedded_hal::SetConfig; |
| 6 | use embassy_futures::select::{select, Either}; | ||
| 7 | use embassy_hal_internal::drop::OnDrop; | ||
| 4 | use embassy_hal_internal::{into_ref, PeripheralRef}; | 8 | use embassy_hal_internal::{into_ref, PeripheralRef}; |
| 5 | 9 | ||
| 6 | use crate::dma::NoDma; | 10 | use super::*; |
| 11 | use crate::dma::{NoDma, Transfer}; | ||
| 7 | use crate::gpio::sealed::AFType; | 12 | use crate::gpio::sealed::AFType; |
| 8 | use crate::gpio::Pull; | 13 | use crate::gpio::Pull; |
| 9 | use crate::i2c::{Error, Instance, SclPin, SdaPin}; | 14 | use crate::interrupt::typelevel::Interrupt; |
| 10 | use crate::pac::i2c; | 15 | use crate::pac::i2c; |
| 11 | use crate::time::Hertz; | 16 | use crate::time::Hertz; |
| 12 | use crate::{interrupt, Peripheral}; | 17 | use crate::{interrupt, Peripheral}; |
| 13 | 18 | ||
| 14 | /// Interrupt handler. | 19 | pub unsafe fn on_interrupt<T: Instance>() { |
| 15 | pub 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(); | |
| 19 | impl<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 | ||
| 30 | pub struct State {} | ||
| 31 | |||
| 32 | impl State { | ||
| 33 | pub(crate) const fn new() -> Self { | ||
| 34 | Self {} | ||
| 35 | } | ||
| 36 | } | ||
| 37 | |||
| 38 | pub struct I2c<'d, T: Instance, TXDMA = NoDma, RXDMA = NoDma> { | 40 | pub 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 | ||
| 341 | impl<'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 | ||
| 347 | impl<'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 | ||
| 355 | impl<'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 | ||
| 363 | impl<'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 |
| 372 | mod 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 | |||
| 716 | impl<'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 @@ | |||
| 1 | use core::cmp; | 1 | use core::cmp; |
| 2 | use core::future::poll_fn; | 2 | use core::future::poll_fn; |
| 3 | use core::marker::PhantomData; | ||
| 4 | use core::task::Poll; | 3 | use core::task::Poll; |
| 5 | 4 | ||
| 6 | use embassy_embedded_hal::SetConfig; | 5 | use embassy_embedded_hal::SetConfig; |
| 7 | use embassy_hal_internal::drop::OnDrop; | 6 | use embassy_hal_internal::drop::OnDrop; |
| 8 | use embassy_hal_internal::{into_ref, PeripheralRef}; | 7 | use embassy_hal_internal::{into_ref, PeripheralRef}; |
| 9 | use embassy_sync::waitqueue::AtomicWaker; | ||
| 10 | #[cfg(feature = "time")] | 8 | #[cfg(feature = "time")] |
| 11 | use embassy_time::{Duration, Instant}; | 9 | use embassy_time::{Duration, Instant}; |
| 12 | 10 | ||
| 11 | use super::*; | ||
| 13 | use crate::dma::{NoDma, Transfer}; | 12 | use crate::dma::{NoDma, Transfer}; |
| 14 | use crate::gpio::sealed::AFType; | 13 | use crate::gpio::sealed::AFType; |
| 15 | use crate::gpio::Pull; | 14 | use crate::gpio::Pull; |
| 16 | use crate::i2c::{Error, Instance, SclPin, SdaPin}; | ||
| 17 | use crate::interrupt::typelevel::Interrupt; | 15 | use crate::interrupt::typelevel::Interrupt; |
| 18 | use crate::pac::i2c; | 16 | use crate::pac::i2c; |
| 19 | use crate::time::Hertz; | 17 | use 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. | 37 | pub unsafe fn on_interrupt<T: Instance>() { |
| 40 | pub struct InterruptHandler<T: Instance> { | 38 | let regs = T::regs(); |
| 41 | _phantom: PhantomData<T>, | 39 | let isr = regs.isr().read(); |
| 42 | } | ||
| 43 | |||
| 44 | impl<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 | ||
| 80 | pub struct State { | ||
| 81 | waker: AtomicWaker, | ||
| 82 | } | ||
| 83 | |||
| 84 | impl State { | ||
| 85 | pub(crate) const fn new() -> Self { | ||
| 86 | Self { | ||
| 87 | waker: AtomicWaker::new(), | ||
| 88 | } | ||
| 89 | } | ||
| 90 | } | ||
| 91 | |||
| 92 | pub struct I2c<'d, T: Instance, TXDMA = NoDma, RXDMA = NoDma> { | 71 | pub 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")] | ||
| 991 | mod 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")] | ||
| 1144 | mod 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"))] | ||
| 1191 | mod 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 | |||
| 1220 | impl<'d, T: Instance> SetConfig for I2c<'d, T> { | 1095 | impl<'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; | |||
| 14 | const WHOAMI: u8 = 0x0F; | 14 | const WHOAMI: u8 = 0x0F; |
| 15 | 15 | ||
| 16 | bind_interrupts!(struct Irqs { | 16 | bind_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 | |||
| 8 | use defmt::*; | ||
| 9 | use embassy_executor::Spawner; | ||
| 10 | use embassy_stm32::i2c::I2c; | ||
| 11 | use embassy_stm32::time::Hertz; | ||
| 12 | use embassy_stm32::{bind_interrupts, i2c, peripherals}; | ||
| 13 | use {defmt_rtt as _, panic_probe as _}; | ||
| 14 | |||
| 15 | const ADDRESS: u8 = 96; | ||
| 16 | |||
| 17 | bind_interrupts!(struct Irqs { | ||
| 18 | I2C1_EV => i2c::EventInterruptHandler<peripherals::I2C1>; | ||
| 19 | I2C1_ER => i2c::ErrorInterruptHandler<peripherals::I2C1>; | ||
| 20 | }); | ||
| 21 | |||
| 22 | #[embassy_executor::main] | ||
| 23 | async 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 | |||
| 11 | use defmt::*; | ||
| 12 | use embassy_executor::Spawner; | ||
| 13 | use embassy_stm32::i2c::I2c; | ||
| 14 | use embassy_stm32::time::Hertz; | ||
| 15 | use embassy_stm32::{bind_interrupts, i2c, peripherals}; | ||
| 16 | use embassy_time::Instant; | ||
| 17 | use futures::future::try_join3; | ||
| 18 | use {defmt_rtt as _, panic_probe as _}; | ||
| 19 | |||
| 20 | const ADDRESS: u8 = 96; | ||
| 21 | |||
| 22 | bind_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. | ||
| 32 | fn 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] | ||
| 48 | async 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; | |||
| 13 | const WHOAMI: u8 = 0x0F; | 13 | const WHOAMI: u8 = 0x0F; |
| 14 | 14 | ||
| 15 | bind_interrupts!(struct Irqs { | 15 | bind_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; | |||
| 19 | static mut FRAME: [u32; WIDTH * HEIGHT / 2] = [0u32; WIDTH * HEIGHT / 2]; | 19 | static mut FRAME: [u32; WIDTH * HEIGHT / 2] = [0u32; WIDTH * HEIGHT / 2]; |
| 20 | 20 | ||
| 21 | bind_interrupts!(struct Irqs { | 21 | bind_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; | |||
| 13 | const WHOAMI: u8 = 0x0F; | 13 | const WHOAMI: u8 = 0x0F; |
| 14 | 14 | ||
| 15 | bind_interrupts!(struct Irqs { | 15 | bind_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; | |||
| 14 | const WHOAMI: u8 = 0x0F; | 14 | const WHOAMI: u8 = 0x0F; |
| 15 | 15 | ||
| 16 | bind_interrupts!(struct Irqs { | 16 | bind_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; | |||
| 16 | const WHOAMI: u8 = 0x0F; | 16 | const WHOAMI: u8 = 0x0F; |
| 17 | 17 | ||
| 18 | bind_interrupts!(struct Irqs { | 18 | bind_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; | |||
| 13 | const WHOAMI: u8 = 0x0F; | 13 | const WHOAMI: u8 = 0x0F; |
| 14 | 14 | ||
| 15 | bind_interrupts!(struct Irqs { | 15 | bind_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; | |||
| 40 | use {embassy_stm32 as hal, panic_probe as _}; | 40 | use {embassy_stm32 as hal, panic_probe as _}; |
| 41 | 41 | ||
| 42 | bind_interrupts!(struct Irqs { | 42 | bind_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 | ||
