py32_hal/i2c/
mod.rs

1//! Inter-Integrated-Circuit (I2C)
2#![macro_use]
3
4// The following code is modified from embassy-stm32
5// https://github.com/embassy-rs/embassy/tree/main/embassy-stm32
6// Special thanks to the Embassy Project and its contributors for their work!
7
8mod v1;
9
10use core::future::Future;
11use core::iter;
12use core::marker::PhantomData;
13
14use embassy_hal_internal::{Peripheral, PeripheralRef};
15use embassy_sync::waitqueue::AtomicWaker;
16#[cfg(feature = "time")]
17use embassy_time::{Duration, Instant};
18
19#[cfg(dma)]
20use crate::dma::ChannelAndRequest;
21use crate::gpio::{AfType, AnyPin, OutputType, SealedPin as _, Speed};
22use crate::interrupt::typelevel::Interrupt;
23use crate::mode::{Async, Blocking, Mode};
24use crate::rcc::{RccInfo, SealedRccPeripheral};
25use crate::time::Hertz;
26use crate::{interrupt, peripherals};
27
28/// I2C error.
29#[derive(Debug, PartialEq, Eq, Copy, Clone)]
30#[cfg_attr(feature = "defmt", derive(defmt::Format))]
31pub enum Error {
32    /// Bus error
33    Bus,
34    /// Arbitration lost
35    Arbitration,
36    /// ACK not received (either to the address or to a data byte)
37    Nack,
38    /// Timeout
39    Timeout,
40    /// CRC error
41    Crc,
42    /// Overrun error
43    Overrun,
44    /// Zero-length transfers are not allowed.
45    ZeroLengthTransfer,
46}
47
48/// I2C config
49#[non_exhaustive]
50#[derive(Copy, Clone)]
51pub struct Config {
52    // /// Enable internal pullup on SDA.
53    // ///
54    // /// Using external pullup resistors is recommended for I2C. If you do
55    // /// have external pullups you should not enable this.
56    // pub sda_pullup: bool,
57    // /// Enable internal pullup on SCL.
58    // ///
59    // /// Using external pullup resistors is recommended for I2C. If you do
60    // /// have external pullups you should not enable this.
61    // pub scl_pullup: bool,
62    /// Timeout.
63    #[cfg(feature = "time")]
64    pub timeout: embassy_time::Duration,
65}
66
67impl Default for Config {
68    fn default() -> Self {
69        Self {
70            // sda_pullup: false,
71            // scl_pullup: false,
72            #[cfg(feature = "time")]
73            timeout: embassy_time::Duration::from_millis(1000),
74        }
75    }
76}
77
78impl Config {
79    fn scl_af(&self) -> AfType {
80        return AfType::output(OutputType::OpenDrain, Speed::Medium);
81        // return AfType::output_pull(
82        //     OutputType::OpenDrain,
83        //     Speed::Medium,
84        //     match self.scl_pullup {
85        //         true => Pull::Up,
86        //         false => Pull::None,
87        //     },
88        // );
89    }
90
91    fn sda_af(&self) -> AfType {
92        return AfType::output(OutputType::OpenDrain, Speed::Medium);
93        // return AfType::output_pull(
94        //     OutputType::OpenDrain,
95        //     Speed::Medium,
96        //     match self.sda_pullup {
97        //         true => Pull::Up,
98        //         false => Pull::None,
99        //     },
100        // );
101    }
102}
103
104/// I2C driver.
105pub struct I2c<'d, M: Mode> {
106    info: &'static Info,
107    #[allow(dead_code)]
108    state: &'static State,
109    kernel_clock: Hertz,
110    scl: Option<PeripheralRef<'d, AnyPin>>,
111    sda: Option<PeripheralRef<'d, AnyPin>>,
112    #[cfg(dma)] tx_dma: Option<ChannelAndRequest<'d>>,
113    #[cfg(dma)] rx_dma: Option<ChannelAndRequest<'d>>,
114    #[cfg(feature = "time")]
115    timeout: Duration,
116    _phantom: PhantomData<M>,
117}
118
119impl<'d> I2c<'d, Async> {
120    /// Create a new I2C driver.
121    pub fn new<T: Instance>(
122        peri: impl Peripheral<P = T> + 'd,
123        scl: impl Peripheral<P = impl SclPin<T>> + 'd,
124        sda: impl Peripheral<P = impl SdaPin<T>> + 'd,
125        _irq: impl interrupt::typelevel::Binding<T::GlobalInterrupt, GlobalInterruptHandler<T>> + 'd,
126        #[cfg(dma)] tx_dma: impl Peripheral<P = impl TxDma<T>> + 'd,
127        #[cfg(dma)] rx_dma: impl Peripheral<P = impl RxDma<T>> + 'd,
128        freq: Hertz,
129        config: Config,
130    ) -> Self {
131        Self::new_inner(
132            peri,
133            new_pin!(scl, config.scl_af()),
134            new_pin!(sda, config.sda_af()),
135            #[cfg(dma)] new_dma!(tx_dma),
136            #[cfg(dma)] new_dma!(rx_dma),
137            freq,
138            config,
139        )
140    }
141}
142
143impl<'d> I2c<'d, Blocking> {
144    /// Create a new blocking I2C driver.
145    pub fn new_blocking<T: Instance>(
146        peri: impl Peripheral<P = T> + 'd,
147        scl: impl Peripheral<P = impl SclPin<T>> + 'd,
148        sda: impl Peripheral<P = impl SdaPin<T>> + 'd,
149        freq: Hertz,
150        config: Config,
151    ) -> Self {
152        Self::new_inner(
153            peri,
154            new_pin!(scl, config.scl_af()),
155            new_pin!(sda, config.sda_af()),
156            #[cfg(dma)] None,
157            #[cfg(dma)] None,
158            freq,
159            config,
160        )
161    }
162}
163
164impl<'d, M: Mode> I2c<'d, M> {
165    /// Create a new I2C driver.
166    fn new_inner<T: Instance>(
167        _peri: impl Peripheral<P = T> + 'd,
168        scl: Option<PeripheralRef<'d, AnyPin>>,
169        sda: Option<PeripheralRef<'d, AnyPin>>,
170        #[cfg(dma)] tx_dma: Option<ChannelAndRequest<'d>>,
171        #[cfg(dma)] rx_dma: Option<ChannelAndRequest<'d>>,
172        freq: Hertz,
173        config: Config,
174    ) -> Self {
175        unsafe { T::GlobalInterrupt::enable() };
176
177        let mut this = Self {
178            info: T::info(),
179            state: T::state(),
180            kernel_clock: T::frequency(),
181            scl,
182            sda,
183            #[cfg(dma)] tx_dma,
184            #[cfg(dma)] rx_dma,
185            #[cfg(feature = "time")]
186            timeout: config.timeout,
187            _phantom: PhantomData,
188        };
189        this.enable_and_init(freq, config);
190        this
191    }
192
193    fn enable_and_init(&mut self, freq: Hertz, config: Config) {
194        self.info.rcc.enable_and_reset();
195        self.init(freq, config);
196    }
197
198    fn timeout(&self) -> Timeout {
199        Timeout {
200            #[cfg(feature = "time")]
201            deadline: Instant::now() + self.timeout,
202        }
203    }
204}
205
206impl<'d, M: Mode> Drop for I2c<'d, M> {
207    fn drop(&mut self) {
208        self.scl.as_ref().map(|x| x.set_as_disconnected());
209        self.sda.as_ref().map(|x| x.set_as_disconnected());
210
211        self.info.rcc.disable()
212    }
213}
214
215#[derive(Copy, Clone)]
216struct Timeout {
217    #[cfg(feature = "time")]
218    deadline: Instant,
219}
220
221#[allow(dead_code)]
222impl Timeout {
223    #[inline]
224    fn check(self) -> Result<(), Error> {
225        #[cfg(feature = "time")]
226        if Instant::now() > self.deadline {
227            return Err(Error::Timeout);
228        }
229
230        Ok(())
231    }
232
233    #[inline]
234    fn with<R>(
235        self,
236        fut: impl Future<Output = Result<R, Error>>,
237    ) -> impl Future<Output = Result<R, Error>> {
238        #[cfg(feature = "time")]
239        {
240            use futures_util::FutureExt;
241
242            embassy_futures::select::select(embassy_time::Timer::at(self.deadline), fut).map(|r| {
243                match r {
244                    embassy_futures::select::Either::First(_) => Err(Error::Timeout),
245                    embassy_futures::select::Either::Second(r) => r,
246                }
247            })
248        }
249
250        #[cfg(not(feature = "time"))]
251        fut
252    }
253}
254
255struct State {
256    #[allow(unused)]
257    waker: AtomicWaker,
258}
259
260impl State {
261    const fn new() -> Self {
262        Self {
263            waker: AtomicWaker::new(),
264        }
265    }
266}
267
268struct Info {
269    regs: crate::pac::i2c::I2c,
270    rcc: RccInfo,
271}
272
273peri_trait!(
274    irqs: [GlobalInterrupt],
275);
276
277pin_trait!(SclPin, Instance);
278pin_trait!(SdaPin, Instance);
279#[cfg(dma)] dma_trait!(RxDma, Instance);
280#[cfg(dma)] dma_trait!(TxDma, Instance);
281
282/// Global interrupt handler.
283pub struct GlobalInterruptHandler<T: Instance> {
284    _phantom: PhantomData<T>,
285}
286
287impl<T: Instance> interrupt::typelevel::Handler<T::GlobalInterrupt> for GlobalInterruptHandler<T> {
288    unsafe fn on_interrupt() {
289        v1::on_interrupt::<T>()
290    }
291}
292
293foreach_peripheral!(
294    (i2c, $inst:ident) => {
295        #[allow(private_interfaces)]
296        impl SealedInstance for peripherals::$inst {
297            fn info() -> &'static Info {
298                static INFO: Info = Info{
299                    regs: crate::pac::$inst,
300                    rcc: crate::peripherals::$inst::RCC_INFO,
301                };
302                &INFO
303            }
304            fn state() -> &'static State {
305                static STATE: State = State::new();
306                &STATE
307            }
308        }
309
310        impl Instance for peripherals::$inst {
311            type GlobalInterrupt = crate::_generated::peripheral_interrupts::$inst::GLOBAL;
312        }
313    };
314);
315
316impl<'d, M: Mode> embedded_hal_02::blocking::i2c::Read for I2c<'d, M> {
317    type Error = Error;
318
319    fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error> {
320        self.blocking_read(address, buffer)
321    }
322}
323
324impl<'d, M: Mode> embedded_hal_02::blocking::i2c::Write for I2c<'d, M> {
325    type Error = Error;
326
327    fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Self::Error> {
328        self.blocking_write(address, write)
329    }
330}
331
332impl<'d, M: Mode> embedded_hal_02::blocking::i2c::WriteRead for I2c<'d, M> {
333    type Error = Error;
334
335    fn write_read(
336        &mut self,
337        address: u8,
338        write: &[u8],
339        read: &mut [u8],
340    ) -> Result<(), Self::Error> {
341        self.blocking_write_read(address, write, read)
342    }
343}
344
345impl embedded_hal_1::i2c::Error for Error {
346    fn kind(&self) -> embedded_hal_1::i2c::ErrorKind {
347        match *self {
348            Self::Bus => embedded_hal_1::i2c::ErrorKind::Bus,
349            Self::Arbitration => embedded_hal_1::i2c::ErrorKind::ArbitrationLoss,
350            Self::Nack => embedded_hal_1::i2c::ErrorKind::NoAcknowledge(
351                embedded_hal_1::i2c::NoAcknowledgeSource::Unknown,
352            ),
353            Self::Timeout => embedded_hal_1::i2c::ErrorKind::Other,
354            Self::Crc => embedded_hal_1::i2c::ErrorKind::Other,
355            Self::Overrun => embedded_hal_1::i2c::ErrorKind::Overrun,
356            Self::ZeroLengthTransfer => embedded_hal_1::i2c::ErrorKind::Other,
357        }
358    }
359}
360
361impl<'d, M: Mode> embedded_hal_1::i2c::ErrorType for I2c<'d, M> {
362    type Error = Error;
363}
364
365impl<'d, M: Mode> embedded_hal_1::i2c::I2c for I2c<'d, M> {
366    fn read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Self::Error> {
367        self.blocking_read(address, read)
368    }
369
370    fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Self::Error> {
371        self.blocking_write(address, write)
372    }
373
374    fn write_read(
375        &mut self,
376        address: u8,
377        write: &[u8],
378        read: &mut [u8],
379    ) -> Result<(), Self::Error> {
380        self.blocking_write_read(address, write, read)
381    }
382
383    fn transaction(
384        &mut self,
385        address: u8,
386        operations: &mut [embedded_hal_1::i2c::Operation<'_>],
387    ) -> Result<(), Self::Error> {
388        self.blocking_transaction(address, operations)
389    }
390}
391
392#[cfg(dma)] 
393impl<'d> embedded_hal_async::i2c::I2c for I2c<'d, Async> {
394    async fn read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Self::Error> {
395        self.read(address, read).await
396    }
397
398    async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Self::Error> {
399        self.write(address, write).await
400    }
401
402    async fn write_read(
403        &mut self,
404        address: u8,
405        write: &[u8],
406        read: &mut [u8],
407    ) -> Result<(), Self::Error> {
408        self.write_read(address, write, read).await
409    }
410
411    async fn transaction(
412        &mut self,
413        address: u8,
414        operations: &mut [embedded_hal_1::i2c::Operation<'_>],
415    ) -> Result<(), Self::Error> {
416        self.transaction(address, operations).await
417    }
418}
419
420/// Frame type in I2C transaction.
421///
422/// This tells each method what kind of framing to use, to generate a (repeated) start condition (ST
423/// or SR), and/or a stop condition (SP). For read operations, this also controls whether to send an
424/// ACK or NACK after the last byte received.
425///
426/// For write operations, the following options are identical because they differ only in the (N)ACK
427/// treatment relevant for read operations:
428///
429/// - `FirstFrame` and `FirstAndNextFrame`
430/// - `NextFrame` and `LastFrameNoStop`
431///
432/// Abbreviations used below:
433///
434/// - `ST` = start condition
435/// - `SR` = repeated start condition
436/// - `SP` = stop condition
437/// - `ACK`/`NACK` = last byte in read operation
438#[derive(Copy, Clone)]
439#[allow(dead_code)]
440enum FrameOptions {
441    /// `[ST/SR]+[NACK]+[SP]` First frame (of this type) in transaction and also last frame overall.
442    FirstAndLastFrame,
443    /// `[ST/SR]+[NACK]` First frame of this type in transaction, last frame in a read operation but
444    /// not the last frame overall.
445    FirstFrame,
446    /// `[ST/SR]+[ACK]` First frame of this type in transaction, neither last frame overall nor last
447    /// frame in a read operation.
448    FirstAndNextFrame,
449    /// `[ACK]` Middle frame in a read operation (neither first nor last).
450    NextFrame,
451    /// `[NACK]+[SP]` Last frame overall in this transaction but not the first frame.
452    LastFrame,
453    /// `[NACK]` Last frame in a read operation but not last frame overall in this transaction.
454    LastFrameNoStop,
455}
456
457#[allow(dead_code)]
458impl FrameOptions {
459    /// Sends start or repeated start condition before transfer.
460    fn send_start(self) -> bool {
461        match self {
462            Self::FirstAndLastFrame | Self::FirstFrame | Self::FirstAndNextFrame => true,
463            Self::NextFrame | Self::LastFrame | Self::LastFrameNoStop => false,
464        }
465    }
466
467    /// Sends stop condition after transfer.
468    fn send_stop(self) -> bool {
469        match self {
470            Self::FirstAndLastFrame | Self::LastFrame => true,
471            Self::FirstFrame
472            | Self::FirstAndNextFrame
473            | Self::NextFrame
474            | Self::LastFrameNoStop => false,
475        }
476    }
477
478    /// Sends NACK after last byte received, indicating end of read operation.
479    fn send_nack(self) -> bool {
480        match self {
481            Self::FirstAndLastFrame
482            | Self::FirstFrame
483            | Self::LastFrame
484            | Self::LastFrameNoStop => true,
485            Self::FirstAndNextFrame | Self::NextFrame => false,
486        }
487    }
488}
489
490/// Iterates over operations in transaction.
491///
492/// Returns necessary frame options for each operation to uphold the [transaction contract] and have
493/// the right start/stop/(N)ACK conditions on the wire.
494///
495/// [transaction contract]: embedded_hal_1::i2c::I2c::transaction
496#[allow(dead_code)]
497fn operation_frames<'a, 'b: 'a>(
498    operations: &'a mut [embedded_hal_1::i2c::Operation<'b>],
499) -> Result<
500    impl IntoIterator<Item = (&'a mut embedded_hal_1::i2c::Operation<'b>, FrameOptions)>,
501    Error,
502> {
503    use embedded_hal_1::i2c::Operation::{Read, Write};
504
505    // Check empty read buffer before starting transaction. Otherwise, we would risk halting with an
506    // error in the middle of the transaction.
507    //
508    // In principle, we could allow empty read frames within consecutive read operations, as long as
509    // at least one byte remains in the final (merged) read operation, but that makes the logic more
510    // complicated and error-prone.
511    if operations.iter().any(|op| match op {
512        Read(read) => read.is_empty(),
513        Write(_) => false,
514    }) {
515        return Err(Error::Overrun);
516    }
517
518    let mut operations = operations.iter_mut().peekable();
519
520    let mut next_first_frame = true;
521
522    Ok(iter::from_fn(move || {
523        let Some(op) = operations.next() else {
524            return None;
525        };
526
527        // Is `op` first frame of its type?
528        let first_frame = next_first_frame;
529        let next_op = operations.peek();
530
531        // Get appropriate frame options as combination of the following properties:
532        //
533        // - For each first operation of its type, generate a (repeated) start condition.
534        // - For the last operation overall in the entire transaction, generate a stop condition.
535        // - For read operations, check the next operation: if it is also a read operation, we merge
536        //   these and send ACK for all bytes in the current operation; send NACK only for the final
537        //   read operation's last byte (before write or end of entire transaction) to indicate last
538        //   byte read and release the bus for transmission of the bus master's next byte (or stop).
539        //
540        // We check the third property unconditionally, i.e. even for write opeartions. This is okay
541        // because the resulting frame options are identical for write operations.
542        let frame = match (first_frame, next_op) {
543            (true, None) => FrameOptions::FirstAndLastFrame,
544            (true, Some(Read(_))) => FrameOptions::FirstAndNextFrame,
545            (true, Some(Write(_))) => FrameOptions::FirstFrame,
546            //
547            (false, None) => FrameOptions::LastFrame,
548            (false, Some(Read(_))) => FrameOptions::NextFrame,
549            (false, Some(Write(_))) => FrameOptions::LastFrameNoStop,
550        };
551
552        // Pre-calculate if `next_op` is the first operation of its type. We do this here and not at
553        // the beginning of the loop because we hand out `op` as iterator value and cannot access it
554        // anymore in the next iteration.
555        next_first_frame = match (&op, next_op) {
556            (_, None) => false,
557            (Read(_), Some(Write(_))) | (Write(_), Some(Read(_))) => true,
558            (Read(_), Some(Read(_))) | (Write(_), Some(Write(_))) => false,
559        };
560
561        Some((op, frame))
562    }))
563}