Skip to content

Commit

Permalink
Add I2C loopback example with large buffer support
Browse files Browse the repository at this point in the history
  • Loading branch information
akshat2112 committed Mar 6, 2025
1 parent 2329ef5 commit 7d8ce43
Show file tree
Hide file tree
Showing 2 changed files with 136 additions and 4 deletions.
13 changes: 9 additions & 4 deletions examples/rt685s-evk/.cargo/config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,21 @@
runner = 'probe-rs run --chip MIMXRT685SFVKB'

rustflags = [
"-C", "linker=flip-link",
"-C", "link-arg=-Tlink.x",
"-C", "link-arg=-Tdefmt.x",
"-C",
"linker=flip-link",
"-C",
"link-arg=-Tlink.x",
"-C",
"link-arg=-Tdefmt.x",
# This is needed if your flash or ram addresses are not aligned to 0x10000 in memory.x
# See https://github.com/rust-embedded/cortex-m-quickstart/pull/95
"-C", "link-arg=--nmagic",
"-C",
"link-arg=--nmagic",
]

[build]
target = "thumbv8m.main-none-eabihf" # Cortex-M33

[env]
DEFMT_LOG = "trace"
EMBASSY_EXECUTOR_TASK_ARENA_SIZE = "16384"
127 changes: 127 additions & 0 deletions examples/rt685s-evk/src/bin/i2c-loopback-largebuf.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
#![no_std]
#![no_main]

extern crate embassy_imxrt_examples;

use defmt::info;
use embassy_executor::Spawner;
use embassy_imxrt::i2c::master::{I2cMaster, Speed};
use embassy_imxrt::i2c::slave::{Address, Command, I2cSlave, Response};
use embassy_imxrt::i2c::{self, Async, MAX_I2C_CHUNK_SIZE};
use embassy_imxrt::{bind_interrupts, peripherals};
use embedded_hal_async::i2c::I2c;

const ADDR: u8 = 0x20;
const BUFLEN: usize = 2500;
const SLAVE_ADDR: Option<Address> = Address::new(ADDR);

bind_interrupts!(struct Irqs {
FLEXCOMM2 => i2c::InterruptHandler<peripherals::FLEXCOMM2>;
FLEXCOMM4 => i2c::InterruptHandler<peripherals::FLEXCOMM4>;
});

/// Generate a buffer with increment numbers in each segment
fn generate_buffer<const SIZE: usize>() -> [u8; SIZE] {
let mut buf = [0xAA; SIZE];
for (i, e) in buf.iter_mut().enumerate() {
*e = ((i / MAX_I2C_CHUNK_SIZE) as u8) + 1;
}
buf
}

#[embassy_executor::task]
async fn slave_service(mut slave: I2cSlave<'static, Async>) {
// Buffer containing data read by the master
let t_buf: [u8; BUFLEN] = generate_buffer();

// Buffer that the master writes to
let mut r_buf = [0xAA; BUFLEN];
// Buffer to compare with written data
let expected_buf: [u8; BUFLEN] = generate_buffer();

let mut r_offset = 0;
let mut t_offset = 0;

loop {
match slave.listen().await.unwrap() {
Command::Probe => {
info!("Probe, nothing to do");
}
Command::Read => {
info!("Read");
loop {
let end = (t_offset + MAX_I2C_CHUNK_SIZE).min(t_buf.len());
let t_chunk = &t_buf[t_offset..end];
match slave.respond_to_read(t_chunk).await.unwrap() {
Response::Complete(n) => {
t_offset += n;
info!("Response complete read with {} bytes", n);
break;
}
Response::Pending(n) => {
t_offset += n;
info!("Response to read got {} bytes, more bytes to fill", n);
}
}
}
}
Command::Write => {
info!("Write");
loop {
let end = (r_offset + MAX_I2C_CHUNK_SIZE).min(r_buf.len());
let r_chunk = &mut r_buf[r_offset..end];
match slave.respond_to_write(r_chunk).await.unwrap() {
Response::Complete(n) => {
r_offset += n;
info!("Response complete write with {} bytes", n);

// Compare written data with expected data
assert!(r_buf[0..n] == expected_buf[0..n]);
break;
}
Response::Pending(n) => {
r_offset += n;
info!("Response to write got {} bytes, more bytes pending", n);
}
}
}
}
}
}
}

#[embassy_executor::task]
async fn master_service(mut master: I2cMaster<'static, Async>) {
const ADDR: u8 = 0x20;

// Buffer containing data to write to slave
let w_buf: [u8; BUFLEN] = generate_buffer();

// Buffer to compare with read data
let expected_buf: [u8; BUFLEN] = generate_buffer();
// Buffer to store data read from slave
let mut r_buf = [0xAA; BUFLEN];

let w_end = w_buf.len();
info!("i2cm write {} bytes", w_end);
master.write(ADDR, &w_buf[0..w_end]).await.unwrap();

let r_end = r_buf.len();
info!("i2cm read {} bytes", r_end);
master.read(ADDR, &mut r_buf[0..r_end]).await.unwrap();

assert!(r_buf[0..r_end] == expected_buf[0..r_end]);
}

#[embassy_executor::main]
async fn main(spawner: Spawner) {
info!("i2c loopback bigbuffer example");
let p = embassy_imxrt::init(Default::default());

let slave = I2cSlave::new_async(p.FLEXCOMM2, p.PIO0_18, p.PIO0_17, Irqs, SLAVE_ADDR.unwrap(), p.DMA0_CH4).unwrap();

let master = I2cMaster::new_async(p.FLEXCOMM4, p.PIO0_29, p.PIO0_30, Irqs, Speed::Standard, p.DMA0_CH9).unwrap();

spawner.must_spawn(master_service(master));
spawner.must_spawn(slave_service(slave));
}

0 comments on commit 7d8ce43

Please sign in to comment.