embassy_stm32/i2c/
config.rs

1#[cfg(gpio_v2)]
2use crate::gpio::Pull;
3use crate::gpio::{AfType, OutputType, Speed};
4use crate::time::Hertz;
5
6#[repr(u8)]
7#[derive(Copy, Clone)]
8#[cfg_attr(feature = "defmt", derive(defmt::Format))]
9/// Bits of the I2C OA2 register to mask out.
10pub enum AddrMask {
11    /// No mask
12    NOMASK,
13    /// OA2\[1\] is masked and don’t care. Only OA2\[7:2\] are compared.
14    MASK1,
15    /// OA2\[2:1\] are masked and don’t care. Only OA2\[7:3\] are compared.
16    MASK2,
17    /// OA2\[3:1\] are masked and don’t care. Only OA2\[7:4\] are compared.
18    MASK3,
19    /// OA2\[4:1\] are masked and don’t care. Only OA2\[7:5\] are compared.
20    MASK4,
21    /// OA2\[5:1\] are masked and don’t care. Only OA2\[7:6\] are compared.
22    MASK5,
23    /// OA2\[6:1\] are masked and don’t care. Only OA2\[7:6\] are compared.
24    MASK6,
25    /// OA2\[7:1\] are masked and don’t care. No comparison is done, and all (except reserved) 7-bit received addresses are acknowledged
26    MASK7,
27}
28
29#[derive(Debug, Copy, Clone, PartialEq, Eq)]
30#[cfg_attr(feature = "defmt", derive(defmt::Format))]
31/// An I2C address. Either 7 or 10 bit.
32pub enum Address {
33    /// A 7 bit address
34    SevenBit(u8),
35    /// A 10 bit address.
36    ///
37    /// When using an address to configure the Own Address, only the OA1 register can be set to a 10-bit address.
38    TenBit(u16),
39}
40impl From<u8> for Address {
41    fn from(value: u8) -> Self {
42        Address::SevenBit(value)
43    }
44}
45impl From<u16> for Address {
46    fn from(value: u16) -> Self {
47        assert!(value < 0x400, "Ten bit address must be less than 0x400");
48        Address::TenBit(value)
49    }
50}
51impl Address {
52    /// Get the inner address as a u16.
53    ///
54    /// For 7 bit addresses, the u8 that was used to store the address is returned as a u16.
55    pub fn addr(&self) -> u16 {
56        match self {
57            Address::SevenBit(addr) => *addr as u16,
58            Address::TenBit(addr) => *addr,
59        }
60    }
61}
62
63#[derive(Copy, Clone)]
64#[cfg_attr(feature = "defmt", derive(defmt::Format))]
65/// The second Own Address register.
66pub struct OA2 {
67    /// The address.
68    pub addr: u8,
69    /// The bit mask that will affect how the own address 2 register is compared.
70    pub mask: AddrMask,
71}
72
73#[derive(Copy, Clone)]
74#[cfg_attr(feature = "defmt", derive(defmt::Format))]
75/// The Own Address(es) of the I2C peripheral.
76pub enum OwnAddresses {
77    /// Configuration for only the OA1 register.
78    OA1(Address),
79    /// Configuration for only the OA2 register.
80    OA2(OA2),
81    /// Configuration for both the OA1 and OA2 registers.
82    Both {
83        /// The [Address] for the OA1 register.
84        oa1: Address,
85        /// The [OA2] configuration.
86        oa2: OA2,
87    },
88}
89
90/// Slave Configuration
91#[derive(Copy, Clone)]
92#[cfg_attr(feature = "defmt", derive(defmt::Format))]
93pub struct SlaveAddrConfig {
94    /// Target Address(es)
95    pub addr: OwnAddresses,
96    /// Control if the peripheral should respond to the general call address
97    pub general_call: bool,
98}
99impl SlaveAddrConfig {
100    /// Create a new slave address configuration with only the OA1 register set in 7 bit mode and the general call disabled.
101    pub fn basic(addr: u8) -> Self {
102        Self {
103            addr: OwnAddresses::OA1(Address::SevenBit(addr)),
104            general_call: false,
105        }
106    }
107}
108
109/// I2C config
110#[non_exhaustive]
111#[derive(Copy, Clone)]
112pub struct Config {
113    /// Frequency
114    pub frequency: Hertz,
115    /// GPIO Speed
116    pub gpio_speed: Speed,
117    /// Enable internal pullup on SDA.
118    ///
119    /// Using external pullup resistors is recommended for I2C. If you do
120    /// have external pullups you should not enable this.
121    #[cfg(gpio_v2)]
122    pub sda_pullup: bool,
123    /// Enable internal pullup on SCL.
124    ///
125    /// Using external pullup resistors is recommended for I2C. If you do
126    /// have external pullups you should not enable this.
127    #[cfg(gpio_v2)]
128    pub scl_pullup: bool,
129    /// Timeout.
130    #[cfg(feature = "time")]
131    pub timeout: embassy_time::Duration,
132}
133
134impl Default for Config {
135    fn default() -> Self {
136        Self {
137            frequency: Hertz::khz(100),
138            gpio_speed: Speed::Medium,
139            #[cfg(gpio_v2)]
140            sda_pullup: false,
141            #[cfg(gpio_v2)]
142            scl_pullup: false,
143            #[cfg(feature = "time")]
144            timeout: embassy_time::Duration::from_millis(1000),
145        }
146    }
147}
148
149impl Config {
150    pub(super) fn scl_af(&self) -> AfType {
151        #[cfg(gpio_v1)]
152        return AfType::output(OutputType::OpenDrain, self.gpio_speed);
153        #[cfg(gpio_v2)]
154        return AfType::output_pull(
155            OutputType::OpenDrain,
156            self.gpio_speed,
157            match self.scl_pullup {
158                true => Pull::Up,
159                false => Pull::None,
160            },
161        );
162    }
163
164    pub(super) fn sda_af(&self) -> AfType {
165        #[cfg(gpio_v1)]
166        return AfType::output(OutputType::OpenDrain, self.gpio_speed);
167        #[cfg(gpio_v2)]
168        return AfType::output_pull(
169            OutputType::OpenDrain,
170            self.gpio_speed,
171            match self.sda_pullup {
172                true => Pull::Up,
173                false => Pull::None,
174            },
175        );
176    }
177}