atsamd_hal/sercom/i2c/
reg.rs

1//! Register-level access to I2C configuration
2
3use super::flags::{BusState, Error};
4use super::InactiveTimeout;
5use super::{Flags, Status};
6use crate::pac;
7use crate::sercom::Sercom;
8use crate::time::Hertz;
9use atsamd_hal_macros::hal_cfg;
10
11const MASTER_ACT_READ: u8 = 2;
12const MASTER_ACT_STOP: u8 = 3;
13const MASTER_ACT_REPEATED_START: u8 = 1;
14
15#[hal_cfg(any("sercom0-d11", "sercom0-d21"))]
16type DataReg = u8;
17
18#[hal_cfg("sercom0-d5x")]
19type DataReg = u32;
20
21pub(in super::super) struct Registers<S: Sercom> {
22    pub sercom: S,
23}
24
25// SAFETY: It is safe to implement Sync for Registers, because it erases the
26// interior mutability of the PAC SERCOM struct.
27unsafe impl<S: Sercom> Sync for Registers<S> {}
28
29impl<S: Sercom> Registers<S> {
30    /// Create a new `Registers` instance
31    #[inline]
32    pub(super) fn new(sercom: S) -> Self {
33        Self { sercom }
34    }
35
36    /// Helper function to access the underlying `I2cm` from the given `SERCOM`
37    #[inline]
38    pub(in super::super) fn i2c_master(&self) -> &pac::sercom0::I2cm {
39        self.sercom.i2cm()
40    }
41
42    /// Get a pointer to the `DATA` register
43    pub(super) fn data_ptr<T>(&self) -> *mut T {
44        self.i2c_master().data().as_ptr() as *mut _
45    }
46
47    /// Free the `Registers` struct and return the underlying `Sercom` instance
48    #[inline]
49    pub(super) fn free(self) -> S {
50        self.sercom
51    }
52
53    /// Reset the SERCOM peripheral
54    #[inline]
55    pub(super) fn swrst(&mut self) {
56        self.i2c_master().ctrla().write(|w| w.swrst().set_bit());
57        while self.i2c_master().syncbusy().read().swrst().bit_is_set() {}
58    }
59
60    /// Configure the SERCOM to use I2C master mode
61    #[inline]
62    pub(super) fn set_op_mode(&mut self, mode: pac::sercom0::i2cm::ctrla::Modeselect) {
63        self.i2c_master()
64            .ctrla()
65            .modify(|_, w| w.mode().variant(mode));
66    }
67
68    /// Configure the baudrate for I2C master mode
69    pub(super) fn set_baud(&mut self, clock_freq: impl Into<Hertz>, baud: impl Into<Hertz>) {
70        // Since BAUDLOW is 0, the baud rate is used to generate both SCL high and SCL
71        // low periods.
72        let baud = (clock_freq.into().to_Hz() / (2 * baud.into().to_Hz()) - 1) as u8;
73
74        unsafe {
75            self.i2c_master().baud().modify(|_, w| w.baud().bits(baud));
76        }
77    }
78
79    /// Get the contents of the `BAUD` register.
80    #[inline]
81    pub(super) fn get_baud(&self) -> u32 {
82        self.i2c_master().baud().read().bits()
83    }
84
85    /// Set SCL Low Time-Out
86    ///
87    /// If SCL is held low for 25ms-35ms, the master will release its clock
88    /// hold, if enabled, and complete the current transaction. A stop condition
89    /// will automatically be transmitted. INTFLAG.SB or INTFLAG.MB will be set
90    /// as normal, but the clock hold will be released. The STATUS.LOWTOUT and
91    /// STATUS.BUSERR status bits will be set.
92    #[inline]
93    pub(super) fn set_low_timeout(&mut self, set: bool) {
94        self.i2c_master()
95            .ctrla()
96            .modify(|_, w| w.lowtouten().bit(set));
97    }
98
99    /// Get SCL Low Time-Out
100    ///
101    /// If SCL is held low for 25ms-35ms, the master will release its clock
102    /// hold, if enabled, and complete the current transaction. A stop condition
103    /// will automatically be transmitted. INTFLAG.SB or INTFLAG.MB will be set
104    /// as normal, but the clock hold will be released. The STATUS.LOWTOUT and
105    /// STATUS.BUSERR status bits will be set.
106    #[inline]
107    pub(super) fn get_low_timeout(&mut self) -> bool {
108        self.i2c_master().ctrla().read().lowtouten().bit()
109    }
110
111    /// Set the inactive timeout after which the bus state will be set to IDLE.
112    /// Necessary for SMBus compatibility.
113    #[inline]
114    pub(super) fn set_inactive_timeout(&mut self, timeout: super::InactiveTimeout) {
115        // `unused_unsafe` is allowed here because `inactout().bits()` is unsafe on
116        // thumbv6m targets, but not thumbv7em.
117        #[allow(unused_unsafe)]
118        self.i2c_master()
119            .ctrla()
120            .modify(|_, w| unsafe { w.inactout().bits(timeout as u8) })
121    }
122
123    /// Get the inactive timeout setting.
124    #[inline]
125    pub(super) fn get_inactive_timeout(&mut self) -> InactiveTimeout {
126        let timeout = self.i2c_master().ctrla().read().inactout().bits();
127
128        match timeout {
129            0 => InactiveTimeout::Disabled,
130            1 => InactiveTimeout::Us55,
131            2 => InactiveTimeout::Us105,
132            3 => InactiveTimeout::Us205,
133            _ => unreachable!(),
134        }
135    }
136
137    /// Run in standby mode
138    ///
139    /// When set, the I2C peripheral will run in standby mode. See the
140    /// datasheet for more details.
141    #[inline]
142    pub(super) fn set_run_in_standby(&mut self, set: bool) {
143        self.i2c_master()
144            .ctrla()
145            .modify(|_, w| w.runstdby().bit(set));
146    }
147
148    /// Get the current run in standby mode
149    #[inline]
150    pub(super) fn get_run_in_standby(&self) -> bool {
151        self.i2c_master().ctrla().read().runstdby().bit()
152    }
153
154    /// Set Smart Mode
155    #[inline]
156    pub(super) fn set_smart_mode(&mut self, set: bool) {
157        self.i2c_master().ctrlb().modify(|_, w| w.smen().bit(set));
158    }
159
160    /// Get the current Smart Mode setting
161    #[inline]
162    pub(super) fn get_smart_mode(&self) -> bool {
163        self.i2c_master().ctrlb().read().smen().bit()
164    }
165
166    /// Clear specified interrupt flags
167    #[inline]
168    pub(super) fn clear_flags(&mut self, flags: Flags) {
169        self.i2c_master()
170            .intflag()
171            .modify(|_, w| unsafe { w.bits(flags.bits()) });
172    }
173
174    /// Read interrupt flags
175    #[inline]
176    pub(super) fn read_flags(&self) -> Flags {
177        Flags::from_bits_truncate(self.i2c_master().intflag().read().bits())
178    }
179
180    /// Enable specified interrupts
181    #[inline]
182    pub(super) fn enable_interrupts(&mut self, flags: Flags) {
183        self.i2c_master()
184            .intenset()
185            .write(|w| unsafe { w.bits(flags.bits()) });
186    }
187
188    /// Disable specified interrupts
189    #[inline]
190    pub(super) fn disable_interrupts(&mut self, flags: Flags) {
191        self.i2c_master()
192            .intenclr()
193            .write(|w| unsafe { w.bits(flags.bits()) });
194    }
195
196    /// Clear specified status flags
197    #[inline]
198    pub(super) fn clear_status(&mut self, status: Status) {
199        self.i2c_master()
200            .status()
201            .modify(|_, w| unsafe { w.bits(status.into()) });
202    }
203
204    /// Read status flags
205    #[inline]
206    pub(super) fn read_status(&self) -> Status {
207        self.i2c_master().status().read().bits().into()
208    }
209
210    pub(super) fn check_bus_status(&self) -> Result<(), Error> {
211        let status = self.read_status();
212        if status.busstate() == BusState::Busy
213            || (status.arblost() && status.busstate() != BusState::Idle)
214            || status.busstate() == BusState::Unknown
215        {
216            Err(Error::BusError)
217        } else {
218            Ok(())
219        }
220    }
221
222    /// Start a write transaction. May be used by [`start_write_blocking`], or
223    /// an async method.
224    #[inline]
225    pub(super) fn start_write(&mut self, addr: u8) -> Result<(), Error> {
226        if self.get_smart_mode() {
227            self.disable();
228            self.set_smart_mode(false);
229            self.enable();
230        }
231
232        self.check_bus_status()?;
233
234        // RESET the `ADDR` register, then signal start and transmit encoded
235        // address for a write transaction.
236        unsafe {
237            self.i2c_master()
238                .addr()
239                .write(|w| w.addr().bits(encode_write_address(addr)));
240        }
241
242        Ok(())
243    }
244
245    /// Start a blocking write transaction
246    #[inline]
247    pub(super) fn start_write_blocking(&mut self, addr: u8) -> Result<(), Error> {
248        self.start_write(addr)?;
249
250        // wait for transmission to complete
251        while !self.i2c_master().intflag().read().mb().bit_is_set() {}
252        self.read_status().check_bus_error()
253    }
254
255    /// Start a write transaction. May be used by [`start_write_blocking`], or
256    /// an async method.
257    pub(super) fn start_read(&mut self, addr: u8) -> Result<(), Error> {
258        if self.get_smart_mode() {
259            self.disable();
260            self.set_smart_mode(false);
261            self.enable();
262        }
263
264        self.check_bus_status()?;
265
266        self.i2c_master()
267            .intflag()
268            .modify(|_, w| w.error().clear_bit());
269
270        // RESET the `ADDR` register, then signal start (or repeated start if
271        // appropriate) and transmit encoded address for a read transaction.
272        unsafe {
273            self.i2c_master()
274                .addr()
275                .write(|w| w.addr().bits(encode_read_address(addr)));
276        }
277
278        Ok(())
279    }
280
281    /// Start a blocking read transaction
282    #[inline]
283    pub(super) fn start_read_blocking(&mut self, addr: u8) -> Result<(), Error> {
284        self.start_read(addr)?;
285
286        // wait for transmission to complete
287        loop {
288            let intflag = self.i2c_master().intflag().read();
289            // If arbitration was lost, it will be signalled via the mb bit
290            if intflag.mb().bit_is_set() {
291                return Err(Error::ArbitrationLost);
292            }
293            if intflag.sb().bit_is_set() || intflag.error().bit_is_set() {
294                break;
295            }
296        }
297
298        self.read_status().check_bus_error()
299    }
300
301    /// Start DMA write:
302    /// * Write `ADDR.LENEN` to 1
303    /// * Write the transaction length in `ADDR.LEN`.
304    /// * Write `ADDR.ADDR` to the encoded write address
305    ///
306    /// After ADDR.LEN bytes have been transmitted, a NACK (for master reads)
307    /// and STOP are automatically generated.
308    #[cfg(feature = "dma")]
309    #[inline]
310    pub(in super::super) fn start_dma_write(&mut self, address: u8, xfer_len: u8) {
311        if !self.get_smart_mode() {
312            self.disable();
313            self.set_smart_mode(true);
314            self.enable();
315        }
316
317        self.i2c_master().addr().write(|w| unsafe {
318            w.addr().bits(encode_write_address(address));
319            w.len().bits(xfer_len);
320            w.lenen().set_bit()
321        });
322
323        self.sync_sysop();
324    }
325
326    /// Start DMA read:
327    /// * Write `ADDR.LENEN` to 1
328    /// * Write the transaction length in `ADDR.LEN`.
329    /// * Write `ADDR.ADDR` to the encoded write address
330    ///
331    /// After ADDR.LEN bytes have been received, a NACK (for master reads) and
332    /// STOP are automatically generated.
333    #[cfg(feature = "dma")]
334    #[inline]
335    pub(in super::super) fn start_dma_read(&mut self, address: u8, xfer_len: u8) {
336        if !self.get_smart_mode() {
337            self.disable();
338            self.set_smart_mode(true);
339            self.enable();
340        }
341
342        self.i2c_master().addr().write(|w| unsafe {
343            w.addr().bits(encode_read_address(address));
344            w.len().bits(xfer_len);
345            w.lenen().set_bit()
346        });
347
348        self.sync_sysop();
349    }
350
351    /// Send a STOP condition. If the I2C is performing a read, will also send a
352    /// NACK to the slave.
353    #[inline]
354    pub(super) fn cmd_stop(&mut self) {
355        unsafe {
356            self.i2c_master().ctrlb().modify(|_, w| {
357                // set bit means send NACK
358                w.ackact().set_bit();
359                w.cmd().bits(MASTER_ACT_STOP)
360            });
361        }
362        self.sync_sysop();
363    }
364
365    /// Send a REPEATED START condition. If the I2C is performing a read, will
366    /// also send a NACK to the slave.
367    #[inline]
368    pub(super) fn cmd_repeated_start(&mut self) {
369        unsafe {
370            self.i2c_master().ctrlb().modify(|_, w| {
371                // set bit means send NACK
372                w.ackact().set_bit();
373                w.cmd().bits(MASTER_ACT_REPEATED_START)
374            });
375        }
376        self.sync_sysop();
377    }
378
379    #[inline]
380    pub(super) fn cmd_read(&mut self) {
381        unsafe {
382            self.i2c_master().ctrlb().modify(|_, w| {
383                // clear bit means send ack
384                w.ackact().clear_bit();
385                w.cmd().bits(MASTER_ACT_READ)
386            });
387        }
388        self.sync_sysop();
389    }
390
391    #[inline]
392    pub(super) fn write_one(&mut self, byte: u8) {
393        unsafe {
394            self.i2c_master().data().write(|w| w.bits(byte as DataReg));
395        }
396    }
397
398    #[inline]
399    pub(super) fn send_bytes(&mut self, bytes: &[u8]) -> Result<(), Error> {
400        for b in bytes {
401            self.write_one(*b);
402
403            loop {
404                let intflag = self.i2c_master().intflag().read();
405                if intflag.mb().bit_is_set() || intflag.error().bit_is_set() {
406                    break;
407                }
408            }
409            self.read_status().check_bus_error()?;
410        }
411        Ok(())
412    }
413
414    #[inline]
415    #[allow(clippy::unnecessary_cast)]
416    pub(super) fn read_one(&mut self) -> u8 {
417        // SAMx5x: u32 -> u8 conversion is fine as long as we don't set CTRLC.DATA32B to
418        // 1.
419        self.i2c_master().data().read().bits() as u8
420    }
421
422    #[inline]
423    pub(super) fn read_one_blocking(&mut self) -> u8 {
424        while !self.i2c_master().intflag().read().sb().bit_is_set() {
425            core::hint::spin_loop();
426        }
427        self.read_one()
428    }
429
430    #[inline]
431    pub(super) fn fill_buffer(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
432        // Some manual iterator gumph because we need to ack bytes after the first.
433        let mut iter = buffer.iter_mut();
434        *iter.next().expect("buffer len is at least 1") = self.read_one_blocking();
435
436        loop {
437            match iter.next() {
438                None => break,
439                Some(dest) => {
440                    // Ack the last byte so that we can receive another one
441                    self.cmd_read();
442                    *dest = self.read_one_blocking();
443                }
444            }
445        }
446
447        // arrange to send nack on next command to
448        // stop slave from transmitting more data
449        self.i2c_master()
450            .ctrlb()
451            .modify(|_, w| w.ackact().set_bit());
452
453        Ok(())
454    }
455
456    #[inline]
457    pub(super) fn do_write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Error> {
458        self.start_write_blocking(addr)?;
459        self.send_bytes(bytes)
460    }
461
462    /// Continue a write operation that was issued before with
463    /// [`do_write`](Self::do_write) or [`continue_write`](Self::continue_write)
464    /// without a repeated start condition in between
465    #[inline]
466    pub(super) fn continue_write(&mut self, bytes: &[u8]) -> Result<(), Error> {
467        self.send_bytes(bytes)
468    }
469
470    #[inline]
471    pub(super) fn do_read(&mut self, addr: u8, buffer: &mut [u8]) -> Result<(), Error> {
472        self.start_read_blocking(addr)?;
473        self.fill_buffer(buffer)
474    }
475
476    /// Continue a read operation that was issued before with
477    /// [`do_read`](Self::do_read) or [`continue_read`](Self::continue_read)
478    /// without a repeated start condition in between
479    #[inline]
480    pub(super) fn continue_read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
481        self.fill_buffer(buffer)
482    }
483
484    #[inline]
485    pub(super) fn do_write_read(
486        &mut self,
487        addr: u8,
488        bytes: &[u8],
489        buffer: &mut [u8],
490    ) -> Result<(), Error> {
491        self.start_write_blocking(addr)?;
492        self.send_bytes(bytes)?;
493        self.start_read_blocking(addr)?;
494        self.fill_buffer(buffer)?;
495        Ok(())
496    }
497
498    /// Set the bus to IDLE
499    #[inline]
500    pub(super) fn bus_idle(&mut self) {
501        // Set the bus idle
502        self.i2c_master()
503            .status()
504            .modify(|_, w| unsafe { w.busstate().bits(BusState::Idle as u8) });
505        // Wait for it to take effect
506        self.sync_sysop();
507    }
508
509    #[inline]
510    fn sync_sysop(&mut self) {
511        while self.i2c_master().syncbusy().read().sysop().bit_is_set() {}
512    }
513
514    /// Enable the I2C peripheral
515    ///
516    /// I2C transactions are not possible until the peripheral is enabled.
517    #[inline]
518    pub(super) fn enable(&mut self) {
519        // Globally enable peripheral
520        self.enable_peripheral(true);
521        // Set the bus state to IDLE
522        self.bus_idle();
523    }
524
525    #[inline]
526    pub(super) fn disable(&mut self) {
527        self.enable_peripheral(false);
528    }
529
530    /// Enable or disable the SERCOM peripheral, and wait for the ENABLE bit to
531    /// synchronize.
532    #[inline]
533    pub(super) fn enable_peripheral(&mut self, enable: bool) {
534        self.i2c_master()
535            .ctrla()
536            .modify(|_, w| w.enable().bit(enable));
537        while self.i2c_master().syncbusy().read().enable().bit_is_set() {}
538    }
539}
540
541fn encode_write_address(addr_7_bits: u8) -> u16 {
542    (addr_7_bits as u16) << 1
543}
544
545fn encode_read_address(addr_7_bits: u8) -> u16 {
546    ((addr_7_bits as u16) << 1) | 1
547}