aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCaleb Jamison <[email protected]>2023-08-14 16:50:57 -0400
committerDario Nieuwenhuis <[email protected]>2023-09-10 23:01:15 +0200
commit26e0823c3507a537d72fa5d6d7e97126314c0f0c (patch)
tree12336d61c85117019e4012531c89ffb64a12c5cc
parentceca8b4336d8706a9e767c0d397182d02527d8cc (diff)
rp2040 I2cDevice
Move i2c to mod, split device and controller Remove mode generic: I don't think it's reasonable to use the i2c in device mode while blocking, so I'm cutting the generic.
-rw-r--r--embassy-rp/src/i2c/i2c.rs (renamed from embassy-rp/src/i2c.rs)171
-rw-r--r--embassy-rp/src/i2c/i2c_device.rs313
-rw-r--r--embassy-rp/src/i2c/mod.rs175
-rw-r--r--tests/rp/src/bin/i2c.rs215
4 files changed, 709 insertions, 165 deletions
diff --git a/embassy-rp/src/i2c.rs b/embassy-rp/src/i2c/i2c.rs
index 7a5ddd325..13124dd81 100644
--- a/embassy-rp/src/i2c.rs
+++ b/embassy-rp/src/i2c/i2c.rs
@@ -3,45 +3,19 @@ use core::marker::PhantomData;
3use core::task::Poll; 3use core::task::Poll;
4 4
5use embassy_hal_internal::{into_ref, PeripheralRef}; 5use embassy_hal_internal::{into_ref, PeripheralRef};
6use embassy_sync::waitqueue::AtomicWaker;
7use pac::i2c; 6use pac::i2c;
8 7
8use super::{
9 i2c_reserved_addr, AbortReason, Async, Blocking, Error, Instance, InterruptHandler, Mode, SclPin, SdaPin, FIFO_SIZE,
10};
9use crate::gpio::sealed::Pin; 11use crate::gpio::sealed::Pin;
10use crate::gpio::AnyPin; 12use crate::gpio::AnyPin;
11use crate::interrupt::typelevel::{Binding, Interrupt}; 13use crate::interrupt::typelevel::{Binding, Interrupt};
12use crate::{interrupt, pac, peripherals, Peripheral}; 14use crate::{pac, Peripheral};
13
14/// I2C error abort reason
15#[derive(Debug)]
16#[cfg_attr(feature = "defmt", derive(defmt::Format))]
17pub enum AbortReason {
18 /// A bus operation was not acknowledged, e.g. due to the addressed device
19 /// not being available on the bus or the device not being ready to process
20 /// requests at the moment
21 NoAcknowledge,
22 /// The arbitration was lost, e.g. electrical problems with the clock signal
23 ArbitrationLoss,
24 Other(u32),
25}
26
27/// I2C error
28#[derive(Debug)]
29#[cfg_attr(feature = "defmt", derive(defmt::Format))]
30pub enum Error {
31 /// I2C abort with error
32 Abort(AbortReason),
33 /// User passed in a read buffer that was 0 length
34 InvalidReadBufferLength,
35 /// User passed in a write buffer that was 0 length
36 InvalidWriteBufferLength,
37 /// Target i2c address is out of range
38 AddressOutOfRange(u16),
39 /// Target i2c address is reserved
40 AddressReserved(u16),
41}
42 15
43#[non_exhaustive] 16#[non_exhaustive]
44#[derive(Copy, Clone)] 17#[derive(Copy, Clone)]
18#[cfg_attr(feature = "defmt", derive(defmt::Format))]
45pub struct Config { 19pub struct Config {
46 pub frequency: u32, 20 pub frequency: u32,
47} 21}
@@ -52,8 +26,6 @@ impl Default for Config {
52 } 26 }
53} 27}
54 28
55const FIFO_SIZE: u8 = 16;
56
57pub struct I2c<'d, T: Instance, M: Mode> { 29pub struct I2c<'d, T: Instance, M: Mode> {
58 phantom: PhantomData<(&'d mut T, M)>, 30 phantom: PhantomData<(&'d mut T, M)>,
59} 31}
@@ -302,20 +274,6 @@ impl<'d, T: Instance> I2c<'d, T, Async> {
302 } 274 }
303} 275}
304 276
305pub struct InterruptHandler<T: Instance> {
306 _uart: PhantomData<T>,
307}
308
309impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
310 // Mask interrupts and wake any task waiting for this interrupt
311 unsafe fn on_interrupt() {
312 let i2c = T::regs();
313 i2c.ic_intr_mask().write_value(pac::i2c::regs::IcIntrMask::default());
314
315 T::waker().wake();
316 }
317}
318
319impl<'d, T: Instance + 'd, M: Mode> I2c<'d, T, M> { 277impl<'d, T: Instance + 'd, M: Mode> I2c<'d, T, M> {
320 fn new_inner( 278 fn new_inner(
321 _peri: impl Peripheral<P = T> + 'd, 279 _peri: impl Peripheral<P = T> + 'd,
@@ -636,6 +594,7 @@ mod eh1 {
636 Self::Abort(AbortReason::NoAcknowledge) => { 594 Self::Abort(AbortReason::NoAcknowledge) => {
637 embedded_hal_1::i2c::ErrorKind::NoAcknowledge(embedded_hal_1::i2c::NoAcknowledgeSource::Address) 595 embedded_hal_1::i2c::ErrorKind::NoAcknowledge(embedded_hal_1::i2c::NoAcknowledgeSource::Address)
638 } 596 }
597 Self::Abort(AbortReason::TxNotEmpty(_)) => embedded_hal_1::i2c::ErrorKind::Other,
639 Self::Abort(AbortReason::Other(_)) => embedded_hal_1::i2c::ErrorKind::Other, 598 Self::Abort(AbortReason::Other(_)) => embedded_hal_1::i2c::ErrorKind::Other,
640 Self::InvalidReadBufferLength => embedded_hal_1::i2c::ErrorKind::Other, 599 Self::InvalidReadBufferLength => embedded_hal_1::i2c::ErrorKind::Other,
641 Self::InvalidWriteBufferLength => embedded_hal_1::i2c::ErrorKind::Other, 600 Self::InvalidWriteBufferLength => embedded_hal_1::i2c::ErrorKind::Other,
@@ -737,121 +696,3 @@ mod nightly {
737 } 696 }
738 } 697 }
739} 698}
740
741fn i2c_reserved_addr(addr: u16) -> bool {
742 (addr & 0x78) == 0 || (addr & 0x78) == 0x78
743}
744
745mod sealed {
746 use embassy_sync::waitqueue::AtomicWaker;
747
748 use crate::interrupt;
749
750 pub trait Instance {
751 const TX_DREQ: u8;
752 const RX_DREQ: u8;
753
754 type Interrupt: interrupt::typelevel::Interrupt;
755
756 fn regs() -> crate::pac::i2c::I2c;
757 fn reset() -> crate::pac::resets::regs::Peripherals;
758 fn waker() -> &'static AtomicWaker;
759 }
760
761 pub trait Mode {}
762
763 pub trait SdaPin<T: Instance> {}
764 pub trait SclPin<T: Instance> {}
765}
766
767pub trait Mode: sealed::Mode {}
768
769macro_rules! impl_mode {
770 ($name:ident) => {
771 impl sealed::Mode for $name {}
772 impl Mode for $name {}
773 };
774}
775
776pub struct Blocking;
777pub struct Async;
778
779impl_mode!(Blocking);
780impl_mode!(Async);
781
782pub trait Instance: sealed::Instance {}
783
784macro_rules! impl_instance {
785 ($type:ident, $irq:ident, $reset:ident, $tx_dreq:expr, $rx_dreq:expr) => {
786 impl sealed::Instance for peripherals::$type {
787 const TX_DREQ: u8 = $tx_dreq;
788 const RX_DREQ: u8 = $rx_dreq;
789
790 type Interrupt = crate::interrupt::typelevel::$irq;
791
792 #[inline]
793 fn regs() -> pac::i2c::I2c {
794 pac::$type
795 }
796
797 #[inline]
798 fn reset() -> pac::resets::regs::Peripherals {
799 let mut ret = pac::resets::regs::Peripherals::default();
800 ret.$reset(true);
801 ret
802 }
803
804 #[inline]
805 fn waker() -> &'static AtomicWaker {
806 static WAKER: AtomicWaker = AtomicWaker::new();
807
808 &WAKER
809 }
810 }
811 impl Instance for peripherals::$type {}
812 };
813}
814
815impl_instance!(I2C0, I2C0_IRQ, set_i2c0, 32, 33);
816impl_instance!(I2C1, I2C1_IRQ, set_i2c1, 34, 35);
817
818pub trait SdaPin<T: Instance>: sealed::SdaPin<T> + crate::gpio::Pin {}
819pub trait SclPin<T: Instance>: sealed::SclPin<T> + crate::gpio::Pin {}
820
821macro_rules! impl_pin {
822 ($pin:ident, $instance:ident, $function:ident) => {
823 impl sealed::$function<peripherals::$instance> for peripherals::$pin {}
824 impl $function<peripherals::$instance> for peripherals::$pin {}
825 };
826}
827
828impl_pin!(PIN_0, I2C0, SdaPin);
829impl_pin!(PIN_1, I2C0, SclPin);
830impl_pin!(PIN_2, I2C1, SdaPin);
831impl_pin!(PIN_3, I2C1, SclPin);
832impl_pin!(PIN_4, I2C0, SdaPin);
833impl_pin!(PIN_5, I2C0, SclPin);
834impl_pin!(PIN_6, I2C1, SdaPin);
835impl_pin!(PIN_7, I2C1, SclPin);
836impl_pin!(PIN_8, I2C0, SdaPin);
837impl_pin!(PIN_9, I2C0, SclPin);
838impl_pin!(PIN_10, I2C1, SdaPin);
839impl_pin!(PIN_11, I2C1, SclPin);
840impl_pin!(PIN_12, I2C0, SdaPin);
841impl_pin!(PIN_13, I2C0, SclPin);
842impl_pin!(PIN_14, I2C1, SdaPin);
843impl_pin!(PIN_15, I2C1, SclPin);
844impl_pin!(PIN_16, I2C0, SdaPin);
845impl_pin!(PIN_17, I2C0, SclPin);
846impl_pin!(PIN_18, I2C1, SdaPin);
847impl_pin!(PIN_19, I2C1, SclPin);
848impl_pin!(PIN_20, I2C0, SdaPin);
849impl_pin!(PIN_21, I2C0, SclPin);
850impl_pin!(PIN_22, I2C1, SdaPin);
851impl_pin!(PIN_23, I2C1, SclPin);
852impl_pin!(PIN_24, I2C0, SdaPin);
853impl_pin!(PIN_25, I2C0, SclPin);
854impl_pin!(PIN_26, I2C1, SdaPin);
855impl_pin!(PIN_27, I2C1, SclPin);
856impl_pin!(PIN_28, I2C0, SdaPin);
857impl_pin!(PIN_29, I2C0, SclPin);
diff --git a/embassy-rp/src/i2c/i2c_device.rs b/embassy-rp/src/i2c/i2c_device.rs
new file mode 100644
index 000000000..915c0424e
--- /dev/null
+++ b/embassy-rp/src/i2c/i2c_device.rs
@@ -0,0 +1,313 @@
1use core::future;
2use core::marker::PhantomData;
3use core::task::Poll;
4
5use embassy_hal_internal::into_ref;
6use pac::i2c;
7
8use super::{i2c_reserved_addr, AbortReason, Error, Instance, InterruptHandler, SclPin, SdaPin, FIFO_SIZE};
9use crate::interrupt::typelevel::{Binding, Interrupt};
10use crate::{pac, Peripheral};
11
12/// Received command
13#[derive(Debug, Copy, Clone, Eq, PartialEq)]
14#[cfg_attr(feature = "defmt", derive(defmt::Format))]
15pub enum Command {
16 /// General Call
17 GeneralCall(usize),
18 /// Read
19 Read,
20 /// Write+read
21 WriteRead(usize),
22 /// Write
23 Write(usize),
24}
25
26/// Possible responses to responding to a read
27#[derive(Debug, Copy, Clone, Eq, PartialEq)]
28#[cfg_attr(feature = "defmt", derive(defmt::Format))]
29pub enum ReadStatus {
30 /// Transaction Complete, controller naked our last byte
31 Done,
32 /// Transaction Incomplete, controller trying to read more bytes than were provided
33 NeedMoreBytes,
34 /// Transaction Complere, but controller stopped reading bytes before we ran out
35 LeftoverBytes(u16),
36}
37
38/// Device Configuration
39#[non_exhaustive]
40#[derive(Copy, Clone)]
41#[cfg_attr(feature = "defmt", derive(defmt::Format))]
42pub struct DeviceConfig {
43 /// Target Address
44 pub addr: u16,
45}
46
47impl Default for DeviceConfig {
48 fn default() -> Self {
49 Self { addr: 0x55 }
50 }
51}
52
53pub struct I2cDevice<'d, T: Instance> {
54 phantom: PhantomData<&'d mut T>,
55}
56
57impl<'d, T: Instance> I2cDevice<'d, T> {
58 pub fn new(
59 _peri: impl Peripheral<P = T> + 'd,
60 scl: impl Peripheral<P = impl SclPin<T>> + 'd,
61 sda: impl Peripheral<P = impl SdaPin<T>> + 'd,
62 _irq: impl Binding<T::Interrupt, InterruptHandler<T>>,
63 config: DeviceConfig,
64 ) -> Self {
65 into_ref!(_peri, scl, sda);
66
67 assert!(!i2c_reserved_addr(config.addr));
68 assert!(config.addr != 0);
69
70 let p = T::regs();
71
72 let reset = T::reset();
73 crate::reset::reset(reset);
74 crate::reset::unreset_wait(reset);
75
76 p.ic_enable().write(|w| w.set_enable(false));
77
78 p.ic_sar().write(|w| w.set_ic_sar(config.addr));
79 p.ic_con().modify(|w| {
80 w.set_master_mode(false);
81 w.set_ic_slave_disable(false);
82 w.set_tx_empty_ctrl(true);
83 });
84
85 // Set FIFO watermarks to 1 to make things simpler. This is encoded
86 // by a register value of 0. Rx watermark should never change, but Tx watermark will be
87 // adjusted in operation.
88 p.ic_tx_tl().write(|w| w.set_tx_tl(0));
89 p.ic_rx_tl().write(|w| w.set_rx_tl(0));
90
91 // Configure SCL & SDA pins
92 scl.gpio().ctrl().write(|w| w.set_funcsel(3));
93 sda.gpio().ctrl().write(|w| w.set_funcsel(3));
94
95 scl.pad_ctrl().write(|w| {
96 w.set_schmitt(true);
97 w.set_ie(true);
98 w.set_od(false);
99 w.set_pue(true);
100 w.set_pde(false);
101 });
102 sda.pad_ctrl().write(|w| {
103 w.set_schmitt(true);
104 w.set_ie(true);
105 w.set_od(false);
106 w.set_pue(true);
107 w.set_pde(false);
108 });
109
110 // Clear interrupts
111 p.ic_clr_intr().read();
112
113 // Enable I2C block
114 p.ic_enable().write(|w| w.set_enable(true));
115
116 // mask everything initially
117 p.ic_intr_mask().write_value(i2c::regs::IcIntrMask(0));
118 T::Interrupt::unpend();
119 unsafe { T::Interrupt::enable() };
120
121 Self { phantom: PhantomData }
122 }
123
124 /// Calls `f` to check if we are ready or not.
125 /// If not, `g` is called once the waker is set (to eg enable the required interrupts).
126 #[inline(always)]
127 async fn wait_on<F, U, G>(&mut self, mut f: F, mut g: G) -> U
128 where
129 F: FnMut(&mut Self) -> Poll<U>,
130 G: FnMut(&mut Self),
131 {
132 future::poll_fn(|cx| {
133 let r = f(self);
134
135 trace!("intr p: {:013b}", T::regs().ic_raw_intr_stat().read().0);
136
137 if r.is_pending() {
138 T::waker().register(cx.waker());
139 g(self);
140 }
141
142 r
143 })
144 .await
145 }
146
147 #[inline(always)]
148 fn drain_fifo(&mut self, buffer: &mut [u8], offset: usize) -> usize {
149 let p = T::regs();
150 let len = p.ic_rxflr().read().rxflr() as usize;
151 let end = offset + len;
152 for i in offset..end {
153 buffer[i] = p.ic_data_cmd().read().dat();
154 }
155 end
156 }
157
158 #[inline(always)]
159 fn write_to_fifo(&mut self, buffer: &[u8]) {
160 let p = T::regs();
161 for byte in buffer {
162 p.ic_data_cmd().write(|w| w.set_dat(*byte));
163 }
164 }
165
166 /// Wait asynchronously for commands from an I2C master.
167 /// `buffer` is provided in case master does a 'write' and is unused for 'read'.
168 pub async fn listen(&mut self, buffer: &mut [u8]) -> Result<Command, Error> {
169 let p = T::regs();
170
171 p.ic_clr_intr().read();
172 // set rx fifo watermark to 1 byte
173 p.ic_rx_tl().write(|w| w.set_rx_tl(0));
174
175 let mut len = 0;
176 let ret = self
177 .wait_on(
178 |me| {
179 let stat = p.ic_raw_intr_stat().read();
180 if p.ic_rxflr().read().rxflr() > 0 {
181 len = me.drain_fifo(buffer, len);
182 // we're recieving data, set rx fifo watermark to 12 bytes to reduce interrupt noise
183 p.ic_rx_tl().write(|w| w.set_rx_tl(11));
184 }
185
186 if stat.restart_det() && stat.rd_req() {
187 Poll::Ready(Ok(Command::WriteRead(len)))
188 } else if stat.gen_call() && stat.stop_det() && len > 0 {
189 Poll::Ready(Ok(Command::GeneralCall(len)))
190 } else if stat.stop_det() {
191 Poll::Ready(Ok(Command::Write(len)))
192 } else if stat.rd_req() {
193 Poll::Ready(Ok(Command::Read))
194 } else {
195 Poll::Pending
196 }
197 },
198 |_me| {
199 p.ic_intr_mask().modify(|w| {
200 w.set_m_stop_det(true);
201 w.set_m_restart_det(true);
202 w.set_m_gen_call(true);
203 w.set_m_rd_req(true);
204 w.set_m_rx_full(true);
205 });
206 },
207 )
208 .await;
209
210 p.ic_clr_intr().read();
211
212 ret
213 }
214
215 /// Respond to an I2C master READ command, asynchronously.
216 pub async fn respond_to_read(&mut self, buffer: &[u8]) -> Result<ReadStatus, Error> {
217 let p = T::regs();
218
219 info!("buff: {}", buffer);
220 let mut chunks = buffer.chunks(FIFO_SIZE as usize);
221
222 let ret = self
223 .wait_on(
224 |me| {
225 if let Err(abort_reason) = me.read_and_clear_abort_reason() {
226 info!("ar: {}", abort_reason);
227 if let Error::Abort(AbortReason::TxNotEmpty(bytes)) = abort_reason {
228 return Poll::Ready(Ok(ReadStatus::LeftoverBytes(bytes)));
229 } else {
230 return Poll::Ready(Err(abort_reason));
231 }
232 }
233
234 if let Some(chunk) = chunks.next() {
235 me.write_to_fifo(chunk);
236
237 Poll::Pending
238 } else {
239 let stat = p.ic_raw_intr_stat().read();
240
241 if stat.rx_done() && stat.stop_det() {
242 Poll::Ready(Ok(ReadStatus::Done))
243 } else if stat.rd_req() {
244 Poll::Ready(Ok(ReadStatus::NeedMoreBytes))
245 } else {
246 Poll::Pending
247 }
248 }
249 },
250 |_me| {
251 p.ic_intr_mask().modify(|w| {
252 w.set_m_stop_det(true);
253 w.set_m_rx_done(true);
254 w.set_m_tx_empty(true);
255 w.set_m_tx_abrt(true);
256 })
257 },
258 )
259 .await;
260
261 p.ic_clr_intr().read();
262
263 ret
264 }
265
266 /// Respond to reads with the fill byte until the controller stops asking
267 pub async fn respond_till_stop(&mut self, fill: u8) -> Result<(), Error> {
268 loop {
269 match self.respond_to_read(&[fill]).await {
270 Ok(ReadStatus::NeedMoreBytes) => (),
271 Ok(_) => break Ok(()),
272 Err(e) => break Err(e),
273 }
274 }
275 }
276
277 #[inline(always)]
278 fn read_and_clear_abort_reason(&mut self) -> Result<(), Error> {
279 let p = T::regs();
280 let mut abort_reason = p.ic_tx_abrt_source().read();
281
282 // Mask off fifo flush count
283 let tx_flush_cnt = abort_reason.tx_flush_cnt();
284 abort_reason.set_tx_flush_cnt(0);
285
286 // Mask off master_dis
287 abort_reason.set_abrt_master_dis(false);
288
289 if abort_reason.0 != 0 {
290 // Note clearing the abort flag also clears the reason, and this
291 // instance of flag is clear-on-read! Note also the
292 // IC_CLR_TX_ABRT register always reads as 0.
293 p.ic_clr_tx_abrt().read();
294
295 let reason = if abort_reason.abrt_7b_addr_noack()
296 | abort_reason.abrt_10addr1_noack()
297 | abort_reason.abrt_10addr2_noack()
298 {
299 AbortReason::NoAcknowledge
300 } else if abort_reason.arb_lost() {
301 AbortReason::ArbitrationLoss
302 } else if abort_reason.abrt_slvflush_txfifo() {
303 AbortReason::TxNotEmpty(tx_flush_cnt)
304 } else {
305 AbortReason::Other(abort_reason.0)
306 };
307
308 Err(Error::Abort(reason))
309 } else {
310 Ok(())
311 }
312 }
313}
diff --git a/embassy-rp/src/i2c/mod.rs b/embassy-rp/src/i2c/mod.rs
new file mode 100644
index 000000000..2b3523d69
--- /dev/null
+++ b/embassy-rp/src/i2c/mod.rs
@@ -0,0 +1,175 @@
1mod i2c;
2mod i2c_device;
3
4use core::marker::PhantomData;
5
6use embassy_sync::waitqueue::AtomicWaker;
7pub use i2c::{Config, I2c};
8pub use i2c_device::{Command, DeviceConfig, I2cDevice, ReadStatus};
9
10use crate::{interrupt, pac, peripherals};
11
12const FIFO_SIZE: u8 = 16;
13
14/// I2C error abort reason
15#[derive(Debug, PartialEq, Eq)]
16#[cfg_attr(feature = "defmt", derive(defmt::Format))]
17pub enum AbortReason {
18 /// A bus operation was not acknowledged, e.g. due to the addressed device
19 /// not being available on the bus or the device not being ready to process
20 /// requests at the moment
21 NoAcknowledge,
22 /// The arbitration was lost, e.g. electrical problems with the clock signal
23 ArbitrationLoss,
24 /// Transmit ended with data still in fifo
25 TxNotEmpty(u16),
26 Other(u32),
27}
28
29/// I2C error
30#[derive(Debug, PartialEq, Eq)]
31#[cfg_attr(feature = "defmt", derive(defmt::Format))]
32pub enum Error {
33 /// I2C abort with error
34 Abort(AbortReason),
35 /// User passed in a read buffer that was 0 length
36 InvalidReadBufferLength,
37 /// User passed in a write buffer that was 0 length
38 InvalidWriteBufferLength,
39 /// Target i2c address is out of range
40 AddressOutOfRange(u16),
41 /// Target i2c address is reserved
42 AddressReserved(u16),
43}
44
45pub struct InterruptHandler<T: Instance> {
46 _uart: PhantomData<T>,
47}
48
49impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
50 // Mask interrupts and wake any task waiting for this interrupt
51 unsafe fn on_interrupt() {
52 let i2c = T::regs();
53 i2c.ic_intr_mask().write_value(pac::i2c::regs::IcIntrMask::default());
54
55 T::waker().wake();
56 }
57}
58
59fn i2c_reserved_addr(addr: u16) -> bool {
60 ((addr & 0x78) == 0 || (addr & 0x78) == 0x78) && addr != 0
61}
62
63mod sealed {
64 use embassy_sync::waitqueue::AtomicWaker;
65
66 use crate::interrupt;
67
68 pub trait Instance {
69 const TX_DREQ: u8;
70 const RX_DREQ: u8;
71
72 type Interrupt: interrupt::typelevel::Interrupt;
73
74 fn regs() -> crate::pac::i2c::I2c;
75 fn reset() -> crate::pac::resets::regs::Peripherals;
76 fn waker() -> &'static AtomicWaker;
77 }
78
79 pub trait Mode {}
80
81 pub trait SdaPin<T: Instance> {}
82 pub trait SclPin<T: Instance> {}
83}
84
85pub trait Mode: sealed::Mode {}
86
87macro_rules! impl_mode {
88 ($name:ident) => {
89 impl sealed::Mode for $name {}
90 impl Mode for $name {}
91 };
92}
93
94pub struct Blocking;
95pub struct Async;
96
97impl_mode!(Blocking);
98impl_mode!(Async);
99
100pub trait Instance: sealed::Instance {}
101
102macro_rules! impl_instance {
103 ($type:ident, $irq:ident, $reset:ident, $tx_dreq:expr, $rx_dreq:expr) => {
104 impl sealed::Instance for peripherals::$type {
105 const TX_DREQ: u8 = $tx_dreq;
106 const RX_DREQ: u8 = $rx_dreq;
107
108 type Interrupt = crate::interrupt::typelevel::$irq;
109
110 #[inline]
111 fn regs() -> pac::i2c::I2c {
112 pac::$type
113 }
114
115 #[inline]
116 fn reset() -> pac::resets::regs::Peripherals {
117 let mut ret = pac::resets::regs::Peripherals::default();
118 ret.$reset(true);
119 ret
120 }
121
122 #[inline]
123 fn waker() -> &'static AtomicWaker {
124 static WAKER: AtomicWaker = AtomicWaker::new();
125
126 &WAKER
127 }
128 }
129 impl Instance for peripherals::$type {}
130 };
131}
132
133impl_instance!(I2C0, I2C0_IRQ, set_i2c0, 32, 33);
134impl_instance!(I2C1, I2C1_IRQ, set_i2c1, 34, 35);
135
136pub trait SdaPin<T: Instance>: sealed::SdaPin<T> + crate::gpio::Pin {}
137pub trait SclPin<T: Instance>: sealed::SclPin<T> + crate::gpio::Pin {}
138
139macro_rules! impl_pin {
140 ($pin:ident, $instance:ident, $function:ident) => {
141 impl sealed::$function<peripherals::$instance> for peripherals::$pin {}
142 impl $function<peripherals::$instance> for peripherals::$pin {}
143 };
144}
145
146impl_pin!(PIN_0, I2C0, SdaPin);
147impl_pin!(PIN_1, I2C0, SclPin);
148impl_pin!(PIN_2, I2C1, SdaPin);
149impl_pin!(PIN_3, I2C1, SclPin);
150impl_pin!(PIN_4, I2C0, SdaPin);
151impl_pin!(PIN_5, I2C0, SclPin);
152impl_pin!(PIN_6, I2C1, SdaPin);
153impl_pin!(PIN_7, I2C1, SclPin);
154impl_pin!(PIN_8, I2C0, SdaPin);
155impl_pin!(PIN_9, I2C0, SclPin);
156impl_pin!(PIN_10, I2C1, SdaPin);
157impl_pin!(PIN_11, I2C1, SclPin);
158impl_pin!(PIN_12, I2C0, SdaPin);
159impl_pin!(PIN_13, I2C0, SclPin);
160impl_pin!(PIN_14, I2C1, SdaPin);
161impl_pin!(PIN_15, I2C1, SclPin);
162impl_pin!(PIN_16, I2C0, SdaPin);
163impl_pin!(PIN_17, I2C0, SclPin);
164impl_pin!(PIN_18, I2C1, SdaPin);
165impl_pin!(PIN_19, I2C1, SclPin);
166impl_pin!(PIN_20, I2C0, SdaPin);
167impl_pin!(PIN_21, I2C0, SclPin);
168impl_pin!(PIN_22, I2C1, SdaPin);
169impl_pin!(PIN_23, I2C1, SclPin);
170impl_pin!(PIN_24, I2C0, SdaPin);
171impl_pin!(PIN_25, I2C0, SclPin);
172impl_pin!(PIN_26, I2C1, SdaPin);
173impl_pin!(PIN_27, I2C1, SclPin);
174impl_pin!(PIN_28, I2C0, SdaPin);
175impl_pin!(PIN_29, I2C0, SclPin);
diff --git a/tests/rp/src/bin/i2c.rs b/tests/rp/src/bin/i2c.rs
new file mode 100644
index 000000000..63dd00233
--- /dev/null
+++ b/tests/rp/src/bin/i2c.rs
@@ -0,0 +1,215 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::{assert_eq, info, panic, unwrap};
6use embassy_executor::Executor;
7use embassy_executor::_export::StaticCell;
8use embassy_rp::bind_interrupts;
9use embassy_rp::i2c::{self, Async, InterruptHandler};
10use embassy_rp::multicore::{spawn_core1, Stack};
11use embassy_rp::peripherals::{I2C0, I2C1};
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 => InterruptHandler<I2C0>;
24 I2C1_IRQ => InterruptHandler<I2C1>;
25});
26
27const DEV_ADDR: u8 = 0x42;
28
29#[embassy_executor::task]
30async fn device_task(mut dev: i2c::I2cDevice<'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::Command::GeneralCall(len)) => {
39 assert_eq!(buf[..len], [0xCA, 0x11], "recieving the general call failed");
40 info!("General Call - OK");
41 }
42 Ok(i2c::Command::Read) => {
43 loop {
44 //info!("Responding to read, count {}", count);
45 let a = dev.respond_to_read(&[count]).await;
46 //info!("x {}", a);
47 match a {
48 Ok(x) => match x {
49 i2c::ReadStatus::Done => break,
50 i2c::ReadStatus::NeedMoreBytes => count += 1,
51 i2c::ReadStatus::LeftoverBytes(x) => {
52 info!("tried to write {} extra bytes", x);
53 break;
54 }
55 },
56 Err(e) => match e {
57 embassy_rp::i2c::Error::Abort(AbortReason::Other(n)) => panic!("Other {:b}", n),
58 _ => panic!("{}", e),
59 },
60 }
61 }
62 count += 1;
63 }
64 Ok(i2c::Command::Write(len)) => match len {
65 1 => {
66 assert_eq!(buf[..len], [0xAA], "recieving a single byte failed");
67 info!("Single Byte Write - OK")
68 }
69 4 => {
70 assert_eq!(buf[..len], [0xAA, 0xBB, 0xCC, 0xDD], "recieving 4 bytes failed");
71 info!("4 Byte Write - OK")
72 }
73 32 => {
74 assert_eq!(
75 buf[..len],
76 [
77 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,
78 25, 26, 27, 28, 29, 30, 31
79 ],
80 "recieving 32 bytes failed"
81 );
82 info!("32 Byte Write - OK")
83 }
84 _ => panic!("Invalid write length {}", len),
85 },
86 Ok(i2c::Command::WriteRead(len)) => {
87 info!("device recieved write read: {:x}", buf[..len]);
88 match buf[0] {
89 0xC2 => {
90 let resp_buff = [0xD1, 0xD2, 0xD3, 0xD4];
91 dev.respond_to_read(&resp_buff).await.unwrap();
92 }
93 0xC8 => {
94 let mut resp_buff = [0u8; 32];
95 for i in 0..32 {
96 resp_buff[i] = i as u8;
97 }
98 dev.respond_to_read(&resp_buff).await.unwrap();
99 }
100 x => panic!("Invalid Write Read {:x}", x),
101 }
102 }
103 Err(e) => match e {
104 embassy_rp::i2c::Error::Abort(AbortReason::Other(n)) => panic!("Other {:b}", n),
105 _ => panic!("{}", e),
106 },
107 }
108 }
109}
110
111#[embassy_executor::task]
112async fn controller_task(mut con: i2c::I2c<'static, I2C0, Async>) {
113 info!("Device start");
114
115 {
116 let buf = [0xCA, 0x11];
117 con.write(0u16, &buf).await.unwrap();
118 info!("Controler general call write");
119 embassy_futures::yield_now().await;
120 }
121
122 {
123 let mut buf = [0u8];
124 con.read(DEV_ADDR, &mut buf).await.unwrap();
125 assert_eq!(buf, [0xD0], "single byte read failed");
126 info!("single byte read - OK");
127 embassy_futures::yield_now().await;
128 }
129
130 {
131 let mut buf = [0u8; 4];
132 con.read(DEV_ADDR, &mut buf).await.unwrap();
133 assert_eq!(buf, [0xD1, 0xD2, 0xD3, 0xD4], "single byte read failed");
134 info!("4 byte read - OK");
135 embassy_futures::yield_now().await;
136 }
137
138 {
139 let buf = [0xAA];
140 con.write(DEV_ADDR, &buf).await.unwrap();
141 info!("Controler single byte write");
142 embassy_futures::yield_now().await;
143 }
144
145 {
146 let buf = [0xAA, 0xBB, 0xCC, 0xDD];
147 con.write(DEV_ADDR, &buf).await.unwrap();
148 info!("Controler 4 byte write");
149 embassy_futures::yield_now().await;
150 }
151
152 {
153 let mut buf = [0u8; 32];
154 for i in 0..32 {
155 buf[i] = i as u8;
156 }
157 con.write(DEV_ADDR, &buf).await.unwrap();
158 info!("Controler 32 byte write");
159 embassy_futures::yield_now().await;
160 }
161
162 {
163 let mut buf = [0u8; 4];
164 let mut ops = [Operation::Write(&[0xC2]), Operation::Read(&mut buf)];
165 con.transaction(DEV_ADDR, &mut ops).await.unwrap();
166 assert_eq!(buf, [0xD1, 0xD2, 0xD3, 0xD4], "write_read failed");
167 info!("write_read - OK");
168 embassy_futures::yield_now().await;
169 }
170
171 {
172 let mut buf = [0u8; 32];
173 let mut ops = [Operation::Write(&[0xC8]), Operation::Read(&mut buf)];
174 con.transaction(DEV_ADDR, &mut ops).await.unwrap();
175 assert_eq!(
176 buf,
177 [
178 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,
179 28, 29, 30, 31
180 ],
181 "write_read of 32 bytes failed"
182 );
183 info!("large write_read - OK")
184 }
185
186 info!("Test OK");
187 cortex_m::asm::bkpt();
188}
189
190#[cortex_m_rt::entry]
191fn main() -> ! {
192 let p = embassy_rp::init(Default::default());
193 info!("Hello World!");
194
195 let d_sda = p.PIN_19;
196 let d_scl = p.PIN_18;
197 let mut config = i2c::DeviceConfig::default();
198 config.addr = DEV_ADDR as u16;
199 let device = i2c::I2cDevice::new(p.I2C1, d_sda, d_scl, Irqs, config);
200
201 spawn_core1(p.CORE1, unsafe { &mut CORE1_STACK }, move || {
202 let executor1 = EXECUTOR1.init(Executor::new());
203 executor1.run(|spawner| unwrap!(spawner.spawn(device_task(device))));
204 });
205
206 let executor0 = EXECUTOR0.init(Executor::new());
207
208 let c_sda = p.PIN_21;
209 let c_scl = p.PIN_20;
210 let mut config = i2c::Config::default();
211 config.frequency = 5_000;
212 let controller = i2c::I2c::new_async(p.I2C0, c_sda, c_scl, Irqs, config);
213
214 executor0.run(|spawner| unwrap!(spawner.spawn(controller_task(controller))));
215}