Skip to content

Commit fad570d

Browse files
committed
I2C example working
1 parent ddc85fd commit fad570d

File tree

4 files changed

+117
-76
lines changed

4 files changed

+117
-76
lines changed

e310x-hal/src/i2c.rs

Lines changed: 52 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -114,30 +114,12 @@ impl<I2C: I2cX, PINS> I2c<I2C, PINS> {
114114
self.clear_interrupt();
115115
}
116116

117-
/// Set the start bit in the control register. The next byte sent
118-
/// through the bus will be preceded by a (repeated) start condition.
119-
///
120-
/// # Note
121-
///
122-
/// This function does not start the transmission. You must call
123-
/// [`Self::write_to_slave`] to start the transmission.
124-
fn set_start(&self) {
125-
self.i2c.cr().write(|w| w.sta().set_bit());
126-
}
127-
128117
/// Set the stop bit in the control register.
129118
/// A stop condition will be sent on the bus.
130119
fn set_stop(&self) {
131120
self.i2c.cr().write(|w| w.sto().set_bit());
132121
}
133122

134-
/// Set the ACK bit in the control register. If `ack` is `true`, the
135-
/// I2C will **NOT** acknowledge the next byte received. If `ack`
136-
/// is `false`, the I2C will acknowledge the next byte received.
137-
fn set_ack(&self, ack: bool) {
138-
self.i2c.cr().write(|w| w.ack().bit(ack));
139-
}
140-
141123
/// Set the next byte to be transmitted to the I2C slave device.
142124
///
143125
/// # Note
@@ -160,8 +142,10 @@ impl<I2C: I2cX, PINS> I2c<I2C, PINS> {
160142
///
161143
/// This function does not block until the write is complete. You must call
162144
/// [`Self::wait_for_write`] to wait for the write to complete.
163-
fn write_to_slave(&self) {
164-
self.i2c.cr().write(|w| w.wr().set_bit());
145+
fn trigger_write(&self, start: bool, stop: bool) {
146+
self.i2c
147+
.cr()
148+
.write(|w| w.sta().bit(start).wr().set_bit().sto().bit(stop));
165149
}
166150

167151
/// Trigger a read from the slave device.
@@ -171,16 +155,20 @@ impl<I2C: I2cX, PINS> I2c<I2C, PINS> {
171155
///
172156
/// This function does not block until the read is complete. You must call
173157
/// [`Self::wait_for_read`] to wait for the read to complete.
174-
fn read_from_slave(&self) {
175-
self.i2c.cr().write(|w| w.rd().set_bit());
158+
fn trigger_read(&self, ack: bool, stop: bool) {
159+
self.i2c
160+
.cr()
161+
.write(|w| w.rd().set_bit().ack().bit(ack).sto().bit(stop));
176162
}
177163

178164
/// Check if the I2C peripheral is idle.
179-
fn is_idle(&self) -> nb::Result<(), ErrorKind> {
180-
match self.read_sr().busy().bit_is_set() {
181-
true => Err(nb::Error::WouldBlock),
182-
false => Ok(()),
183-
}
165+
fn is_idle(&self) -> bool {
166+
!self.read_sr().busy().bit_is_set()
167+
}
168+
169+
/// Blocking version of [`Self::is_idle`].
170+
fn wait_idle(&self) {
171+
while !self.is_idle() {}
184172
}
185173

186174
/// Acknowledge an interrupt.
@@ -191,36 +179,27 @@ impl<I2C: I2cX, PINS> I2c<I2C, PINS> {
191179
/// and an [`ErrorKind::ArbitrationLoss`] is returned.
192180
fn ack_interrupt(&self) -> nb::Result<(), ErrorKind> {
193181
let sr = self.read_sr();
194-
195-
if sr.al().bit_is_set() {
196-
self.set_stop();
197-
Err(nb::Error::Other(ErrorKind::ArbitrationLoss))
198-
} else if sr.if_().bit_is_set() {
182+
if sr.if_().bit_is_set() {
199183
self.clear_interrupt();
200-
Ok(())
184+
if sr.al().bit_is_set() {
185+
self.set_stop();
186+
Err(nb::Error::Other(ErrorKind::ArbitrationLoss))
187+
} else {
188+
Ok(())
189+
}
201190
} else {
202191
Err(nb::Error::WouldBlock)
203192
}
204193
}
205194

206-
/// Blocking version of [`Self::is_idle`].
207-
fn wait_idle(&self) {
208-
nb::block!(self.is_idle()).unwrap();
209-
}
210-
211195
/// Wait for a read operation to complete.
212196
///
213197
/// # Errors
214198
///
215199
/// In case of arbitration loss it waits until the bus is idle
216200
/// before returning an [`ErrorKind::ArbitrationLoss`] error.
217201
fn wait_for_read(&self) -> Result<(), ErrorKind> {
218-
if let Err(e) = nb::block!(self.ack_interrupt()) {
219-
self.wait_idle();
220-
Err(e)
221-
} else {
222-
Ok(())
223-
}
202+
nb::block!(self.ack_interrupt())
224203
}
225204

226205
/// Wait for a write operation to complete.
@@ -232,13 +211,11 @@ impl<I2C: I2cX, PINS> I2c<I2C, PINS> {
232211
///
233212
/// In case of arbitration loss it waits until the bus is idle
234213
/// before returning an [`ErrorKind::ArbitrationLoss`] error.
235-
fn wait_for_write(&self) -> Result<(), ErrorKind> {
236-
if let Err(e) = nb::block!(self.ack_interrupt()) {
237-
self.wait_idle();
238-
Err(e)
239-
} else if self.read_sr().rx_ack().bit_is_set() {
214+
fn wait_for_write(&self, source: NoAcknowledgeSource) -> Result<(), ErrorKind> {
215+
nb::block!(self.ack_interrupt())?;
216+
if self.read_sr().rx_ack().bit_is_set() {
240217
self.set_stop();
241-
Err(ErrorKind::NoAcknowledge(NoAcknowledgeSource::Unknown))
218+
Err(ErrorKind::NoAcknowledge(source))
242219
} else {
243220
Ok(())
244221
}
@@ -258,53 +235,54 @@ impl<I2C: I2cX, PINS> i2c::I2c for I2c<I2C, PINS> {
258235
address: u8,
259236
operations: &mut [Operation<'_>],
260237
) -> Result<(), Self::Error> {
238+
let n_ops = operations.len();
239+
if n_ops == 0 {
240+
return Ok(());
241+
}
242+
261243
self.wait_idle();
262244
self.reset();
263245

264-
self.set_start();
265-
let mut last_op_was_read = false;
266-
for operation in operations.iter_mut() {
246+
// we use this flag to detect when we need to send a (repeated) start
247+
let mut last_op_was_read = match &operations[0] {
248+
Operation::Read(_) => false,
249+
Operation::Write(_) => true,
250+
};
251+
252+
for (i, operation) in operations.iter_mut().enumerate() {
267253
match operation {
268254
Operation::Write(bytes) => {
269-
if last_op_was_read {
270-
self.set_start();
271-
last_op_was_read = false;
272-
}
273255
// Send write command
274256
self.write_txr((address << 1) + FLAG_WRITE);
275-
self.write_to_slave();
276-
self.wait_for_write()?;
257+
self.trigger_write(last_op_was_read, false);
258+
self.wait_for_write(NoAcknowledgeSource::Address)?;
259+
last_op_was_read = false;
277260

278261
// Write bytes
279-
for byte in bytes.iter() {
262+
let n_bytes = bytes.len();
263+
for (j, byte) in bytes.iter().enumerate() {
280264
self.write_txr(*byte);
281-
self.write_to_slave();
282-
self.wait_for_write()?;
265+
self.trigger_write(false, (i == n_ops - 1) && (j == n_bytes - 1));
266+
self.wait_for_write(NoAcknowledgeSource::Data)?;
283267
}
284268
}
285269
Operation::Read(buffer) => {
286-
if !last_op_was_read {
287-
self.set_start();
288-
last_op_was_read = true;
289-
}
290270
// Send read command
291271
self.write_txr((address << 1) + FLAG_READ);
292-
self.write_to_slave();
293-
self.wait_for_write()?;
272+
self.trigger_write(!last_op_was_read, false);
273+
self.wait_for_write(NoAcknowledgeSource::Address)?;
274+
last_op_was_read = true;
294275

295276
// Read bytes
296-
let buffer_len = buffer.len();
297-
for (i, byte) in buffer.iter_mut().enumerate() {
298-
// Set ACK on all but the last byte
299-
self.set_ack(i == buffer_len - 1);
300-
self.read_from_slave();
277+
let n_bytes = buffer.len();
278+
for (j, byte) in buffer.iter_mut().enumerate() {
279+
self.trigger_read(j == n_bytes - 1, (i == n_ops - 1) && (j == n_bytes - 1));
301280
self.wait_for_read()?;
302281
*byte = self.read_rxr();
303282
}
304283
}
305284
}
306285
}
307-
self.set_stop();
308286
self.wait_idle();
309287

310288
Ok(())

e310x-hal/src/prelude.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ pub use e310x::interrupt::{
1313
pub use embedded_hal::{
1414
delay::DelayNs,
1515
digital::{InputPin, OutputPin, StatefulOutputPin},
16-
i2c::I2c,
16+
i2c::I2c as _embedded_hal_i2c_I2c,
1717
pwm::SetDutyCycle,
1818
spi::{SpiBus, SpiDevice},
1919
};

hifive1-examples/Cargo.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,10 @@ critical-section = { version = "1.2.0" }
1717
hifive1 = { path = "../hifive1", version = "0.14.0", features = ["board-hifive1-revb"] } # Change to your board
1818
riscv = { version = "0.12.1" }
1919
riscv-rt = { version = "0.13.0", features = ["single-hart"] }
20-
panic-halt = "0.2.0"
20+
panic-halt = "1.0.0"
2121
semihosting = { version = "0.1", features = ["stdio", "panic-handler"] }
22+
# max3010x = "0.2.0" # TODO uncomment when the driver is published
23+
max3010x = { git = "https://github.com/romancardenas/max3010x-rs.git" }
2224

2325
[features]
2426
v-trap = ["hifive1/v-trap"]
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
//! Basic blinking LEDs example using mtime/mtimecmp registers for "sleep" in a loop.
2+
//! Blinks each led once and goes to the next one.
3+
4+
#![no_std]
5+
#![no_main]
6+
7+
use hifive1::{
8+
clock,
9+
hal::{
10+
e310x::CLINT,
11+
i2c::{I2c, Speed},
12+
prelude::*,
13+
DeviceResources,
14+
},
15+
pin, sprintln,
16+
};
17+
use max3010x::{Led, Max3010x, SampleAveraging};
18+
extern crate panic_halt;
19+
20+
#[riscv_rt::entry]
21+
fn main() -> ! {
22+
let dr = DeviceResources::take().unwrap();
23+
let p = dr.peripherals;
24+
let pins = dr.pins;
25+
26+
// Configure clocks
27+
let clocks = clock::configure(p.PRCI, p.AONCLK, 320.mhz().into());
28+
29+
// Configure UART for stdout
30+
hifive1::stdout::configure(
31+
p.UART0,
32+
pin!(pins, uart0_tx),
33+
pin!(pins, uart0_rx),
34+
115_200.bps(),
35+
clocks,
36+
);
37+
38+
let sda = pin!(pins, i2c0_sda).into_iof0();
39+
let scl = pin!(pins, i2c0_scl).into_iof0();
40+
let i2c = I2c::new(p.I2C0, sda, scl, Speed::Normal, clocks);
41+
42+
let mut sensor = Max3010x::new_max30102(i2c);
43+
let part_id = sensor.get_part_id().unwrap();
44+
sprintln!("Part ID: {:x}", part_id); // This should print "Part ID: 0x15" for a MAX30102.
45+
46+
let mut sensor = sensor.into_heart_rate().unwrap();
47+
sensor.set_sample_averaging(SampleAveraging::Sa4).unwrap();
48+
sensor.set_pulse_amplitude(Led::All, 15).unwrap();
49+
sensor.enable_fifo_rollover().unwrap();
50+
51+
let mut data = [0; 3];
52+
53+
// Get the sleep struct from CLINT
54+
let mut sleep = CLINT::delay();
55+
const STEP: u32 = 1000; // 1s
56+
loop {
57+
let samples_read = sensor.read_fifo(&mut data).unwrap();
58+
sprintln!("Samples read: {}", samples_read);
59+
sleep.delay_ms(STEP);
60+
}
61+
}

0 commit comments

Comments
 (0)