Skip to content

Commit 56572ef

Browse files
authored
Merge pull request #2909 from jrmoulton/i2c-slave-new
stm32 i2c slave
2 parents 6186d11 + 4efb3b4 commit 56572ef

File tree

7 files changed

+867
-131
lines changed

7 files changed

+867
-131
lines changed

embassy-stm32/src/i2c/config.rs

Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
}

0 commit comments

Comments
 (0)