diff options
| author | Caleb Jamison <[email protected]> | 2023-09-10 02:05:58 -0400 |
|---|---|---|
| committer | Dario Nieuwenhuis <[email protected]> | 2023-09-10 23:01:15 +0200 |
| commit | 8201979d719f7f2647c7cb83b8e28bfc636b9d4a (patch) | |
| tree | 3efb2b383bfefb9c10403df088457bc73e236f3b | |
| parent | 2d9f50addc5f509f5549e69f594c382cebe739e6 (diff) | |
Add example, fix small bug in respond_and_fill
| -rw-r--r-- | embassy-rp/src/i2c_slave.rs | 12 | ||||
| -rw-r--r-- | examples/rp/src/bin/i2c_slave.rs | 118 |
2 files changed, 130 insertions, 0 deletions
diff --git a/embassy-rp/src/i2c_slave.rs b/embassy-rp/src/i2c_slave.rs index a65250116..6136d69c6 100644 --- a/embassy-rp/src/i2c_slave.rs +++ b/embassy-rp/src/i2c_slave.rs | |||
| @@ -287,6 +287,18 @@ impl<'d, T: Instance> I2cSlave<'d, T> { | |||
| 287 | } | 287 | } |
| 288 | } | 288 | } |
| 289 | 289 | ||
| 290 | /// Respond to a master read, then fill any remaining read bytes with `fill` | ||
| 291 | pub async fn respond_and_fill(&mut self, buffer: &[u8], fill: u8) -> Result<ReadStatus, Error> { | ||
| 292 | let resp_stat = self.respond_to_read(buffer).await?; | ||
| 293 | |||
| 294 | if resp_stat == ReadStatus::NeedMoreBytes { | ||
| 295 | self.respond_till_stop(fill).await?; | ||
| 296 | Ok(ReadStatus::Done) | ||
| 297 | } else { | ||
| 298 | Ok(resp_stat) | ||
| 299 | } | ||
| 300 | } | ||
| 301 | |||
| 290 | #[inline(always)] | 302 | #[inline(always)] |
| 291 | fn read_and_clear_abort_reason(&mut self) -> Result<(), Error> { | 303 | fn read_and_clear_abort_reason(&mut self) -> Result<(), Error> { |
| 292 | let p = T::regs(); | 304 | let p = T::regs(); |
diff --git a/examples/rp/src/bin/i2c_slave.rs b/examples/rp/src/bin/i2c_slave.rs new file mode 100644 index 000000000..7de300fb8 --- /dev/null +++ b/examples/rp/src/bin/i2c_slave.rs | |||
| @@ -0,0 +1,118 @@ | |||
| 1 | //! This example shows how to use the 2040 as an i2c slave. | ||
| 2 | #![no_std] | ||
| 3 | #![no_main] | ||
| 4 | #![feature(type_alias_impl_trait)] | ||
| 5 | |||
| 6 | use defmt::*; | ||
| 7 | use embassy_executor::Spawner; | ||
| 8 | use embassy_rp::peripherals::{I2C0, I2C1}; | ||
| 9 | use embassy_rp::{bind_interrupts, i2c, i2c_slave}; | ||
| 10 | use embassy_time::{Duration, Timer}; | ||
| 11 | use embedded_hal_async::i2c::I2c; | ||
| 12 | use {defmt_rtt as _, panic_probe as _}; | ||
| 13 | |||
| 14 | bind_interrupts!(struct Irqs { | ||
| 15 | I2C0_IRQ => i2c::InterruptHandler<I2C0>; | ||
| 16 | I2C1_IRQ => i2c::InterruptHandler<I2C1>; | ||
| 17 | }); | ||
| 18 | |||
| 19 | const DEV_ADDR: u8 = 0x42; | ||
| 20 | |||
| 21 | #[embassy_executor::task] | ||
| 22 | async fn device_task(mut dev: i2c_slave::I2cSlave<'static, I2C1>) -> ! { | ||
| 23 | info!("Device start"); | ||
| 24 | |||
| 25 | let mut state = 0; | ||
| 26 | |||
| 27 | loop { | ||
| 28 | let mut buf = [0u8; 128]; | ||
| 29 | match dev.listen(&mut buf).await { | ||
| 30 | Ok(i2c_slave::Command::GeneralCall(len)) => info!("Device recieved general call write: {}", buf[..len]), | ||
| 31 | Ok(i2c_slave::Command::Read) => loop { | ||
| 32 | match dev.respond_to_read(&[state]).await { | ||
| 33 | Ok(x) => match x { | ||
| 34 | i2c_slave::ReadStatus::Done => break, | ||
| 35 | i2c_slave::ReadStatus::NeedMoreBytes => (), | ||
| 36 | i2c_slave::ReadStatus::LeftoverBytes(x) => { | ||
| 37 | info!("tried to write {} extra bytes", x); | ||
| 38 | break; | ||
| 39 | } | ||
| 40 | }, | ||
| 41 | Err(e) => error!("error while responding {}", e), | ||
| 42 | } | ||
| 43 | }, | ||
| 44 | Ok(i2c_slave::Command::Write(len)) => info!("Device recieved write: {}", buf[..len]), | ||
| 45 | Ok(i2c_slave::Command::WriteRead(len)) => { | ||
| 46 | info!("device recieved write read: {:x}", buf[..len]); | ||
| 47 | match buf[0] { | ||
| 48 | // Set the state | ||
| 49 | 0xC2 => { | ||
| 50 | state = buf[1]; | ||
| 51 | match dev.respond_and_fill(&[state], 0x00).await { | ||
| 52 | Ok(read_status) => info!("response read status {}", read_status), | ||
| 53 | Err(e) => error!("error while responding {}", e), | ||
| 54 | } | ||
| 55 | } | ||
| 56 | // Reset State | ||
| 57 | 0xC8 => { | ||
| 58 | state = 0; | ||
| 59 | match dev.respond_and_fill(&[state], 0x00).await { | ||
| 60 | Ok(read_status) => info!("response read status {}", read_status), | ||
| 61 | Err(e) => error!("error while responding {}", e), | ||
| 62 | } | ||
| 63 | } | ||
| 64 | x => error!("Invalid Write Read {:x}", x), | ||
| 65 | } | ||
| 66 | } | ||
| 67 | Err(e) => error!("{}", e), | ||
| 68 | } | ||
| 69 | } | ||
| 70 | } | ||
| 71 | |||
| 72 | #[embassy_executor::task] | ||
| 73 | async fn controller_task(mut con: i2c::I2c<'static, I2C0, i2c::Async>) { | ||
| 74 | info!("Controller start"); | ||
| 75 | |||
| 76 | loop { | ||
| 77 | let mut resp_buff = [0u8; 2]; | ||
| 78 | for i in 0..10 { | ||
| 79 | match con.write_read(DEV_ADDR, &[0xC2, i], &mut resp_buff).await { | ||
| 80 | Ok(_) => info!("write_read response: {}", resp_buff), | ||
| 81 | Err(e) => error!("Error writing {}", e), | ||
| 82 | } | ||
| 83 | |||
| 84 | Timer::after(Duration::from_millis(100)).await; | ||
| 85 | } | ||
| 86 | match con.read(DEV_ADDR, &mut resp_buff).await { | ||
| 87 | Ok(_) => info!("read response: {}", resp_buff), | ||
| 88 | Err(e) => error!("Error writing {}", e), | ||
| 89 | } | ||
| 90 | match con.write_read(DEV_ADDR, &[0xC8], &mut resp_buff).await { | ||
| 91 | Ok(_) => info!("write_read response: {}", resp_buff), | ||
| 92 | Err(e) => error!("Error writing {}", e), | ||
| 93 | } | ||
| 94 | Timer::after(Duration::from_millis(100)).await; | ||
| 95 | } | ||
| 96 | } | ||
| 97 | |||
| 98 | #[embassy_executor::main] | ||
| 99 | async fn main(spawner: Spawner) { | ||
| 100 | let p = embassy_rp::init(Default::default()); | ||
| 101 | info!("Hello World!"); | ||
| 102 | |||
| 103 | let d_sda = p.PIN_3; | ||
| 104 | let d_scl = p.PIN_2; | ||
| 105 | let mut config = i2c_slave::Config::default(); | ||
| 106 | config.addr = DEV_ADDR as u16; | ||
| 107 | let device = i2c_slave::I2cSlave::new(p.I2C1, d_sda, d_scl, Irqs, config); | ||
| 108 | |||
| 109 | unwrap!(spawner.spawn(device_task(device))); | ||
| 110 | |||
| 111 | let c_sda = p.PIN_1; | ||
| 112 | let c_scl = p.PIN_0; | ||
| 113 | let mut config = i2c::Config::default(); | ||
| 114 | config.frequency = 5_000; | ||
| 115 | let controller = i2c::I2c::new_async(p.I2C0, c_sda, c_scl, Irqs, config); | ||
| 116 | |||
| 117 | unwrap!(spawner.spawn(controller_task(controller))); | ||
| 118 | } | ||
