aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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/lib.rs1
-rw-r--r--embassy-nrf/src/twim.rs531
8 files changed, 548 insertions, 0 deletions
diff --git a/embassy-nrf/src/chips/nrf52810.rs b/embassy-nrf/src/chips/nrf52810.rs
index 7fe35b27f..9f3ed9cf3 100644
--- a/embassy-nrf/src/chips/nrf52810.rs
+++ b/embassy-nrf/src/chips/nrf52810.rs
@@ -114,6 +114,8 @@ impl_uarte!(UARTE0, UARTE0, UARTE0_UART0);
114 114
115impl_spim!(SPI0, SPIM0, SPIM0_SPIS0_SPI0); 115impl_spim!(SPI0, SPIM0, SPIM0_SPIS0_SPI0);
116 116
117impl_twim!(TWI0, TWIM0, TWIM0_TWIS0_TWI0);
118
117impl_timer!(TIMER0, TIMER0, TIMER0); 119impl_timer!(TIMER0, TIMER0, TIMER0);
118impl_timer!(TIMER1, TIMER1, TIMER1); 120impl_timer!(TIMER1, TIMER1, TIMER1);
119impl_timer!(TIMER2, TIMER2, TIMER2); 121impl_timer!(TIMER2, TIMER2, TIMER2);
diff --git a/embassy-nrf/src/chips/nrf52811.rs b/embassy-nrf/src/chips/nrf52811.rs
index e3f4f18ba..6728f6a41 100644
--- a/embassy-nrf/src/chips/nrf52811.rs
+++ b/embassy-nrf/src/chips/nrf52811.rs
@@ -115,6 +115,8 @@ impl_uarte!(UARTE0, UARTE0, UARTE0_UART0);
115impl_spim!(TWISPI0, SPIM0, TWIM0_TWIS0_TWI0_SPIM0_SPIS0_SPI0); 115impl_spim!(TWISPI0, SPIM0, TWIM0_TWIS0_TWI0_SPIM0_SPIS0_SPI0);
116impl_spim!(SPI1, SPIM1, SPIM1_SPIS1_SPI1); 116impl_spim!(SPI1, SPIM1, SPIM1_SPIS1_SPI1);
117 117
118impl_twim!(TWISPI0, TWIM0, TWIM0_TWIS0_TWI0_SPIM0_SPIS0_SPI0);
119
118impl_timer!(TIMER0, TIMER0, TIMER0); 120impl_timer!(TIMER0, TIMER0, TIMER0);
119impl_timer!(TIMER1, TIMER1, TIMER1); 121impl_timer!(TIMER1, TIMER1, TIMER1);
120impl_timer!(TIMER2, TIMER2, TIMER2); 122impl_timer!(TIMER2, TIMER2, TIMER2);
diff --git a/embassy-nrf/src/chips/nrf52820.rs b/embassy-nrf/src/chips/nrf52820.rs
index e367a7916..2f9eb5f53 100644
--- a/embassy-nrf/src/chips/nrf52820.rs
+++ b/embassy-nrf/src/chips/nrf52820.rs
@@ -116,6 +116,9 @@ impl_uarte!(UARTE0, UARTE0, UARTE0_UART0);
116impl_spim!(TWISPI0, SPIM0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); 116impl_spim!(TWISPI0, SPIM0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0);
117impl_spim!(TWISPI1, SPIM1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); 117impl_spim!(TWISPI1, SPIM1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1);
118 118
119impl_twim!(TWISPI0, TWIM0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0);
120impl_twim!(TWISPI1, TWIM1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1);
121
119impl_timer!(TIMER0, TIMER0, TIMER0); 122impl_timer!(TIMER0, TIMER0, TIMER0);
120impl_timer!(TIMER1, TIMER1, TIMER1); 123impl_timer!(TIMER1, TIMER1, TIMER1);
121impl_timer!(TIMER2, TIMER2, TIMER2); 124impl_timer!(TIMER2, TIMER2, TIMER2);
diff --git a/embassy-nrf/src/chips/nrf52832.rs b/embassy-nrf/src/chips/nrf52832.rs
index e0669d93e..015bc51f8 100644
--- a/embassy-nrf/src/chips/nrf52832.rs
+++ b/embassy-nrf/src/chips/nrf52832.rs
@@ -121,6 +121,9 @@ impl_spim!(TWISPI0, SPIM0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0);
121impl_spim!(TWISPI1, SPIM1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); 121impl_spim!(TWISPI1, SPIM1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1);
122impl_spim!(SPI2, SPIM2, SPIM2_SPIS2_SPI2); 122impl_spim!(SPI2, SPIM2, SPIM2_SPIS2_SPI2);
123 123
124impl_twim!(TWISPI0, TWIM0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0);
125impl_twim!(TWISPI1, TWIM1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1);
126
124impl_timer!(TIMER0, TIMER0, TIMER0); 127impl_timer!(TIMER0, TIMER0, TIMER0);
125impl_timer!(TIMER1, TIMER1, TIMER1); 128impl_timer!(TIMER1, TIMER1, TIMER1);
126impl_timer!(TIMER2, TIMER2, TIMER2); 129impl_timer!(TIMER2, TIMER2, TIMER2);
diff --git a/embassy-nrf/src/chips/nrf52833.rs b/embassy-nrf/src/chips/nrf52833.rs
index a0b434229..404883934 100644
--- a/embassy-nrf/src/chips/nrf52833.rs
+++ b/embassy-nrf/src/chips/nrf52833.rs
@@ -142,6 +142,9 @@ impl_spim!(TWISPI1, SPIM1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1);
142impl_spim!(SPI2, SPIM2, SPIM2_SPIS2_SPI2); 142impl_spim!(SPI2, SPIM2, SPIM2_SPIS2_SPI2);
143impl_spim!(SPI3, SPIM3, SPIM3); 143impl_spim!(SPI3, SPIM3, SPIM3);
144 144
145impl_twim!(TWISPI0, TWIM0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0);
146impl_twim!(TWISPI1, TWIM1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1);
147
145impl_timer!(TIMER0, TIMER0, TIMER0); 148impl_timer!(TIMER0, TIMER0, TIMER0);
146impl_timer!(TIMER1, TIMER1, TIMER1); 149impl_timer!(TIMER1, TIMER1, TIMER1);
147impl_timer!(TIMER2, TIMER2, TIMER2); 150impl_timer!(TIMER2, TIMER2, TIMER2);
diff --git a/embassy-nrf/src/chips/nrf52840.rs b/embassy-nrf/src/chips/nrf52840.rs
index 9a9f99201..26dfc7e8f 100644
--- a/embassy-nrf/src/chips/nrf52840.rs
+++ b/embassy-nrf/src/chips/nrf52840.rs
@@ -145,6 +145,9 @@ impl_spim!(TWISPI1, SPIM1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1);
145impl_spim!(SPI2, SPIM2, SPIM2_SPIS2_SPI2); 145impl_spim!(SPI2, SPIM2, SPIM2_SPIS2_SPI2);
146impl_spim!(SPI3, SPIM3, SPIM3); 146impl_spim!(SPI3, SPIM3, SPIM3);
147 147
148impl_twim!(TWISPI0, TWIM0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0);
149impl_twim!(TWISPI1, TWIM1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1);
150
148impl_timer!(TIMER0, TIMER0, TIMER0); 151impl_timer!(TIMER0, TIMER0, TIMER0);
149impl_timer!(TIMER1, TIMER1, TIMER1); 152impl_timer!(TIMER1, TIMER1, TIMER1);
150impl_timer!(TIMER2, TIMER2, TIMER2); 153impl_timer!(TIMER2, TIMER2, TIMER2);
diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs
index 066bf5f6f..2b35fdd6a 100644
--- a/embassy-nrf/src/lib.rs
+++ b/embassy-nrf/src/lib.rs
@@ -37,6 +37,7 @@ pub mod saadc;
37pub mod spim; 37pub mod spim;
38pub mod system; 38pub mod system;
39pub mod timer; 39pub mod timer;
40pub mod twim;
40pub mod uarte; 41pub mod uarte;
41 42
42// This mod MUST go last, so that it sees all the `impl_foo!` macros 43// This mod MUST go last, so that it sees all the `impl_foo!` macros
diff --git a/embassy-nrf/src/twim.rs b/embassy-nrf/src/twim.rs
new file mode 100644
index 000000000..cbaf97dff
--- /dev/null
+++ b/embassy-nrf/src/twim.rs
@@ -0,0 +1,531 @@
1#![macro_use]
2
3//! HAL interface to the TWIM peripheral.
4//!
5//! See product specification:
6//!
7//! - nRF52832: Section 33
8//! - nRF52840: Section 6.31
9use core::marker::PhantomData;
10use core::sync::atomic::{compiler_fence, Ordering::SeqCst};
11use embassy::interrupt::{Interrupt, InterruptExt};
12use embassy::util::{AtomicWaker, Unborrow};
13use embassy_extras::unborrow;
14
15use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE};
16use crate::fmt::*;
17use crate::gpio::Pin as GpioPin;
18use crate::pac;
19use crate::util::{slice_in_ram, slice_in_ram_or};
20
21pub enum Frequency {
22 #[doc = "26738688: 100 kbps"]
23 K100 = 26738688,
24 #[doc = "67108864: 250 kbps"]
25 K250 = 67108864,
26 #[doc = "104857600: 400 kbps"]
27 K400 = 104857600,
28}
29
30#[non_exhaustive]
31pub struct Config {
32 pub frequency: Frequency,
33}
34
35impl Default for Config {
36 fn default() -> Self {
37 Self {
38 frequency: Frequency::K100,
39 }
40 }
41}
42
43/// Interface to a TWIM instance.
44pub struct Twim<'d, T: Instance> {
45 peri: T,
46 irq: T::Interrupt,
47 phantom: PhantomData<&'d mut T>,
48}
49
50impl<'d, T: Instance> Twim<'d, T> {
51 pub fn new(
52 twim: impl Unborrow<Target = T> + 'd,
53 irq: impl Unborrow<Target = T::Interrupt> + 'd,
54 sda: impl Unborrow<Target = impl GpioPin> + 'd,
55 scl: impl Unborrow<Target = impl GpioPin> + 'd,
56 config: Config,
57 ) -> Self {
58 unborrow!(twim, irq, sda, scl);
59
60 let r = T::regs();
61
62 // Configure pins
63 sda.conf().write(|w| {
64 w.dir().input();
65 w.input().connect();
66 w.pull().pullup();
67 w.drive().s0d1();
68 w
69 });
70 scl.conf().write(|w| {
71 w.dir().input();
72 w.input().connect();
73 w.pull().pullup();
74 w.drive().s0d1();
75 w
76 });
77
78 // Select pins.
79 r.psel.sda.write(|w| unsafe { w.bits(sda.psel_bits()) });
80 r.psel.scl.write(|w| unsafe { w.bits(scl.psel_bits()) });
81
82 // Enable TWIM instance.
83 r.enable.write(|w| w.enable().enabled());
84
85 // Configure frequency.
86 r.frequency
87 .write(|w| unsafe { w.frequency().bits(config.frequency as u32) });
88
89 // Disable all events interrupts
90 r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) });
91
92 irq.set_handler(Self::on_interrupt);
93 irq.unpend();
94 irq.enable();
95
96 Self {
97 peri: twim,
98 irq,
99 phantom: PhantomData,
100 }
101 }
102
103 fn on_interrupt(_: *mut ()) {
104 let r = T::regs();
105 let s = T::state();
106
107 if r.events_stopped.read().bits() != 0 {
108 s.end_waker.wake();
109 r.intenclr.write(|w| w.stopped().clear());
110 }
111 if r.events_error.read().bits() != 0 {
112 s.end_waker.wake();
113 r.intenclr.write(|w| w.error().clear());
114 }
115 }
116
117 /// Set TX buffer, checking that it is in RAM and has suitable length.
118 unsafe fn set_tx_buffer(&mut self, buffer: &[u8]) -> Result<(), Error> {
119 slice_in_ram_or(buffer, Error::DMABufferNotInDataMemory)?;
120
121 if buffer.len() == 0 {
122 return Err(Error::TxBufferZeroLength);
123 }
124 if buffer.len() > EASY_DMA_SIZE {
125 return Err(Error::TxBufferTooLong);
126 }
127
128 let r = T::regs();
129
130 r.txd.ptr.write(|w|
131 // We're giving the register a pointer to the stack. Since we're
132 // waiting for the I2C transaction to end before this stack pointer
133 // becomes invalid, there's nothing wrong here.
134 //
135 // The PTR field is a full 32 bits wide and accepts the full range
136 // of values.
137 w.ptr().bits(buffer.as_ptr() as u32));
138 r.txd.maxcnt.write(|w|
139 // We're giving it the length of the buffer, so no danger of
140 // accessing invalid memory. We have verified that the length of the
141 // buffer fits in an `u8`, so the cast to `u8` is also fine.
142 //
143 // The MAXCNT field is 8 bits wide and accepts the full range of
144 // values.
145 w.maxcnt().bits(buffer.len() as _));
146
147 Ok(())
148 }
149
150 /// Set RX buffer, checking that it has suitable length.
151 unsafe fn set_rx_buffer(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
152 // NOTE: RAM slice check is not necessary, as a mutable
153 // slice can only be built from data located in RAM.
154
155 if buffer.len() == 0 {
156 return Err(Error::RxBufferZeroLength);
157 }
158 if buffer.len() > EASY_DMA_SIZE {
159 return Err(Error::RxBufferTooLong);
160 }
161
162 let r = T::regs();
163
164 r.rxd.ptr.write(|w|
165 // We're giving the register a pointer to the stack. Since we're
166 // waiting for the I2C transaction to end before this stack pointer
167 // becomes invalid, there's nothing wrong here.
168 //
169 // The PTR field is a full 32 bits wide and accepts the full range
170 // of values.
171 w.ptr().bits(buffer.as_mut_ptr() as u32));
172 r.rxd.maxcnt.write(|w|
173 // We're giving it the length of the buffer, so no danger of
174 // accessing invalid memory. We have verified that the length of the
175 // buffer fits in an `u8`, so the cast to the type of maxcnt
176 // is also fine.
177 //
178 // Note that that nrf52840 maxcnt is a wider
179 // type than a u8, so we use a `_` cast rather than a `u8` cast.
180 // The MAXCNT field is thus at least 8 bits wide and accepts the
181 // full range of values that fit in a `u8`.
182 w.maxcnt().bits(buffer.len() as _));
183
184 Ok(())
185 }
186
187 fn clear_errorsrc(&mut self) {
188 let r = T::regs();
189 r.errorsrc
190 .write(|w| w.anack().bit(true).dnack().bit(true).overrun().bit(true));
191 }
192
193 /// Get Error instance, if any occurred.
194 fn read_errorsrc(&self) -> Result<(), Error> {
195 let r = T::regs();
196
197 let err = r.errorsrc.read();
198 if err.anack().is_received() {
199 return Err(Error::AddressNack);
200 }
201 if err.dnack().is_received() {
202 return Err(Error::DataNack);
203 }
204 if err.overrun().is_received() {
205 return Err(Error::DataNack);
206 }
207 Ok(())
208 }
209
210 /// Wait for stop or error
211 fn wait(&mut self) {
212 let r = T::regs();
213 loop {
214 if r.events_stopped.read().bits() != 0 {
215 r.events_stopped.reset();
216 break;
217 }
218 if r.events_error.read().bits() != 0 {
219 r.events_error.reset();
220 r.tasks_stop.write(|w| unsafe { w.bits(1) });
221 }
222 }
223 }
224
225 /// Write to an I2C slave.
226 ///
227 /// The buffer must have a length of at most 255 bytes on the nRF52832
228 /// and at most 65535 bytes on the nRF52840.
229 pub fn write(&mut self, address: u8, buffer: &[u8]) -> Result<(), Error> {
230 let r = T::regs();
231
232 // Conservative compiler fence to prevent optimizations that do not
233 // take in to account actions by DMA. The fence has been placed here,
234 // before any DMA action has started.
235 compiler_fence(SeqCst);
236
237 r.address.write(|w| unsafe { w.address().bits(address) });
238
239 // Set up the DMA write.
240 unsafe { self.set_tx_buffer(buffer)? };
241
242 // Clear events
243 r.events_stopped.reset();
244 r.events_error.reset();
245 r.events_lasttx.reset();
246 self.clear_errorsrc();
247
248 // Start write operation.
249 r.shorts.write(|w| w.lasttx_stop().enabled());
250 r.tasks_starttx.write(|w|
251 // `1` is a valid value to write to task registers.
252 unsafe { w.bits(1) });
253
254 self.wait();
255
256 // Conservative compiler fence to prevent optimizations that do not
257 // take in to account actions by DMA. The fence has been placed here,
258 // after all possible DMA actions have completed.
259 compiler_fence(SeqCst);
260
261 self.read_errorsrc()?;
262
263 if r.txd.amount.read().bits() != buffer.len() as u32 {
264 return Err(Error::Transmit);
265 }
266
267 Ok(())
268 }
269
270 /// Read from an I2C slave.
271 ///
272 /// The buffer must have a length of at most 255 bytes on the nRF52832
273 /// and at most 65535 bytes on the nRF52840.
274 pub fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> {
275 let r = T::regs();
276
277 // Conservative compiler fence to prevent optimizations that do not
278 // take in to account actions by DMA. The fence has been placed here,
279 // before any DMA action has started.
280 compiler_fence(SeqCst);
281
282 r.address.write(|w| unsafe { w.address().bits(address) });
283
284 // Set up the DMA read.
285 unsafe { self.set_rx_buffer(buffer)? };
286
287 // Clear events
288 r.events_stopped.reset();
289 r.events_error.reset();
290 self.clear_errorsrc();
291
292 // Start read operation.
293 r.shorts.write(|w| w.lastrx_stop().enabled());
294 r.tasks_startrx.write(|w|
295 // `1` is a valid value to write to task registers.
296 unsafe { w.bits(1) });
297
298 self.wait();
299
300 // Conservative compiler fence to prevent optimizations that do not
301 // take in to account actions by DMA. The fence has been placed here,
302 // after all possible DMA actions have completed.
303 compiler_fence(SeqCst);
304
305 self.read_errorsrc()?;
306
307 if r.rxd.amount.read().bits() != buffer.len() as u32 {
308 return Err(Error::Receive);
309 }
310
311 Ok(())
312 }
313
314 /// Write data to an I2C slave, then read data from the slave without
315 /// triggering a stop condition between the two.
316 ///
317 /// The buffers must have a length of at most 255 bytes on the nRF52832
318 /// and at most 65535 bytes on the nRF52840.
319 pub fn write_then_read(
320 &mut self,
321 address: u8,
322 wr_buffer: &[u8],
323 rd_buffer: &mut [u8],
324 ) -> Result<(), Error> {
325 let r = T::regs();
326
327 // Conservative compiler fence to prevent optimizations that do not
328 // take in to account actions by DMA. The fence has been placed here,
329 // before any DMA action has started.
330 compiler_fence(SeqCst);
331
332 r.address.write(|w| unsafe { w.address().bits(address) });
333
334 // Set up DMA buffers.
335 unsafe {
336 self.set_tx_buffer(wr_buffer)?;
337 self.set_rx_buffer(rd_buffer)?;
338 }
339
340 // Clear events
341 r.events_stopped.reset();
342 r.events_error.reset();
343 self.clear_errorsrc();
344
345 // Start write+read operation.
346 r.shorts.write(|w| {
347 w.lasttx_startrx().enabled();
348 w.lastrx_stop().enabled();
349 w
350 });
351 // `1` is a valid value to write to task registers.
352 r.tasks_starttx.write(|w| unsafe { w.bits(1) });
353
354 self.wait();
355
356 // Conservative compiler fence to prevent optimizations that do not
357 // take in to account actions by DMA. The fence has been placed here,
358 // after all possible DMA actions have completed.
359 compiler_fence(SeqCst);
360
361 self.read_errorsrc()?;
362
363 let bad_write = r.txd.amount.read().bits() != wr_buffer.len() as u32;
364 let bad_read = r.rxd.amount.read().bits() != rd_buffer.len() as u32;
365
366 if bad_write {
367 return Err(Error::Transmit);
368 }
369
370 if bad_read {
371 return Err(Error::Receive);
372 }
373
374 Ok(())
375 }
376
377 /// Copy data into RAM and write to an I2C slave.
378 ///
379 /// The write buffer must have a length of at most 255 bytes on the nRF52832
380 /// and at most 1024 bytes on the nRF52840.
381 pub fn copy_write(&mut self, address: u8, wr_buffer: &[u8]) -> Result<(), Error> {
382 if wr_buffer.len() > FORCE_COPY_BUFFER_SIZE {
383 return Err(Error::TxBufferTooLong);
384 }
385
386 // Copy to RAM
387 let wr_ram_buffer = &mut [0; FORCE_COPY_BUFFER_SIZE][..wr_buffer.len()];
388 wr_ram_buffer.copy_from_slice(wr_buffer);
389
390 self.write(address, wr_ram_buffer)
391 }
392
393 /// Copy data into RAM and write to an I2C slave, then read data from the slave without
394 /// triggering a stop condition between the two.
395 ///
396 /// The write buffer must have a length of at most 255 bytes on the nRF52832
397 /// and at most 1024 bytes on the nRF52840.
398 ///
399 /// The read buffer must have a length of at most 255 bytes on the nRF52832
400 /// and at most 65535 bytes on the nRF52840.
401 pub fn copy_write_then_read(
402 &mut self,
403 address: u8,
404 wr_buffer: &[u8],
405 rd_buffer: &mut [u8],
406 ) -> Result<(), Error> {
407 if wr_buffer.len() > FORCE_COPY_BUFFER_SIZE {
408 return Err(Error::TxBufferTooLong);
409 }
410
411 // Copy to RAM
412 let wr_ram_buffer = &mut [0; FORCE_COPY_BUFFER_SIZE][..wr_buffer.len()];
413 wr_ram_buffer.copy_from_slice(wr_buffer);
414
415 self.write_then_read(address, wr_ram_buffer, rd_buffer)
416 }
417}
418
419impl<'a, T: Instance> Drop for Twim<'a, T> {
420 fn drop(&mut self) {
421 info!("twim drop");
422
423 // TODO when implementing async here, check for abort
424
425 // disable!
426 let r = T::regs();
427 r.enable.write(|w| w.enable().disabled());
428
429 info!("uarte drop: done");
430
431 // TODO: disable pins
432 }
433}
434
435impl<'a, T: Instance> embedded_hal::blocking::i2c::Write for Twim<'a, T> {
436 type Error = Error;
437
438 fn write<'w>(&mut self, addr: u8, bytes: &'w [u8]) -> Result<(), Error> {
439 if slice_in_ram(bytes) {
440 self.write(addr, bytes)
441 } else {
442 let buf = &mut [0; FORCE_COPY_BUFFER_SIZE][..];
443 for chunk in bytes.chunks(FORCE_COPY_BUFFER_SIZE) {
444 buf[..chunk.len()].copy_from_slice(chunk);
445 self.write(addr, &buf[..chunk.len()])?;
446 }
447 Ok(())
448 }
449 }
450}
451
452impl<'a, T: Instance> embedded_hal::blocking::i2c::Read for Twim<'a, T> {
453 type Error = Error;
454
455 fn read<'w>(&mut self, addr: u8, bytes: &'w mut [u8]) -> Result<(), Error> {
456 self.read(addr, bytes)
457 }
458}
459
460impl<'a, T: Instance> embedded_hal::blocking::i2c::WriteRead for Twim<'a, T> {
461 type Error = Error;
462
463 fn write_read<'w>(
464 &mut self,
465 addr: u8,
466 bytes: &'w [u8],
467 buffer: &'w mut [u8],
468 ) -> Result<(), Error> {
469 if slice_in_ram(bytes) {
470 self.write_then_read(addr, bytes, buffer)
471 } else {
472 self.copy_write_then_read(addr, bytes, buffer)
473 }
474 }
475}
476
477#[derive(Debug, Copy, Clone, Eq, PartialEq)]
478pub enum Error {
479 TxBufferTooLong,
480 RxBufferTooLong,
481 TxBufferZeroLength,
482 RxBufferZeroLength,
483 Transmit,
484 Receive,
485 DMABufferNotInDataMemory,
486 AddressNack,
487 DataNack,
488 Overrun,
489}
490
491pub(crate) mod sealed {
492 use super::*;
493
494 pub struct State {
495 pub end_waker: AtomicWaker,
496 }
497
498 impl State {
499 pub const fn new() -> Self {
500 Self {
501 end_waker: AtomicWaker::new(),
502 }
503 }
504 }
505
506 pub trait Instance {
507 fn regs() -> &'static pac::twim0::RegisterBlock;
508 fn state() -> &'static State;
509 }
510}
511
512pub trait Instance: sealed::Instance + 'static {
513 type Interrupt: Interrupt;
514}
515
516macro_rules! impl_twim {
517 ($type:ident, $pac_type:ident, $irq:ident) => {
518 impl crate::twim::sealed::Instance for peripherals::$type {
519 fn regs() -> &'static pac::twim0::RegisterBlock {
520 unsafe { &*pac::$pac_type::ptr() }
521 }
522 fn state() -> &'static crate::twim::sealed::State {
523 static STATE: crate::twim::sealed::State = crate::twim::sealed::State::new();
524 &STATE
525 }
526 }
527 impl crate::twim::Instance for peripherals::$type {
528 type Interrupt = crate::interrupt::$irq;
529 }
530 };
531}