Skip to content

Commit

Permalink
examples: i2c: add master/slave examples
Browse files Browse the repository at this point in the history
Adds a master/slave sample that can be used to communicate with
eachother.

These two samples were verified using 2x Particle Borons (nrf52840 based).
With one sample running on one board, the other on the 2nd board.

Signed-off-by: Wilfred Mallawa <wilfred.mallawa@wdc.com>
  • Loading branch information
twilfredo committed Nov 30, 2023
1 parent 46da34b commit a67d6b1
Show file tree
Hide file tree
Showing 2 changed files with 177 additions and 0 deletions.
93 changes: 93 additions & 0 deletions examples/i2c_master_write_read.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
//! This sample demonstrates setting up the i2c ip (assuming board has support)
//! for master mode. In the event loop, we write some bytes to the target, then
//! attempt to read some bytes from the target.
//!
//! This sample is tested with `i2c_slave_send_recv.rs` sample running on the
//! slave device. That sample uses the synchronous slave api, so the order of operations
//! is important to ensure we don't cause the slave to stretch clocks if it hasn't setup
//! send buffers in time.

#![no_main]
#![no_std]
use core::fmt::Write;
use libtock::alarm::{Alarm, Milliseconds};
use libtock::console::Console;
use libtock::i2c_master_slave::I2CMasterSlave;
use libtock::runtime::{set_main, stack_size};

set_main! {main}
stack_size! {0x400}

pub const SLAVE_DEVICE_ADDR: u16 = 0x69;

fn main() {
let addr = SLAVE_DEVICE_ADDR;
// 7-bit addressing
assert!(addr <= 0x7f);
let mut tx_buf: [u8; 4] = [0; 4];
// Write 4 bytes to the slave
let tx_len = 4;
let mut rx_buf: [u8; 2] = [0; 2];
// Attempt to read 2 bytes from the slave
let rx_len = 2;

writeln!(Console::writer(), "i2c-master: write-read sample\r").unwrap();
writeln!(
Console::writer(),
"i2c-master: slave address 0x{:x}!\r",
addr
)
.unwrap();

let mut i: u32 = 0;
loop {
writeln!(
Console::writer(),
"i2c-master: write-read operation {:?}\r",
i
)
.unwrap();

// Change up the data in tx-buffer
tx_buf[0] = tx_buf[0].wrapping_add(2);
tx_buf[1] = tx_buf[1].wrapping_add(4);
tx_buf[2] = tx_buf[2].wrapping_add(6);
tx_buf[3] = tx_buf[3].wrapping_add(8);

if let Err(why) = I2CMasterSlave::i2c_master_slave_write_sync(addr, &tx_buf, tx_len) {
writeln!(
Console::writer(),
"i2c-master: write operation failed {:?}",
why
)
.unwrap();
} else {
// This sample target the i2c_slave_send_recv.rs sample, which is synchronous.
// so allow some time for it to setup 'send' buffer.
Alarm::sleep_for(Milliseconds(200)).unwrap();

let r = I2CMasterSlave::i2c_master_slave_read_sync(addr, &mut rx_buf, rx_len);
match r.1 {
Ok(()) => {
writeln!(
Console::writer(),
"{:} bytes read from slave | data received (0h): {:x?}\r\n",
r.0,
rx_buf
)
.unwrap();
}
Err(why) => {
writeln!(
Console::writer(),
"i2c-master: read operation failed {:?}",
why
)
.unwrap();
}
}
i += 1;
}
Alarm::sleep_for(Milliseconds(1000)).unwrap();
}
}
84 changes: 84 additions & 0 deletions examples/i2c_slave_send_recv.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
//! This sample demonstrates setting up the i2c ip (assuming board has support)
//! for target mode. In the event loop, we first expect the master to write some data
//! then we setup a response packet.
//!
//! NOTE: The device (based on hwip) may stretch clocks by holding the SCL line low if the master attempts to
//! read data before we have setup the read data buffers.
//!
//! This sample is tested with `i2c_master_write_read.rs` sample running on the
//! master device.

#![no_main]
#![no_std]
use core::fmt::Write;
use libtock::console::Console;
use libtock::i2c_master_slave::I2CMasterSlave;
use libtock::runtime::{set_main, stack_size};

set_main! {main}
stack_size! {0x400}
pub const SLAVE_DEVICE_ADDR: u8 = 0x69;
fn main() {
let mut rx_buf: [u8; 8] = [0; 8];
let mut tx_buf: [u8; 8] = [0; 8];
let addr: u8 = SLAVE_DEVICE_ADDR;
// 7-bit addressing
assert!(addr <= 0x7f);

writeln!(Console::writer(), "i2c-slave: setting up\r").unwrap();
writeln!(Console::writer(), "i2c-slave: address 0x{:x}!\r", addr).unwrap();

I2CMasterSlave::i2c_master_slave_set_slave_address(addr).expect("i2c-target: Failed to listen");
let mut i: u32 = 0;
loop {
writeln!(Console::writer(), "i2c-slave: operation {:?}\r", i).unwrap();

// Expect a write, if the master reads here, the IP may stretch clocks!
let r = I2CMasterSlave::i2c_master_slave_write_recv_sync(&mut rx_buf);

if let Err(why) = r.1 {
writeln!(
Console::writer(),
"i2c-slave: error to receiving data {:?}\r",
why
)
.unwrap();
} else {
writeln!(
Console::writer(),
"{:} bytes received from master | buf: {:x?}\r",
r.0,
rx_buf
)
.unwrap();

// Note: The master should allow a little delay when communicating with this slave
// as we are doing everything synchronously.
// Expect a 2 byte read by master and let's keep changing the values
tx_buf[0] = tx_buf[0].wrapping_add(1);
tx_buf[1] = tx_buf[1].wrapping_add(5);
let r = I2CMasterSlave::i2c_master_slave_read_send_sync(&tx_buf, tx_buf.len());

match r.1 {
Ok(()) => {
writeln!(
Console::writer(),
"{:} bytes read by master | data sent: {:x?}\r",
r.0,
tx_buf
)
.unwrap();
i += 1;
}
Err(why) => {
writeln!(
Console::writer(),
"i2c-slave: error setting up read_send {:?}\r",
why
)
.unwrap();
}
}
}
}
}

0 comments on commit a67d6b1

Please sign in to comment.