nrf52_hal_common/twim.rs
1//! HAL interface to the TWIM peripheral
2//!
3//! See product specification:
4//!
5//! - nrf52832: Section 33
6//! - nrf52840: Section 6.31
7use core::ops::Deref;
8use core::sync::atomic::{compiler_fence, Ordering::SeqCst};
9
10use crate::target::{
11 twim0,
12 P0,
13 TWIM0,
14};
15
16#[cfg(any(feature = "52832", feature = "52840"))]
17use crate::target::TWIM1;
18
19use crate::gpio::{
20 Pin,
21 Floating,
22 Input,
23};
24
25use crate::target_constants::EASY_DMA_SIZE;
26
27pub use crate::target::twim0::frequency::FREQUENCYW as Frequency;
28
29pub trait TwimExt: Deref<Target=twim0::RegisterBlock> + Sized {
30 fn constrain(self, pins: Pins, frequency: Frequency)
31 -> Twim<Self>;
32}
33
34macro_rules! impl_twim_ext {
35 ($($twim:ty,)*) => {
36 $(
37 impl TwimExt for $twim {
38 fn constrain(self, pins: Pins, frequency: Frequency)
39 -> Twim<Self>
40 {
41 Twim::new(self, pins, frequency)
42 }
43 }
44 )*
45 }
46}
47
48impl_twim_ext!(TWIM0,);
49
50#[cfg(any(feature = "52832", feature = "52840"))]
51impl_twim_ext!(TWIM1,);
52
53/// Interface to a TWIM instance
54///
55/// This is a very basic interface that comes with the following limitation:
56/// The TWIM instances share the same address space with instances of SPIM,
57/// SPIS, SPI, TWIS, and TWI. For example, TWIM0 conflicts with SPIM0, SPIS0,
58/// etc.; TWIM1 conflicts with SPIM1, SPIS1, etc. You need to make sure that
59/// conflicting instances are disabled before using `Twim`. Please refer to the
60/// product specification for more information (section 15.2 for nRF52832,
61/// section 6.1.2 for nRF52840).
62pub struct Twim<T>(T);
63
64impl<T> Twim<T> where T: TwimExt {
65 pub fn new(twim: T, pins: Pins, frequency: Frequency) -> Self {
66 // The TWIM peripheral requires the pins to be in a mode that is not
67 // exposed through the GPIO API, and might it might not make sense to
68 // expose it there.
69 //
70 // Until we've figured out what to do about this, let's just configure
71 // the pins through the raw peripheral API. All of the following is
72 // safe, as we own the pins now and have exclusive access to their
73 // registers.
74 for &pin in &[pins.scl.pin, pins.sda.pin] {
75 unsafe { &*P0::ptr() }.pin_cnf[pin as usize].write(|w|
76 w
77 .dir().input()
78 .input().connect()
79 .pull().pullup()
80 .drive().s0d1()
81 .sense().disabled()
82 );
83 }
84
85 // Select pins
86 twim.psel.scl.write(|w| {
87 let w = unsafe { w.pin().bits(pins.scl.pin) };
88 #[cfg(feature = "52840")]
89 let w = w.port().bit(pins.scl.port);
90 w.connect().connected()
91 });
92 twim.psel.sda.write(|w| {
93 let w = unsafe { w.pin().bits(pins.sda.pin) };
94 #[cfg(feature = "52840")]
95 let w = w.port().bit(pins.sda.port);
96 w.connect().connected()
97 });
98
99 // Enable TWIM instance
100 twim.enable.write(|w|
101 w.enable().enabled()
102 );
103
104 // Configure frequency
105 twim.frequency.write(|w| w.frequency().variant(frequency));
106
107
108 Twim(twim)
109 }
110
111 /// Write to an I2C slave
112 ///
113 /// The buffer must have a length of at most 255 bytes on the nRF52832
114 /// and at most 65535 bytes on the nRF52840.
115 pub fn write(&mut self,
116 address: u8,
117 buffer: &[u8],
118 )
119 -> Result<(), Error>
120 {
121
122 if buffer.len() > EASY_DMA_SIZE {
123 return Err(Error::TxBufferTooLong);
124 }
125
126 // Conservative compiler fence to prevent optimizations that do not
127 // take in to account actions by DMA. The fence has been placed here,
128 // before any DMA action has started
129 compiler_fence(SeqCst);
130
131 self.0.address.write(|w| unsafe { w.address().bits(address) });
132
133 // Set up the DMA write
134 self.0.txd.ptr.write(|w|
135 // We're giving the register a pointer to the stack. Since we're
136 // waiting for the I2C transaction to end before this stack pointer
137 // becomes invalid, there's nothing wrong here.
138 //
139 // The PTR field is a full 32 bits wide and accepts the full range
140 // of values.
141 unsafe { w.ptr().bits(buffer.as_ptr() as u32) }
142 );
143 self.0.txd.maxcnt.write(|w|
144 // We're giving it the length of the buffer, so no danger of
145 // accessing invalid memory. We have verified that the length of the
146 // buffer fits in an `u8`, so the cast to `u8` is also fine.
147 //
148 // The MAXCNT field is 8 bits wide and accepts the full range of
149 // values.
150 unsafe { w.maxcnt().bits(buffer.len() as _) }
151 );
152
153 // Start write operation
154 self.0.tasks_starttx.write(|w|
155 // `1` is a valid value to write to task registers.
156 unsafe { w.bits(1) }
157 );
158
159 // Wait until write operation is about to end
160 while self.0.events_lasttx.read().bits() == 0 {}
161 self.0.events_lasttx.write(|w| w); // reset event
162
163 // Stop read operation
164 self.0.tasks_stop.write(|w|
165 // `1` is a valid value to write to task registers.
166 unsafe { w.bits(1) }
167 );
168
169 // Wait until write operation has ended
170 while self.0.events_stopped.read().bits() == 0 {}
171 self.0.events_stopped.write(|w| w); // reset event
172
173 // Conservative compiler fence to prevent optimizations that do not
174 // take in to account actions by DMA. The fence has been placed here,
175 // after all possible DMA actions have completed
176 compiler_fence(SeqCst);
177
178 if self.0.txd.amount.read().bits() != buffer.len() as u32 {
179 return Err(Error::Transmit);
180 }
181
182 Ok(())
183 }
184
185 /// Read from an I2C slave
186 ///
187 /// The buffer must have a length of at most 255 bytes on the nRF52832
188 /// and at most 65535 bytes on the nRF52840.
189 pub fn read(&mut self,
190 address: u8,
191 buffer: &mut [u8],
192 )
193 -> Result<(), Error>
194 {
195 if buffer.len() > EASY_DMA_SIZE {
196 return Err(Error::RxBufferTooLong);
197 }
198
199 // Conservative compiler fence to prevent optimizations that do not
200 // take in to account actions by DMA. The fence has been placed here,
201 // before any DMA action has started
202 compiler_fence(SeqCst);
203
204 self.0.address.write(|w| unsafe { w.address().bits(address) });
205
206 // Set up the DMA read
207 self.0.rxd.ptr.write(|w|
208 // We're giving the register a pointer to the stack. Since we're
209 // waiting for the I2C transaction to end before this stack pointer
210 // becomes invalid, there's nothing wrong here.
211 //
212 // The PTR field is a full 32 bits wide and accepts the full range
213 // of values.
214 unsafe { w.ptr().bits(buffer.as_mut_ptr() as u32) }
215 );
216 self.0.rxd.maxcnt.write(|w|
217 // We're giving it the length of the buffer, so no danger of
218 // accessing invalid memory. We have verified that the length of the
219 // buffer fits in an `u8`, so the cast to the type of maxcnt
220 // is also fine.
221 //
222 // Note that that nrf52840 maxcnt is a wider
223 // type than a u8, so we use a `_` cast rather than a `u8` cast.
224 // The MAXCNT field is thus at least 8 bits wide and accepts the
225 // full range of values that fit in a `u8`.
226 unsafe { w.maxcnt().bits(buffer.len() as _) }
227 );
228
229 // Start read operation
230 self.0.tasks_startrx.write(|w|
231 // `1` is a valid value to write to task registers.
232 unsafe { w.bits(1) }
233 );
234
235 // Wait until read operation is about to end
236 while self.0.events_lastrx.read().bits() == 0 {}
237 self.0.events_lastrx.write(|w| w); // reset event
238
239 // Stop read operation
240 self.0.tasks_stop.write(|w|
241 // `1` is a valid value to write to task registers.
242 unsafe { w.bits(1) }
243 );
244
245 // Wait until read operation has ended
246 while self.0.events_stopped.read().bits() == 0 {}
247 self.0.events_stopped.write(|w| w); // reset event
248
249 // Conservative compiler fence to prevent optimizations that do not
250 // take in to account actions by DMA. The fence has been placed here,
251 // after all possible DMA actions have completed
252 compiler_fence(SeqCst);
253
254 if self.0.rxd.amount.read().bits() != buffer.len() as u32 {
255 return Err(Error::Receive);
256 }
257
258 Ok(())
259 }
260
261 /// Write data to an I2C slave, then read data from the slave without
262 /// triggering a stop condition between the two
263 ///
264 /// The buffer must have a length of at most 255 bytes.
265 pub fn write_then_read(&mut self,
266 address: u8,
267 wr_buffer: &[u8],
268 rd_buffer: &mut [u8],
269 )
270 -> Result<(), Error>
271 {
272 if wr_buffer.len() > EASY_DMA_SIZE {
273 return Err(Error::TxBufferTooLong);
274 }
275
276 if rd_buffer.len() > EASY_DMA_SIZE {
277 return Err(Error::RxBufferTooLong);
278 }
279
280 // Conservative compiler fence to prevent optimizations that do not
281 // take in to account actions by DMA. The fence has been placed here,
282 // before any DMA action has started
283 compiler_fence(SeqCst);
284
285 self.0.address.write(|w| unsafe { w.address().bits(address) });
286
287 // Set up the DMA write
288 self.0.txd.ptr.write(|w|
289 // We're giving the register a pointer to the stack. Since we're
290 // waiting for the I2C transaction to end before this stack pointer
291 // becomes invalid, there's nothing wrong here.
292 //
293 // The PTR field is a full 32 bits wide and accepts the full range
294 // of values.
295 unsafe { w.ptr().bits(wr_buffer.as_ptr() as u32) }
296 );
297 self.0.txd.maxcnt.write(|w|
298 // We're giving it the length of the buffer, so no danger of
299 // accessing invalid memory. We have verified that the length of the
300 // buffer fits in an `u8`, so the cast to `u8` is also fine.
301 //
302 // The MAXCNT field is 8 bits wide and accepts the full range of
303 // values.
304 unsafe { w.maxcnt().bits(wr_buffer.len() as _) }
305 );
306
307 // Set up the DMA read
308 self.0.rxd.ptr.write(|w|
309 // We're giving the register a pointer to the stack. Since we're
310 // waiting for the I2C transaction to end before this stack pointer
311 // becomes invalid, there's nothing wrong here.
312 //
313 // The PTR field is a full 32 bits wide and accepts the full range
314 // of values.
315 unsafe { w.ptr().bits(rd_buffer.as_mut_ptr() as u32) }
316 );
317 self.0.rxd.maxcnt.write(|w|
318 // We're giving it the length of the buffer, so no danger of
319 // accessing invalid memory. We have verified that the length of the
320 // buffer fits in an `u8`, so the cast to the type of maxcnt
321 // is also fine.
322 //
323 // Note that that nrf52840 maxcnt is a wider
324 // type than a u8, so we use a `_` cast rather than a `u8` cast.
325 // The MAXCNT field is thus at least 8 bits wide and accepts the
326 // full range of values that fit in a `u8`.
327 unsafe { w.maxcnt().bits(rd_buffer.len() as _) }
328 );
329
330 // Immediately start RX after TX, then stop
331 self.0.shorts.modify(|_r, w|
332 w.lasttx_startrx().enabled()
333 .lastrx_stop().enabled()
334 );
335
336 // Start write operation
337 self.0.tasks_starttx.write(|w|
338 // `1` is a valid value to write to task registers.
339 unsafe { w.bits(1) }
340 );
341
342 // Wait until total operation has ended
343 while self.0.events_stopped.read().bits() == 0 {}
344
345 self.0.events_lasttx.write(|w| w); // reset event
346 self.0.events_lastrx.write(|w| w); // reset event
347 self.0.events_stopped.write(|w| w); // reset event
348 self.0.shorts.write(|w| w);
349
350 // Conservative compiler fence to prevent optimizations that do not
351 // take in to account actions by DMA. The fence has been placed here,
352 // after all possible DMA actions have completed
353 compiler_fence(SeqCst);
354
355 let bad_write = self.0.txd.amount.read().bits() != wr_buffer.len() as u32;
356 let bad_read = self.0.rxd.amount.read().bits() != rd_buffer.len() as u32;
357
358 if bad_write {
359 return Err(Error::Transmit);
360 }
361
362 if bad_read {
363 return Err(Error::Receive);
364 }
365
366 Ok(())
367 }
368
369 /// Return the raw interface to the underlying TWIM peripheral
370 pub fn free(self) -> T {
371 self.0
372 }
373}
374
375/// Implementation of embedded_hal::blocking::i2c Traits
376
377impl<T> embedded_hal::blocking::i2c::Write for Twim<T> where T: TwimExt {
378 type Error = Error;
379
380 fn write<'w>(&mut self, addr: u8, bytes: &'w [u8]) -> Result<(), Error> {
381 self.write(addr, bytes)
382 }
383}
384
385impl<T> embedded_hal::blocking::i2c::Read for Twim<T> where T: TwimExt {
386 type Error = Error;
387
388 fn read<'w>(&mut self, addr: u8, bytes: &'w mut [u8]) -> Result<(), Error> {
389 self.read(addr, bytes)
390 }
391}
392
393impl<T> embedded_hal::blocking::i2c::WriteRead for Twim<T> where T: TwimExt {
394 type Error = Error;
395
396 fn write_read<'w>(&mut self, addr: u8, bytes:&'w[u8], buffer: &'w mut [u8]) -> Result<(), Error> {
397 self.write_then_read(addr, bytes, buffer)
398 }
399}
400
401/// The pins used by the TWIN peripheral
402///
403/// Currently, only P0 pins are supported.
404pub struct Pins {
405 // Serial Clock Line
406 pub scl: Pin<Input<Floating>>,
407
408 // Serial Data Line
409 pub sda: Pin<Input<Floating>>,
410}
411
412
413#[derive(Debug)]
414pub enum Error {
415 TxBufferTooLong,
416 RxBufferTooLong,
417 Transmit,
418 Receive,
419}