Skip to content

Commit 7875043

Browse files
committed
[WIP] Add I2C slave.
1 parent e679ab1 commit 7875043

File tree

2 files changed

+385
-0
lines changed

2 files changed

+385
-0
lines changed

src/i2c_slave.rs

+383
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,383 @@
1+
use super::i2c::{SclPin, SdaPin};
2+
use super::pac::I2C1;
3+
4+
#[derive(PartialEq)]
5+
pub enum TransferState {
6+
Idle,
7+
Addressed,
8+
RegisterSet,
9+
Receiving,
10+
Transmitting,
11+
}
12+
13+
#[derive(Copy, Clone)]
14+
pub enum State {
15+
DataRequested(u8),
16+
DataReceived(u8),
17+
}
18+
19+
const BUFFER_SIZE: usize = 32;
20+
21+
pub struct I2CSlave<SDA, SCL> {
22+
i2c: I2C1,
23+
transfer_buffer: [u8; BUFFER_SIZE],
24+
transfer_len: usize,
25+
buffer_index: usize,
26+
register: u8,
27+
transfer_state: TransferState,
28+
state: Option<State>,
29+
_sda: SDA,
30+
_scl: SCL,
31+
}
32+
33+
// direction as specified in the datasheet
34+
#[derive(PartialEq)]
35+
pub enum Direction {
36+
Write, // slave is receiver
37+
Read, // slave is transmitter
38+
}
39+
40+
impl From<Direction> for bool {
41+
fn from(dir: Direction) -> Self {
42+
match dir {
43+
Direction::Write => false,
44+
Direction::Read => true,
45+
}
46+
}
47+
}
48+
49+
impl From<bool> for Direction {
50+
fn from(raw: bool) -> Self {
51+
if raw {
52+
Direction::Read
53+
} else {
54+
Direction::Write
55+
}
56+
}
57+
}
58+
59+
pub enum Status {
60+
AddressMatch(Direction),
61+
Busy,
62+
Timeout,
63+
Overrun,
64+
ArbitrationLost,
65+
BusError,
66+
TransferCompleteReload,
67+
Stop,
68+
NACKReceived,
69+
RxNotEmpty,
70+
TxDataMustBeWritten,
71+
TxEmpty,
72+
}
73+
74+
impl<SDA, SCL> I2CSlave<SDA, SCL>
75+
where
76+
SDA: SdaPin<I2C1>,
77+
SCL: SclPin<I2C1>,
78+
{
79+
pub fn new(i2c: I2C1, address: u8, sda: SDA, scl: SCL) -> Self {
80+
let rcc = unsafe { &(*stm32f0xx_hal::pac::RCC::ptr()) };
81+
rcc.apb1enr.modify(|_, w| w.i2c1en().enabled());
82+
rcc.apb1rstr.modify(|_, w| w.i2c1rst().set_bit());
83+
rcc.apb1rstr.modify(|_, w| w.i2c1rst().clear_bit());
84+
85+
i2c.cr1.write(|w| {
86+
w.nostretch()
87+
.enabled() // enable clock stretching
88+
.anfoff()
89+
.enabled() // enable analog filter
90+
.dnf()
91+
.no_filter() // disable digital filter
92+
.errie()
93+
.enabled() // error interrupt enabled
94+
.stopie()
95+
.enabled() // stop interrupt enabled
96+
.nackie()
97+
.enabled() // nack interrupt enabled
98+
.addrie()
99+
.enabled() // address match interrupt enabled
100+
.rxie() // rx interrupt enabled
101+
.enabled()
102+
.wupen()
103+
.enabled() // wake up when address match
104+
});
105+
106+
// TODO set up timing for nostretch mode
107+
// let scll = cmp::max((((48_000_000 >> 1) >> 1) / KiloHertz(100).0) - 1, 255) as u8;
108+
// i2c.timingr.write(|w| {
109+
// w.presc()
110+
// .bits(1)
111+
// .scldel()
112+
// .bits(4)
113+
// .sdadel()
114+
// .bits(2)
115+
// .sclh()
116+
// .bits(scll - 4)
117+
// .scll()
118+
// .bits(scll)
119+
// });
120+
121+
i2c.oar1.write(|w| {
122+
w.oa1en()
123+
.enabled()
124+
.oa1()
125+
.bits((address as u16) << 1)
126+
.oa1mode()
127+
.bit7()
128+
});
129+
130+
i2c.cr1.modify(
131+
|_, w| w.pe().enabled(), // enable peripheral
132+
);
133+
134+
I2CSlave {
135+
i2c,
136+
transfer_buffer: [0u8; BUFFER_SIZE],
137+
transfer_len: 0,
138+
buffer_index: 0,
139+
register: 0,
140+
transfer_state: TransferState::Idle,
141+
state: None,
142+
_sda: sda,
143+
_scl: scl,
144+
}
145+
}
146+
147+
pub fn is_status(&self, status: Status, clear: bool) -> bool {
148+
let isr = self.i2c.isr.read();
149+
150+
match status {
151+
Status::AddressMatch(dir) => {
152+
if isr.addr().bit_is_set() {
153+
if dir != isr.dir().bit().into() {
154+
return false;
155+
}
156+
if clear {
157+
self.i2c.icr.write(|w| w.addrcf().clear());
158+
}
159+
return true;
160+
} else {
161+
false
162+
}
163+
}
164+
Status::Busy => {
165+
return isr.busy().bit_is_set();
166+
}
167+
Status::Timeout => {
168+
if isr.timeout().bit_is_set() {
169+
if clear {
170+
self.i2c.icr.write(|w| w.timoutcf().clear());
171+
}
172+
return true;
173+
}
174+
return false;
175+
}
176+
Status::Overrun => {
177+
if isr.ovr().bit_is_set() {
178+
if clear {
179+
self.i2c.icr.write(|w| w.ovrcf().clear());
180+
}
181+
return true;
182+
}
183+
return false;
184+
}
185+
Status::ArbitrationLost => {
186+
if isr.arlo().bit_is_set() {
187+
if clear {
188+
self.i2c.icr.write(|w| w.arlocf().clear());
189+
}
190+
return true;
191+
}
192+
return false;
193+
}
194+
Status::BusError => {
195+
if isr.berr().bit_is_set() {
196+
if clear {
197+
self.i2c.icr.write(|w| w.berrcf().clear());
198+
}
199+
return true;
200+
}
201+
return false;
202+
}
203+
Status::TransferCompleteReload => {
204+
if isr.tcr().bit_is_set() {
205+
if clear {
206+
// defmt::error!("Cannot be cleared.");
207+
}
208+
return true;
209+
}
210+
return false;
211+
}
212+
Status::Stop => {
213+
if isr.stopf().bit_is_set() {
214+
if clear {
215+
self.i2c.icr.write(|w| w.stopcf().clear());
216+
}
217+
return true;
218+
}
219+
return false;
220+
}
221+
Status::NACKReceived => {
222+
if isr.nackf().bit_is_set() {
223+
if clear {
224+
self.i2c.icr.write(|w| w.nackcf().clear());
225+
}
226+
return true;
227+
}
228+
return false;
229+
}
230+
Status::RxNotEmpty => {
231+
if isr.rxne().bit_is_set() {
232+
if clear {
233+
// defmt::error!("Cannot be cleared.");
234+
}
235+
return true;
236+
}
237+
return false;
238+
}
239+
Status::TxDataMustBeWritten => {
240+
if isr.txis().bit_is_set() {
241+
if clear {
242+
// defmt::error!("Cannot be cleared.");
243+
}
244+
return true;
245+
}
246+
return false;
247+
}
248+
Status::TxEmpty => {
249+
if isr.txe().bit_is_set() {
250+
if clear {
251+
// defmt::error!("Cannot be cleared.");
252+
}
253+
return true;
254+
}
255+
return false;
256+
}
257+
}
258+
}
259+
260+
pub fn read(&self) -> u8 {
261+
self.i2c.rxdr.read().bits() as u8
262+
}
263+
264+
pub fn write(&self, value: u8) {
265+
self.i2c.txdr.write(|w| w.txdata().bits(value));
266+
}
267+
268+
pub fn set_txe(&self) {
269+
self.i2c.isr.modify(|_, w| w.txe().set_bit());
270+
}
271+
272+
pub fn enable_txie(&self, enable: bool) {
273+
self.i2c
274+
.cr1
275+
.modify(|_, w| w.txie().bit(enable).tcie().bit(enable));
276+
}
277+
278+
pub fn interrupt(&mut self) {
279+
if self.transfer_state == TransferState::Idle {
280+
self.state = None;
281+
self.enable_txie(false);
282+
}
283+
284+
if self.is_status(Status::BusError, true) {
285+
self.handle_error();
286+
return;
287+
}
288+
if self.is_status(Status::Overrun, true) {
289+
self.handle_error();
290+
return;
291+
}
292+
if self.is_status(Status::ArbitrationLost, true) {
293+
self.handle_error();
294+
return;
295+
}
296+
if self.is_status(Status::NACKReceived, true) {
297+
self.handle_error();
298+
return;
299+
}
300+
if self.is_status(Status::Timeout, true) {
301+
self.handle_error();
302+
return;
303+
}
304+
305+
if self.is_status(Status::RxNotEmpty, false) {
306+
if self.transfer_state == TransferState::Addressed {
307+
self.transfer_state = TransferState::RegisterSet;
308+
self.register = self.read();
309+
} else if self.transfer_state == TransferState::RegisterSet {
310+
self.transfer_state = TransferState::Receiving;
311+
} else if self.transfer_state == TransferState::Receiving {
312+
// do not change state, just read
313+
self.transfer_buffer[self.buffer_index] = self.read();
314+
self.buffer_index += 1;
315+
}
316+
}
317+
318+
if self.is_status(Status::Stop, true) {
319+
// handle reception
320+
if self.transfer_state == TransferState::Receiving {
321+
self.state = Some(State::DataReceived(self.register));
322+
} else if self.transfer_state == TransferState::Transmitting {
323+
// data was transmitted, nothing else to do
324+
self.state = None;
325+
}
326+
self.i2c.isr.modify(|_, w| w.txe().set_bit()); // flush txdr
327+
self.transfer_state = TransferState::Idle;
328+
}
329+
330+
if self.is_status(Status::AddressMatch(Direction::Write), true) {
331+
self.transfer_state = TransferState::Addressed;
332+
}
333+
if self.is_status(Status::TxDataMustBeWritten, false) {
334+
// this may be true more times than actual data length, ignore then
335+
if self.transfer_state == TransferState::Transmitting {
336+
// state is not changed
337+
if self.buffer_index < self.transfer_len {
338+
self.write(self.transfer_buffer[self.buffer_index]);
339+
self.buffer_index += 1;
340+
} else {
341+
self.enable_txie(false);
342+
self.state = None;
343+
}
344+
}
345+
}
346+
if self.is_status(Status::AddressMatch(Direction::Read), true) {
347+
if self.transfer_state == TransferState::RegisterSet {
348+
self.enable_txie(true);
349+
self.transfer_state = TransferState::Transmitting;
350+
self.state = Some(State::DataRequested(self.register));
351+
}
352+
}
353+
}
354+
355+
fn handle_error(&mut self) {
356+
self.transfer_state = TransferState::Idle;
357+
self.state = None;
358+
self.transfer_len = 0;
359+
self.buffer_index = 0;
360+
self.i2c.isr.modify(|_, w| w.txe().set_bit()); // flush txdr
361+
}
362+
363+
pub fn set_transmit_buffer(&mut self, buffer: &[u8]) {
364+
for (index, item) in buffer.iter().enumerate() {
365+
self.transfer_buffer[index] = *item;
366+
}
367+
self.transfer_len = buffer.len();
368+
self.buffer_index = 0;
369+
self.state = None
370+
}
371+
372+
pub fn get_received_data(&mut self) -> &[u8] {
373+
let data = &self.transfer_buffer[..self.buffer_index];
374+
self.state = None;
375+
self.buffer_index = 0;
376+
self.transfer_len = 0;
377+
data
378+
}
379+
380+
pub fn get_state(&self) -> Option<State> {
381+
self.state
382+
}
383+
}

src/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ pub mod gpio;
4444
#[cfg(feature = "device-selected")]
4545
pub mod i2c;
4646
#[cfg(feature = "device-selected")]
47+
pub mod i2c_slave;
48+
#[cfg(feature = "device-selected")]
4749
pub mod prelude;
4850
#[cfg(feature = "device-selected")]
4951
pub mod rcc;

0 commit comments

Comments
 (0)