diff options
| author | Ulf Lilleengen <[email protected]> | 2025-06-11 05:09:08 +0000 |
|---|---|---|
| committer | GitHub <[email protected]> | 2025-06-11 05:09:08 +0000 |
| commit | 56572ef0adffd6258adc10fb424e37a8b4ddc19c (patch) | |
| tree | 5cacb71ceca12180e95031791c93c53e83bca307 /embassy-stm32 | |
| parent | 6186d111a5c150946ee5b7e9e68d987a38c1a463 (diff) | |
| parent | 4efb3b4f3f0178b98ea25f3957393ab6977c89de (diff) | |
Merge pull request #2909 from jrmoulton/i2c-slave-new
stm32 i2c slave
Diffstat (limited to 'embassy-stm32')
| -rw-r--r-- | embassy-stm32/src/i2c/config.rs | 170 | ||||
| -rw-r--r-- | embassy-stm32/src/i2c/mod.rs | 173 | ||||
| -rw-r--r-- | embassy-stm32/src/i2c/v1.rs | 7 | ||||
| -rw-r--r-- | embassy-stm32/src/i2c/v2.rs | 491 |
4 files changed, 714 insertions, 127 deletions
diff --git a/embassy-stm32/src/i2c/config.rs b/embassy-stm32/src/i2c/config.rs new file mode 100644 index 000000000..daae43bcd --- /dev/null +++ b/embassy-stm32/src/i2c/config.rs | |||
| @@ -0,0 +1,170 @@ | |||
| 1 | #[cfg(gpio_v2)] | ||
| 2 | use crate::gpio::Pull; | ||
| 3 | use crate::gpio::{AfType, OutputType, Speed}; | ||
| 4 | |||
| 5 | #[repr(u8)] | ||
| 6 | #[derive(Copy, Clone)] | ||
| 7 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 8 | /// Bits of the I2C OA2 register to mask out. | ||
| 9 | pub enum AddrMask { | ||
| 10 | /// No mask | ||
| 11 | NOMASK, | ||
| 12 | /// OA2\[1\] is masked and don’t care. Only OA2\[7:2\] are compared. | ||
| 13 | MASK1, | ||
| 14 | /// OA2\[2:1\] are masked and don’t care. Only OA2\[7:3\] are compared. | ||
| 15 | MASK2, | ||
| 16 | /// OA2\[3:1\] are masked and don’t care. Only OA2\[7:4\] are compared. | ||
| 17 | MASK3, | ||
| 18 | /// OA2\[4:1\] are masked and don’t care. Only OA2\[7:5\] are compared. | ||
| 19 | MASK4, | ||
| 20 | /// OA2\[5:1\] are masked and don’t care. Only OA2\[7:6\] are compared. | ||
| 21 | MASK5, | ||
| 22 | /// OA2\[6:1\] are masked and don’t care. Only OA2\[7:6\] are compared. | ||
| 23 | MASK6, | ||
| 24 | /// OA2\[7:1\] are masked and don’t care. No comparison is done, and all (except reserved) 7-bit received addresses are acknowledged | ||
| 25 | MASK7, | ||
| 26 | } | ||
| 27 | |||
| 28 | #[derive(Debug, Copy, Clone, PartialEq, Eq)] | ||
| 29 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 30 | /// An I2C address. Either 7 or 10 bit. | ||
| 31 | pub enum Address { | ||
| 32 | /// A 7 bit address | ||
| 33 | SevenBit(u8), | ||
| 34 | /// A 10 bit address. | ||
| 35 | /// | ||
| 36 | /// When using an address to configure the Own Address, only the OA1 register can be set to a 10-bit address. | ||
| 37 | TenBit(u16), | ||
| 38 | } | ||
| 39 | impl From<u8> for Address { | ||
| 40 | fn from(value: u8) -> Self { | ||
| 41 | Address::SevenBit(value) | ||
| 42 | } | ||
| 43 | } | ||
| 44 | impl From<u16> for Address { | ||
| 45 | fn from(value: u16) -> Self { | ||
| 46 | assert!(value < 0x400, "Ten bit address must be less than 0x400"); | ||
| 47 | Address::TenBit(value) | ||
| 48 | } | ||
| 49 | } | ||
| 50 | impl Address { | ||
| 51 | /// Get the inner address as a u16. | ||
| 52 | /// | ||
| 53 | /// For 7 bit addresses, the u8 that was used to store the address is returned as a u16. | ||
| 54 | pub fn addr(&self) -> u16 { | ||
| 55 | match self { | ||
| 56 | Address::SevenBit(addr) => *addr as u16, | ||
| 57 | Address::TenBit(addr) => *addr, | ||
| 58 | } | ||
| 59 | } | ||
| 60 | } | ||
| 61 | |||
| 62 | #[derive(Copy, Clone)] | ||
| 63 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 64 | /// The second Own Address register. | ||
| 65 | pub struct OA2 { | ||
| 66 | /// The address. | ||
| 67 | pub addr: u8, | ||
| 68 | /// The bit mask that will affect how the own address 2 register is compared. | ||
| 69 | pub mask: AddrMask, | ||
| 70 | } | ||
| 71 | |||
| 72 | #[derive(Copy, Clone)] | ||
| 73 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 74 | /// The Own Address(es) of the I2C peripheral. | ||
| 75 | pub enum OwnAddresses { | ||
| 76 | /// Configuration for only the OA1 register. | ||
| 77 | OA1(Address), | ||
| 78 | /// Configuration for only the OA2 register. | ||
| 79 | OA2(OA2), | ||
| 80 | /// Configuration for both the OA1 and OA2 registers. | ||
| 81 | Both { | ||
| 82 | /// The [Address] for the OA1 register. | ||
| 83 | oa1: Address, | ||
| 84 | /// The [OA2] configuration. | ||
| 85 | oa2: OA2, | ||
| 86 | }, | ||
| 87 | } | ||
| 88 | |||
| 89 | /// Slave Configuration | ||
| 90 | #[derive(Copy, Clone)] | ||
| 91 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 92 | pub struct SlaveAddrConfig { | ||
| 93 | /// Target Address(es) | ||
| 94 | pub addr: OwnAddresses, | ||
| 95 | /// Control if the peripheral should respond to the general call address | ||
| 96 | pub general_call: bool, | ||
| 97 | } | ||
| 98 | impl SlaveAddrConfig { | ||
| 99 | /// Create a new slave address configuration with only the OA1 register set in 7 bit mode and the general call disabled. | ||
| 100 | pub fn basic(addr: u8) -> Self { | ||
| 101 | Self { | ||
| 102 | addr: OwnAddresses::OA1(Address::SevenBit(addr)), | ||
| 103 | general_call: false, | ||
| 104 | } | ||
| 105 | } | ||
| 106 | } | ||
| 107 | |||
| 108 | /// I2C config | ||
| 109 | #[non_exhaustive] | ||
| 110 | #[derive(Copy, Clone)] | ||
| 111 | pub struct Config { | ||
| 112 | /// Enable internal pullup on SDA. | ||
| 113 | /// | ||
| 114 | /// Using external pullup resistors is recommended for I2C. If you do | ||
| 115 | /// have external pullups you should not enable this. | ||
| 116 | #[cfg(gpio_v2)] | ||
| 117 | pub sda_pullup: bool, | ||
| 118 | /// Enable internal pullup on SCL. | ||
| 119 | /// | ||
| 120 | /// Using external pullup resistors is recommended for I2C. If you do | ||
| 121 | /// have external pullups you should not enable this. | ||
| 122 | #[cfg(gpio_v2)] | ||
| 123 | pub scl_pullup: bool, | ||
| 124 | /// Timeout. | ||
| 125 | #[cfg(feature = "time")] | ||
| 126 | pub timeout: embassy_time::Duration, | ||
| 127 | } | ||
| 128 | |||
| 129 | impl Default for Config { | ||
| 130 | fn default() -> Self { | ||
| 131 | Self { | ||
| 132 | #[cfg(gpio_v2)] | ||
| 133 | sda_pullup: false, | ||
| 134 | #[cfg(gpio_v2)] | ||
| 135 | scl_pullup: false, | ||
| 136 | #[cfg(feature = "time")] | ||
| 137 | timeout: embassy_time::Duration::from_millis(1000), | ||
| 138 | } | ||
| 139 | } | ||
| 140 | } | ||
| 141 | |||
| 142 | impl Config { | ||
| 143 | pub(super) fn scl_af(&self) -> AfType { | ||
| 144 | #[cfg(gpio_v1)] | ||
| 145 | return AfType::output(OutputType::OpenDrain, Speed::Medium); | ||
| 146 | #[cfg(gpio_v2)] | ||
| 147 | return AfType::output_pull( | ||
| 148 | OutputType::OpenDrain, | ||
| 149 | Speed::Medium, | ||
| 150 | match self.scl_pullup { | ||
| 151 | true => Pull::Up, | ||
| 152 | false => Pull::Down, | ||
| 153 | }, | ||
| 154 | ); | ||
| 155 | } | ||
| 156 | |||
| 157 | pub(super) fn sda_af(&self) -> AfType { | ||
| 158 | #[cfg(gpio_v1)] | ||
| 159 | return AfType::output(OutputType::OpenDrain, Speed::Medium); | ||
| 160 | #[cfg(gpio_v2)] | ||
| 161 | return AfType::output_pull( | ||
| 162 | OutputType::OpenDrain, | ||
| 163 | Speed::Medium, | ||
| 164 | match self.sda_pullup { | ||
| 165 | true => Pull::Up, | ||
| 166 | false => Pull::Down, | ||
| 167 | }, | ||
| 168 | ); | ||
| 169 | } | ||
| 170 | } | ||
diff --git a/embassy-stm32/src/i2c/mod.rs b/embassy-stm32/src/i2c/mod.rs index 1689fdb84..825dd240c 100644 --- a/embassy-stm32/src/i2c/mod.rs +++ b/embassy-stm32/src/i2c/mod.rs | |||
| @@ -5,19 +5,22 @@ | |||
| 5 | #[cfg_attr(any(i2c_v2, i2c_v3), path = "v2.rs")] | 5 | #[cfg_attr(any(i2c_v2, i2c_v3), path = "v2.rs")] |
| 6 | mod _version; | 6 | mod _version; |
| 7 | 7 | ||
| 8 | mod config; | ||
| 9 | |||
| 8 | use core::future::Future; | 10 | use core::future::Future; |
| 9 | use core::iter; | 11 | use core::iter; |
| 10 | use core::marker::PhantomData; | 12 | use core::marker::PhantomData; |
| 11 | 13 | ||
| 14 | pub use config::*; | ||
| 12 | use embassy_hal_internal::Peri; | 15 | use embassy_hal_internal::Peri; |
| 13 | use embassy_sync::waitqueue::AtomicWaker; | 16 | use embassy_sync::waitqueue::AtomicWaker; |
| 14 | #[cfg(feature = "time")] | 17 | #[cfg(feature = "time")] |
| 15 | use embassy_time::{Duration, Instant}; | 18 | use embassy_time::{Duration, Instant}; |
| 19 | use mode::MasterMode; | ||
| 20 | pub use mode::{Master, MultiMaster}; | ||
| 16 | 21 | ||
| 17 | use crate::dma::ChannelAndRequest; | 22 | use crate::dma::ChannelAndRequest; |
| 18 | #[cfg(gpio_v2)] | 23 | use crate::gpio::{AnyPin, SealedPin as _}; |
| 19 | use crate::gpio::Pull; | ||
| 20 | use crate::gpio::{AfType, AnyPin, OutputType, SealedPin as _, Speed}; | ||
| 21 | use crate::interrupt::typelevel::Interrupt; | 24 | use crate::interrupt::typelevel::Interrupt; |
| 22 | use crate::mode::{Async, Blocking, Mode}; | 25 | use crate::mode::{Async, Blocking, Mode}; |
| 23 | use crate::rcc::{RccInfo, SealedRccPeripheral}; | 26 | use crate::rcc::{RccInfo, SealedRccPeripheral}; |
| @@ -62,85 +65,89 @@ impl core::fmt::Display for Error { | |||
| 62 | 65 | ||
| 63 | impl core::error::Error for Error {} | 66 | impl core::error::Error for Error {} |
| 64 | 67 | ||
| 65 | /// I2C config | 68 | /// I2C modes |
| 66 | #[non_exhaustive] | 69 | pub mod mode { |
| 67 | #[derive(Copy, Clone)] | 70 | trait SealedMode {} |
| 68 | pub struct Config { | 71 | |
| 69 | /// Enable internal pullup on SDA. | 72 | /// Trait for I2C master operations. |
| 70 | /// | 73 | #[allow(private_bounds)] |
| 71 | /// Using external pullup resistors is recommended for I2C. If you do | 74 | pub trait MasterMode: SealedMode {} |
| 72 | /// have external pullups you should not enable this. | 75 | |
| 73 | #[cfg(gpio_v2)] | 76 | /// Mode allowing for I2C master operations. |
| 74 | pub sda_pullup: bool, | 77 | pub struct Master; |
| 75 | /// Enable internal pullup on SCL. | 78 | /// Mode allowing for I2C master and slave operations. |
| 76 | /// | 79 | pub struct MultiMaster; |
| 77 | /// Using external pullup resistors is recommended for I2C. If you do | 80 | |
| 78 | /// have external pullups you should not enable this. | 81 | impl SealedMode for Master {} |
| 79 | #[cfg(gpio_v2)] | 82 | impl MasterMode for Master {} |
| 80 | pub scl_pullup: bool, | 83 | |
| 81 | /// Timeout. | 84 | impl SealedMode for MultiMaster {} |
| 82 | #[cfg(feature = "time")] | 85 | impl MasterMode for MultiMaster {} |
| 83 | pub timeout: embassy_time::Duration, | ||
| 84 | } | 86 | } |
| 85 | 87 | ||
| 86 | impl Default for Config { | 88 | #[derive(Debug, Clone, PartialEq, Eq)] |
| 87 | fn default() -> Self { | 89 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
| 88 | Self { | 90 | /// The command kind to the slave from the master |
| 89 | #[cfg(gpio_v2)] | 91 | pub enum SlaveCommandKind { |
| 90 | sda_pullup: false, | 92 | /// Write to the slave |
| 91 | #[cfg(gpio_v2)] | 93 | Write, |
| 92 | scl_pullup: false, | 94 | /// Read from the slave |
| 93 | #[cfg(feature = "time")] | 95 | Read, |
| 94 | timeout: embassy_time::Duration::from_millis(1000), | ||
| 95 | } | ||
| 96 | } | ||
| 97 | } | 96 | } |
| 98 | 97 | ||
| 99 | impl Config { | 98 | #[derive(Debug, Clone, PartialEq, Eq)] |
| 100 | fn scl_af(&self) -> AfType { | 99 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
| 101 | #[cfg(gpio_v1)] | 100 | /// The command kind to the slave from the master and the address that the slave matched |
| 102 | return AfType::output(OutputType::OpenDrain, Speed::Medium); | 101 | pub struct SlaveCommand { |
| 103 | #[cfg(gpio_v2)] | 102 | /// The kind of command |
| 104 | return AfType::output_pull( | 103 | pub kind: SlaveCommandKind, |
| 105 | OutputType::OpenDrain, | 104 | /// The address that the slave matched |
| 106 | Speed::Medium, | 105 | pub address: Address, |
| 107 | match self.scl_pullup { | 106 | } |
| 108 | true => Pull::Up, | ||
| 109 | false => Pull::None, | ||
| 110 | }, | ||
| 111 | ); | ||
| 112 | } | ||
| 113 | 107 | ||
| 114 | fn sda_af(&self) -> AfType { | 108 | #[derive(Debug, Clone, PartialEq, Eq)] |
| 115 | #[cfg(gpio_v1)] | 109 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
| 116 | return AfType::output(OutputType::OpenDrain, Speed::Medium); | 110 | /// The status of the slave send operation |
| 117 | #[cfg(gpio_v2)] | 111 | pub enum SendStatus { |
| 118 | return AfType::output_pull( | 112 | /// The slave send operation is done, all bytes have been sent and the master is not requesting more |
| 119 | OutputType::OpenDrain, | 113 | Done, |
| 120 | Speed::Medium, | 114 | /// The slave send operation is done, but there are leftover bytes that the master did not read |
| 121 | match self.sda_pullup { | 115 | LeftoverBytes(usize), |
| 122 | true => Pull::Up, | 116 | } |
| 123 | false => Pull::None, | 117 | |
| 124 | }, | 118 | struct I2CDropGuard<'d> { |
| 125 | ); | 119 | info: &'static Info, |
| 120 | scl: Option<Peri<'d, AnyPin>>, | ||
| 121 | sda: Option<Peri<'d, AnyPin>>, | ||
| 122 | } | ||
| 123 | impl<'d> Drop for I2CDropGuard<'d> { | ||
| 124 | fn drop(&mut self) { | ||
| 125 | if let Some(x) = self.scl.as_ref() { | ||
| 126 | x.set_as_disconnected() | ||
| 127 | } | ||
| 128 | if let Some(x) = self.sda.as_ref() { | ||
| 129 | x.set_as_disconnected() | ||
| 130 | } | ||
| 131 | |||
| 132 | self.info.rcc.disable(); | ||
| 126 | } | 133 | } |
| 127 | } | 134 | } |
| 128 | 135 | ||
| 129 | /// I2C driver. | 136 | /// I2C driver. |
| 130 | pub struct I2c<'d, M: Mode> { | 137 | pub struct I2c<'d, M: Mode, IM: MasterMode> { |
| 131 | info: &'static Info, | 138 | info: &'static Info, |
| 132 | state: &'static State, | 139 | state: &'static State, |
| 133 | kernel_clock: Hertz, | 140 | kernel_clock: Hertz, |
| 134 | scl: Option<Peri<'d, AnyPin>>, | ||
| 135 | sda: Option<Peri<'d, AnyPin>>, | ||
| 136 | tx_dma: Option<ChannelAndRequest<'d>>, | 141 | tx_dma: Option<ChannelAndRequest<'d>>, |
| 137 | rx_dma: Option<ChannelAndRequest<'d>>, | 142 | rx_dma: Option<ChannelAndRequest<'d>>, |
| 138 | #[cfg(feature = "time")] | 143 | #[cfg(feature = "time")] |
| 139 | timeout: Duration, | 144 | timeout: Duration, |
| 140 | _phantom: PhantomData<M>, | 145 | _phantom: PhantomData<M>, |
| 146 | _phantom2: PhantomData<IM>, | ||
| 147 | _drop_guard: I2CDropGuard<'d>, | ||
| 141 | } | 148 | } |
| 142 | 149 | ||
| 143 | impl<'d> I2c<'d, Async> { | 150 | impl<'d> I2c<'d, Async, Master> { |
| 144 | /// Create a new I2C driver. | 151 | /// Create a new I2C driver. |
| 145 | pub fn new<T: Instance>( | 152 | pub fn new<T: Instance>( |
| 146 | peri: Peri<'d, T>, | 153 | peri: Peri<'d, T>, |
| @@ -166,7 +173,7 @@ impl<'d> I2c<'d, Async> { | |||
| 166 | } | 173 | } |
| 167 | } | 174 | } |
| 168 | 175 | ||
| 169 | impl<'d> I2c<'d, Blocking> { | 176 | impl<'d> I2c<'d, Blocking, Master> { |
| 170 | /// Create a new blocking I2C driver. | 177 | /// Create a new blocking I2C driver. |
| 171 | pub fn new_blocking<T: Instance>( | 178 | pub fn new_blocking<T: Instance>( |
| 172 | peri: Peri<'d, T>, | 179 | peri: Peri<'d, T>, |
| @@ -187,7 +194,7 @@ impl<'d> I2c<'d, Blocking> { | |||
| 187 | } | 194 | } |
| 188 | } | 195 | } |
| 189 | 196 | ||
| 190 | impl<'d, M: Mode> I2c<'d, M> { | 197 | impl<'d, M: Mode> I2c<'d, M, Master> { |
| 191 | /// Create a new I2C driver. | 198 | /// Create a new I2C driver. |
| 192 | fn new_inner<T: Instance>( | 199 | fn new_inner<T: Instance>( |
| 193 | _peri: Peri<'d, T>, | 200 | _peri: Peri<'d, T>, |
| @@ -205,15 +212,20 @@ impl<'d, M: Mode> I2c<'d, M> { | |||
| 205 | info: T::info(), | 212 | info: T::info(), |
| 206 | state: T::state(), | 213 | state: T::state(), |
| 207 | kernel_clock: T::frequency(), | 214 | kernel_clock: T::frequency(), |
| 208 | scl, | ||
| 209 | sda, | ||
| 210 | tx_dma, | 215 | tx_dma, |
| 211 | rx_dma, | 216 | rx_dma, |
| 212 | #[cfg(feature = "time")] | 217 | #[cfg(feature = "time")] |
| 213 | timeout: config.timeout, | 218 | timeout: config.timeout, |
| 214 | _phantom: PhantomData, | 219 | _phantom: PhantomData, |
| 220 | _phantom2: PhantomData, | ||
| 221 | _drop_guard: I2CDropGuard { | ||
| 222 | info: T::info(), | ||
| 223 | scl, | ||
| 224 | sda, | ||
| 225 | }, | ||
| 215 | }; | 226 | }; |
| 216 | this.enable_and_init(freq, config); | 227 | this.enable_and_init(freq, config); |
| 228 | |||
| 217 | this | 229 | this |
| 218 | } | 230 | } |
| 219 | 231 | ||
| @@ -221,7 +233,9 @@ impl<'d, M: Mode> I2c<'d, M> { | |||
| 221 | self.info.rcc.enable_and_reset(); | 233 | self.info.rcc.enable_and_reset(); |
| 222 | self.init(freq, config); | 234 | self.init(freq, config); |
| 223 | } | 235 | } |
| 236 | } | ||
| 224 | 237 | ||
| 238 | impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { | ||
| 225 | fn timeout(&self) -> Timeout { | 239 | fn timeout(&self) -> Timeout { |
| 226 | Timeout { | 240 | Timeout { |
| 227 | #[cfg(feature = "time")] | 241 | #[cfg(feature = "time")] |
| @@ -230,15 +244,6 @@ impl<'d, M: Mode> I2c<'d, M> { | |||
| 230 | } | 244 | } |
| 231 | } | 245 | } |
| 232 | 246 | ||
| 233 | impl<'d, M: Mode> Drop for I2c<'d, M> { | ||
| 234 | fn drop(&mut self) { | ||
| 235 | self.scl.as_ref().map(|x| x.set_as_disconnected()); | ||
| 236 | self.sda.as_ref().map(|x| x.set_as_disconnected()); | ||
| 237 | |||
| 238 | self.info.rcc.disable() | ||
| 239 | } | ||
| 240 | } | ||
| 241 | |||
| 242 | #[derive(Copy, Clone)] | 247 | #[derive(Copy, Clone)] |
| 243 | struct Timeout { | 248 | struct Timeout { |
| 244 | #[cfg(feature = "time")] | 249 | #[cfg(feature = "time")] |
| @@ -347,7 +352,7 @@ foreach_peripheral!( | |||
| 347 | }; | 352 | }; |
| 348 | ); | 353 | ); |
| 349 | 354 | ||
| 350 | impl<'d, M: Mode> embedded_hal_02::blocking::i2c::Read for I2c<'d, M> { | 355 | impl<'d, M: Mode, IM: MasterMode> embedded_hal_02::blocking::i2c::Read for I2c<'d, M, IM> { |
| 351 | type Error = Error; | 356 | type Error = Error; |
| 352 | 357 | ||
| 353 | fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error> { | 358 | fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error> { |
| @@ -355,7 +360,7 @@ impl<'d, M: Mode> embedded_hal_02::blocking::i2c::Read for I2c<'d, M> { | |||
| 355 | } | 360 | } |
| 356 | } | 361 | } |
| 357 | 362 | ||
| 358 | impl<'d, M: Mode> embedded_hal_02::blocking::i2c::Write for I2c<'d, M> { | 363 | impl<'d, M: Mode, IM: MasterMode> embedded_hal_02::blocking::i2c::Write for I2c<'d, M, IM> { |
| 359 | type Error = Error; | 364 | type Error = Error; |
| 360 | 365 | ||
| 361 | fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Self::Error> { | 366 | fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Self::Error> { |
| @@ -363,7 +368,7 @@ impl<'d, M: Mode> embedded_hal_02::blocking::i2c::Write for I2c<'d, M> { | |||
| 363 | } | 368 | } |
| 364 | } | 369 | } |
| 365 | 370 | ||
| 366 | impl<'d, M: Mode> embedded_hal_02::blocking::i2c::WriteRead for I2c<'d, M> { | 371 | impl<'d, M: Mode, IM: MasterMode> embedded_hal_02::blocking::i2c::WriteRead for I2c<'d, M, IM> { |
| 367 | type Error = Error; | 372 | type Error = Error; |
| 368 | 373 | ||
| 369 | fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Self::Error> { | 374 | fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Self::Error> { |
| @@ -387,11 +392,11 @@ impl embedded_hal_1::i2c::Error for Error { | |||
| 387 | } | 392 | } |
| 388 | } | 393 | } |
| 389 | 394 | ||
| 390 | impl<'d, M: Mode> embedded_hal_1::i2c::ErrorType for I2c<'d, M> { | 395 | impl<'d, M: Mode, IM: MasterMode> embedded_hal_1::i2c::ErrorType for I2c<'d, M, IM> { |
| 391 | type Error = Error; | 396 | type Error = Error; |
| 392 | } | 397 | } |
| 393 | 398 | ||
| 394 | impl<'d, M: Mode> embedded_hal_1::i2c::I2c for I2c<'d, M> { | 399 | impl<'d, M: Mode, IM: MasterMode> embedded_hal_1::i2c::I2c for I2c<'d, M, IM> { |
| 395 | fn read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Self::Error> { | 400 | fn read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Self::Error> { |
| 396 | self.blocking_read(address, read) | 401 | self.blocking_read(address, read) |
| 397 | } | 402 | } |
| @@ -413,7 +418,7 @@ impl<'d, M: Mode> embedded_hal_1::i2c::I2c for I2c<'d, M> { | |||
| 413 | } | 418 | } |
| 414 | } | 419 | } |
| 415 | 420 | ||
| 416 | impl<'d> embedded_hal_async::i2c::I2c for I2c<'d, Async> { | 421 | impl<'d, IM: MasterMode> embedded_hal_async::i2c::I2c for I2c<'d, Async, IM> { |
| 417 | async fn read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Self::Error> { | 422 | async fn read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Self::Error> { |
| 418 | self.read(address, read).await | 423 | self.read(address, read).await |
| 419 | } | 424 | } |
| @@ -529,9 +534,7 @@ fn operation_frames<'a, 'b: 'a>( | |||
| 529 | let mut next_first_frame = true; | 534 | let mut next_first_frame = true; |
| 530 | 535 | ||
| 531 | Ok(iter::from_fn(move || { | 536 | Ok(iter::from_fn(move || { |
| 532 | let Some(op) = operations.next() else { | 537 | let op = operations.next()?; |
| 533 | return None; | ||
| 534 | }; | ||
| 535 | 538 | ||
| 536 | // Is `op` first frame of its type? | 539 | // Is `op` first frame of its type? |
| 537 | let first_frame = next_first_frame; | 540 | let first_frame = next_first_frame; |
diff --git a/embassy-stm32/src/i2c/v1.rs b/embassy-stm32/src/i2c/v1.rs index 28026f83c..35f13ab46 100644 --- a/embassy-stm32/src/i2c/v1.rs +++ b/embassy-stm32/src/i2c/v1.rs | |||
| @@ -11,6 +11,7 @@ use embassy_embedded_hal::SetConfig; | |||
| 11 | use embassy_futures::select::{select, Either}; | 11 | use embassy_futures::select::{select, Either}; |
| 12 | use embassy_hal_internal::drop::OnDrop; | 12 | use embassy_hal_internal::drop::OnDrop; |
| 13 | use embedded_hal_1::i2c::Operation; | 13 | use embedded_hal_1::i2c::Operation; |
| 14 | use mode::Master; | ||
| 14 | 15 | ||
| 15 | use super::*; | 16 | use super::*; |
| 16 | use crate::mode::Mode as PeriMode; | 17 | use crate::mode::Mode as PeriMode; |
| @@ -41,7 +42,7 @@ pub unsafe fn on_interrupt<T: Instance>() { | |||
| 41 | }); | 42 | }); |
| 42 | } | 43 | } |
| 43 | 44 | ||
| 44 | impl<'d, M: PeriMode> I2c<'d, M> { | 45 | impl<'d, M: PeriMode, IM: MasterMode> I2c<'d, M, IM> { |
| 45 | pub(crate) fn init(&mut self, freq: Hertz, _config: Config) { | 46 | pub(crate) fn init(&mut self, freq: Hertz, _config: Config) { |
| 46 | self.info.regs.cr1().modify(|reg| { | 47 | self.info.regs.cr1().modify(|reg| { |
| 47 | reg.set_pe(false); | 48 | reg.set_pe(false); |
| @@ -354,7 +355,7 @@ impl<'d, M: PeriMode> I2c<'d, M> { | |||
| 354 | } | 355 | } |
| 355 | } | 356 | } |
| 356 | 357 | ||
| 357 | impl<'d> I2c<'d, Async> { | 358 | impl<'d, IM: MasterMode> I2c<'d, Async, IM> { |
| 358 | async fn write_frame(&mut self, address: u8, write: &[u8], frame: FrameOptions) -> Result<(), Error> { | 359 | async fn write_frame(&mut self, address: u8, write: &[u8], frame: FrameOptions) -> Result<(), Error> { |
| 359 | self.info.regs.cr2().modify(|w| { | 360 | self.info.regs.cr2().modify(|w| { |
| 360 | // Note: Do not enable the ITBUFEN bit in the I2C_CR2 register if DMA is used for | 361 | // Note: Do not enable the ITBUFEN bit in the I2C_CR2 register if DMA is used for |
| @@ -800,7 +801,7 @@ impl Timings { | |||
| 800 | } | 801 | } |
| 801 | } | 802 | } |
| 802 | 803 | ||
| 803 | impl<'d, M: PeriMode> SetConfig for I2c<'d, M> { | 804 | impl<'d, M: PeriMode> SetConfig for I2c<'d, M, Master> { |
| 804 | type Config = Hertz; | 805 | type Config = Hertz; |
| 805 | type ConfigError = (); | 806 | type ConfigError = (); |
| 806 | fn set_config(&mut self, config: &Self::Config) -> Result<(), ()> { | 807 | fn set_config(&mut self, config: &Self::Config) -> Result<(), ()> { |
diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs index 50a25754e..35dc91c86 100644 --- a/embassy-stm32/src/i2c/v2.rs +++ b/embassy-stm32/src/i2c/v2.rs | |||
| @@ -2,22 +2,52 @@ use core::cmp; | |||
| 2 | use core::future::poll_fn; | 2 | use core::future::poll_fn; |
| 3 | use core::task::Poll; | 3 | use core::task::Poll; |
| 4 | 4 | ||
| 5 | use config::{Address, OwnAddresses, OA2}; | ||
| 5 | use embassy_embedded_hal::SetConfig; | 6 | use embassy_embedded_hal::SetConfig; |
| 6 | use embassy_hal_internal::drop::OnDrop; | 7 | use embassy_hal_internal::drop::OnDrop; |
| 7 | use embedded_hal_1::i2c::Operation; | 8 | use embedded_hal_1::i2c::Operation; |
| 9 | use mode::{Master, MultiMaster}; | ||
| 10 | use stm32_metapac::i2c::vals::{Addmode, Oamsk}; | ||
| 8 | 11 | ||
| 9 | use super::*; | 12 | use super::*; |
| 10 | use crate::pac::i2c; | 13 | use crate::pac::i2c; |
| 11 | 14 | ||
| 15 | impl From<AddrMask> for Oamsk { | ||
| 16 | fn from(value: AddrMask) -> Self { | ||
| 17 | match value { | ||
| 18 | AddrMask::NOMASK => Oamsk::NO_MASK, | ||
| 19 | AddrMask::MASK1 => Oamsk::MASK1, | ||
| 20 | AddrMask::MASK2 => Oamsk::MASK2, | ||
| 21 | AddrMask::MASK3 => Oamsk::MASK3, | ||
| 22 | AddrMask::MASK4 => Oamsk::MASK4, | ||
| 23 | AddrMask::MASK5 => Oamsk::MASK5, | ||
| 24 | AddrMask::MASK6 => Oamsk::MASK6, | ||
| 25 | AddrMask::MASK7 => Oamsk::MASK7, | ||
| 26 | } | ||
| 27 | } | ||
| 28 | } | ||
| 29 | |||
| 30 | impl Address { | ||
| 31 | pub(super) fn add_mode(&self) -> stm32_metapac::i2c::vals::Addmode { | ||
| 32 | match self { | ||
| 33 | Address::SevenBit(_) => stm32_metapac::i2c::vals::Addmode::BIT7, | ||
| 34 | Address::TenBit(_) => stm32_metapac::i2c::vals::Addmode::BIT10, | ||
| 35 | } | ||
| 36 | } | ||
| 37 | } | ||
| 38 | |||
| 12 | pub(crate) unsafe fn on_interrupt<T: Instance>() { | 39 | pub(crate) unsafe fn on_interrupt<T: Instance>() { |
| 13 | let regs = T::info().regs; | 40 | let regs = T::info().regs; |
| 14 | let isr = regs.isr().read(); | 41 | let isr = regs.isr().read(); |
| 15 | 42 | ||
| 16 | if isr.tcr() || isr.tc() || isr.nackf() || isr.berr() || isr.arlo() || isr.ovr() { | 43 | if isr.tcr() || isr.tc() || isr.addr() || isr.stopf() || isr.nackf() || isr.berr() || isr.arlo() || isr.ovr() { |
| 17 | T::state().waker.wake(); | 44 | T::state().waker.wake(); |
| 18 | } | 45 | } |
| 46 | |||
| 19 | critical_section::with(|_| { | 47 | critical_section::with(|_| { |
| 20 | regs.cr1().modify(|w| { | 48 | regs.cr1().modify(|w| { |
| 49 | w.set_addrie(false); | ||
| 50 | w.set_stopie(false); | ||
| 21 | // The flag can only be cleared by writting to nbytes, we won't do that here | 51 | // The flag can only be cleared by writting to nbytes, we won't do that here |
| 22 | w.set_tcie(false); | 52 | w.set_tcie(false); |
| 23 | // Error flags are to be read in the routines, so we also don't clear them here | 53 | // Error flags are to be read in the routines, so we also don't clear them here |
| @@ -27,7 +57,7 @@ pub(crate) unsafe fn on_interrupt<T: Instance>() { | |||
| 27 | }); | 57 | }); |
| 28 | } | 58 | } |
| 29 | 59 | ||
| 30 | impl<'d, M: Mode> I2c<'d, M> { | 60 | impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { |
| 31 | pub(crate) fn init(&mut self, freq: Hertz, _config: Config) { | 61 | pub(crate) fn init(&mut self, freq: Hertz, _config: Config) { |
| 32 | self.info.regs.cr1().modify(|reg| { | 62 | self.info.regs.cr1().modify(|reg| { |
| 33 | reg.set_pe(false); | 63 | reg.set_pe(false); |
| @@ -55,7 +85,7 @@ impl<'d, M: Mode> I2c<'d, M> { | |||
| 55 | 85 | ||
| 56 | fn master_read( | 86 | fn master_read( |
| 57 | info: &'static Info, | 87 | info: &'static Info, |
| 58 | address: u8, | 88 | address: Address, |
| 59 | length: usize, | 89 | length: usize, |
| 60 | stop: Stop, | 90 | stop: Stop, |
| 61 | reload: bool, | 91 | reload: bool, |
| @@ -84,8 +114,8 @@ impl<'d, M: Mode> I2c<'d, M> { | |||
| 84 | }; | 114 | }; |
| 85 | 115 | ||
| 86 | info.regs.cr2().modify(|w| { | 116 | info.regs.cr2().modify(|w| { |
| 87 | w.set_sadd((address << 1 | 0) as u16); | 117 | w.set_sadd(address.addr() << 1); |
| 88 | w.set_add10(i2c::vals::Addmode::BIT7); | 118 | w.set_add10(address.add_mode()); |
| 89 | w.set_dir(i2c::vals::Dir::READ); | 119 | w.set_dir(i2c::vals::Dir::READ); |
| 90 | w.set_nbytes(length as u8); | 120 | w.set_nbytes(length as u8); |
| 91 | w.set_start(true); | 121 | w.set_start(true); |
| @@ -98,7 +128,7 @@ impl<'d, M: Mode> I2c<'d, M> { | |||
| 98 | 128 | ||
| 99 | fn master_write( | 129 | fn master_write( |
| 100 | info: &'static Info, | 130 | info: &'static Info, |
| 101 | address: u8, | 131 | address: Address, |
| 102 | length: usize, | 132 | length: usize, |
| 103 | stop: Stop, | 133 | stop: Stop, |
| 104 | reload: bool, | 134 | reload: bool, |
| @@ -128,8 +158,8 @@ impl<'d, M: Mode> I2c<'d, M> { | |||
| 128 | // START bit can be set even if the bus is BUSY or | 158 | // START bit can be set even if the bus is BUSY or |
| 129 | // I2C is in slave mode. | 159 | // I2C is in slave mode. |
| 130 | info.regs.cr2().modify(|w| { | 160 | info.regs.cr2().modify(|w| { |
| 131 | w.set_sadd((address << 1 | 0) as u16); | 161 | w.set_sadd(address.addr() << 1); |
| 132 | w.set_add10(i2c::vals::Addmode::BIT7); | 162 | w.set_add10(address.add_mode()); |
| 133 | w.set_dir(i2c::vals::Dir::WRITE); | 163 | w.set_dir(i2c::vals::Dir::WRITE); |
| 134 | w.set_nbytes(length as u8); | 164 | w.set_nbytes(length as u8); |
| 135 | w.set_start(true); | 165 | w.set_start(true); |
| @@ -140,14 +170,14 @@ impl<'d, M: Mode> I2c<'d, M> { | |||
| 140 | Ok(()) | 170 | Ok(()) |
| 141 | } | 171 | } |
| 142 | 172 | ||
| 143 | fn master_continue(info: &'static Info, length: usize, reload: bool, timeout: Timeout) -> Result<(), Error> { | 173 | fn reload(info: &'static Info, length: usize, will_reload: bool, timeout: Timeout) -> Result<(), Error> { |
| 144 | assert!(length < 256 && length > 0); | 174 | assert!(length < 256 && length > 0); |
| 145 | 175 | ||
| 146 | while !info.regs.isr().read().tcr() { | 176 | while !info.regs.isr().read().tcr() { |
| 147 | timeout.check()?; | 177 | timeout.check()?; |
| 148 | } | 178 | } |
| 149 | 179 | ||
| 150 | let reload = if reload { | 180 | let will_reload = if will_reload { |
| 151 | i2c::vals::Reload::NOT_COMPLETED | 181 | i2c::vals::Reload::NOT_COMPLETED |
| 152 | } else { | 182 | } else { |
| 153 | i2c::vals::Reload::COMPLETED | 183 | i2c::vals::Reload::COMPLETED |
| @@ -155,7 +185,7 @@ impl<'d, M: Mode> I2c<'d, M> { | |||
| 155 | 185 | ||
| 156 | info.regs.cr2().modify(|w| { | 186 | info.regs.cr2().modify(|w| { |
| 157 | w.set_nbytes(length as u8); | 187 | w.set_nbytes(length as u8); |
| 158 | w.set_reload(reload); | 188 | w.set_reload(will_reload); |
| 159 | }); | 189 | }); |
| 160 | 190 | ||
| 161 | Ok(()) | 191 | Ok(()) |
| @@ -233,7 +263,13 @@ impl<'d, M: Mode> I2c<'d, M> { | |||
| 233 | } | 263 | } |
| 234 | } | 264 | } |
| 235 | 265 | ||
| 236 | fn read_internal(&mut self, address: u8, read: &mut [u8], restart: bool, timeout: Timeout) -> Result<(), Error> { | 266 | fn read_internal( |
| 267 | &mut self, | ||
| 268 | address: Address, | ||
| 269 | read: &mut [u8], | ||
| 270 | restart: bool, | ||
| 271 | timeout: Timeout, | ||
| 272 | ) -> Result<(), Error> { | ||
| 237 | let completed_chunks = read.len() / 255; | 273 | let completed_chunks = read.len() / 255; |
| 238 | let total_chunks = if completed_chunks * 255 == read.len() { | 274 | let total_chunks = if completed_chunks * 255 == read.len() { |
| 239 | completed_chunks | 275 | completed_chunks |
| @@ -254,7 +290,7 @@ impl<'d, M: Mode> I2c<'d, M> { | |||
| 254 | 290 | ||
| 255 | for (number, chunk) in read.chunks_mut(255).enumerate() { | 291 | for (number, chunk) in read.chunks_mut(255).enumerate() { |
| 256 | if number != 0 { | 292 | if number != 0 { |
| 257 | Self::master_continue(self.info, chunk.len(), number != last_chunk_idx, timeout)?; | 293 | Self::reload(self.info, chunk.len(), number != last_chunk_idx, timeout)?; |
| 258 | } | 294 | } |
| 259 | 295 | ||
| 260 | for byte in chunk { | 296 | for byte in chunk { |
| @@ -267,7 +303,13 @@ impl<'d, M: Mode> I2c<'d, M> { | |||
| 267 | Ok(()) | 303 | Ok(()) |
| 268 | } | 304 | } |
| 269 | 305 | ||
| 270 | fn write_internal(&mut self, address: u8, write: &[u8], send_stop: bool, timeout: Timeout) -> Result<(), Error> { | 306 | fn write_internal( |
| 307 | &mut self, | ||
| 308 | address: Address, | ||
| 309 | write: &[u8], | ||
| 310 | send_stop: bool, | ||
| 311 | timeout: Timeout, | ||
| 312 | ) -> Result<(), Error> { | ||
| 271 | let completed_chunks = write.len() / 255; | 313 | let completed_chunks = write.len() / 255; |
| 272 | let total_chunks = if completed_chunks * 255 == write.len() { | 314 | let total_chunks = if completed_chunks * 255 == write.len() { |
| 273 | completed_chunks | 315 | completed_chunks |
| @@ -295,7 +337,7 @@ impl<'d, M: Mode> I2c<'d, M> { | |||
| 295 | 337 | ||
| 296 | for (number, chunk) in write.chunks(255).enumerate() { | 338 | for (number, chunk) in write.chunks(255).enumerate() { |
| 297 | if number != 0 { | 339 | if number != 0 { |
| 298 | Self::master_continue(self.info, chunk.len(), number != last_chunk_idx, timeout)?; | 340 | Self::reload(self.info, chunk.len(), number != last_chunk_idx, timeout)?; |
| 299 | } | 341 | } |
| 300 | 342 | ||
| 301 | for byte in chunk { | 343 | for byte in chunk { |
| @@ -325,20 +367,20 @@ impl<'d, M: Mode> I2c<'d, M> { | |||
| 325 | 367 | ||
| 326 | /// Blocking read. | 368 | /// Blocking read. |
| 327 | pub fn blocking_read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Error> { | 369 | pub fn blocking_read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Error> { |
| 328 | self.read_internal(address, read, false, self.timeout()) | 370 | self.read_internal(address.into(), read, false, self.timeout()) |
| 329 | // Automatic Stop | 371 | // Automatic Stop |
| 330 | } | 372 | } |
| 331 | 373 | ||
| 332 | /// Blocking write. | 374 | /// Blocking write. |
| 333 | pub fn blocking_write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> { | 375 | pub fn blocking_write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> { |
| 334 | self.write_internal(address, write, true, self.timeout()) | 376 | self.write_internal(address.into(), write, true, self.timeout()) |
| 335 | } | 377 | } |
| 336 | 378 | ||
| 337 | /// Blocking write, restart, read. | 379 | /// Blocking write, restart, read. |
| 338 | pub fn blocking_write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> { | 380 | pub fn blocking_write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> { |
| 339 | let timeout = self.timeout(); | 381 | let timeout = self.timeout(); |
| 340 | self.write_internal(address, write, false, timeout)?; | 382 | self.write_internal(address.into(), write, false, timeout)?; |
| 341 | self.read_internal(address, read, true, timeout) | 383 | self.read_internal(address.into(), read, true, timeout) |
| 342 | // Automatic Stop | 384 | // Automatic Stop |
| 343 | } | 385 | } |
| 344 | 386 | ||
| @@ -368,7 +410,7 @@ impl<'d, M: Mode> I2c<'d, M> { | |||
| 368 | 410 | ||
| 369 | if let Err(err) = Self::master_write( | 411 | if let Err(err) = Self::master_write( |
| 370 | self.info, | 412 | self.info, |
| 371 | address, | 413 | address.into(), |
| 372 | first_length.min(255), | 414 | first_length.min(255), |
| 373 | Stop::Software, | 415 | Stop::Software, |
| 374 | (first_length > 255) || (last_slice_index != 0), | 416 | (first_length > 255) || (last_slice_index != 0), |
| @@ -389,7 +431,7 @@ impl<'d, M: Mode> I2c<'d, M> { | |||
| 389 | let last_chunk_idx = total_chunks.saturating_sub(1); | 431 | let last_chunk_idx = total_chunks.saturating_sub(1); |
| 390 | 432 | ||
| 391 | if idx != 0 { | 433 | if idx != 0 { |
| 392 | if let Err(err) = Self::master_continue( | 434 | if let Err(err) = Self::reload( |
| 393 | self.info, | 435 | self.info, |
| 394 | slice_len.min(255), | 436 | slice_len.min(255), |
| 395 | (idx != last_slice_index) || (slice_len > 255), | 437 | (idx != last_slice_index) || (slice_len > 255), |
| @@ -402,7 +444,7 @@ impl<'d, M: Mode> I2c<'d, M> { | |||
| 402 | 444 | ||
| 403 | for (number, chunk) in slice.chunks(255).enumerate() { | 445 | for (number, chunk) in slice.chunks(255).enumerate() { |
| 404 | if number != 0 { | 446 | if number != 0 { |
| 405 | if let Err(err) = Self::master_continue( | 447 | if let Err(err) = Self::reload( |
| 406 | self.info, | 448 | self.info, |
| 407 | chunk.len(), | 449 | chunk.len(), |
| 408 | (number != last_chunk_idx) || (idx != last_slice_index), | 450 | (number != last_chunk_idx) || (idx != last_slice_index), |
| @@ -435,10 +477,10 @@ impl<'d, M: Mode> I2c<'d, M> { | |||
| 435 | } | 477 | } |
| 436 | } | 478 | } |
| 437 | 479 | ||
| 438 | impl<'d> I2c<'d, Async> { | 480 | impl<'d, IM: MasterMode> I2c<'d, Async, IM> { |
| 439 | async fn write_dma_internal( | 481 | async fn write_dma_internal( |
| 440 | &mut self, | 482 | &mut self, |
| 441 | address: u8, | 483 | address: Address, |
| 442 | write: &[u8], | 484 | write: &[u8], |
| 443 | first_slice: bool, | 485 | first_slice: bool, |
| 444 | last_slice: bool, | 486 | last_slice: bool, |
| @@ -512,7 +554,7 @@ impl<'d> I2c<'d, Async> { | |||
| 512 | timeout, | 554 | timeout, |
| 513 | )?; | 555 | )?; |
| 514 | } else { | 556 | } else { |
| 515 | Self::master_continue(self.info, total_len.min(255), (total_len > 255) || !last_slice, timeout)?; | 557 | Self::reload(self.info, total_len.min(255), (total_len > 255) || !last_slice, timeout)?; |
| 516 | self.info.regs.cr1().modify(|w| w.set_tcie(true)); | 558 | self.info.regs.cr1().modify(|w| w.set_tcie(true)); |
| 517 | } | 559 | } |
| 518 | } else if !(isr.tcr() || isr.tc()) { | 560 | } else if !(isr.tcr() || isr.tc()) { |
| @@ -523,7 +565,7 @@ impl<'d> I2c<'d, Async> { | |||
| 523 | } else { | 565 | } else { |
| 524 | let last_piece = (remaining_len <= 255) && last_slice; | 566 | let last_piece = (remaining_len <= 255) && last_slice; |
| 525 | 567 | ||
| 526 | if let Err(e) = Self::master_continue(self.info, remaining_len.min(255), !last_piece, timeout) { | 568 | if let Err(e) = Self::reload(self.info, remaining_len.min(255), !last_piece, timeout) { |
| 527 | return Poll::Ready(Err(e)); | 569 | return Poll::Ready(Err(e)); |
| 528 | } | 570 | } |
| 529 | self.info.regs.cr1().modify(|w| w.set_tcie(true)); | 571 | self.info.regs.cr1().modify(|w| w.set_tcie(true)); |
| @@ -551,7 +593,7 @@ impl<'d> I2c<'d, Async> { | |||
| 551 | 593 | ||
| 552 | async fn read_dma_internal( | 594 | async fn read_dma_internal( |
| 553 | &mut self, | 595 | &mut self, |
| 554 | address: u8, | 596 | address: Address, |
| 555 | buffer: &mut [u8], | 597 | buffer: &mut [u8], |
| 556 | restart: bool, | 598 | restart: bool, |
| 557 | timeout: Timeout, | 599 | timeout: Timeout, |
| @@ -626,7 +668,7 @@ impl<'d> I2c<'d, Async> { | |||
| 626 | } else { | 668 | } else { |
| 627 | let last_piece = remaining_len <= 255; | 669 | let last_piece = remaining_len <= 255; |
| 628 | 670 | ||
| 629 | if let Err(e) = Self::master_continue(self.info, remaining_len.min(255), !last_piece, timeout) { | 671 | if let Err(e) = Self::reload(self.info, remaining_len.min(255), !last_piece, timeout) { |
| 630 | return Poll::Ready(Err(e)); | 672 | return Poll::Ready(Err(e)); |
| 631 | } | 673 | } |
| 632 | // Return here if we are on last chunk, | 674 | // Return here if we are on last chunk, |
| @@ -647,7 +689,6 @@ impl<'d> I2c<'d, Async> { | |||
| 647 | 689 | ||
| 648 | Ok(()) | 690 | Ok(()) |
| 649 | } | 691 | } |
| 650 | |||
| 651 | // ========================= | 692 | // ========================= |
| 652 | // Async public API | 693 | // Async public API |
| 653 | 694 | ||
| @@ -655,10 +696,10 @@ impl<'d> I2c<'d, Async> { | |||
| 655 | pub async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> { | 696 | pub async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> { |
| 656 | let timeout = self.timeout(); | 697 | let timeout = self.timeout(); |
| 657 | if write.is_empty() { | 698 | if write.is_empty() { |
| 658 | self.write_internal(address, write, true, timeout) | 699 | self.write_internal(address.into(), write, true, timeout) |
| 659 | } else { | 700 | } else { |
| 660 | timeout | 701 | timeout |
| 661 | .with(self.write_dma_internal(address, write, true, true, true, timeout)) | 702 | .with(self.write_dma_internal(address.into(), write, true, true, true, timeout)) |
| 662 | .await | 703 | .await |
| 663 | } | 704 | } |
| 664 | } | 705 | } |
| @@ -666,7 +707,7 @@ impl<'d> I2c<'d, Async> { | |||
| 666 | /// Write multiple buffers. | 707 | /// Write multiple buffers. |
| 667 | /// | 708 | /// |
| 668 | /// The buffers are concatenated in a single write transaction. | 709 | /// The buffers are concatenated in a single write transaction. |
| 669 | pub async fn write_vectored(&mut self, address: u8, write: &[&[u8]]) -> Result<(), Error> { | 710 | pub async fn write_vectored(&mut self, address: Address, write: &[&[u8]]) -> Result<(), Error> { |
| 670 | let timeout = self.timeout(); | 711 | let timeout = self.timeout(); |
| 671 | 712 | ||
| 672 | if write.is_empty() { | 713 | if write.is_empty() { |
| @@ -693,9 +734,9 @@ impl<'d> I2c<'d, Async> { | |||
| 693 | let timeout = self.timeout(); | 734 | let timeout = self.timeout(); |
| 694 | 735 | ||
| 695 | if buffer.is_empty() { | 736 | if buffer.is_empty() { |
| 696 | self.read_internal(address, buffer, false, timeout) | 737 | self.read_internal(address.into(), buffer, false, timeout) |
| 697 | } else { | 738 | } else { |
| 698 | let fut = self.read_dma_internal(address, buffer, false, timeout); | 739 | let fut = self.read_dma_internal(address.into(), buffer, false, timeout); |
| 699 | timeout.with(fut).await | 740 | timeout.with(fut).await |
| 700 | } | 741 | } |
| 701 | } | 742 | } |
| @@ -705,16 +746,16 @@ impl<'d> I2c<'d, Async> { | |||
| 705 | let timeout = self.timeout(); | 746 | let timeout = self.timeout(); |
| 706 | 747 | ||
| 707 | if write.is_empty() { | 748 | if write.is_empty() { |
| 708 | self.write_internal(address, write, false, timeout)?; | 749 | self.write_internal(address.into(), write, false, timeout)?; |
| 709 | } else { | 750 | } else { |
| 710 | let fut = self.write_dma_internal(address, write, true, true, false, timeout); | 751 | let fut = self.write_dma_internal(address.into(), write, true, true, false, timeout); |
| 711 | timeout.with(fut).await?; | 752 | timeout.with(fut).await?; |
| 712 | } | 753 | } |
| 713 | 754 | ||
| 714 | if read.is_empty() { | 755 | if read.is_empty() { |
| 715 | self.read_internal(address, read, true, timeout)?; | 756 | self.read_internal(address.into(), read, true, timeout)?; |
| 716 | } else { | 757 | } else { |
| 717 | let fut = self.read_dma_internal(address, read, true, timeout); | 758 | let fut = self.read_dma_internal(address.into(), read, true, timeout); |
| 718 | timeout.with(fut).await?; | 759 | timeout.with(fut).await?; |
| 719 | } | 760 | } |
| 720 | 761 | ||
| @@ -733,6 +774,360 @@ impl<'d> I2c<'d, Async> { | |||
| 733 | } | 774 | } |
| 734 | } | 775 | } |
| 735 | 776 | ||
| 777 | impl<'d, M: Mode> I2c<'d, M, Master> { | ||
| 778 | /// Configure the I2C driver for slave operations, allowing for the driver to be used as a slave and a master (multimaster) | ||
| 779 | pub fn into_slave_multimaster(mut self, slave_addr_config: SlaveAddrConfig) -> I2c<'d, M, MultiMaster> { | ||
| 780 | let mut slave = I2c { | ||
| 781 | info: self.info, | ||
| 782 | state: self.state, | ||
| 783 | kernel_clock: self.kernel_clock, | ||
| 784 | tx_dma: self.tx_dma.take(), | ||
| 785 | rx_dma: self.rx_dma.take(), | ||
| 786 | #[cfg(feature = "time")] | ||
| 787 | timeout: self.timeout, | ||
| 788 | _phantom: PhantomData, | ||
| 789 | _phantom2: PhantomData, | ||
| 790 | _drop_guard: self._drop_guard, | ||
| 791 | }; | ||
| 792 | slave.init_slave(slave_addr_config); | ||
| 793 | slave | ||
| 794 | } | ||
| 795 | } | ||
| 796 | |||
| 797 | impl<'d, M: Mode> I2c<'d, M, MultiMaster> { | ||
| 798 | pub(crate) fn init_slave(&mut self, config: SlaveAddrConfig) { | ||
| 799 | self.info.regs.cr1().modify(|reg| { | ||
| 800 | reg.set_pe(false); | ||
| 801 | }); | ||
| 802 | |||
| 803 | self.info.regs.cr1().modify(|reg| { | ||
| 804 | reg.set_nostretch(false); | ||
| 805 | reg.set_gcen(config.general_call); | ||
| 806 | reg.set_sbc(true); | ||
| 807 | reg.set_pe(true); | ||
| 808 | }); | ||
| 809 | |||
| 810 | self.reconfigure_addresses(config.addr); | ||
| 811 | } | ||
| 812 | |||
| 813 | /// Configure the slave address. | ||
| 814 | pub fn reconfigure_addresses(&mut self, addresses: OwnAddresses) { | ||
| 815 | match addresses { | ||
| 816 | OwnAddresses::OA1(oa1) => self.configure_oa1(oa1), | ||
| 817 | OwnAddresses::OA2(oa2) => self.configure_oa2(oa2), | ||
| 818 | OwnAddresses::Both { oa1, oa2 } => { | ||
| 819 | self.configure_oa1(oa1); | ||
| 820 | self.configure_oa2(oa2); | ||
| 821 | } | ||
| 822 | } | ||
| 823 | } | ||
| 824 | |||
| 825 | fn configure_oa1(&mut self, oa1: Address) { | ||
| 826 | match oa1 { | ||
| 827 | Address::SevenBit(addr) => self.info.regs.oar1().write(|reg| { | ||
| 828 | reg.set_oa1en(false); | ||
| 829 | reg.set_oa1((addr << 1) as u16); | ||
| 830 | reg.set_oa1mode(Addmode::BIT7); | ||
| 831 | reg.set_oa1en(true); | ||
| 832 | }), | ||
| 833 | Address::TenBit(addr) => self.info.regs.oar1().write(|reg| { | ||
| 834 | reg.set_oa1en(false); | ||
| 835 | reg.set_oa1(addr); | ||
| 836 | reg.set_oa1mode(Addmode::BIT10); | ||
| 837 | reg.set_oa1en(true); | ||
| 838 | }), | ||
| 839 | } | ||
| 840 | } | ||
| 841 | |||
| 842 | fn configure_oa2(&mut self, oa2: OA2) { | ||
| 843 | self.info.regs.oar2().write(|reg| { | ||
| 844 | reg.set_oa2en(false); | ||
| 845 | reg.set_oa2msk(oa2.mask.into()); | ||
| 846 | reg.set_oa2(oa2.addr << 1); | ||
| 847 | reg.set_oa2en(true); | ||
| 848 | }); | ||
| 849 | } | ||
| 850 | |||
| 851 | fn determine_matched_address(&self) -> Result<Address, Error> { | ||
| 852 | let matched = self.info.regs.isr().read().addcode(); | ||
| 853 | |||
| 854 | if matched >> 3 == 0b11110 { | ||
| 855 | // is 10-bit address and we need to get the other 8 bits from the rxdr | ||
| 856 | // we do this by doing a blocking read of 1 byte | ||
| 857 | let mut buffer = [0]; | ||
| 858 | self.slave_read_internal(&mut buffer, self.timeout())?; | ||
| 859 | Ok(Address::TenBit((matched as u16) << 6 | buffer[0] as u16)) | ||
| 860 | } else { | ||
| 861 | Ok(Address::SevenBit(matched)) | ||
| 862 | } | ||
| 863 | } | ||
| 864 | } | ||
| 865 | |||
| 866 | impl<'d, M: Mode> I2c<'d, M, MultiMaster> { | ||
| 867 | /// # Safety | ||
| 868 | /// This function will clear the address flag which will stop the clock stretching. | ||
| 869 | /// This should only be done after the dma transfer has been set up. | ||
| 870 | fn slave_start(info: &'static Info, length: usize, reload: bool) { | ||
| 871 | assert!(length < 256); | ||
| 872 | |||
| 873 | let reload = if reload { | ||
| 874 | i2c::vals::Reload::NOT_COMPLETED | ||
| 875 | } else { | ||
| 876 | i2c::vals::Reload::COMPLETED | ||
| 877 | }; | ||
| 878 | |||
| 879 | info.regs.cr2().modify(|w| { | ||
| 880 | w.set_nbytes(length as u8); | ||
| 881 | w.set_reload(reload); | ||
| 882 | }); | ||
| 883 | |||
| 884 | // clear the address flag, will stop the clock stretching. | ||
| 885 | // this should only be done after the dma transfer has been set up. | ||
| 886 | info.regs.icr().modify(|reg| reg.set_addrcf(true)); | ||
| 887 | } | ||
| 888 | |||
| 889 | // A blocking read operation | ||
| 890 | fn slave_read_internal(&self, read: &mut [u8], timeout: Timeout) -> Result<(), Error> { | ||
| 891 | let completed_chunks = read.len() / 255; | ||
| 892 | let total_chunks = if completed_chunks * 255 == read.len() { | ||
| 893 | completed_chunks | ||
| 894 | } else { | ||
| 895 | completed_chunks + 1 | ||
| 896 | }; | ||
| 897 | let last_chunk_idx = total_chunks.saturating_sub(1); | ||
| 898 | for (number, chunk) in read.chunks_mut(255).enumerate() { | ||
| 899 | if number != 0 { | ||
| 900 | Self::reload(self.info, chunk.len(), number != last_chunk_idx, timeout)?; | ||
| 901 | } | ||
| 902 | |||
| 903 | for byte in chunk { | ||
| 904 | // Wait until we have received something | ||
| 905 | self.wait_rxne(timeout)?; | ||
| 906 | |||
| 907 | *byte = self.info.regs.rxdr().read().rxdata(); | ||
| 908 | } | ||
| 909 | } | ||
| 910 | |||
| 911 | Ok(()) | ||
| 912 | } | ||
| 913 | |||
| 914 | // A blocking write operation | ||
| 915 | fn slave_write_internal(&mut self, write: &[u8], timeout: Timeout) -> Result<(), Error> { | ||
| 916 | let completed_chunks = write.len() / 255; | ||
| 917 | let total_chunks = if completed_chunks * 255 == write.len() { | ||
| 918 | completed_chunks | ||
| 919 | } else { | ||
| 920 | completed_chunks + 1 | ||
| 921 | }; | ||
| 922 | let last_chunk_idx = total_chunks.saturating_sub(1); | ||
| 923 | |||
| 924 | for (number, chunk) in write.chunks(255).enumerate() { | ||
| 925 | if number != 0 { | ||
| 926 | Self::reload(self.info, chunk.len(), number != last_chunk_idx, timeout)?; | ||
| 927 | } | ||
| 928 | |||
| 929 | for byte in chunk { | ||
| 930 | // Wait until we are allowed to send data | ||
| 931 | // (START has been ACKed or last byte when | ||
| 932 | // through) | ||
| 933 | self.wait_txe(timeout)?; | ||
| 934 | |||
| 935 | self.info.regs.txdr().write(|w| w.set_txdata(*byte)); | ||
| 936 | } | ||
| 937 | } | ||
| 938 | Ok(()) | ||
| 939 | } | ||
| 940 | |||
| 941 | /// Listen for incoming I2C messages. | ||
| 942 | /// | ||
| 943 | /// The listen method is an asynchronous method but it does not require DMA to be asynchronous. | ||
| 944 | pub async fn listen(&mut self) -> Result<SlaveCommand, Error> { | ||
| 945 | let state = self.state; | ||
| 946 | self.info.regs.cr1().modify(|reg| { | ||
| 947 | reg.set_addrie(true); | ||
| 948 | }); | ||
| 949 | |||
| 950 | poll_fn(|cx| { | ||
| 951 | state.waker.register(cx.waker()); | ||
| 952 | let isr = self.info.regs.isr().read(); | ||
| 953 | if !isr.addr() { | ||
| 954 | Poll::Pending | ||
| 955 | } else { | ||
| 956 | // we do not clear the address flag here as it will be cleared by the dma read/write | ||
| 957 | // if we clear it here the clock stretching will stop and the master will read in data before the slave is ready to send it | ||
| 958 | match isr.dir() { | ||
| 959 | i2c::vals::Dir::WRITE => Poll::Ready(Ok(SlaveCommand { | ||
| 960 | kind: SlaveCommandKind::Write, | ||
| 961 | address: self.determine_matched_address()?, | ||
| 962 | })), | ||
| 963 | i2c::vals::Dir::READ => Poll::Ready(Ok(SlaveCommand { | ||
| 964 | kind: SlaveCommandKind::Read, | ||
| 965 | address: self.determine_matched_address()?, | ||
| 966 | })), | ||
| 967 | } | ||
| 968 | } | ||
| 969 | }) | ||
| 970 | .await | ||
| 971 | } | ||
| 972 | |||
| 973 | /// Respond to a write command. | ||
| 974 | pub fn blocking_respond_to_write(&self, read: &mut [u8]) -> Result<(), Error> { | ||
| 975 | let timeout = self.timeout(); | ||
| 976 | self.slave_read_internal(read, timeout) | ||
| 977 | } | ||
| 978 | |||
| 979 | /// Respond to a read command. | ||
| 980 | pub fn blocking_respond_to_read(&mut self, write: &[u8]) -> Result<(), Error> { | ||
| 981 | let timeout = self.timeout(); | ||
| 982 | self.slave_write_internal(write, timeout) | ||
| 983 | } | ||
| 984 | } | ||
| 985 | |||
| 986 | impl<'d> I2c<'d, Async, MultiMaster> { | ||
| 987 | /// Respond to a write command. | ||
| 988 | /// | ||
| 989 | /// Returns the total number of bytes received. | ||
| 990 | pub async fn respond_to_write(&mut self, buffer: &mut [u8]) -> Result<usize, Error> { | ||
| 991 | let timeout = self.timeout(); | ||
| 992 | timeout.with(self.read_dma_internal_slave(buffer, timeout)).await | ||
| 993 | } | ||
| 994 | |||
| 995 | /// Respond to a read request from an I2C master. | ||
| 996 | pub async fn respond_to_read(&mut self, write: &[u8]) -> Result<SendStatus, Error> { | ||
| 997 | let timeout = self.timeout(); | ||
| 998 | timeout.with(self.write_dma_internal_slave(write, timeout)).await | ||
| 999 | } | ||
| 1000 | |||
| 1001 | // for data reception in slave mode | ||
| 1002 | // | ||
| 1003 | // returns the total number of bytes received | ||
| 1004 | async fn read_dma_internal_slave(&mut self, buffer: &mut [u8], timeout: Timeout) -> Result<usize, Error> { | ||
| 1005 | let total_len = buffer.len(); | ||
| 1006 | let mut remaining_len = total_len; | ||
| 1007 | |||
| 1008 | let regs = self.info.regs; | ||
| 1009 | |||
| 1010 | let dma_transfer = unsafe { | ||
| 1011 | regs.cr1().modify(|w| { | ||
| 1012 | w.set_rxdmaen(true); | ||
| 1013 | w.set_stopie(true); | ||
| 1014 | w.set_tcie(true); | ||
| 1015 | }); | ||
| 1016 | let src = regs.rxdr().as_ptr() as *mut u8; | ||
| 1017 | |||
| 1018 | self.rx_dma.as_mut().unwrap().read(src, buffer, Default::default()) | ||
| 1019 | }; | ||
| 1020 | |||
| 1021 | let state = self.state; | ||
| 1022 | |||
| 1023 | let on_drop = OnDrop::new(|| { | ||
| 1024 | regs.cr1().modify(|w| { | ||
| 1025 | w.set_rxdmaen(false); | ||
| 1026 | w.set_stopie(false); | ||
| 1027 | w.set_tcie(false); | ||
| 1028 | }) | ||
| 1029 | }); | ||
| 1030 | |||
| 1031 | let total_received = poll_fn(|cx| { | ||
| 1032 | state.waker.register(cx.waker()); | ||
| 1033 | |||
| 1034 | let isr = regs.isr().read(); | ||
| 1035 | |||
| 1036 | if remaining_len == total_len { | ||
| 1037 | Self::slave_start(self.info, total_len.min(255), total_len > 255); | ||
| 1038 | remaining_len = remaining_len.saturating_sub(255); | ||
| 1039 | Poll::Pending | ||
| 1040 | } else if isr.tcr() { | ||
| 1041 | let is_last_slice = remaining_len <= 255; | ||
| 1042 | if let Err(e) = Self::reload(self.info, remaining_len.min(255), !is_last_slice, timeout) { | ||
| 1043 | return Poll::Ready(Err(e)); | ||
| 1044 | } | ||
| 1045 | remaining_len = remaining_len.saturating_sub(255); | ||
| 1046 | regs.cr1().modify(|w| w.set_tcie(true)); | ||
| 1047 | Poll::Pending | ||
| 1048 | } else if isr.stopf() { | ||
| 1049 | regs.icr().write(|reg| reg.set_stopcf(true)); | ||
| 1050 | let poll = Poll::Ready(Ok(total_len - remaining_len)); | ||
| 1051 | poll | ||
| 1052 | } else { | ||
| 1053 | Poll::Pending | ||
| 1054 | } | ||
| 1055 | }) | ||
| 1056 | .await?; | ||
| 1057 | |||
| 1058 | dma_transfer.await; | ||
| 1059 | |||
| 1060 | drop(on_drop); | ||
| 1061 | |||
| 1062 | Ok(total_received) | ||
| 1063 | } | ||
| 1064 | |||
| 1065 | async fn write_dma_internal_slave(&mut self, buffer: &[u8], timeout: Timeout) -> Result<SendStatus, Error> { | ||
| 1066 | let total_len = buffer.len(); | ||
| 1067 | let mut remaining_len = total_len; | ||
| 1068 | |||
| 1069 | let mut dma_transfer = unsafe { | ||
| 1070 | let regs = self.info.regs; | ||
| 1071 | regs.cr1().modify(|w| { | ||
| 1072 | w.set_txdmaen(true); | ||
| 1073 | w.set_stopie(true); | ||
| 1074 | w.set_tcie(true); | ||
| 1075 | }); | ||
| 1076 | let dst = regs.txdr().as_ptr() as *mut u8; | ||
| 1077 | |||
| 1078 | self.tx_dma.as_mut().unwrap().write(buffer, dst, Default::default()) | ||
| 1079 | }; | ||
| 1080 | |||
| 1081 | let on_drop = OnDrop::new(|| { | ||
| 1082 | let regs = self.info.regs; | ||
| 1083 | regs.cr1().modify(|w| { | ||
| 1084 | w.set_txdmaen(false); | ||
| 1085 | w.set_stopie(false); | ||
| 1086 | w.set_tcie(false); | ||
| 1087 | }) | ||
| 1088 | }); | ||
| 1089 | |||
| 1090 | let state = self.state; | ||
| 1091 | |||
| 1092 | let size = poll_fn(|cx| { | ||
| 1093 | state.waker.register(cx.waker()); | ||
| 1094 | |||
| 1095 | let isr = self.info.regs.isr().read(); | ||
| 1096 | |||
| 1097 | if remaining_len == total_len { | ||
| 1098 | Self::slave_start(self.info, total_len.min(255), total_len > 255); | ||
| 1099 | remaining_len = remaining_len.saturating_sub(255); | ||
| 1100 | Poll::Pending | ||
| 1101 | } else if isr.tcr() { | ||
| 1102 | let is_last_slice = remaining_len <= 255; | ||
| 1103 | if let Err(e) = Self::reload(self.info, remaining_len.min(255), !is_last_slice, timeout) { | ||
| 1104 | return Poll::Ready(Err(e)); | ||
| 1105 | } | ||
| 1106 | remaining_len = remaining_len.saturating_sub(255); | ||
| 1107 | self.info.regs.cr1().modify(|w| w.set_tcie(true)); | ||
| 1108 | Poll::Pending | ||
| 1109 | } else if isr.stopf() { | ||
| 1110 | self.info.regs.icr().write(|reg| reg.set_stopcf(true)); | ||
| 1111 | if remaining_len > 0 { | ||
| 1112 | dma_transfer.request_stop(); | ||
| 1113 | Poll::Ready(Ok(SendStatus::LeftoverBytes(remaining_len as usize))) | ||
| 1114 | } else { | ||
| 1115 | Poll::Ready(Ok(SendStatus::Done)) | ||
| 1116 | } | ||
| 1117 | } else { | ||
| 1118 | Poll::Pending | ||
| 1119 | } | ||
| 1120 | }) | ||
| 1121 | .await?; | ||
| 1122 | |||
| 1123 | dma_transfer.await; | ||
| 1124 | |||
| 1125 | drop(on_drop); | ||
| 1126 | |||
| 1127 | Ok(size) | ||
| 1128 | } | ||
| 1129 | } | ||
| 1130 | |||
| 736 | /// I2C Stop Configuration | 1131 | /// I2C Stop Configuration |
| 737 | /// | 1132 | /// |
| 738 | /// Peripheral options for generating the STOP condition | 1133 | /// Peripheral options for generating the STOP condition |
| @@ -857,7 +1252,7 @@ impl Timings { | |||
| 857 | } | 1252 | } |
| 858 | } | 1253 | } |
| 859 | 1254 | ||
| 860 | impl<'d, M: Mode> SetConfig for I2c<'d, M> { | 1255 | impl<'d, M: Mode> SetConfig for I2c<'d, M, Master> { |
| 861 | type Config = Hertz; | 1256 | type Config = Hertz; |
| 862 | type ConfigError = (); | 1257 | type ConfigError = (); |
| 863 | fn set_config(&mut self, config: &Self::Config) -> Result<(), ()> { | 1258 | fn set_config(&mut self, config: &Self::Config) -> Result<(), ()> { |
| @@ -882,3 +1277,21 @@ impl<'d, M: Mode> SetConfig for I2c<'d, M> { | |||
| 882 | Ok(()) | 1277 | Ok(()) |
| 883 | } | 1278 | } |
| 884 | } | 1279 | } |
| 1280 | |||
| 1281 | impl<'d, M: Mode> SetConfig for I2c<'d, M, MultiMaster> { | ||
| 1282 | type Config = (Hertz, SlaveAddrConfig); | ||
| 1283 | type ConfigError = (); | ||
| 1284 | fn set_config(&mut self, (config, addr_config): &Self::Config) -> Result<(), ()> { | ||
| 1285 | let timings = Timings::new(self.kernel_clock, *config); | ||
| 1286 | self.info.regs.timingr().write(|reg| { | ||
| 1287 | reg.set_presc(timings.prescale); | ||
| 1288 | reg.set_scll(timings.scll); | ||
| 1289 | reg.set_sclh(timings.sclh); | ||
| 1290 | reg.set_sdadel(timings.sdadel); | ||
| 1291 | reg.set_scldel(timings.scldel); | ||
| 1292 | }); | ||
| 1293 | self.init_slave(*addr_config); | ||
| 1294 | |||
| 1295 | Ok(()) | ||
| 1296 | } | ||
| 1297 | } | ||
