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}