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}