aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorkalkyl <[email protected]>2022-11-13 22:15:19 +0100
committerkalkyl <[email protected]>2022-11-13 22:15:19 +0100
commiteba42cb5f4c4dc1be54c27729325e982d85fc8b0 (patch)
tree1d99f0e9ea675e67743d839008d75f0682e4e855
parentd05979c7085675c33615700f6590b1543ed69323 (diff)
embassy-nrf: Add TWIS module
-rw-r--r--embassy-nrf/src/chips/nrf52805.rs2
-rw-r--r--embassy-nrf/src/chips/nrf52810.rs2
-rw-r--r--embassy-nrf/src/chips/nrf52811.rs2
-rw-r--r--embassy-nrf/src/chips/nrf52820.rs3
-rw-r--r--embassy-nrf/src/chips/nrf52832.rs3
-rw-r--r--embassy-nrf/src/chips/nrf52833.rs3
-rw-r--r--embassy-nrf/src/chips/nrf52840.rs3
-rw-r--r--embassy-nrf/src/chips/nrf5340_app.rs5
-rw-r--r--embassy-nrf/src/chips/nrf5340_net.rs1
-rw-r--r--embassy-nrf/src/chips/nrf9160.rs5
-rw-r--r--embassy-nrf/src/lib.rs7
-rw-r--r--embassy-nrf/src/twis.rs734
-rw-r--r--examples/nrf/src/bin/twis.rs45
13 files changed, 815 insertions, 0 deletions
diff --git a/embassy-nrf/src/chips/nrf52805.rs b/embassy-nrf/src/chips/nrf52805.rs
index dec31a84c..0630c0fbf 100644
--- a/embassy-nrf/src/chips/nrf52805.rs
+++ b/embassy-nrf/src/chips/nrf52805.rs
@@ -133,6 +133,8 @@ impl_spim!(SPI0, SPIM0, SPIM0_SPIS0_SPI0);
133 133
134impl_twim!(TWI0, TWIM0, TWIM0_TWIS0_TWI0); 134impl_twim!(TWI0, TWIM0, TWIM0_TWIS0_TWI0);
135 135
136impl_twis!(TWI0, TWIS0, TWIM0_TWIS0_TWI0);
137
136impl_timer!(TIMER0, TIMER0, TIMER0); 138impl_timer!(TIMER0, TIMER0, TIMER0);
137impl_timer!(TIMER1, TIMER1, TIMER1); 139impl_timer!(TIMER1, TIMER1, TIMER1);
138impl_timer!(TIMER2, TIMER2, TIMER2); 140impl_timer!(TIMER2, TIMER2, TIMER2);
diff --git a/embassy-nrf/src/chips/nrf52810.rs b/embassy-nrf/src/chips/nrf52810.rs
index e57a4a383..3867fbd92 100644
--- a/embassy-nrf/src/chips/nrf52810.rs
+++ b/embassy-nrf/src/chips/nrf52810.rs
@@ -139,6 +139,8 @@ impl_spim!(SPI0, SPIM0, SPIM0_SPIS0_SPI0);
139 139
140impl_twim!(TWI0, TWIM0, TWIM0_TWIS0_TWI0); 140impl_twim!(TWI0, TWIM0, TWIM0_TWIS0_TWI0);
141 141
142impl_twis!(TWI0, TWIS0, TWIM0_TWIS0_TWI0);
143
142impl_pwm!(PWM0, PWM0, PWM0); 144impl_pwm!(PWM0, PWM0, PWM0);
143 145
144impl_timer!(TIMER0, TIMER0, TIMER0); 146impl_timer!(TIMER0, TIMER0, TIMER0);
diff --git a/embassy-nrf/src/chips/nrf52811.rs b/embassy-nrf/src/chips/nrf52811.rs
index 918404cf1..36efd1dbd 100644
--- a/embassy-nrf/src/chips/nrf52811.rs
+++ b/embassy-nrf/src/chips/nrf52811.rs
@@ -140,6 +140,8 @@ impl_spim!(SPI1, SPIM1, SPIM1_SPIS1_SPI1);
140 140
141impl_twim!(TWISPI0, TWIM0, TWIM0_TWIS0_TWI0_SPIM0_SPIS0_SPI0); 141impl_twim!(TWISPI0, TWIM0, TWIM0_TWIS0_TWI0_SPIM0_SPIS0_SPI0);
142 142
143impl_twis!(TWISPI0, TWIS0, TWIM0_TWIS0_TWI0_SPIM0_SPIS0_SPI0);
144
143impl_pwm!(PWM0, PWM0, PWM0); 145impl_pwm!(PWM0, PWM0, PWM0);
144 146
145impl_timer!(TIMER0, TIMER0, TIMER0); 147impl_timer!(TIMER0, TIMER0, TIMER0);
diff --git a/embassy-nrf/src/chips/nrf52820.rs b/embassy-nrf/src/chips/nrf52820.rs
index dba033b0f..33a07bbc4 100644
--- a/embassy-nrf/src/chips/nrf52820.rs
+++ b/embassy-nrf/src/chips/nrf52820.rs
@@ -139,6 +139,9 @@ impl_spim!(TWISPI1, SPIM1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1);
139impl_twim!(TWISPI0, TWIM0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); 139impl_twim!(TWISPI0, TWIM0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0);
140impl_twim!(TWISPI1, TWIM1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); 140impl_twim!(TWISPI1, TWIM1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1);
141 141
142impl_twis!(TWISPI0, TWIS0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0);
143impl_twis!(TWISPI1, TWIS1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1);
144
142impl_timer!(TIMER0, TIMER0, TIMER0); 145impl_timer!(TIMER0, TIMER0, TIMER0);
143impl_timer!(TIMER1, TIMER1, TIMER1); 146impl_timer!(TIMER1, TIMER1, TIMER1);
144impl_timer!(TIMER2, TIMER2, TIMER2); 147impl_timer!(TIMER2, TIMER2, TIMER2);
diff --git a/embassy-nrf/src/chips/nrf52832.rs b/embassy-nrf/src/chips/nrf52832.rs
index 81e66c193..b1c33c395 100644
--- a/embassy-nrf/src/chips/nrf52832.rs
+++ b/embassy-nrf/src/chips/nrf52832.rs
@@ -149,6 +149,9 @@ impl_spim!(SPI2, SPIM2, SPIM2_SPIS2_SPI2);
149impl_twim!(TWISPI0, TWIM0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); 149impl_twim!(TWISPI0, TWIM0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0);
150impl_twim!(TWISPI1, TWIM1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); 150impl_twim!(TWISPI1, TWIM1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1);
151 151
152impl_twis!(TWISPI0, TWIS0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0);
153impl_twis!(TWISPI1, TWIS1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1);
154
152impl_pwm!(PWM0, PWM0, PWM0); 155impl_pwm!(PWM0, PWM0, PWM0);
153impl_pwm!(PWM1, PWM1, PWM1); 156impl_pwm!(PWM1, PWM1, PWM1);
154impl_pwm!(PWM2, PWM2, PWM2); 157impl_pwm!(PWM2, PWM2, PWM2);
diff --git a/embassy-nrf/src/chips/nrf52833.rs b/embassy-nrf/src/chips/nrf52833.rs
index 92499e3c9..db0a87bd9 100644
--- a/embassy-nrf/src/chips/nrf52833.rs
+++ b/embassy-nrf/src/chips/nrf52833.rs
@@ -177,6 +177,9 @@ impl_spim!(SPI3, SPIM3, SPIM3);
177impl_twim!(TWISPI0, TWIM0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); 177impl_twim!(TWISPI0, TWIM0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0);
178impl_twim!(TWISPI1, TWIM1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); 178impl_twim!(TWISPI1, TWIM1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1);
179 179
180impl_twis!(TWISPI0, TWIS0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0);
181impl_twis!(TWISPI1, TWIS1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1);
182
180impl_pwm!(PWM0, PWM0, PWM0); 183impl_pwm!(PWM0, PWM0, PWM0);
181impl_pwm!(PWM1, PWM1, PWM1); 184impl_pwm!(PWM1, PWM1, PWM1);
182impl_pwm!(PWM2, PWM2, PWM2); 185impl_pwm!(PWM2, PWM2, PWM2);
diff --git a/embassy-nrf/src/chips/nrf52840.rs b/embassy-nrf/src/chips/nrf52840.rs
index 4beadfba8..3f4c8b8f1 100644
--- a/embassy-nrf/src/chips/nrf52840.rs
+++ b/embassy-nrf/src/chips/nrf52840.rs
@@ -180,6 +180,9 @@ impl_spim!(SPI3, SPIM3, SPIM3);
180impl_twim!(TWISPI0, TWIM0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); 180impl_twim!(TWISPI0, TWIM0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0);
181impl_twim!(TWISPI1, TWIM1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); 181impl_twim!(TWISPI1, TWIM1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1);
182 182
183impl_twis!(TWISPI0, TWIS0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0);
184impl_twis!(TWISPI1, TWIS1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1);
185
183impl_pwm!(PWM0, PWM0, PWM0); 186impl_pwm!(PWM0, PWM0, PWM0);
184impl_pwm!(PWM1, PWM1, PWM1); 187impl_pwm!(PWM1, PWM1, PWM1);
185impl_pwm!(PWM2, PWM2, PWM2); 188impl_pwm!(PWM2, PWM2, PWM2);
diff --git a/embassy-nrf/src/chips/nrf5340_app.rs b/embassy-nrf/src/chips/nrf5340_app.rs
index 7845d4a8e..632c02ccd 100644
--- a/embassy-nrf/src/chips/nrf5340_app.rs
+++ b/embassy-nrf/src/chips/nrf5340_app.rs
@@ -366,6 +366,11 @@ impl_twim!(UARTETWISPI1, TWIM1, SERIAL1);
366impl_twim!(UARTETWISPI2, TWIM2, SERIAL2); 366impl_twim!(UARTETWISPI2, TWIM2, SERIAL2);
367impl_twim!(UARTETWISPI3, TWIM3, SERIAL3); 367impl_twim!(UARTETWISPI3, TWIM3, SERIAL3);
368 368
369impl_twis!(UARTETWISPI0, TWIS0, SERIAL0);
370impl_twis!(UARTETWISPI1, TWIS1, SERIAL1);
371impl_twis!(UARTETWISPI2, TWIS2, SERIAL2);
372impl_twis!(UARTETWISPI3, TWIS3, SERIAL3);
373
369impl_pwm!(PWM0, PWM0, PWM0); 374impl_pwm!(PWM0, PWM0, PWM0);
370impl_pwm!(PWM1, PWM1, PWM1); 375impl_pwm!(PWM1, PWM1, PWM1);
371impl_pwm!(PWM2, PWM2, PWM2); 376impl_pwm!(PWM2, PWM2, PWM2);
diff --git a/embassy-nrf/src/chips/nrf5340_net.rs b/embassy-nrf/src/chips/nrf5340_net.rs
index ae136e09d..917d1a867 100644
--- a/embassy-nrf/src/chips/nrf5340_net.rs
+++ b/embassy-nrf/src/chips/nrf5340_net.rs
@@ -239,6 +239,7 @@ embassy_hal_common::peripherals! {
239impl_uarte!(UARTETWISPI0, UARTE0, SERIAL0); 239impl_uarte!(UARTETWISPI0, UARTE0, SERIAL0);
240impl_spim!(UARTETWISPI0, SPIM0, SERIAL0); 240impl_spim!(UARTETWISPI0, SPIM0, SERIAL0);
241impl_twim!(UARTETWISPI0, TWIM0, SERIAL0); 241impl_twim!(UARTETWISPI0, TWIM0, SERIAL0);
242impl_twis!(UARTETWISPI0, TWIS0, SERIAL0);
242 243
243impl_timer!(TIMER0, TIMER0, TIMER0); 244impl_timer!(TIMER0, TIMER0, TIMER0);
244impl_timer!(TIMER1, TIMER1, TIMER1); 245impl_timer!(TIMER1, TIMER1, TIMER1);
diff --git a/embassy-nrf/src/chips/nrf9160.rs b/embassy-nrf/src/chips/nrf9160.rs
index b5a53ed80..70285531f 100644
--- a/embassy-nrf/src/chips/nrf9160.rs
+++ b/embassy-nrf/src/chips/nrf9160.rs
@@ -280,6 +280,11 @@ impl_twim!(UARTETWISPI1, TWIM1, UARTE1_SPIM1_SPIS1_TWIM1_TWIS1);
280impl_twim!(UARTETWISPI2, TWIM2, UARTE2_SPIM2_SPIS2_TWIM2_TWIS2); 280impl_twim!(UARTETWISPI2, TWIM2, UARTE2_SPIM2_SPIS2_TWIM2_TWIS2);
281impl_twim!(UARTETWISPI3, TWIM3, UARTE3_SPIM3_SPIS3_TWIM3_TWIS3); 281impl_twim!(UARTETWISPI3, TWIM3, UARTE3_SPIM3_SPIS3_TWIM3_TWIS3);
282 282
283impl_twis!(UARTETWISPI0, TWIS0, UARTE0_SPIM0_SPIS0_TWIM0_TWIS0);
284impl_twis!(UARTETWISPI1, TWIS1, UARTE1_SPIM1_SPIS1_TWIM1_TWIS1);
285impl_twis!(UARTETWISPI2, TWIS2, UARTE2_SPIM2_SPIS2_TWIM2_TWIS2);
286impl_twis!(UARTETWISPI3, TWIS3, UARTE3_SPIM3_SPIS3_TWIM3_TWIS3);
287
283impl_pwm!(PWM0, PWM0, PWM0); 288impl_pwm!(PWM0, PWM0, PWM0);
284impl_pwm!(PWM1, PWM1, PWM1); 289impl_pwm!(PWM1, PWM1, PWM1);
285impl_pwm!(PWM2, PWM2, PWM2); 290impl_pwm!(PWM2, PWM2, PWM2);
diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs
index bc70fc2f6..6c5a3202a 100644
--- a/embassy-nrf/src/lib.rs
+++ b/embassy-nrf/src/lib.rs
@@ -100,6 +100,7 @@ pub mod spim;
100pub mod temp; 100pub mod temp;
101pub mod timer; 101pub mod timer;
102pub mod twim; 102pub mod twim;
103pub mod twis;
103pub mod uarte; 104pub mod uarte;
104#[cfg(any( 105#[cfg(any(
105 feature = "_nrf5340-app", 106 feature = "_nrf5340-app",
@@ -267,5 +268,11 @@ pub fn init(config: config::Config) -> Peripherals {
267 #[cfg(feature = "_time-driver")] 268 #[cfg(feature = "_time-driver")]
268 time_driver::init(config.time_interrupt_priority); 269 time_driver::init(config.time_interrupt_priority);
269 270
271 // Disable UARTE (enabled by default for some reason)
272 #[cfg(feature = "_nrf9160")]
273 unsafe {
274 (*pac::UARTE0::ptr()).enable.write(|w| w.enable().disabled());
275 (*pac::UARTE1::ptr()).enable.write(|w| w.enable().disabled());
276 }
270 peripherals 277 peripherals
271} 278}
diff --git a/embassy-nrf/src/twis.rs b/embassy-nrf/src/twis.rs
new file mode 100644
index 000000000..8c9cb54ea
--- /dev/null
+++ b/embassy-nrf/src/twis.rs
@@ -0,0 +1,734 @@
1#![macro_use]
2
3//! HAL interface to the TWIS peripheral.
4//!
5//! See product specification:
6//!
7//! - nRF52832: Section 33
8//! - nRF52840: Section 6.31
9use core::future::{poll_fn, Future};
10use core::sync::atomic::compiler_fence;
11use core::sync::atomic::Ordering::SeqCst;
12use core::task::Poll;
13
14use embassy_hal_common::{into_ref, PeripheralRef};
15use embassy_sync::waitqueue::AtomicWaker;
16#[cfg(feature = "time")]
17use embassy_time::{Duration, Instant};
18
19use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE};
20use crate::gpio::Pin as GpioPin;
21use crate::interrupt::{Interrupt, InterruptExt};
22use crate::util::slice_in_ram_or;
23use crate::{gpio, pac, Peripheral};
24
25#[non_exhaustive]
26pub struct Config {
27 pub addr0: u8,
28 pub addr1: Option<u8>,
29 pub orc: u8,
30 pub sda_high_drive: bool,
31 pub sda_pullup: bool,
32 pub scl_high_drive: bool,
33 pub scl_pullup: bool,
34}
35
36impl Default for Config {
37 fn default() -> Self {
38 Self {
39 addr0: 0x55,
40 addr1: None,
41 orc: 0x00,
42 scl_high_drive: false,
43 sda_pullup: false,
44 sda_high_drive: false,
45 scl_pullup: false,
46 }
47 }
48}
49
50#[derive(Debug, Copy, Clone, Eq, PartialEq)]
51#[cfg_attr(feature = "defmt", derive(defmt::Format))]
52enum Status {
53 Read,
54 Write,
55}
56
57#[derive(Debug, Copy, Clone, Eq, PartialEq)]
58#[cfg_attr(feature = "defmt", derive(defmt::Format))]
59#[non_exhaustive]
60pub enum Error {
61 TxBufferTooLong,
62 RxBufferTooLong,
63 DataNack,
64 Bus,
65 DMABufferNotInDataMemory,
66 Overflow,
67 OverRead,
68 Timeout,
69}
70
71#[derive(Debug, Copy, Clone, Eq, PartialEq)]
72#[cfg_attr(feature = "defmt", derive(defmt::Format))]
73pub enum Command {
74 Read,
75 WriteRead(usize),
76 Write(usize),
77}
78
79/// Interface to a TWIS instance using EasyDMA to offload the transmission and reception workload.
80///
81/// For more details about EasyDMA, consult the module documentation.
82pub struct Twis<'d, T: Instance> {
83 _p: PeripheralRef<'d, T>,
84}
85
86impl<'d, T: Instance> Twis<'d, T> {
87 pub fn new(
88 twis: impl Peripheral<P = T> + 'd,
89 irq: impl Peripheral<P = T::Interrupt> + 'd,
90 sda: impl Peripheral<P = impl GpioPin> + 'd,
91 scl: impl Peripheral<P = impl GpioPin> + 'd,
92 config: Config,
93 ) -> Self {
94 into_ref!(twis, irq, sda, scl);
95
96 let r = T::regs();
97
98 // Configure pins
99 sda.conf().write(|w| {
100 w.dir().input();
101 w.input().connect();
102 if config.sda_high_drive {
103 w.drive().h0d1();
104 } else {
105 w.drive().s0d1();
106 }
107 if config.sda_pullup {
108 w.pull().pullup();
109 }
110 w
111 });
112 scl.conf().write(|w| {
113 w.dir().input();
114 w.input().connect();
115 if config.scl_high_drive {
116 w.drive().h0d1();
117 } else {
118 w.drive().s0d1();
119 }
120 if config.scl_pullup {
121 w.pull().pullup();
122 }
123 w
124 });
125
126 // Select pins.
127 r.psel.sda.write(|w| unsafe { w.bits(sda.psel_bits()) });
128 r.psel.scl.write(|w| unsafe { w.bits(scl.psel_bits()) });
129
130 // Enable TWIS instance.
131 r.enable.write(|w| w.enable().enabled());
132
133 // Disable all events interrupts
134 r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) });
135
136 // Set address
137 r.address[0].write(|w| unsafe { w.address().bits(config.addr0) });
138 r.config.modify(|_r, w| w.address0().enabled());
139 if let Some(addr1) = config.addr1 {
140 r.address[1].write(|w| unsafe { w.address().bits(addr1) });
141 r.config.modify(|_r, w| w.address1().enabled());
142 }
143
144 // Set over-read character
145 r.orc.write(|w| unsafe { w.orc().bits(config.orc) });
146
147 // Generate suspend on read event
148 r.shorts.write(|w| w.read_suspend().enabled());
149
150 irq.set_handler(Self::on_interrupt);
151 irq.unpend();
152 irq.enable();
153
154 Self { _p: twis }
155 }
156
157 fn on_interrupt(_: *mut ()) {
158 let r = T::regs();
159 let s = T::state();
160
161 if r.events_read.read().bits() != 0 || r.events_write.read().bits() != 0 {
162 s.waker.wake();
163 r.intenclr.modify(|_r, w| w.read().clear().write().clear());
164 }
165 if r.events_stopped.read().bits() != 0 {
166 s.waker.wake();
167 r.intenclr.modify(|_r, w| w.stopped().clear());
168 }
169 if r.events_error.read().bits() != 0 {
170 s.waker.wake();
171 r.intenclr.modify(|_r, w| w.error().clear());
172 }
173 }
174
175 /// Set TX buffer, checking that it is in RAM and has suitable length.
176 unsafe fn set_tx_buffer(&mut self, buffer: &[u8]) -> Result<(), Error> {
177 slice_in_ram_or(buffer, Error::DMABufferNotInDataMemory)?;
178
179 if buffer.len() > EASY_DMA_SIZE {
180 return Err(Error::TxBufferTooLong);
181 }
182
183 let r = T::regs();
184
185 r.txd.ptr.write(|w|
186 // We're giving the register a pointer to the stack. Since we're
187 // waiting for the I2C transaction to end before this stack pointer
188 // becomes invalid, there's nothing wrong here.
189 //
190 // The PTR field is a full 32 bits wide and accepts the full range
191 // of values.
192 w.ptr().bits(buffer.as_ptr() as u32));
193 r.txd.maxcnt.write(|w|
194 // We're giving it the length of the buffer, so no danger of
195 // accessing invalid memory. We have verified that the length of the
196 // buffer fits in an `u8`, so the cast to `u8` is also fine.
197 //
198 // The MAXCNT field is 8 bits wide and accepts the full range of
199 // values.
200 w.maxcnt().bits(buffer.len() as _));
201
202 Ok(())
203 }
204
205 /// Set RX buffer, checking that it has suitable length.
206 unsafe fn set_rx_buffer(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
207 // NOTE: RAM slice check is not necessary, as a mutable
208 // slice can only be built from data located in RAM.
209
210 if buffer.len() > EASY_DMA_SIZE {
211 return Err(Error::RxBufferTooLong);
212 }
213
214 let r = T::regs();
215
216 r.rxd.ptr.write(|w|
217 // We're giving the register a pointer to the stack. Since we're
218 // waiting for the I2C transaction to end before this stack pointer
219 // becomes invalid, there's nothing wrong here.
220 //
221 // The PTR field is a full 32 bits wide and accepts the full range
222 // of values.
223 w.ptr().bits(buffer.as_mut_ptr() as u32));
224 r.rxd.maxcnt.write(|w|
225 // We're giving it the length of the buffer, so no danger of
226 // accessing invalid memory. We have verified that the length of the
227 // buffer fits in an `u8`, so the cast to the type of maxcnt
228 // is also fine.
229 //
230 // Note that that nrf52840 maxcnt is a wider
231 // type than a u8, so we use a `_` cast rather than a `u8` cast.
232 // The MAXCNT field is thus at least 8 bits wide and accepts the
233 // full range of values that fit in a `u8`.
234 w.maxcnt().bits(buffer.len() as _));
235
236 Ok(())
237 }
238
239 fn clear_errorsrc(&mut self) {
240 let r = T::regs();
241 r.errorsrc
242 .write(|w| w.overflow().bit(true).overread().bit(true).dnack().bit(true));
243 }
244
245 /// Wait for stop or error
246 fn blocking_listen_wait(&mut self) -> Result<Status, Error> {
247 let r = T::regs();
248 loop {
249 if r.events_error.read().bits() != 0 {
250 r.events_error.reset();
251 r.tasks_stop.write(|w| unsafe { w.bits(1) });
252 while r.events_stopped.read().bits() == 0 {}
253 return Err(Error::Overflow);
254 }
255 if r.events_stopped.read().bits() != 0 {
256 r.events_stopped.reset();
257 return Err(Error::Bus);
258 }
259 if r.events_read.read().bits() != 0 {
260 r.events_read.reset();
261 return Ok(Status::Read);
262 }
263 if r.events_write.read().bits() != 0 {
264 r.events_write.reset();
265 return Ok(Status::Write);
266 }
267 }
268 }
269
270 /// Wait for stop or error
271 fn blocking_listen_wait_end(&mut self, status: Status) -> Result<Command, Error> {
272 let r = T::regs();
273 loop {
274 // stop if an error occured
275 if r.events_error.read().bits() != 0 {
276 r.events_error.reset();
277 r.tasks_stop.write(|w| unsafe { w.bits(1) });
278 return Err(Error::Overflow);
279 } else if r.events_stopped.read().bits() != 0 {
280 r.events_stopped.reset();
281 return match status {
282 Status::Read => Ok(Command::Read),
283 Status::Write => {
284 let n = r.rxd.amount.read().bits() as usize;
285 Ok(Command::Write(n))
286 }
287 };
288 } else if r.events_read.read().bits() != 0 {
289 r.events_read.reset();
290 let n = r.rxd.amount.read().bits() as usize;
291 return Ok(Command::WriteRead(n));
292 }
293 }
294 }
295
296 /// Wait for stop or error
297 fn blocking_wait(&mut self) -> Result<(), Error> {
298 let r = T::regs();
299 loop {
300 // stop if an error occured
301 if r.events_error.read().bits() != 0 {
302 r.events_error.reset();
303 r.tasks_stop.write(|w| unsafe { w.bits(1) });
304 let errorsrc = r.errorsrc.read();
305 if errorsrc.overread().is_detected() {
306 return Err(Error::OverRead);
307 } else if errorsrc.dnack().is_received() {
308 return Err(Error::DataNack);
309 } else {
310 return Err(Error::Bus);
311 }
312 } else if r.events_stopped.read().bits() != 0 {
313 r.events_stopped.reset();
314 return Ok(());
315 }
316 }
317 }
318
319 /// Wait for stop or error
320 #[cfg(feature = "time")]
321 fn blocking_listen_wait_timeout(&mut self, timeout: Duration) -> Result<Status, Error> {
322 let r = T::regs();
323 let deadline = Instant::now() + timeout;
324 loop {
325 if r.events_error.read().bits() != 0 {
326 r.events_error.reset();
327 r.tasks_stop.write(|w| unsafe { w.bits(1) });
328 while r.events_stopped.read().bits() == 0 {}
329 return Err(Error::Overflow);
330 }
331 if r.events_stopped.read().bits() != 0 {
332 r.events_stopped.reset();
333 return Err(Error::Bus);
334 }
335 if r.events_read.read().bits() != 0 {
336 r.events_read.reset();
337 return Ok(Status::Read);
338 }
339 if r.events_write.read().bits() != 0 {
340 r.events_write.reset();
341 return Ok(Status::Write);
342 }
343 if Instant::now() > deadline {
344 r.tasks_stop.write(|w| unsafe { w.bits(1) });
345 return Err(Error::Timeout);
346 }
347 }
348 }
349
350 /// Wait for stop or error
351 #[cfg(feature = "time")]
352 fn blocking_listen_wait_end_timeout(&mut self, status: Status, timeout: Duration) -> Result<Command, Error> {
353 let r = T::regs();
354 let deadline = Instant::now() + timeout;
355 loop {
356 // stop if an error occured
357 if r.events_error.read().bits() != 0 {
358 r.events_error.reset();
359 r.tasks_stop.write(|w| unsafe { w.bits(1) });
360 return Err(Error::Overflow);
361 } else if r.events_stopped.read().bits() != 0 {
362 r.events_stopped.reset();
363 return match status {
364 Status::Read => Ok(Command::Read),
365 Status::Write => {
366 let n = r.rxd.amount.read().bits() as usize;
367 Ok(Command::Write(n))
368 }
369 };
370 } else if r.events_read.read().bits() != 0 {
371 r.events_read.reset();
372 let n = r.rxd.amount.read().bits() as usize;
373 return Ok(Command::WriteRead(n));
374 } else if Instant::now() > deadline {
375 r.tasks_stop.write(|w| unsafe { w.bits(1) });
376 return Err(Error::Timeout);
377 }
378 }
379 }
380
381 /// Wait for stop or error
382 #[cfg(feature = "time")]
383 fn blocking_wait_timeout(&mut self, timeout: Duration) -> Result<(), Error> {
384 let r = T::regs();
385 let deadline = Instant::now() + timeout;
386 loop {
387 // stop if an error occured
388 if r.events_error.read().bits() != 0 {
389 r.events_error.reset();
390 r.tasks_stop.write(|w| unsafe { w.bits(1) });
391 let errorsrc = r.errorsrc.read();
392 if errorsrc.overread().is_detected() {
393 return Err(Error::OverRead);
394 } else if errorsrc.dnack().is_received() {
395 return Err(Error::DataNack);
396 } else {
397 return Err(Error::Bus);
398 }
399 } else if r.events_stopped.read().bits() != 0 {
400 r.events_stopped.reset();
401 return Ok(());
402 } else if Instant::now() > deadline {
403 r.tasks_stop.write(|w| unsafe { w.bits(1) });
404 return Err(Error::Timeout);
405 }
406 }
407 }
408
409 /// Wait for stop or error
410 fn async_wait(&mut self) -> impl Future<Output = Result<(), Error>> {
411 poll_fn(move |cx| {
412 let r = T::regs();
413 let s = T::state();
414
415 s.waker.register(cx.waker());
416
417 // stop if an error occured
418 if r.events_error.read().bits() != 0 {
419 r.events_error.reset();
420 r.tasks_stop.write(|w| unsafe { w.bits(1) });
421 let errorsrc = r.errorsrc.read();
422 if errorsrc.overread().is_detected() {
423 return Poll::Ready(Err(Error::OverRead));
424 } else if errorsrc.dnack().is_received() {
425 return Poll::Ready(Err(Error::DataNack));
426 } else {
427 return Poll::Ready(Err(Error::Bus));
428 }
429 } else if r.events_stopped.read().bits() != 0 {
430 r.events_stopped.reset();
431 return Poll::Ready(Ok(()));
432 }
433
434 Poll::Pending
435 })
436 }
437
438 /// Wait for read or write
439 fn async_listen_wait(&mut self) -> impl Future<Output = Result<Status, Error>> {
440 poll_fn(move |cx| {
441 let r = T::regs();
442 let s = T::state();
443
444 s.waker.register(cx.waker());
445
446 // stop if an error occured
447 if r.events_error.read().bits() != 0 {
448 r.events_error.reset();
449 r.tasks_stop.write(|w| unsafe { w.bits(1) });
450 return Poll::Ready(Err(Error::Overflow));
451 } else if r.events_read.read().bits() != 0 {
452 r.events_read.reset();
453 return Poll::Ready(Ok(Status::Read));
454 } else if r.events_write.read().bits() != 0 {
455 r.events_write.reset();
456 return Poll::Ready(Ok(Status::Write));
457 } else if r.events_stopped.read().bits() != 0 {
458 r.events_stopped.reset();
459 return Poll::Ready(Err(Error::Bus));
460 }
461 Poll::Pending
462 })
463 }
464
465 /// Wait for stop or error
466 fn async_listen_wait_end(&mut self, status: Status) -> impl Future<Output = Result<Command, Error>> {
467 poll_fn(move |cx| {
468 let r = T::regs();
469 let s = T::state();
470
471 s.waker.register(cx.waker());
472
473 // stop if an error occured
474 if r.events_error.read().bits() != 0 {
475 r.events_error.reset();
476 r.tasks_stop.write(|w| unsafe { w.bits(1) });
477 return Poll::Ready(Err(Error::Overflow));
478 } else if r.events_stopped.read().bits() != 0 {
479 r.events_stopped.reset();
480 return match status {
481 Status::Read => Poll::Ready(Ok(Command::Read)),
482 Status::Write => {
483 let n = r.rxd.amount.read().bits() as usize;
484 Poll::Ready(Ok(Command::Write(n)))
485 }
486 };
487 } else if r.events_read.read().bits() != 0 {
488 r.events_read.reset();
489 let n = r.rxd.amount.read().bits() as usize;
490 return Poll::Ready(Ok(Command::WriteRead(n)));
491 }
492 Poll::Pending
493 })
494 }
495
496 fn setup_write_from_ram(&mut self, buffer: &[u8], inten: bool) -> Result<(), Error> {
497 let r = T::regs();
498
499 compiler_fence(SeqCst);
500
501 // Set up the DMA write.
502 unsafe { self.set_tx_buffer(buffer)? };
503
504 // Clear events
505 r.events_stopped.reset();
506 r.events_error.reset();
507 self.clear_errorsrc();
508
509 if inten {
510 r.intenset.write(|w| w.stopped().set().error().set());
511 } else {
512 r.intenclr.write(|w| w.stopped().clear().error().clear());
513 }
514
515 // Start write operation.
516 r.tasks_preparetx.write(|w| unsafe { w.bits(1) });
517 r.tasks_resume.write(|w| unsafe { w.bits(1) });
518 Ok(())
519 }
520
521 fn setup_write(&mut self, wr_buffer: &[u8], inten: bool) -> Result<(), Error> {
522 match self.setup_write_from_ram(wr_buffer, inten) {
523 Ok(_) => Ok(()),
524 Err(Error::DMABufferNotInDataMemory) => {
525 trace!("Copying TWIS tx buffer into RAM for DMA");
526 let tx_ram_buf = &mut [0; FORCE_COPY_BUFFER_SIZE][..wr_buffer.len()];
527 tx_ram_buf.copy_from_slice(wr_buffer);
528 self.setup_write_from_ram(&tx_ram_buf, inten)
529 }
530 Err(error) => Err(error),
531 }
532 }
533
534 fn setup_listen(&mut self, buffer: &mut [u8], inten: bool) -> Result<(), Error> {
535 let r = T::regs();
536 compiler_fence(SeqCst);
537
538 // Set up the DMA read.
539 unsafe { self.set_rx_buffer(buffer)? };
540
541 // Clear events
542 r.events_read.reset();
543 r.events_write.reset();
544 r.events_stopped.reset();
545 r.events_error.reset();
546 self.clear_errorsrc();
547
548 if inten {
549 r.intenset
550 .write(|w| w.stopped().set().error().set().read().set().write().set());
551 } else {
552 r.intenclr
553 .write(|w| w.stopped().clear().error().clear().read().clear().write().clear());
554 }
555
556 // Start read operation.
557 r.tasks_preparerx.write(|w| unsafe { w.bits(1) });
558
559 Ok(())
560 }
561
562 fn setup_listen_end(&mut self, inten: bool) -> Result<(), Error> {
563 let r = T::regs();
564 compiler_fence(SeqCst);
565
566 // Clear events
567 r.events_read.reset();
568 r.events_write.reset();
569 r.events_stopped.reset();
570 r.events_error.reset();
571 self.clear_errorsrc();
572
573 if inten {
574 r.intenset.write(|w| w.stopped().set().error().set().read().set());
575 } else {
576 r.intenclr.write(|w| w.stopped().clear().error().clear().read().clear());
577 }
578
579 Ok(())
580 }
581
582 /// Listen for commands from an I2C master.
583 ///
584 /// The buffer must have a length of at most 255 bytes on the nRF52832
585 /// and at most 65535 bytes on the nRF52840.
586 pub fn blocking_listen(&mut self, buffer: &mut [u8]) -> Result<Command, Error> {
587 self.setup_listen(buffer, false)?;
588 let status = self.blocking_listen_wait()?;
589 if status == Status::Write {
590 self.setup_listen_end(false)?;
591 let command = self.blocking_listen_wait_end(status)?;
592 return Ok(command);
593 }
594 Ok(Command::Read)
595 }
596
597 /// Write to an I2C master.
598 ///
599 /// The buffer must have a length of at most 255 bytes on the nRF52832
600 /// and at most 65535 bytes on the nRF52840.
601 pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> {
602 self.setup_write(buffer, false)?;
603 self.blocking_wait()?;
604 Ok(())
605 }
606
607 /// Same as [`blocking_write`](Twis::blocking_write) but will fail instead of copying data into RAM. Consult the module level documentation to learn more.
608 pub fn blocking_write_from_ram(&mut self, buffer: &[u8]) -> Result<(), Error> {
609 self.setup_write_from_ram(buffer, false)?;
610 self.blocking_wait()?;
611 Ok(())
612 }
613
614 // ===========================================
615
616 /// Listen for commands from an I2C master.
617 ///
618 /// The buffer must have a length of at most 255 bytes on the nRF52832
619 /// and at most 65535 bytes on the nRF52840.
620 #[cfg(feature = "time")]
621 pub fn blocking_listen_timeout(&mut self, buffer: &mut [u8], timeout: Duration) -> Result<Command, Error> {
622 self.setup_listen(buffer, false)?;
623 let status = self.blocking_listen_wait_timeout(timeout)?;
624 if status == Status::Write {
625 self.setup_listen_end(false)?;
626 let command = self.blocking_listen_wait_end_timeout(status, timeout)?;
627 return Ok(command);
628 }
629 Ok(Command::Read)
630 }
631
632 /// Write to an I2C master with timeout.
633 ///
634 /// See [`blocking_write`].
635 #[cfg(feature = "time")]
636 pub fn blocking_write_timeout(&mut self, buffer: &[u8], timeout: Duration) -> Result<(), Error> {
637 self.setup_write(buffer, false)?;
638 self.blocking_wait_timeout(timeout)?;
639 Ok(())
640 }
641
642 /// Same as [`blocking_write`](Twis::blocking_write) but will fail instead of copying data into RAM. Consult the module level documentation to learn more.
643 #[cfg(feature = "time")]
644 pub fn blocking_write_from_ram_timeout(&mut self, buffer: &[u8], timeout: Duration) -> Result<(), Error> {
645 self.setup_write_from_ram(buffer, false)?;
646 self.blocking_wait_timeout(timeout)?;
647 Ok(())
648 }
649
650 // ===========================================
651
652 pub async fn listen(&mut self, buffer: &mut [u8]) -> Result<Command, Error> {
653 self.setup_listen(buffer, true)?;
654 let status = self.async_listen_wait().await?;
655 if status == Status::Write {
656 self.setup_listen_end(true)?;
657 let command = self.async_listen_wait_end(status).await?;
658 return Ok(command);
659 }
660 Ok(Command::Read)
661 }
662
663 pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> {
664 self.setup_write(buffer, true)?;
665 self.async_wait().await?;
666 Ok(())
667 }
668
669 /// Same as [`write`](Twis::write) but will fail instead of copying data into RAM. Consult the module level documentation to learn more.
670 pub async fn write_from_ram(&mut self, buffer: &[u8]) -> Result<(), Error> {
671 self.setup_write_from_ram(buffer, true)?;
672 self.async_wait().await?;
673 Ok(())
674 }
675}
676
677impl<'a, T: Instance> Drop for Twis<'a, T> {
678 fn drop(&mut self) {
679 trace!("twis drop");
680
681 // TODO: check for abort
682
683 // disable!
684 let r = T::regs();
685 r.enable.write(|w| w.enable().disabled());
686
687 gpio::deconfigure_pin(r.psel.sda.read().bits());
688 gpio::deconfigure_pin(r.psel.scl.read().bits());
689
690 trace!("twis drop: done");
691 }
692}
693
694pub(crate) mod sealed {
695 use super::*;
696
697 pub struct State {
698 pub waker: AtomicWaker,
699 }
700
701 impl State {
702 pub const fn new() -> Self {
703 Self {
704 waker: AtomicWaker::new(),
705 }
706 }
707 }
708
709 pub trait Instance {
710 fn regs() -> &'static pac::twis0::RegisterBlock;
711 fn state() -> &'static State;
712 }
713}
714
715pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static {
716 type Interrupt: Interrupt;
717}
718
719macro_rules! impl_twis {
720 ($type:ident, $pac_type:ident, $irq:ident) => {
721 impl crate::twis::sealed::Instance for peripherals::$type {
722 fn regs() -> &'static pac::twis0::RegisterBlock {
723 unsafe { &*pac::$pac_type::ptr() }
724 }
725 fn state() -> &'static crate::twis::sealed::State {
726 static STATE: crate::twis::sealed::State = crate::twis::sealed::State::new();
727 &STATE
728 }
729 }
730 impl crate::twis::Instance for peripherals::$type {
731 type Interrupt = crate::interrupt::$irq;
732 }
733 };
734}
diff --git a/examples/nrf/src/bin/twis.rs b/examples/nrf/src/bin/twis.rs
new file mode 100644
index 000000000..f85173c08
--- /dev/null
+++ b/examples/nrf/src/bin/twis.rs
@@ -0,0 +1,45 @@
1//! TWIS example
2
3#![no_std]
4#![no_main]
5#![feature(type_alias_impl_trait)]
6
7use defmt::*;
8use embassy_executor::Spawner;
9use embassy_nrf::interrupt;
10use embassy_nrf::twis::{self, Command, Twis};
11use {defmt_rtt as _, panic_probe as _};
12
13#[embassy_executor::main]
14async fn main(_spawner: Spawner) {
15 let p = embassy_nrf::init(Default::default());
16
17 let irq = interrupt::take!(SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0);
18 let mut config = twis::Config::default();
19 // Set i2c address
20 config.addr0 = 0x55;
21 let mut i2c = Twis::new(p.TWISPI0, irq, p.P0_03, p.P0_04, config);
22
23 info!("Listening...");
24 loop {
25 let mut buf = [0u8; 16];
26 let tx_buf = [1, 2, 3, 4, 5, 6, 7, 8];
27 match i2c.listen(&mut buf).await {
28 Ok(Command::Read) => {
29 info!("Got READ command. Writing back data:\n{:?}\n", tx_buf);
30 if let Err(e) = i2c.write(&tx_buf).await {
31 error!("{:?}", e);
32 }
33 }
34 Ok(Command::Write(n)) => info!("Got WRITE command with data:\n{:?}\n", buf[..n]),
35 Ok(Command::WriteRead(n)) => {
36 info!("Got WRITE/READ command with data:\n{:?}", buf[..n]);
37 info!("Writing back data:\n{:?}\n", tx_buf);
38 if let Err(e) = i2c.write(&tx_buf).await {
39 error!("{:?}", e);
40 }
41 }
42 Err(e) => error!("{:?}", e),
43 }
44 }
45}