aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2023-09-10 21:02:32 +0000
committerGitHub <[email protected]>2023-09-10 21:02:32 +0000
commitceb13def1945e164ceef28013497514760fef70f (patch)
tree910a0f6a8712f781149b0e3aa4e567faf3f6cdd8
parentceca8b4336d8706a9e767c0d397182d02527d8cc (diff)
parent5cf494113f7681ac6436bdbd7972e0074d1d26b7 (diff)
Merge pull request #1850 from CBJamo/i2cdev
rp2040: I2cDevice
-rw-r--r--embassy-rp/src/i2c.rs9
-rw-r--r--embassy-rp/src/i2c_slave.rs338
-rw-r--r--embassy-rp/src/lib.rs1
-rw-r--r--examples/rp/src/bin/i2c_slave.rs118
-rw-r--r--tests/rp/src/bin/i2c.rs212
5 files changed, 675 insertions, 3 deletions
diff --git a/embassy-rp/src/i2c.rs b/embassy-rp/src/i2c.rs
index 7a5ddd325..c358682c5 100644
--- a/embassy-rp/src/i2c.rs
+++ b/embassy-rp/src/i2c.rs
@@ -21,6 +21,8 @@ pub enum AbortReason {
21 NoAcknowledge, 21 NoAcknowledge,
22 /// The arbitration was lost, e.g. electrical problems with the clock signal 22 /// The arbitration was lost, e.g. electrical problems with the clock signal
23 ArbitrationLoss, 23 ArbitrationLoss,
24 /// Transmit ended with data still in fifo
25 TxNotEmpty(u16),
24 Other(u32), 26 Other(u32),
25} 27}
26 28
@@ -52,7 +54,7 @@ impl Default for Config {
52 } 54 }
53} 55}
54 56
55const FIFO_SIZE: u8 = 16; 57pub const FIFO_SIZE: u8 = 16;
56 58
57pub struct I2c<'d, T: Instance, M: Mode> { 59pub struct I2c<'d, T: Instance, M: Mode> {
58 phantom: PhantomData<(&'d mut T, M)>, 60 phantom: PhantomData<(&'d mut T, M)>,
@@ -636,6 +638,7 @@ mod eh1 {
636 Self::Abort(AbortReason::NoAcknowledge) => { 638 Self::Abort(AbortReason::NoAcknowledge) => {
637 embedded_hal_1::i2c::ErrorKind::NoAcknowledge(embedded_hal_1::i2c::NoAcknowledgeSource::Address) 639 embedded_hal_1::i2c::ErrorKind::NoAcknowledge(embedded_hal_1::i2c::NoAcknowledgeSource::Address)
638 } 640 }
641 Self::Abort(AbortReason::TxNotEmpty(_)) => embedded_hal_1::i2c::ErrorKind::Other,
639 Self::Abort(AbortReason::Other(_)) => embedded_hal_1::i2c::ErrorKind::Other, 642 Self::Abort(AbortReason::Other(_)) => embedded_hal_1::i2c::ErrorKind::Other,
640 Self::InvalidReadBufferLength => embedded_hal_1::i2c::ErrorKind::Other, 643 Self::InvalidReadBufferLength => embedded_hal_1::i2c::ErrorKind::Other,
641 Self::InvalidWriteBufferLength => embedded_hal_1::i2c::ErrorKind::Other, 644 Self::InvalidWriteBufferLength => embedded_hal_1::i2c::ErrorKind::Other,
@@ -738,8 +741,8 @@ mod nightly {
738 } 741 }
739} 742}
740 743
741fn i2c_reserved_addr(addr: u16) -> bool { 744pub fn i2c_reserved_addr(addr: u16) -> bool {
742 (addr & 0x78) == 0 || (addr & 0x78) == 0x78 745 ((addr & 0x78) == 0 || (addr & 0x78) == 0x78) && addr != 0
743} 746}
744 747
745mod sealed { 748mod sealed {
diff --git a/embassy-rp/src/i2c_slave.rs b/embassy-rp/src/i2c_slave.rs
new file mode 100644
index 000000000..6136d69c6
--- /dev/null
+++ b/embassy-rp/src/i2c_slave.rs
@@ -0,0 +1,338 @@
1use core::future;
2use core::marker::PhantomData;
3use core::task::Poll;
4
5use embassy_hal_internal::into_ref;
6use pac::i2c;
7
8use crate::i2c::{i2c_reserved_addr, AbortReason, Instance, InterruptHandler, SclPin, SdaPin, FIFO_SIZE};
9use crate::interrupt::typelevel::{Binding, Interrupt};
10use crate::{pac, Peripheral};
11
12/// I2C error
13#[derive(Debug)]
14#[cfg_attr(feature = "defmt", derive(defmt::Format))]
15#[non_exhaustive]
16pub enum Error {
17 /// I2C abort with error
18 Abort(AbortReason),
19 /// User passed in a response buffer that was 0 length
20 InvalidResponseBufferLength,
21}
22
23/// Received command
24#[derive(Debug, Copy, Clone, Eq, PartialEq)]
25#[cfg_attr(feature = "defmt", derive(defmt::Format))]
26pub enum Command {
27 /// General Call
28 GeneralCall(usize),
29 /// Read
30 Read,
31 /// Write+read
32 WriteRead(usize),
33 /// Write
34 Write(usize),
35}
36
37/// Possible responses to responding to a read
38#[derive(Debug, Copy, Clone, Eq, PartialEq)]
39#[cfg_attr(feature = "defmt", derive(defmt::Format))]
40pub enum ReadStatus {
41 /// Transaction Complete, controller naked our last byte
42 Done,
43 /// Transaction Incomplete, controller trying to read more bytes than were provided
44 NeedMoreBytes,
45 /// Transaction Complere, but controller stopped reading bytes before we ran out
46 LeftoverBytes(u16),
47}
48
49/// Slave Configuration
50#[non_exhaustive]
51#[derive(Copy, Clone)]
52#[cfg_attr(feature = "defmt", derive(defmt::Format))]
53pub struct Config {
54 /// Target Address
55 pub addr: u16,
56}
57
58impl Default for Config {
59 fn default() -> Self {
60 Self { addr: 0x55 }
61 }
62}
63
64pub struct I2cSlave<'d, T: Instance> {
65 phantom: PhantomData<&'d mut T>,
66}
67
68impl<'d, T: Instance> I2cSlave<'d, T> {
69 pub fn new(
70 _peri: impl Peripheral<P = T> + 'd,
71 scl: impl Peripheral<P = impl SclPin<T>> + 'd,
72 sda: impl Peripheral<P = impl SdaPin<T>> + 'd,
73 _irq: impl Binding<T::Interrupt, InterruptHandler<T>>,
74 config: Config,
75 ) -> Self {
76 into_ref!(_peri, scl, sda);
77
78 assert!(!i2c_reserved_addr(config.addr));
79 assert!(config.addr != 0);
80
81 let p = T::regs();
82
83 let reset = T::reset();
84 crate::reset::reset(reset);
85 crate::reset::unreset_wait(reset);
86
87 p.ic_enable().write(|w| w.set_enable(false));
88
89 p.ic_sar().write(|w| w.set_ic_sar(config.addr));
90 p.ic_con().modify(|w| {
91 w.set_master_mode(false);
92 w.set_ic_slave_disable(false);
93 w.set_tx_empty_ctrl(true);
94 });
95
96 // Set FIFO watermarks to 1 to make things simpler. This is encoded
97 // by a register value of 0. Rx watermark should never change, but Tx watermark will be
98 // adjusted in operation.
99 p.ic_tx_tl().write(|w| w.set_tx_tl(0));
100 p.ic_rx_tl().write(|w| w.set_rx_tl(0));
101
102 // Configure SCL & SDA pins
103 scl.gpio().ctrl().write(|w| w.set_funcsel(3));
104 sda.gpio().ctrl().write(|w| w.set_funcsel(3));
105
106 scl.pad_ctrl().write(|w| {
107 w.set_schmitt(true);
108 w.set_ie(true);
109 w.set_od(false);
110 w.set_pue(true);
111 w.set_pde(false);
112 });
113 sda.pad_ctrl().write(|w| {
114 w.set_schmitt(true);
115 w.set_ie(true);
116 w.set_od(false);
117 w.set_pue(true);
118 w.set_pde(false);
119 });
120
121 // Clear interrupts
122 p.ic_clr_intr().read();
123
124 // Enable I2C block
125 p.ic_enable().write(|w| w.set_enable(true));
126
127 // mask everything initially
128 p.ic_intr_mask().write_value(i2c::regs::IcIntrMask(0));
129 T::Interrupt::unpend();
130 unsafe { T::Interrupt::enable() };
131
132 Self { phantom: PhantomData }
133 }
134
135 /// Calls `f` to check if we are ready or not.
136 /// If not, `g` is called once the waker is set (to eg enable the required interrupts).
137 #[inline(always)]
138 async fn wait_on<F, U, G>(&mut self, mut f: F, mut g: G) -> U
139 where
140 F: FnMut(&mut Self) -> Poll<U>,
141 G: FnMut(&mut Self),
142 {
143 future::poll_fn(|cx| {
144 let r = f(self);
145
146 trace!("intr p: {:013b}", T::regs().ic_raw_intr_stat().read().0);
147
148 if r.is_pending() {
149 T::waker().register(cx.waker());
150 g(self);
151 }
152
153 r
154 })
155 .await
156 }
157
158 #[inline(always)]
159 fn drain_fifo(&mut self, buffer: &mut [u8], offset: usize) -> usize {
160 let p = T::regs();
161 let len = p.ic_rxflr().read().rxflr() as usize;
162 let end = offset + len;
163 for i in offset..end {
164 buffer[i] = p.ic_data_cmd().read().dat();
165 }
166 end
167 }
168
169 #[inline(always)]
170 fn write_to_fifo(&mut self, buffer: &[u8]) {
171 let p = T::regs();
172 for byte in buffer {
173 p.ic_data_cmd().write(|w| w.set_dat(*byte));
174 }
175 }
176
177 /// Wait asynchronously for commands from an I2C master.
178 /// `buffer` is provided in case master does a 'write' and is unused for 'read'.
179 pub async fn listen(&mut self, buffer: &mut [u8]) -> Result<Command, Error> {
180 let p = T::regs();
181
182 p.ic_clr_intr().read();
183 // set rx fifo watermark to 1 byte
184 p.ic_rx_tl().write(|w| w.set_rx_tl(0));
185
186 let mut len = 0;
187 let ret = self
188 .wait_on(
189 |me| {
190 let stat = p.ic_raw_intr_stat().read();
191 if p.ic_rxflr().read().rxflr() > 0 {
192 len = me.drain_fifo(buffer, len);
193 // we're recieving data, set rx fifo watermark to 12 bytes to reduce interrupt noise
194 p.ic_rx_tl().write(|w| w.set_rx_tl(11));
195 }
196
197 if stat.restart_det() && stat.rd_req() {
198 Poll::Ready(Ok(Command::WriteRead(len)))
199 } else if stat.gen_call() && stat.stop_det() && len > 0 {
200 Poll::Ready(Ok(Command::GeneralCall(len)))
201 } else if stat.stop_det() {
202 Poll::Ready(Ok(Command::Write(len)))
203 } else if stat.rd_req() {
204 Poll::Ready(Ok(Command::Read))
205 } else {
206 Poll::Pending
207 }
208 },
209 |_me| {
210 p.ic_intr_mask().modify(|w| {
211 w.set_m_stop_det(true);
212 w.set_m_restart_det(true);
213 w.set_m_gen_call(true);
214 w.set_m_rd_req(true);
215 w.set_m_rx_full(true);
216 });
217 },
218 )
219 .await;
220
221 p.ic_clr_intr().read();
222
223 ret
224 }
225
226 /// Respond to an I2C master READ command, asynchronously.
227 pub async fn respond_to_read(&mut self, buffer: &[u8]) -> Result<ReadStatus, Error> {
228 let p = T::regs();
229
230 if buffer.len() == 0 {
231 return Err(Error::InvalidResponseBufferLength);
232 }
233
234 let mut chunks = buffer.chunks(FIFO_SIZE as usize);
235
236 let ret = self
237 .wait_on(
238 |me| {
239 if let Err(abort_reason) = me.read_and_clear_abort_reason() {
240 if let Error::Abort(AbortReason::TxNotEmpty(bytes)) = abort_reason {
241 return Poll::Ready(Ok(ReadStatus::LeftoverBytes(bytes)));
242 } else {
243 return Poll::Ready(Err(abort_reason));
244 }
245 }
246
247 if let Some(chunk) = chunks.next() {
248 me.write_to_fifo(chunk);
249
250 Poll::Pending
251 } else {
252 let stat = p.ic_raw_intr_stat().read();
253
254 if stat.rx_done() && stat.stop_det() {
255 Poll::Ready(Ok(ReadStatus::Done))
256 } else if stat.rd_req() {
257 Poll::Ready(Ok(ReadStatus::NeedMoreBytes))
258 } else {
259 Poll::Pending
260 }
261 }
262 },
263 |_me| {
264 p.ic_intr_mask().modify(|w| {
265 w.set_m_stop_det(true);
266 w.set_m_rx_done(true);
267 w.set_m_tx_empty(true);
268 w.set_m_tx_abrt(true);
269 })
270 },
271 )
272 .await;
273
274 p.ic_clr_intr().read();
275
276 ret
277 }
278
279 /// Respond to reads with the fill byte until the controller stops asking
280 pub async fn respond_till_stop(&mut self, fill: u8) -> Result<(), Error> {
281 loop {
282 match self.respond_to_read(&[fill]).await {
283 Ok(ReadStatus::NeedMoreBytes) => (),
284 Ok(_) => break Ok(()),
285 Err(e) => break Err(e),
286 }
287 }
288 }
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
302 #[inline(always)]
303 fn read_and_clear_abort_reason(&mut self) -> Result<(), Error> {
304 let p = T::regs();
305 let mut abort_reason = p.ic_tx_abrt_source().read();
306
307 // Mask off fifo flush count
308 let tx_flush_cnt = abort_reason.tx_flush_cnt();
309 abort_reason.set_tx_flush_cnt(0);
310
311 // Mask off master_dis
312 abort_reason.set_abrt_master_dis(false);
313
314 if abort_reason.0 != 0 {
315 // Note clearing the abort flag also clears the reason, and this
316 // instance of flag is clear-on-read! Note also the
317 // IC_CLR_TX_ABRT register always reads as 0.
318 p.ic_clr_tx_abrt().read();
319
320 let reason = if abort_reason.abrt_7b_addr_noack()
321 | abort_reason.abrt_10addr1_noack()
322 | abort_reason.abrt_10addr2_noack()
323 {
324 AbortReason::NoAcknowledge
325 } else if abort_reason.arb_lost() {
326 AbortReason::ArbitrationLoss
327 } else if abort_reason.abrt_slvflush_txfifo() {
328 AbortReason::TxNotEmpty(tx_flush_cnt)
329 } else {
330 AbortReason::Other(abort_reason.0)
331 };
332
333 Err(Error::Abort(reason))
334 } else {
335 Ok(())
336 }
337 }
338}
diff --git a/embassy-rp/src/lib.rs b/embassy-rp/src/lib.rs
index 49bd3533e..2a1bca4b9 100644
--- a/embassy-rp/src/lib.rs
+++ b/embassy-rp/src/lib.rs
@@ -16,6 +16,7 @@ pub mod flash;
16mod float; 16mod float;
17pub mod gpio; 17pub mod gpio;
18pub mod i2c; 18pub mod i2c;
19pub mod i2c_slave;
19pub mod multicore; 20pub mod multicore;
20pub mod pwm; 21pub mod pwm;
21mod reset; 22mod reset;
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
6use defmt::*;
7use embassy_executor::Spawner;
8use embassy_rp::peripherals::{I2C0, I2C1};
9use embassy_rp::{bind_interrupts, i2c, i2c_slave};
10use embassy_time::{Duration, Timer};
11use embedded_hal_async::i2c::I2c;
12use {defmt_rtt as _, panic_probe as _};
13
14bind_interrupts!(struct Irqs {
15 I2C0_IRQ => i2c::InterruptHandler<I2C0>;
16 I2C1_IRQ => i2c::InterruptHandler<I2C1>;
17});
18
19const DEV_ADDR: u8 = 0x42;
20
21#[embassy_executor::task]
22async 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]
73async 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]
99async 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}
diff --git a/tests/rp/src/bin/i2c.rs b/tests/rp/src/bin/i2c.rs
new file mode 100644
index 000000000..425f2d086
--- /dev/null
+++ b/tests/rp/src/bin/i2c.rs
@@ -0,0 +1,212 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4teleprobe_meta::target!(b"rpi-pico");
5
6use defmt::{assert_eq, info, panic, unwrap};
7use embassy_executor::Executor;
8use embassy_executor::_export::StaticCell;
9use embassy_rp::multicore::{spawn_core1, Stack};
10use embassy_rp::peripherals::{I2C0, I2C1};
11use embassy_rp::{bind_interrupts, i2c, i2c_slave};
12use embedded_hal_1::i2c::Operation;
13use embedded_hal_async::i2c::I2c;
14use {defmt_rtt as _, panic_probe as _, panic_probe as _, panic_probe as _};
15
16static mut CORE1_STACK: Stack<1024> = Stack::new();
17static EXECUTOR0: StaticCell<Executor> = StaticCell::new();
18static EXECUTOR1: StaticCell<Executor> = StaticCell::new();
19
20use crate::i2c::AbortReason;
21
22bind_interrupts!(struct Irqs {
23 I2C0_IRQ => i2c::InterruptHandler<I2C0>;
24 I2C1_IRQ => i2c::InterruptHandler<I2C1>;
25});
26
27const DEV_ADDR: u8 = 0x42;
28
29#[embassy_executor::task]
30async fn device_task(mut dev: i2c_slave::I2cSlave<'static, I2C1>) -> ! {
31 info!("Device start");
32
33 let mut count = 0xD0;
34
35 loop {
36 let mut buf = [0u8; 128];
37 match dev.listen(&mut buf).await {
38 Ok(i2c_slave::Command::GeneralCall(len)) => {
39 assert_eq!(buf[..len], [0xCA, 0x11], "recieving the general call failed");
40 info!("General Call - OK");
41 }
42 Ok(i2c_slave::Command::Read) => {
43 loop {
44 match dev.respond_to_read(&[count]).await {
45 Ok(x) => match x {
46 i2c_slave::ReadStatus::Done => break,
47 i2c_slave::ReadStatus::NeedMoreBytes => count += 1,
48 i2c_slave::ReadStatus::LeftoverBytes(x) => {
49 info!("tried to write {} extra bytes", x);
50 break;
51 }
52 },
53 Err(e) => match e {
54 embassy_rp::i2c_slave::Error::Abort(AbortReason::Other(n)) => panic!("Other {:b}", n),
55 _ => panic!("{}", e),
56 },
57 }
58 }
59 count += 1;
60 }
61 Ok(i2c_slave::Command::Write(len)) => match len {
62 1 => {
63 assert_eq!(buf[..len], [0xAA], "recieving a single byte failed");
64 info!("Single Byte Write - OK")
65 }
66 4 => {
67 assert_eq!(buf[..len], [0xAA, 0xBB, 0xCC, 0xDD], "recieving 4 bytes failed");
68 info!("4 Byte Write - OK")
69 }
70 32 => {
71 assert_eq!(
72 buf[..len],
73 [
74 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
75 25, 26, 27, 28, 29, 30, 31
76 ],
77 "recieving 32 bytes failed"
78 );
79 info!("32 Byte Write - OK")
80 }
81 _ => panic!("Invalid write length {}", len),
82 },
83 Ok(i2c_slave::Command::WriteRead(len)) => {
84 info!("device recieved write read: {:x}", buf[..len]);
85 match buf[0] {
86 0xC2 => {
87 let resp_buff = [0xD1, 0xD2, 0xD3, 0xD4];
88 dev.respond_to_read(&resp_buff).await.unwrap();
89 }
90 0xC8 => {
91 let mut resp_buff = [0u8; 32];
92 for i in 0..32 {
93 resp_buff[i] = i as u8;
94 }
95 dev.respond_to_read(&resp_buff).await.unwrap();
96 }
97 x => panic!("Invalid Write Read {:x}", x),
98 }
99 }
100 Err(e) => match e {
101 embassy_rp::i2c_slave::Error::Abort(AbortReason::Other(n)) => panic!("Other {:b}", n),
102 _ => panic!("{}", e),
103 },
104 }
105 }
106}
107
108#[embassy_executor::task]
109async fn controller_task(mut con: i2c::I2c<'static, I2C0, i2c::Async>) {
110 info!("Device start");
111
112 {
113 let buf = [0xCA, 0x11];
114 con.write(0u16, &buf).await.unwrap();
115 info!("Controler general call write");
116 embassy_futures::yield_now().await;
117 }
118
119 {
120 let mut buf = [0u8];
121 con.read(DEV_ADDR, &mut buf).await.unwrap();
122 assert_eq!(buf, [0xD0], "single byte read failed");
123 info!("single byte read - OK");
124 embassy_futures::yield_now().await;
125 }
126
127 {
128 let mut buf = [0u8; 4];
129 con.read(DEV_ADDR, &mut buf).await.unwrap();
130 assert_eq!(buf, [0xD1, 0xD2, 0xD3, 0xD4], "single byte read failed");
131 info!("4 byte read - OK");
132 embassy_futures::yield_now().await;
133 }
134
135 {
136 let buf = [0xAA];
137 con.write(DEV_ADDR, &buf).await.unwrap();
138 info!("Controler single byte write");
139 embassy_futures::yield_now().await;
140 }
141
142 {
143 let buf = [0xAA, 0xBB, 0xCC, 0xDD];
144 con.write(DEV_ADDR, &buf).await.unwrap();
145 info!("Controler 4 byte write");
146 embassy_futures::yield_now().await;
147 }
148
149 {
150 let mut buf = [0u8; 32];
151 for i in 0..32 {
152 buf[i] = i as u8;
153 }
154 con.write(DEV_ADDR, &buf).await.unwrap();
155 info!("Controler 32 byte write");
156 embassy_futures::yield_now().await;
157 }
158
159 {
160 let mut buf = [0u8; 4];
161 let mut ops = [Operation::Write(&[0xC2]), Operation::Read(&mut buf)];
162 con.transaction(DEV_ADDR, &mut ops).await.unwrap();
163 assert_eq!(buf, [0xD1, 0xD2, 0xD3, 0xD4], "write_read failed");
164 info!("write_read - OK");
165 embassy_futures::yield_now().await;
166 }
167
168 {
169 let mut buf = [0u8; 32];
170 let mut ops = [Operation::Write(&[0xC8]), Operation::Read(&mut buf)];
171 con.transaction(DEV_ADDR, &mut ops).await.unwrap();
172 assert_eq!(
173 buf,
174 [
175 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,
176 28, 29, 30, 31
177 ],
178 "write_read of 32 bytes failed"
179 );
180 info!("large write_read - OK")
181 }
182
183 info!("Test OK");
184 cortex_m::asm::bkpt();
185}
186
187#[cortex_m_rt::entry]
188fn main() -> ! {
189 let p = embassy_rp::init(Default::default());
190 info!("Hello World!");
191
192 let d_sda = p.PIN_19;
193 let d_scl = p.PIN_18;
194 let mut config = i2c_slave::Config::default();
195 config.addr = DEV_ADDR as u16;
196 let device = i2c_slave::I2cSlave::new(p.I2C1, d_sda, d_scl, Irqs, config);
197
198 spawn_core1(p.CORE1, unsafe { &mut CORE1_STACK }, move || {
199 let executor1 = EXECUTOR1.init(Executor::new());
200 executor1.run(|spawner| unwrap!(spawner.spawn(device_task(device))));
201 });
202
203 let executor0 = EXECUTOR0.init(Executor::new());
204
205 let c_sda = p.PIN_21;
206 let c_scl = p.PIN_20;
207 let mut config = i2c::Config::default();
208 config.frequency = 5_000;
209 let controller = i2c::I2c::new_async(p.I2C0, c_sda, c_scl, Irqs, config);
210
211 executor0.run(|spawner| unwrap!(spawner.spawn(controller_task(controller))));
212}