Skip to content

Commit b7c1e4e

Browse files
Migrate I2C to embedded-hal 1.0
1 parent a1de970 commit b7c1e4e

File tree

4 files changed

+194
-68
lines changed

4 files changed

+194
-68
lines changed

Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ block-buffer = "0.10"
2020
cipher = "0.4"
2121
cortex-m = "0.7"
2222
digest = "0.10"
23-
embedded-hal = { version = "0.2", features = ["unproven"] }
23+
embedded-hal = { version = "1" }
24+
embedded-hal-027 = { package = "embedded-hal", version = "0.2.7", features = ["unproven"] }
2425
embedded-time = "0.12"
2526
generic-array = "1.0.0"
2627
lpc55-pac = "0.5"

src/drivers/i2c.rs

Lines changed: 189 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
1+
use embedded_hal::i2c::{NoAcknowledgeSource, Operation};
2+
13
use crate::time::Hertz;
24
use crate::traits::wg::blocking::i2c::{Read, Write, WriteRead};
5+
use crate::traits::wg1::i2c::{Error as ErrorTrait, ErrorType, I2c as I2cTrait};
36
use crate::typestates::pin::{
47
flexcomm::{
58
// Trait marking I2C peripherals and pins
@@ -33,6 +36,29 @@ pub enum Error {
3336
StartStop,
3437
}
3538

39+
impl ErrorTrait for Error {
40+
fn kind(&self) -> embedded_hal::i2c::ErrorKind {
41+
use embedded_hal::i2c::ErrorKind;
42+
match self {
43+
Self::Bus => ErrorKind::Bus,
44+
Self::ArbitrationLoss => ErrorKind::ArbitrationLoss,
45+
Self::NackAddress => ErrorKind::NoAcknowledge(NoAcknowledgeSource::Address),
46+
Self::NackData => ErrorKind::NoAcknowledge(NoAcknowledgeSource::Data),
47+
Self::StartStop => ErrorKind::Other,
48+
}
49+
}
50+
}
51+
52+
impl<PIO1, PIO2, I2C, PINS> ErrorType for I2cMaster<PIO1, PIO2, I2C, PINS>
53+
where
54+
PIO1: PinId,
55+
PIO2: PinId,
56+
I2C: I2c,
57+
PINS: I2cPins<PIO1, PIO2, I2C>,
58+
{
59+
type Error = Error;
60+
}
61+
3662
pub type Result<T> = core::result::Result<T, Error>;
3763

3864
// TODO: Parametrize with Master/Slave MODE
@@ -153,27 +179,7 @@ where
153179
Ok(())
154180
}
155181

156-
fn write_without_stop(&mut self, addr: u8, bytes: &[u8]) -> Result<()> {
157-
self.return_on_error()?;
158-
159-
// Write the slave address with the RW bit set to 0 to the master data register MSTDAT.
160-
self.i2c
161-
.mstdat
162-
.modify(|_, w| unsafe { w.data().bits(addr << 1) });
163-
// Start the transmission by setting the MSTSTART bit to 1 in the master control register.
164-
self.i2c.mstctl.write(|w| w.mststart().start());
165-
// Wait for the pending status to be set (MSTPENDING = 1) by polling the STAT register
166-
// TODO: Consider implementing a timeout (loop at most N times...) :TODO
167-
while self.i2c.stat.read().mstpending().is_in_progress() {
168-
continue;
169-
}
170-
171-
self.return_on_error()?;
172-
if !self.i2c.stat.read().mststate().is_transmit_ready() {
173-
// dbg!(Error::Bus);
174-
return Err(Error::Bus);
175-
}
176-
182+
fn write_inner_bytes(&mut self, bytes: &[u8]) -> Result<()> {
177183
// Send bytes
178184
for byte in bytes {
179185
// write a byte
@@ -194,6 +200,35 @@ where
194200
return Err(Error::Bus);
195201
}
196202
}
203+
Ok(())
204+
}
205+
206+
fn start_write(&mut self, addr: u8) -> Result<()> {
207+
self.return_on_error()?;
208+
209+
// Write the slave address with the RW bit set to 0 to the master data register MSTDAT.
210+
self.i2c
211+
.mstdat
212+
.modify(|_, w| unsafe { w.data().bits(addr << 1) });
213+
// Start the transmission by setting the MSTSTART bit to 1 in the master control register.
214+
self.i2c.mstctl.write(|w| w.mststart().start());
215+
// Wait for the pending status to be set (MSTPENDING = 1) by polling the STAT register
216+
// TODO: Consider implementing a timeout (loop at most N times...) :TODO
217+
while self.i2c.stat.read().mstpending().is_in_progress() {
218+
continue;
219+
}
220+
221+
self.return_on_error()?;
222+
if !self.i2c.stat.read().mststate().is_transmit_ready() {
223+
// dbg!(Error::Bus);
224+
return Err(Error::Bus);
225+
}
226+
Ok(())
227+
}
228+
229+
fn write_without_stop(&mut self, addr: u8, bytes: &[u8]) -> Result<()> {
230+
self.start_write(addr)?;
231+
self.write_inner_bytes(bytes)?;
197232

198233
// Fallthrough is success
199234
Ok(())
@@ -214,6 +249,81 @@ where
214249
// Fallthrough is success
215250
Ok(())
216251
}
252+
253+
fn read_byte(&mut self) -> u8 {
254+
self.i2c.mstdat.read().data().bits()
255+
}
256+
257+
fn wait_for_byte_ready(&mut self) -> Result<()> {
258+
// Wait for next byte
259+
while self.i2c.stat.read().mstpending().is_in_progress() {}
260+
261+
self.return_on_error()?;
262+
if !self.i2c.stat.read().mststate().is_receive_ready() {
263+
return Err(Error::Bus);
264+
}
265+
266+
Ok(())
267+
}
268+
269+
fn wait_for_next_byte(&mut self) -> Result<u8> {
270+
// Instruct master to continue
271+
self.i2c.mstctl.write(|w| w.mstcontinue().continue_());
272+
273+
self.wait_for_byte_ready()?;
274+
Ok(self.read_byte())
275+
}
276+
277+
fn start_read(&mut self, addr: u8) -> Result<()> {
278+
// Write the slave address with the RW bit set to 1 to the master data register MSTDAT.
279+
self.i2c
280+
.mstdat
281+
.modify(|_, w| unsafe { w.data().bits((addr << 1) | 1) });
282+
// Start the transmission by setting the MSTSTART bit to 1 in the master control register.
283+
self.i2c.mstctl.write(|w| w.mststart().start());
284+
Ok(())
285+
}
286+
287+
fn read_inner_bytes(&mut self, buffer: &mut [u8]) -> Result<()> {
288+
for byte in buffer {
289+
// Read a byte
290+
*byte = self.wait_for_next_byte()?;
291+
}
292+
Ok(())
293+
}
294+
295+
fn read_without_stop(&mut self, addr: u8, buffer: &mut [u8]) -> Result<()> {
296+
if let Some((first, buffer)) = buffer.split_first_mut() {
297+
self.start_read(addr)?;
298+
299+
self.wait_for_byte_ready()?;
300+
// read first byte
301+
*first = self.read_byte();
302+
self.read_inner_bytes(buffer)?;
303+
}
304+
305+
// Reading to an empty buffer is a noop
306+
Ok(())
307+
}
308+
309+
fn read_(&mut self, addr: u8, buffer: &mut [u8]) -> Result<()> {
310+
self.read_without_stop(addr, buffer)?;
311+
self.stop()?;
312+
313+
Ok(())
314+
}
315+
316+
fn write_(&mut self, addr: u8, bytes: &[u8]) -> Result<()> {
317+
self.write_without_stop(addr, bytes)?;
318+
self.stop()
319+
}
320+
321+
fn write_read_(&mut self, addr: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<()> {
322+
self.write_without_stop(addr, bytes)?;
323+
self.read_(addr, buffer)?;
324+
325+
Ok(())
326+
}
217327
}
218328

219329
impl<PIO1, PIO2, I2C, PINS> Write for I2cMaster<PIO1, PIO2, I2C, PINS>
@@ -226,8 +336,7 @@ where
226336
type Error = Error;
227337

228338
fn write(&mut self, addr: u8, bytes: &[u8]) -> Result<()> {
229-
self.write_without_stop(addr, bytes)?;
230-
self.stop()
339+
<Self as I2cTrait>::write(self, addr, bytes)
231340
}
232341
}
233342

@@ -241,45 +350,7 @@ where
241350
type Error = Error;
242351

243352
fn read(&mut self, addr: u8, buffer: &mut [u8]) -> Result<()> {
244-
if let Some((last, buffer)) = buffer.split_last_mut() {
245-
// Write the slave address with the RW bit set to 1 to the master data register MSTDAT.
246-
self.i2c
247-
.mstdat
248-
.modify(|_, w| unsafe { w.data().bits((addr << 1) | 1) });
249-
// Start the transmission by setting the MSTSTART bit to 1 in the master control register.
250-
self.i2c.mstctl.write(|w| w.mststart().start());
251-
252-
// Wait for the pending status to be set (MSTPENDING = 1) by polling the STAT register
253-
while self.i2c.stat.read().mstpending().is_in_progress() {}
254-
255-
self.return_on_error()?;
256-
if !self.i2c.stat.read().mststate().is_receive_ready() {
257-
return Err(Error::Bus);
258-
}
259-
260-
for byte in buffer {
261-
// Read a byte
262-
*byte = self.i2c.mstdat.read().data().bits();
263-
// Instruct master to continue
264-
self.i2c.mstctl.write(|w| w.mstcontinue().continue_());
265-
266-
// Wait for next byte
267-
while self.i2c.stat.read().mstpending().is_in_progress() {}
268-
269-
self.return_on_error()?;
270-
if !self.i2c.stat.read().mststate().is_receive_ready() {
271-
return Err(Error::Bus);
272-
}
273-
}
274-
275-
// Read last byte
276-
*last = self.i2c.mstdat.read().data().bits();
277-
278-
self.stop()?;
279-
}
280-
281-
// Fallthrough is success
282-
Ok(())
353+
<Self as I2cTrait>::read(self, addr, buffer)
283354
}
284355
}
285356

@@ -293,10 +364,63 @@ where
293364
type Error = Error;
294365

295366
fn write_read(&mut self, addr: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<()> {
296-
self.write_without_stop(addr, bytes)?;
297-
self.read(addr, buffer)?;
367+
<Self as I2cTrait>::write_read(self, addr, bytes, buffer)
368+
}
369+
}
298370

299-
Ok(())
371+
impl<PIO1, PIO2, I2C, PINS> I2cTrait for I2cMaster<PIO1, PIO2, I2C, PINS>
372+
where
373+
PIO1: PinId,
374+
PIO2: PinId,
375+
I2C: I2c,
376+
PINS: I2cPins<PIO1, PIO2, I2C>,
377+
{
378+
fn transaction(
379+
&mut self,
380+
address: u8,
381+
operations: &mut [embedded_hal::i2c::Operation<'_>],
382+
) -> core::result::Result<(), Self::Error> {
383+
let [ref mut current, ref mut rem @ ..] = operations else {
384+
// No operations mean noop
385+
return Ok(());
386+
};
387+
388+
// mut ref mut doesn't work above
389+
let mut current = current;
390+
let mut rem = rem;
391+
let mut previous_was_read = false;
392+
393+
loop {
394+
match current {
395+
Operation::Read(buf) => {
396+
if previous_was_read {
397+
self.read_inner_bytes(buf)?;
398+
} else {
399+
self.read_without_stop(address, buf)?;
400+
}
401+
402+
previous_was_read = true;
403+
}
404+
Operation::Write(buf) => {
405+
if !previous_was_read {
406+
self.write_inner_bytes(buf)?;
407+
} else {
408+
self.write_without_stop(address, buf)?;
409+
}
410+
411+
previous_was_read = false;
412+
}
413+
}
414+
415+
let [ref mut new_current, ref mut new_rem @ ..] = rem else {
416+
// No operations left
417+
self.stop()?;
418+
return Ok(());
419+
};
420+
421+
current = new_current;
422+
rem = new_rem;
423+
}
300424
}
301425
}
302426

src/peripherals/utick.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@
1010
// TODO: move this to drivers section,
1111
// possibly merge with ctimers when they're implemented
1212

13+
use crate::traits::wg::timer;
1314
use core::convert::Infallible;
14-
use embedded_hal::timer;
1515
use nb;
1616
use void::Void;
1717

src/traits.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ pub use digest;
99
// TODO: this pulls in the not-very-well-organised
1010
// entire library, in particular not just traits and types.
1111
// Would be worth being more explicit.
12-
pub use embedded_hal as wg;
12+
pub use embedded_hal as wg1;
13+
pub use embedded_hal_027 as wg;
1314

1415
pub use rand_core;
1516

0 commit comments

Comments
 (0)