lpc8xx_hal/i2c/
master.rs

1//! API for the I2C master mode
2
3use core::{
4    convert::{TryFrom, TryInto as _},
5    fmt,
6    marker::PhantomData,
7};
8
9use embedded_hal::blocking::i2c;
10
11use crate::{
12    dma::{self, transfer::state::Ready},
13    init_state::Enabled,
14    pac::{
15        dma0::channel::xfercfg::{DSTINC_A, SRCINC_A},
16        i2c0::{stat::MSTSTATE_A, MSTCTL, MSTDAT},
17    },
18    reg_proxy::{Reg, RegProxy},
19};
20
21use super::{Error, Instance};
22
23/// API for the I2C master mode
24///
25/// You can get access to this struct through the [`I2C`] struct.
26///
27/// This struct has two type parameters that track its state:
28/// - `State` tracks whether the I2C instance is enabled.
29/// - `ModeState` tracks whether the master mode is enabled.
30///
31/// # `embedded-hal` traits
32/// - [`embedded_hal::blocking::i2c::Read`] for blocking reads
33/// - [`embedded_hal::blocking::i2c::Write`] for blocking writes
34///
35/// [`I2C`]: ../struct.I2C.html
36/// [`embedded_hal::blocking::i2c::Read`]: #impl-Read
37/// [`embedded_hal::blocking::i2c::Write`]: #impl-Write
38pub struct Master<I: Instance, State, ModeState> {
39    _state: PhantomData<State>,
40    _mode_state: PhantomData<ModeState>,
41
42    mstctl: RegProxy<MstCtl<I>>,
43    mstdat: RegProxy<MstDat<I>>,
44}
45
46impl<I, State, ModeState> Master<I, State, ModeState>
47where
48    I: Instance,
49{
50    pub(super) fn new() -> Self {
51        Self {
52            _state: PhantomData,
53            _mode_state: PhantomData,
54
55            mstctl: RegProxy::new(),
56            mstdat: RegProxy::new(),
57        }
58    }
59}
60
61impl<I, C> Master<I, Enabled<PhantomData<C>>, Enabled>
62where
63    I: Instance,
64{
65    /// Writes the provided buffer using DMA
66    ///
67    /// # Panics
68    ///
69    /// Panics, if the length of `buffer` is 0 or larger than 1024.
70    pub fn write_all(
71        mut self,
72        address: u8,
73        buffer: &'static [u8],
74        channel: dma::Channel<I::MstChannel, Enabled>,
75    ) -> Result<dma::Transfer<Ready, I::MstChannel, &'static [u8], Self>, Error>
76    {
77        self.start_operation(address, Rw::Write)?;
78        self.wait_for_state(State::TxReady)?;
79        self.mstctl.modify(|_, w| w.mstdma().enabled());
80        Ok(dma::Transfer::new(channel, buffer, self))
81    }
82
83    /// Reads until the provided buffer is full, using DMA
84    ///
85    /// # Panics
86    ///
87    /// Panics, if the length of `buffer` is 0 or larger than 1024.
88    pub fn read_all(
89        mut self,
90        address: u8,
91        buffer: &'static mut [u8],
92        channel: dma::Channel<I::MstChannel, Enabled>,
93    ) -> Result<
94        dma::Transfer<Ready, I::MstChannel, Self, &'static mut [u8]>,
95        Error,
96    > {
97        self.start_operation(address, Rw::Read)?;
98        self.mstctl.modify(|_, w| w.mstdma().enabled());
99        Ok(dma::Transfer::new(channel, self, buffer))
100    }
101
102    /// Wait while the peripheral is busy
103    ///
104    /// Once this method returns, the peripheral should either be idle or in a
105    /// state that requires software interaction.
106    fn wait_for_state(&self, expected: State) -> Result<(), Error> {
107        // Sound, as we're only reading from the STAT register.
108        let i2c = unsafe { &*I::REGISTERS };
109
110        while i2c.stat.read().mstpending().is_in_progress() {
111            Error::read::<I>()?;
112        }
113
114        let mststate = i2c.stat.read().mststate();
115        let actual =
116            mststate.variant().try_into().map_err(|()| mststate.bits());
117        if Ok(&expected) != actual.as_ref() {
118            return Err(Error::UnexpectedState { expected, actual });
119        }
120
121        Ok(())
122    }
123
124    fn start_operation(&mut self, address: u8, rw: Rw) -> Result<(), Error> {
125        Error::check_address(address)?;
126        self.wait_for_state(State::Idle)?;
127
128        // Write address
129        let address_rw = (address << 1) | rw as u8;
130        self.mstdat.write(|w| unsafe {
131            // Sound, as all 8-bit values are accepted here.
132            w.data().bits(address_rw)
133        });
134
135        // Start operation
136        self.mstctl.write(|w| w.mststart().start());
137
138        Ok(())
139    }
140
141    fn finish_write(&mut self) -> Result<(), Error> {
142        self.wait_for_state(State::TxReady)?;
143
144        // Stop operation
145        self.mstctl.write(|w| w.mststop().stop());
146
147        Ok(())
148    }
149
150    fn finish_read(&mut self) -> Result<(), Error> {
151        self.wait_for_state(State::RxReady)?;
152
153        // Stop operation
154        self.mstctl.write(|w| w.mststop().stop());
155
156        Ok(())
157    }
158}
159
160impl<I, C> i2c::Write for Master<I, Enabled<PhantomData<C>>, Enabled>
161where
162    I: Instance,
163{
164    type Error = Error;
165
166    /// Write to the I2C bus
167    ///
168    /// Please refer to the [embedded-hal documentation] for details.
169    ///
170    /// [embedded-hal documentation]: https://docs.rs/embedded-hal/0.2.1/embedded_hal/blocking/i2c/trait.Write.html#tymethod.write
171    fn write(&mut self, address: u8, data: &[u8]) -> Result<(), Self::Error> {
172        self.start_operation(address, Rw::Write)?;
173
174        for &b in data {
175            self.wait_for_state(State::TxReady)?;
176
177            // Write byte
178            self.mstdat.write(|w| unsafe { w.data().bits(b) });
179
180            // Continue transmission
181            self.mstctl.write(|w| w.mstcontinue().continue_());
182        }
183
184        self.finish_write()?;
185
186        Ok(())
187    }
188}
189
190impl<I, C> i2c::Read for Master<I, Enabled<PhantomData<C>>, Enabled>
191where
192    I: Instance,
193{
194    type Error = Error;
195
196    /// Read from the I2C bus
197    ///
198    /// Please refer to the [embedded-hal documentation] for details.
199    ///
200    /// [embedded-hal documentation]: https://docs.rs/embedded-hal/0.2.1/embedded_hal/blocking/i2c/trait.Read.html#tymethod.read
201    fn read(
202        &mut self,
203        address: u8,
204        buffer: &mut [u8],
205    ) -> Result<(), Self::Error> {
206        self.start_operation(address, Rw::Read)?;
207
208        for (i, b) in buffer.iter_mut().enumerate() {
209            if i != 0 {
210                // Continue transmission
211                self.mstctl.write(|w| w.mstcontinue().continue_());
212            }
213
214            self.wait_for_state(State::RxReady)?;
215
216            // Read received byte
217            *b = self.mstdat.read().data().bits();
218        }
219
220        self.finish_read()?;
221
222        Ok(())
223    }
224}
225
226impl<I, State, ModeState> crate::private::Sealed for Master<I, State, ModeState> where
227    I: Instance
228{
229}
230
231impl<I, C> dma::Dest for Master<I, Enabled<PhantomData<C>>, Enabled>
232where
233    I: Instance,
234{
235    type Error = Error;
236
237    fn is_valid(&self) -> bool {
238        true
239    }
240
241    fn is_full(&self) -> bool {
242        false
243    }
244
245    fn increment(&self) -> DSTINC_A {
246        DSTINC_A::NO_INCREMENT
247    }
248
249    fn transfer_count(&self) -> Option<u16> {
250        None
251    }
252
253    fn end_addr(&mut self) -> *mut u8 {
254        // Sound, because we're dereferencing a register address that is always
255        // valid on the target hardware.
256        (unsafe { &(*I::REGISTERS).mstdat }) as *const _ as *mut u8
257    }
258
259    fn finish(&mut self) -> nb::Result<(), Self::Error> {
260        self.mstctl.modify(|_, w| w.mstdma().disabled());
261        self.finish_write()?;
262        Ok(())
263    }
264}
265
266impl<I, C> dma::Source for Master<I, Enabled<PhantomData<C>>, Enabled>
267where
268    I: Instance,
269{
270    type Error = Error;
271
272    fn is_valid(&self) -> bool {
273        true
274    }
275
276    fn is_empty(&self) -> bool {
277        false
278    }
279
280    fn increment(&self) -> SRCINC_A {
281        SRCINC_A::NO_INCREMENT
282    }
283
284    fn transfer_count(&self) -> Option<u16> {
285        None
286    }
287
288    fn end_addr(&self) -> *const u8 {
289        // Sound, because we're dereferencing a register address that is always
290        // valid on the target hardware.
291        (unsafe { &(*I::REGISTERS).mstdat }) as *const _ as *mut u8
292    }
293
294    fn finish(&mut self) -> nb::Result<(), Self::Error> {
295        self.mstctl.modify(|_, w| w.mstdma().disabled());
296        self.finish_read()?;
297        Ok(())
298    }
299}
300
301// Can't derive, because peripheral structs from the PAC don't implement
302// `Debug`. See https://github.com/rust-embedded/svd2rust/issues/48.
303impl<I, State, ModeState> fmt::Debug for Master<I, State, ModeState>
304where
305    I: Instance,
306{
307    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
308        f.debug_struct("Master")
309            .field("_state", &self._state)
310            .field("_mode_state", &self._mode_state)
311            .field("mstctl", &self.mstctl)
312            .field("mstdat", &self.mstdat)
313            .finish()
314    }
315}
316
317/// Private helper struct to model the R/W bit
318#[repr(u8)]
319enum Rw {
320    Write = 0,
321    Read = 1,
322}
323
324/// The state of an I2C instance set to master mode
325#[derive(Debug, Eq, PartialEq)]
326pub enum State {
327    /// The peripheral is currently idle
328    ///
329    /// A new transaction can be started.
330    Idle,
331
332    /// Data has been received and is available to be read
333    ///
334    /// A read transaction has previously been initiated, and has been
335    /// acknowledged by the slave.
336    RxReady,
337
338    /// Data can be transmitted
339    ///
340    /// A write transaction has previously been initiated, and has been
341    /// acknowledged by the slave.
342    TxReady,
343
344    /// Slave has sent NACK in response to an address
345    NackAddress,
346
347    /// Slave has sent NACK in response to data
348    NackData,
349}
350
351impl TryFrom<Option<MSTSTATE_A>> for State {
352    type Error = ();
353
354    fn try_from(state: Option<MSTSTATE_A>) -> Result<Self, Self::Error> {
355        match state {
356            Some(MSTSTATE_A::IDLE) => Ok(Self::Idle),
357            Some(MSTSTATE_A::RECEIVE_READY) => Ok(Self::RxReady),
358            Some(MSTSTATE_A::TRANSMIT_READY) => Ok(Self::TxReady),
359            Some(MSTSTATE_A::NACK_ADDRESS) => Ok(Self::NackAddress),
360            Some(MSTSTATE_A::NACK_DATA) => Ok(Self::NackData),
361            None => Err(()),
362        }
363    }
364}
365
366struct MstCtl<I>(PhantomData<I>);
367
368// Sound, as the pointer returned is valid for the duration of the program.
369unsafe impl<I> Reg for MstCtl<I>
370where
371    I: Instance,
372{
373    type Target = MSTCTL;
374
375    fn get() -> *const Self::Target {
376        // Sound, as MSTCTL is exclusively used by `Master`, and only one
377        // `RegProxy` instance for it exists.
378        unsafe { &(*I::REGISTERS).mstctl as *const _ }
379    }
380}
381
382// Can't derive, because peripheral structs from the PAC don't implement
383// `Debug`. See https://github.com/rust-embedded/svd2rust/issues/48.
384impl<I> fmt::Debug for MstCtl<I> {
385    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
386        write!(f, "MstCtl(...)")
387    }
388}
389
390struct MstDat<I>(PhantomData<I>);
391
392// Sound, as the pointer returned is valid for the duration of the program.
393unsafe impl<I> Reg for MstDat<I>
394where
395    I: Instance,
396{
397    type Target = MSTDAT;
398
399    fn get() -> *const Self::Target {
400        // Sound, as MSTDAT is exclusively used by `Master`, and only one
401        // `RegProxy` instance for it exists.
402        unsafe { &(*I::REGISTERS).mstdat as *const _ }
403    }
404}
405
406// Can't derive, because peripheral structs from the PAC don't implement
407// `Debug`. See https://github.com/rust-embedded/svd2rust/issues/48.
408impl<I> fmt::Debug for MstDat<I> {
409    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
410        write!(f, "MstDat(...)")
411    }
412}