atsamd_hal/sercom/i2c/
config.rs

1//! I2C [`Config`] definition and implementation
2
3use super::{I2c, InactiveTimeout, PadSet, Registers};
4use crate::{
5    pac::sercom0::i2cm::ctrla::Modeselect,
6    sercom::{ApbClkCtrl, Sercom},
7    time::Hertz,
8    typelevel::{Is, NoneT, Sealed},
9};
10
11//=============================================================================
12// Config
13//=============================================================================
14
15/// A configurable, disabled I2C peripheral
16///
17/// This `struct` represents a configurable I2C peripheral in its disabled
18/// state. It is generic over the set of [`Pads`].
19/// Upon creation, the [`Config`] takes ownership of the
20/// [`Sercom`] and resets it, returning it configured as an I2C peripheral
21/// with a default configuration in Master mode.
22///
23/// [`Config`] uses a builder-pattern API to configure the peripheral,
24/// culminating in a call to [`enable`], which consumes the [`Config`] and
25/// returns an enabled [`I2c`].
26///
27/// [`enable`]: Config::enable
28/// [`Pads`]: super::Pads
29pub struct Config<P>
30where
31    P: PadSet,
32{
33    pub(in super::super) registers: Registers<P::Sercom>,
34    pads: P,
35    freq: Hertz,
36}
37
38impl<P: PadSet> Config<P> {
39    /// Create a new [`Config`] in the default configuration.
40    #[inline]
41    fn default(sercom: P::Sercom, pads: P, freq: impl Into<Hertz>) -> Self {
42        let mut registers = Registers::new(sercom);
43        registers.swrst();
44        registers.set_op_mode(Modeselect::I2cMaster);
45        Self {
46            registers,
47            pads,
48            freq: freq.into(),
49        }
50    }
51
52    /// Create a new [`Config`] in the default configuration
53    ///
54    /// This function will enable the corresponding APB clock, reset the
55    /// [`Sercom`] peripheral, and return a [`Config`] in the default
56    /// configuration. The only available operating mode is currently Master.
57    ///
58    /// Note that [`Config`] takes ownership of both the
59    /// PAC [`Sercom`] struct as well as the [`Pads`](super::Pads).
60    ///
61    /// Users must configure GCLK manually. The `freq` parameter represents the
62    /// GCLK frequency for this [`Sercom`] instance.
63    #[inline]
64    pub fn new(
65        apb_clk_ctrl: &ApbClkCtrl,
66        mut sercom: P::Sercom,
67        pads: P,
68        freq: impl Into<Hertz>,
69    ) -> Self {
70        sercom.enable_apb_clock(apb_clk_ctrl);
71        Self::default(sercom, pads, freq)
72    }
73}
74
75impl<P: PadSet> Config<P> {
76    /// Obtain a reference to the PAC `SERCOM` struct
77    ///
78    /// # Safety
79    ///
80    /// Directly accessing the `SERCOM` could break the invariants of the
81    /// type-level tracking in this module, so it is unsafe.
82    #[inline]
83    pub unsafe fn sercom(&self) -> &P::Sercom {
84        &self.registers.sercom
85    }
86
87    /// Trigger the [`Sercom`]'s SWRST and return a [`Config`] in the
88    /// default configuration.
89    #[inline]
90    pub fn reset(self) -> Config<P> {
91        Config::default(self.registers.sercom, self.pads, self.freq)
92    }
93
94    /// Consume the [`Config`], reset the peripheral, and return the [`Sercom`]
95    /// and [`Pads`](super::Pads)
96    #[inline]
97    pub fn free(mut self) -> (P::Sercom, P) {
98        self.registers.swrst();
99        (self.registers.free(), self.pads)
100    }
101
102    /// Run in standby mode (builder pattern version)
103    ///
104    /// When set, the I2C peripheral will run in standby mode. See the
105    /// datasheet for more details.
106    #[inline]
107    pub fn run_in_standby(mut self, set: bool) -> Self {
108        self.set_run_in_standby(set);
109        self
110    }
111
112    /// Run in standby mode (setter version)
113    ///
114    /// When set, the I2C peripheral will run in standby mode. See the
115    /// datasheet for more details.
116    #[inline]
117    pub fn set_run_in_standby(&mut self, set: bool) {
118        self.registers.set_run_in_standby(set);
119    }
120
121    /// Get the current run in standby mode
122    #[inline]
123    pub fn get_run_in_standby(&self) -> bool {
124        self.registers.get_run_in_standby()
125    }
126
127    /// Set the baud rate (builder pattern version)
128    ///
129    /// This function will calculate the best BAUD register setting based on the
130    /// stored GCLK frequency and desired baud rate. The maximum baud rate is
131    /// GCLK frequency/10. Values outside this range will saturate at
132    /// the maximum supported baud rate.
133    ///
134    /// Note that 3x oversampling is not supported.
135    #[inline]
136    pub fn baud(mut self, baud: impl Into<Hertz>) -> Self {
137        self.set_baud(baud);
138        self
139    }
140
141    /// Set the baud rate (setter version)
142    ///
143    /// This function will calculate the best BAUD register setting based on the
144    /// stored GCLK frequency and desired baud rate. The maximum baud rate is
145    /// GCLK frequency/10. Values outside this range will saturate at
146    /// the maximum supported baud rate.
147    #[inline]
148    pub fn set_baud(&mut self, baud: impl Into<Hertz>) {
149        self.registers.set_baud(self.freq, baud);
150    }
151
152    /// Get the contents of the `BAUD` register and the current baud mode. Note
153    /// that only the CONTENTS of `BAUD` are returned, and not the actual baud
154    /// rate. Refer to the datasheet to convert the `BAUD` register contents
155    /// into a baud rate.
156    #[inline]
157    pub fn get_baud(&self) -> u32 {
158        self.registers.get_baud()
159    }
160
161    /// Set SCL Low Time-Out (builder pattern version)
162    ///
163    /// If SCL is held low for 25ms-35ms, the master will release its clock
164    /// hold, if enabled, and complete the current transaction. A stop condition
165    /// will automatically be transmitted. INTFLAG.SB or INTFLAG.MB will be set
166    /// as normal, but the clock hold will be released. The STATUS.LOWTOUT and
167    /// STATUS.BUSERR status bits will be set.
168    #[inline]
169    pub fn low_timeout(mut self, set: bool) -> Self {
170        self.set_low_timeout(set);
171        self
172    }
173
174    /// Set SCL Low Time-Out (setter version)
175    ///
176    /// If SCL is held low for 25ms-35ms, the master will release its clock
177    /// hold, if enabled, and complete the current transaction. A stop condition
178    /// will automatically be transmitted. INTFLAG.SB or INTFLAG.MB will be set
179    /// as normal, but the clock hold will be released. The STATUS.LOWTOUT and
180    /// STATUS.BUSERR status bits will be set.
181    #[inline]
182    pub fn set_low_timeout(&mut self, set: bool) {
183        self.registers.set_low_timeout(set);
184    }
185
186    /// Get SCL Low Time-Out setting
187    ///
188    /// If SCL is held low for 25ms-35ms, the master will release its clock
189    /// hold, if enabled, and complete the current transaction. A stop condition
190    /// will automatically be transmitted. INTFLAG.SB or INTFLAG.MB will be set
191    /// as normal, but the clock hold will be released. The STATUS.LOWTOUT and
192    /// STATUS.BUSERR status bits will be set.
193    #[inline]
194    pub fn get_low_timeout(&mut self) -> bool {
195        self.registers.get_low_timeout()
196    }
197
198    /// Set the inactive timeout (builder pattern version).
199    ///
200    /// Timeout after which the bus state will be set to IDLE. Necessary for
201    /// SMBus compatibility.
202    #[inline]
203    pub fn inactive_timeout(mut self, timeout: super::InactiveTimeout) -> Self {
204        self.set_inactive_timeout(timeout);
205        self
206    }
207
208    /// Set the inactive timeout (setter version).
209    ///
210    /// Timeout after which the bus state will be set to IDLE. Necessary for
211    /// SMBus compatibility.
212    #[inline]
213    pub fn set_inactive_timeout(&mut self, timeout: super::InactiveTimeout) {
214        self.registers.set_inactive_timeout(timeout);
215    }
216
217    /// Get the inactive timeout setting.
218    #[inline]
219    pub fn get_inactive_timeout(&mut self) -> InactiveTimeout {
220        self.registers.get_inactive_timeout()
221    }
222
223    /// Enable the I2C peripheral
224    ///
225    /// I2C transactions are not possible until the peripheral is enabled.
226    #[inline]
227    pub fn enable(mut self) -> I2c<Self>
228    where
229        Self: AnyConfig,
230    {
231        self.registers.enable();
232
233        I2c {
234            config: self,
235            _dma_channel: NoneT,
236        }
237    }
238}
239
240//=============================================================================
241// AnyConfig
242//=============================================================================
243
244/// Type class for all possible [`Config`] types
245///
246/// This trait uses the [`AnyKind`] trait pattern to create a [type class] for
247/// [`Config`] types. See the [`AnyKind`] documentation for more details on the
248/// pattern.
249///
250/// In addition to the normal, [`AnyKind`] associated types. This trait also
251/// copies the [`Sercom`] type, to make it easier
252/// to apply bounds to these types at the next level of abstraction.
253///
254/// [`AnyKind`]: crate::typelevel#anykind-trait-pattern
255/// [type class]: crate::typelevel#type-classes
256pub trait AnyConfig: Is<Type = SpecificConfig<Self>> {
257    type Sercom: Sercom;
258    type Pads: PadSet<Sercom = Self::Sercom>;
259}
260
261/// Type alias to recover the specific [`Config`] type from an implementation of
262/// [`AnyConfig`]
263pub type SpecificConfig<C> = Config<<C as AnyConfig>::Pads>;
264
265/// Type alias to recover the specific [`Sercom`] type from an implementation of
266/// [`AnyConfig`]
267pub type ConfigSercom<C> = <C as AnyConfig>::Sercom;
268
269impl<P: PadSet> Sealed for Config<P> {}
270
271impl<P: PadSet> AnyConfig for Config<P> {
272    type Sercom = P::Sercom;
273    type Pads = P;
274}
275
276impl<P: PadSet> AsRef<Self> for Config<P> {
277    #[inline]
278    fn as_ref(&self) -> &Self {
279        self
280    }
281}
282
283impl<P: PadSet> AsMut<Self> for Config<P> {
284    #[inline]
285    fn as_mut(&mut self) -> &mut Self {
286        self
287    }
288}