Skip to content

Commit c44ab96

Browse files
committed
Async slave changes for supporting i2c 10 bit addressing
1 parent 942e0c1 commit c44ab96

File tree

1 file changed

+129
-17
lines changed

1 file changed

+129
-17
lines changed

src/i2c/slave.rs

+129-17
Original file line numberDiff line numberDiff line change
@@ -8,42 +8,100 @@ use embassy_hal_internal::{into_ref, Peripheral};
88

99
use super::{
1010
Async, Blocking, Info, Instance, InterruptHandler, Mode, Result, SclPin, SdaPin, SlaveDma, TransferError,
11-
I2C_WAKERS,
11+
I2C_WAKERS, TEN_BIT_PREFIX,
1212
};
1313
use crate::interrupt::typelevel::Interrupt;
1414
use crate::pac::i2c0::stat::Slvstate;
1515
use crate::{dma, interrupt};
1616

17+
/// Address errors
18+
#[derive(Copy, Clone, Debug)]
19+
pub enum AddressError {
20+
/// Invalid address conversion
21+
InvalidConversion,
22+
}
23+
1724
/// I2C address type
1825
#[derive(Copy, Clone, Debug)]
19-
pub struct Address(u8);
26+
pub enum Address {
27+
/// 7-bit address
28+
SevenBit(u8),
29+
/// 10-bit address
30+
TenBit(u16),
31+
}
2032

2133
impl Address {
22-
/// Construct an address type
34+
/// Construct a 7-bit address type
2335
#[must_use]
2436
pub const fn new(addr: u8) -> Option<Self> {
2537
match addr {
26-
0x08..=0x77 => Some(Self(addr)),
38+
0x08..=0x77 => Some(Self::SevenBit(addr)),
39+
_ => None,
40+
}
41+
}
42+
43+
/// Construct a 10-bit address type
44+
#[must_use]
45+
pub const fn new_10bit(addr: u16) -> Option<Self> {
46+
match addr {
47+
0x080..=0x3FF => Some(Self::TenBit(addr)),
2748
_ => None,
2849
}
2950
}
3051

3152
/// interpret address as a read command
3253
#[must_use]
33-
pub fn read(&self) -> u8 {
34-
(self.0 << 1) | 1
54+
pub fn read(&self) -> [u8; 2] {
55+
match self {
56+
Self::SevenBit(addr) => [(addr << 1) | 1, 0],
57+
Self::TenBit(addr) => [(((addr >> 8) as u8) << 1) | TEN_BIT_PREFIX | 1, (addr & 0xFF) as u8],
58+
}
3559
}
3660

3761
/// interpret address as a write command
3862
#[must_use]
39-
pub fn write(&self) -> u8 {
40-
self.0 << 1
63+
pub fn write(&self) -> [u8; 2] {
64+
match self {
65+
Self::SevenBit(addr) => [addr << 1, 0],
66+
Self::TenBit(addr) => [(((addr >> 8) as u8) << 1) | TEN_BIT_PREFIX, (addr & 0xFF) as u8],
67+
}
68+
}
69+
}
70+
71+
impl TryFrom<Address> for u8 {
72+
type Error = AddressError;
73+
74+
fn try_from(value: Address) -> core::result::Result<Self, Self::Error> {
75+
match value {
76+
Address::SevenBit(addr) => Ok(addr),
77+
Address::TenBit(_) => Err(AddressError::InvalidConversion),
78+
}
4179
}
4280
}
4381

44-
impl From<Address> for u8 {
45-
fn from(value: Address) -> Self {
46-
value.0
82+
impl TryFrom<Address> for u16 {
83+
type Error = AddressError;
84+
85+
fn try_from(value: Address) -> core::result::Result<Self, Self::Error> {
86+
match value {
87+
Address::SevenBit(addr) => Ok(addr as u16),
88+
Address::TenBit(addr) => Ok(addr),
89+
}
90+
}
91+
}
92+
93+
#[derive(Copy, Clone, Debug)]
94+
struct TenBitAddressInfo {
95+
first_byte: u8,
96+
second_byte: u8,
97+
}
98+
99+
impl TenBitAddressInfo {
100+
fn new(address: u16) -> Self {
101+
Self {
102+
first_byte: (((address >> 8) as u8) << 1) | TEN_BIT_PREFIX,
103+
second_byte: (address & 0xFF) as u8,
104+
}
47105
}
48106
}
49107

@@ -64,7 +122,7 @@ pub enum Response {
64122
/// I2C transaction complete with this amount of bytes
65123
Complete(usize),
66124

67-
/// I2C transaction pending wutg this amount of bytes completed so far
125+
/// I2C transaction pending with this amount of bytes completed so far
68126
Pending(usize),
69127
}
70128

@@ -73,6 +131,7 @@ pub struct I2cSlave<'a, M: Mode> {
73131
info: Info,
74132
_phantom: PhantomData<M>,
75133
dma_ch: Option<dma::channel::Channel<'a>>,
134+
ten_bit_info: Option<TenBitAddressInfo>,
76135
}
77136

78137
impl<'a, M: Mode> I2cSlave<'a, M> {
@@ -95,6 +154,7 @@ impl<'a, M: Mode> I2cSlave<'a, M> {
95154
// this check should be redundant with T::set_mode()? above
96155
let info = T::info();
97156
let i2c = info.regs;
157+
let mut ten_bit_info = None;
98158

99159
// rates taken assuming SFRO:
100160
//
@@ -111,11 +171,25 @@ impl<'a, M: Mode> I2cSlave<'a, M> {
111171
// SAFETY: only unsafe due to .bits usage
112172
unsafe { w.divval().bits(0) });
113173

114-
// address 0 match = addr, per UM11147 24.3.2.1
115-
i2c.slvadr(0).modify(|_, w|
116-
// note: shift is omitted as performed via w.slvadr()
117-
// SAFETY: unsafe only required due to use of unnamed "bits" field
118-
unsafe {w.slvadr().bits(address.0)}.sadisable().enabled());
174+
match address {
175+
Address::SevenBit(addr) => {
176+
// address 0 match = addr, per UM11147 24.3.2.1
177+
i2c.slvadr(0).modify(|_, w|
178+
// note: shift is omitted as performed via w.slvadr()
179+
// SAFETY: unsafe only required due to use of unnamed "bits" field
180+
unsafe{w.slvadr().bits(addr)}.sadisable().enabled());
181+
}
182+
Address::TenBit(addr) => {
183+
// Save the 10 bit address to use later
184+
ten_bit_info = Some(TenBitAddressInfo::new(addr));
185+
186+
// address 0 match = addr first byte, per UM11147 24.7.4
187+
i2c.slvadr(0).modify(|_, w|
188+
// note: byte needs to be adjusted for shift performed via w.slvadr()
189+
// SAFETY: unsafe only required due to use of unnamed "bits" field
190+
unsafe{w.slvadr().bits(ten_bit_info.unwrap().first_byte >> 1)}.sadisable().enabled());
191+
}
192+
}
119193

120194
// SLVEN = 1, per UM11147 24.3.2.1
121195
i2c.cfg().write(|w| w.slven().enabled());
@@ -124,6 +198,7 @@ impl<'a, M: Mode> I2cSlave<'a, M> {
124198
info,
125199
_phantom: PhantomData,
126200
dma_ch,
201+
ten_bit_info,
127202
})
128203
}
129204
}
@@ -336,6 +411,43 @@ impl I2cSlave<'_, Async> {
336411
// Poll for HW to transitioning from addressed to receive/transmit
337412
self.poll_sw_action().await;
338413

414+
if let Some(ten_bit_address) = self.ten_bit_info {
415+
// For 10 bit address, the first byte received is the second byte of the address
416+
if i2c.slvdat().read().data().bits() == ten_bit_address.second_byte {
417+
i2c.slvctl().write(|w| w.slvcontinue().continue_());
418+
self.poll_sw_action().await;
419+
} else {
420+
// If the second byte of the 10 bit address is not received, then nack the address.
421+
i2c.slvctl().write(|w| w.slvnack().nack());
422+
return Ok(Command::Probe);
423+
}
424+
425+
// Check slave is still selected, master has not sent a stop
426+
if i2c.stat().read().slvsel().is_selected() {
427+
// Check for a restart
428+
if i2c.stat().read().slvstate().is_slave_address() {
429+
// Check if first byte of 10 bit address is received again with read bit set
430+
if i2c.slvdat().read().data().bits() == ten_bit_address.first_byte | 1 {
431+
i2c.slvctl().write(|w| w.slvcontinue().continue_());
432+
self.poll_sw_action().await;
433+
} else {
434+
// If the first byte of the 10 bit address is not received again, then nack the address.
435+
i2c.slvctl().write(|w| w.slvnack().nack());
436+
return Ok(Command::Probe);
437+
}
438+
// Check slave is ready for transmit
439+
if !i2c.stat().read().slvstate().is_slave_transmit() {
440+
return Err(TransferError::WriteFail.into());
441+
}
442+
} else {
443+
// Check slave is ready to receive
444+
if !i2c.stat().read().slvstate().is_slave_receive() {
445+
return Err(TransferError::ReadFail.into());
446+
}
447+
}
448+
}
449+
}
450+
339451
// We are deselected, so it must be an 0 byte write transaction
340452
if i2c.stat().read().slvdesel().is_deselected() {
341453
// Clear the deselected bit

0 commit comments

Comments
 (0)