Skip to content

Commit 9104ae2

Browse files
authored
Merge pull request #784 from stm32-rs/fmpi2c-impls
FMPI2c embedded-hal implementations
2 parents a3f100e + 780d8f8 commit 9104ae2

File tree

6 files changed

+249
-167
lines changed

6 files changed

+249
-167
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
1212
- Use `write` instead of `modify` to clear flags
1313
- Bump `stm32f4-staging` to 0.18, update other dependencies
1414
- `serial` mod refactor
15+
- Fefactor FMPI2c `embedded-hal` implementations [#784]
16+
17+
[#784]: https://github.com/stm32-rs/stm32f4xx-hal/pull/784
1518

1619
## [v0.22.1] - 2024-11-03
1720

src/fmpi2c.rs

Lines changed: 218 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,24 @@
11
use core::ops::Deref;
22

33
use crate::gpio;
4-
use crate::i2c::{Error, NoAcknowledgeSource};
4+
55
use crate::pac::fmpi2c1 as i2c1;
66
use crate::pac::{self, RCC};
77
use crate::rcc::{BusClock, Enable, Reset};
88
use fugit::{HertzU32 as Hertz, RateExtU32};
99

10+
#[path = "i2c/common.rs"]
11+
mod common;
12+
pub use common::{Address, Error, NoAcknowledgeSource};
13+
use common::{Hal02Operation, Hal1Operation};
14+
1015
// Old names
1116
pub use I2c as FmpI2c;
1217
pub use Mode as FmpMode;
1318

19+
#[path = "i2c/hal_02.rs"]
1420
mod hal_02;
21+
#[path = "i2c/hal_1.rs"]
1522
mod hal_1;
1623

1724
pub trait Instance:
@@ -213,6 +220,83 @@ impl<I2C: Instance> I2c<I2C> {
213220
Ok(())
214221
}
215222

223+
/// Sends START and Address for writing
224+
#[inline(always)]
225+
fn prepare_write(&self, addr: Address, datalen: usize) -> Result<(), Error> {
226+
// Set up current slave address for writing and disable autoending
227+
self.i2c.cr2().modify(|_, w| {
228+
match addr {
229+
Address::Seven(addr) => {
230+
w.add10().clear_bit();
231+
w.sadd().set(u16::from(addr) << 1);
232+
}
233+
Address::Ten(addr) => {
234+
w.add10().set_bit();
235+
w.sadd().set(addr);
236+
}
237+
}
238+
w.nbytes().set(datalen as u8);
239+
w.rd_wrn().clear_bit();
240+
w.autoend().clear_bit()
241+
});
242+
243+
// Send a START condition
244+
self.i2c.cr2().modify(|_, w| w.start().set_bit());
245+
246+
// Wait until address was sent
247+
while {
248+
let isr = self.i2c.isr().read();
249+
self.check_and_clear_error_flags(&isr)
250+
.map_err(Error::nack_addr)?;
251+
isr.txis().bit_is_clear() && isr.tc().bit_is_clear()
252+
} {}
253+
254+
Ok(())
255+
}
256+
257+
/// Sends START and Address for reading
258+
fn prepare_read(
259+
&self,
260+
addr: Address,
261+
buflen: usize,
262+
first_transaction: bool,
263+
) -> Result<(), Error> {
264+
// Set up current address for reading
265+
self.i2c.cr2().modify(|_, w| {
266+
match addr {
267+
Address::Seven(addr) => {
268+
w.add10().clear_bit();
269+
w.sadd().set(u16::from(addr) << 1);
270+
}
271+
Address::Ten(addr) => {
272+
w.add10().set_bit();
273+
w.head10r().bit(!first_transaction);
274+
w.sadd().set(addr);
275+
}
276+
}
277+
w.nbytes().set(buflen as u8);
278+
w.rd_wrn().set_bit()
279+
});
280+
281+
// Send a START condition
282+
self.i2c.cr2().modify(|_, w| w.start().set_bit());
283+
284+
// Send the autoend after setting the start to get a restart
285+
self.i2c.cr2().modify(|_, w| w.autoend().set_bit());
286+
287+
Ok(())
288+
}
289+
290+
fn write_bytes(&mut self, bytes: impl Iterator<Item = u8>) -> Result<(), Error> {
291+
// Send bytes
292+
for c in bytes {
293+
self.send_byte(c)?;
294+
}
295+
296+
// Fallthrough is success
297+
Ok(())
298+
}
299+
216300
fn send_byte(&self, byte: u8) -> Result<(), Error> {
217301
// Wait until we're ready for sending
218302
while {
@@ -242,72 +326,38 @@ impl<I2C: Instance> I2c<I2C> {
242326
Ok(value)
243327
}
244328

245-
pub fn read(&mut self, addr: u8, buffer: &mut [u8]) -> Result<(), Error> {
246-
// Set up current address for reading
247-
self.i2c.cr2().modify(|_, w| {
248-
w.sadd().set(u16::from(addr) << 1);
249-
w.nbytes().set(buffer.len() as u8);
250-
w.rd_wrn().set_bit()
251-
});
252-
253-
// Send a START condition
254-
self.i2c.cr2().modify(|_, w| w.start().set_bit());
255-
256-
// Send the autoend after setting the start to get a restart
257-
self.i2c.cr2().modify(|_, w| w.autoend().set_bit());
258-
259-
// Now read in all bytes
260-
for c in buffer.iter_mut() {
329+
fn read_bytes(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
330+
// Receive bytes into buffer
331+
for c in buffer {
261332
*c = self.recv_byte()?;
262333
}
263334

264-
self.end_transaction()
335+
Ok(())
265336
}
266337

267-
pub fn write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Error> {
268-
// Set up current slave address for writing and enable autoending
269-
self.i2c.cr2().modify(|_, w| {
270-
w.sadd().set(u16::from(addr) << 1);
271-
w.nbytes().set(bytes.len() as u8);
272-
w.rd_wrn().clear_bit();
273-
w.autoend().set_bit()
274-
});
275-
276-
// Send a START condition
277-
self.i2c.cr2().modify(|_, w| w.start().set_bit());
278-
279-
// Send out all individual bytes
280-
for c in bytes {
281-
self.send_byte(*c)?;
282-
}
338+
pub fn read(&mut self, addr: impl Into<Address>, buffer: &mut [u8]) -> Result<(), Error> {
339+
self.prepare_read(addr.into(), buffer.len(), true)?;
340+
self.read_bytes(buffer)?;
283341

284342
self.end_transaction()
285343
}
286344

287-
pub fn write_read(&mut self, addr: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Error> {
288-
// Set up current slave address for writing and disable autoending
289-
self.i2c.cr2().modify(|_, w| {
290-
w.sadd().set(u16::from(addr) << 1);
291-
w.nbytes().set(bytes.len() as u8);
292-
w.rd_wrn().clear_bit();
293-
w.autoend().clear_bit()
294-
});
345+
pub fn write(&mut self, addr: impl Into<Address>, bytes: &[u8]) -> Result<(), Error> {
346+
self.prepare_write(addr.into(), bytes.len())?;
347+
self.write_bytes(bytes.iter().cloned())?;
295348

296-
// Send a START condition
297-
self.i2c.cr2().modify(|_, w| w.start().set_bit());
349+
self.end_transaction()
350+
}
298351

299-
// Wait until the transmit buffer is empty and there hasn't been any error condition
300-
while {
301-
let isr = self.i2c.isr().read();
302-
self.check_and_clear_error_flags(&isr)
303-
.map_err(Error::nack_addr)?;
304-
isr.txis().bit_is_clear() && isr.tc().bit_is_clear()
305-
} {}
306-
307-
// Send out all individual bytes
308-
for c in bytes {
309-
self.send_byte(*c)?;
310-
}
352+
pub fn write_read(
353+
&mut self,
354+
addr: impl Into<Address>,
355+
bytes: &[u8],
356+
buffer: &mut [u8],
357+
) -> Result<(), Error> {
358+
let addr = addr.into();
359+
self.prepare_write(addr, bytes.len())?;
360+
self.write_bytes(bytes.iter().cloned())?;
311361

312362
// Wait until data was sent
313363
while {
@@ -317,24 +367,122 @@ impl<I2C: Instance> I2c<I2C> {
317367
isr.tc().bit_is_clear()
318368
} {}
319369

320-
// Set up current address for reading
321-
self.i2c.cr2().modify(|_, w| {
322-
w.sadd().set(u16::from(addr) << 1);
323-
w.nbytes().set(buffer.len() as u8);
324-
w.rd_wrn().set_bit()
325-
});
370+
self.read(addr, buffer)
371+
}
326372

327-
// Send another START condition
328-
self.i2c.cr2().modify(|_, w| w.start().set_bit());
373+
pub fn transaction<'a>(
374+
&mut self,
375+
addr: impl Into<Address>,
376+
mut ops: impl Iterator<Item = Hal1Operation<'a>>,
377+
) -> Result<(), Error> {
378+
let addr = addr.into();
379+
if let Some(mut prev_op) = ops.next() {
380+
// 1. Generate Start for operation
381+
match &prev_op {
382+
Hal1Operation::Read(buf) => self.prepare_read(addr, buf.len(), true)?,
383+
Hal1Operation::Write(data) => self.prepare_write(addr, data.len())?,
384+
};
385+
386+
for op in ops {
387+
// 2. Execute previous operations.
388+
match &mut prev_op {
389+
Hal1Operation::Read(rb) => self.read_bytes(rb)?,
390+
Hal1Operation::Write(wb) => self.write_bytes(wb.iter().cloned())?,
391+
};
392+
// 3. If operation changes type we must generate new start
393+
match (&prev_op, &op) {
394+
(Hal1Operation::Read(_), Hal1Operation::Write(data)) => {
395+
self.prepare_write(addr, data.len())?
396+
}
397+
(Hal1Operation::Write(_), Hal1Operation::Read(buf)) => {
398+
self.prepare_read(addr, buf.len(), false)?
399+
}
400+
_ => {} // No changes if operation have not changed
401+
}
402+
403+
prev_op = op;
404+
}
329405

330-
// Send the autoend after setting the start to get a restart
331-
self.i2c.cr2().modify(|_, w| w.autoend().set_bit());
406+
// 4. Now, prev_op is last command use methods variations that will generate stop
407+
match prev_op {
408+
Hal1Operation::Read(rb) => self.read_bytes(rb)?,
409+
Hal1Operation::Write(wb) => self.write_bytes(wb.iter().cloned())?,
410+
};
332411

333-
// Now read in all bytes
334-
for c in buffer.iter_mut() {
335-
*c = self.recv_byte()?;
412+
self.end_transaction()?;
336413
}
337414

338-
self.end_transaction()
415+
// Fallthrough is success
416+
Ok(())
417+
}
418+
419+
pub fn transaction_slice(
420+
&mut self,
421+
addr: impl Into<Address>,
422+
ops_slice: &mut [Hal1Operation<'_>],
423+
) -> Result<(), Error> {
424+
let addr = addr.into();
425+
transaction_impl!(self, addr, ops_slice, Hal1Operation);
426+
// Fallthrough is success
427+
Ok(())
428+
}
429+
430+
fn transaction_slice_hal_02(
431+
&mut self,
432+
addr: impl Into<Address>,
433+
ops_slice: &mut [Hal02Operation<'_>],
434+
) -> Result<(), Error> {
435+
let addr = addr.into();
436+
transaction_impl!(self, addr, ops_slice, Hal02Operation);
437+
// Fallthrough is success
438+
Ok(())
339439
}
340440
}
441+
442+
macro_rules! transaction_impl {
443+
($self:ident, $addr:ident, $ops_slice:ident, $Operation:ident) => {
444+
let i2c = $self;
445+
let addr = $addr;
446+
let mut ops = $ops_slice.iter_mut();
447+
448+
if let Some(mut prev_op) = ops.next() {
449+
// 1. Generate Start for operation
450+
match &prev_op {
451+
$Operation::Read(buf) => i2c.prepare_read(addr, buf.len(), true)?,
452+
$Operation::Write(data) => i2c.prepare_write(addr, data.len())?,
453+
};
454+
455+
for op in ops {
456+
// 2. Execute previous operations.
457+
match &mut prev_op {
458+
$Operation::Read(rb) => i2c.read_bytes(rb)?,
459+
$Operation::Write(wb) => i2c.write_bytes(wb.iter().cloned())?,
460+
};
461+
// 3. If operation changes type we must generate new start
462+
match (&prev_op, &op) {
463+
($Operation::Read(_), $Operation::Write(data)) => {
464+
i2c.prepare_write(addr, data.len())?
465+
}
466+
($Operation::Write(_), $Operation::Read(buf)) => {
467+
i2c.prepare_read(addr, buf.len(), false)?
468+
}
469+
_ => {} // No changes if operation have not changed
470+
}
471+
472+
prev_op = op;
473+
}
474+
475+
// 4. Now, prev_op is last command use methods variations that will generate stop
476+
match prev_op {
477+
$Operation::Read(rb) => i2c.read_bytes(rb)?,
478+
$Operation::Write(wb) => i2c.write_bytes(wb.iter().cloned())?,
479+
};
480+
481+
i2c.end_transaction()?;
482+
}
483+
};
484+
}
485+
use transaction_impl;
486+
487+
// Note: implementation is from f0xx-hal
488+
// TODO: check error handling. See https://github.com/stm32-rs/stm32f0xx-hal/pull/95/files

src/fmpi2c/hal_02.rs

Lines changed: 0 additions & 28 deletions
This file was deleted.

0 commit comments

Comments
 (0)