nrf52/
i2c.rs

1// Licensed under the Apache License, Version 2.0 or the MIT License.
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3// Copyright Tock Contributors 2022.
4
5//! Implementation of I2C for nRF52 using EasyDMA.
6//!
7//! This module supports nRF52's two I2C master (`TWI`) peripherals,
8//! and the I2C slave (`TWIS`).
9
10use kernel::hil;
11use kernel::utilities::cells::OptionalCell;
12use kernel::utilities::cells::TakeCell;
13use kernel::utilities::cells::VolatileCell;
14use kernel::utilities::registers::interfaces::{ReadWriteable, Readable, Writeable};
15use kernel::utilities::registers::{register_bitfields, register_structs, ReadWrite, WriteOnly};
16use kernel::utilities::StaticRef;
17use nrf5x::pinmux::Pinmux;
18
19/// Uninitialized `TWI` instances.
20const INSTANCES: [StaticRef<TwiRegisters>; 2] = unsafe {
21    [
22        StaticRef::new(0x40003000 as *const TwiRegisters),
23        StaticRef::new(0x40004000 as *const TwiRegisters),
24    ]
25};
26
27/// An I2C master device.
28///
29/// A `TWI` instance wraps a `registers::TWI` together with
30/// additional data necessary to implement an asynchronous interface.
31pub struct TWI<'a> {
32    registers: StaticRef<TwiRegisters>,
33    client: OptionalCell<&'a dyn hil::i2c::I2CHwMasterClient>,
34    slave_client: OptionalCell<&'a dyn hil::i2c::I2CHwSlaveClient>,
35    buf: TakeCell<'static, [u8]>,
36    slave_read_buf: TakeCell<'static, [u8]>,
37}
38
39/// I2C bus speed.
40#[repr(u32)]
41pub enum Speed {
42    K100 = 0x01980000,
43    K250 = 0x04000000,
44    K400 = 0x06400000,
45}
46
47impl TWI<'_> {
48    const fn new(registers: StaticRef<TwiRegisters>) -> Self {
49        Self {
50            registers,
51            client: OptionalCell::empty(),
52            slave_client: OptionalCell::empty(),
53            buf: TakeCell::empty(),
54            slave_read_buf: TakeCell::empty(),
55        }
56    }
57
58    pub const fn new_twi0() -> Self {
59        TWI::new(INSTANCES[0])
60    }
61
62    pub const fn new_twi1() -> Self {
63        TWI::new(INSTANCES[1])
64    }
65
66    /// Configures an already constructed `TWI`.
67    pub fn configure(&self, scl: Pinmux, sda: Pinmux) {
68        self.registers.psel_scl.set(scl);
69        self.registers.psel_sda.set(sda);
70    }
71
72    /// Sets the I2C bus speed to one of three possible values
73    /// enumerated in `Speed`.
74    pub fn set_speed(&self, speed: Speed) {
75        self.registers.frequency.set(speed as u32);
76    }
77
78    /// Clear all pending events
79    /// This is useful when switching between a master and slave mode to ensure
80    /// we start from a clean state.
81    pub fn clear_events(&self) {
82        self.registers.events_stopped.write(EVENT::EVENT::CLEAR);
83        self.registers.events_error.write(EVENT::EVENT::CLEAR);
84        self.registers.events_rxstarted.write(EVENT::EVENT::CLEAR);
85        self.registers.events_txstarted.write(EVENT::EVENT::CLEAR);
86        self.registers.events_write.write(EVENT::EVENT::CLEAR);
87        self.registers.events_read.write(EVENT::EVENT::CLEAR);
88        self.registers.events_suspended.write(EVENT::EVENT::CLEAR);
89        self.registers.events_lastrx.write(EVENT::EVENT::CLEAR);
90        self.registers.events_lasttx.write(EVENT::EVENT::CLEAR);
91    }
92
93    pub fn disable_interrupts(&self) {
94        // Disable all interrupts
95        self.registers.inten.set(0x00);
96        self.registers.intenclr.set(0xFFFF_FFFF);
97    }
98
99    /// Enables hardware TWIM peripheral.
100    fn enable_master(&self) {
101        self.clear_events();
102        self.registers.enable.write(ENABLE::ENABLE::EnableMaster);
103    }
104
105    /// Enables hardware TWIS peripheral.
106    fn enable_slave(&self) {
107        self.clear_events();
108        self.registers.enable.write(ENABLE::ENABLE::EnableSlave);
109    }
110
111    /// Disables hardware TWIM/TWIS peripheral.
112    fn disable(&self) {
113        self.clear_events();
114        self.disable_interrupts();
115        self.registers.enable.write(ENABLE::ENABLE::Disable);
116    }
117
118    pub fn handle_interrupt(&self) {
119        if self.is_master_enabled() {
120            if self.registers.events_stopped.is_set(EVENT::EVENT) {
121                self.registers.events_stopped.write(EVENT::EVENT::CLEAR);
122
123                self.client.map(|client| match self.buf.take() {
124                    None => (),
125                    Some(buf) => {
126                        self.clear_events();
127                        client.command_complete(buf, Ok(()));
128                    }
129                });
130            }
131
132            if self.registers.events_error.is_set(EVENT::EVENT) {
133                self.registers.events_error.write(EVENT::EVENT::CLEAR);
134                let errorsrc = self.registers.errorsrc_master.extract();
135                self.registers
136                    .errorsrc_master
137                    .write(ERRORSRC::ANACK::ErrorDidNotOccur + ERRORSRC::DNACK::ErrorDidNotOccur);
138                self.client.map(|client| match self.buf.take() {
139                    None => (),
140                    Some(buf) => {
141                        let status = if errorsrc.is_set(ERRORSRC::ANACK) {
142                            Err(hil::i2c::Error::AddressNak)
143                        } else if errorsrc.is_set(ERRORSRC::DNACK) {
144                            Err(hil::i2c::Error::DataNak)
145                        } else {
146                            Ok(())
147                        };
148                        self.clear_events();
149                        client.command_complete(buf, status);
150                    }
151                });
152            }
153        } else {
154            self.registers.events_stopped.write(EVENT::EVENT::CLEAR);
155
156            // If RX started (master started write) and we don't have a buffer then report
157            // write_expected()
158            if self.registers.events_rxstarted.is_set(EVENT::EVENT) {
159                self.registers.events_rxstarted.write(EVENT::EVENT::CLEAR);
160                self.slave_client.map(|client| {
161                    if self.buf.is_none() {
162                        client.write_expected();
163                    }
164                });
165            }
166
167            // If TX started (master started read) and we don't have a buffer then report
168            // read_expected()
169            if self.registers.events_txstarted.is_set(EVENT::EVENT) {
170                self.registers.events_txstarted.write(EVENT::EVENT::CLEAR);
171                self.slave_client.map(|client| {
172                    if self.slave_read_buf.is_none() {
173                        client.read_expected();
174                    }
175                });
176            }
177
178            // Write command received
179            if self.registers.events_write.is_set(EVENT::EVENT) {
180                self.registers.events_write.write(EVENT::EVENT::CLEAR);
181                let length = self.registers.rxd_amount.read(AMOUNT::AMOUNT) as usize;
182                self.slave_client.map(|client| match self.buf.take() {
183                    None => (),
184                    Some(buf) => {
185                        self.clear_events();
186                        client.command_complete(
187                            buf,
188                            length,
189                            hil::i2c::SlaveTransmissionType::Write,
190                        );
191                    }
192                });
193            }
194
195            if self.registers.events_read.is_set(EVENT::EVENT) {
196                self.registers.events_read.write(EVENT::EVENT::CLEAR);
197                let length = self.registers.txd_amount.read(AMOUNT::AMOUNT) as usize;
198                self.slave_client
199                    .map(|client| match self.slave_read_buf.take() {
200                        None => (),
201                        Some(buf) => {
202                            self.clear_events();
203                            client.command_complete(
204                                buf,
205                                length,
206                                hil::i2c::SlaveTransmissionType::Read,
207                            );
208                        }
209                    });
210            }
211        }
212
213        // We can blindly clear the following events since we're not using them.
214        self.registers.events_suspended.write(EVENT::EVENT::CLEAR);
215        self.registers.events_lastrx.write(EVENT::EVENT::CLEAR);
216        self.registers.events_lasttx.write(EVENT::EVENT::CLEAR);
217    }
218
219    pub fn is_enabled(&self) -> bool {
220        self.is_master_enabled() || self.is_slave_enabled()
221    }
222
223    fn is_master_enabled(&self) -> bool {
224        self.registers
225            .enable
226            .matches_all(ENABLE::ENABLE::EnableMaster)
227    }
228
229    fn is_slave_enabled(&self) -> bool {
230        self.registers
231            .enable
232            .matches_all(ENABLE::ENABLE::EnableSlave)
233    }
234}
235
236impl<'a> hil::i2c::I2CMaster<'a> for TWI<'a> {
237    fn set_master_client(&self, client: &'a dyn hil::i2c::I2CHwMasterClient) {
238        self.client.set(client);
239    }
240
241    fn enable(&self) {
242        self.enable_master();
243    }
244
245    fn disable(&self) {
246        self.disable();
247    }
248
249    fn write_read(
250        &self,
251        addr: u8,
252        data: &'static mut [u8],
253        write_len: usize,
254        read_len: usize,
255    ) -> Result<(), (hil::i2c::Error, &'static mut [u8])> {
256        self.registers
257            .address_0
258            .write(ADDRESS::ADDRESS.val(addr as u32));
259        self.registers.txd_ptr.set(data.as_mut_ptr() as u32);
260        self.registers
261            .txd_maxcnt
262            .write(MAXCNT::MAXCNT.val(write_len as u32));
263        self.registers.rxd_ptr.set(data.as_mut_ptr() as u32);
264        self.registers
265            .rxd_maxcnt
266            .write(MAXCNT::MAXCNT.val(read_len as u32));
267        // Use the NRF52 shortcut register to configure the peripheral to
268        // switch to RX after TX is complete, and then to switch to the STOP
269        // state once RX is done. This avoids us having to juggle tasks in
270        // the interrupt handler.
271        self.registers
272            .shorts
273            .write(SHORTS::LASTTX_STARTRX::EnableShortcut + SHORTS::LASTRX_STOP::EnableShortcut);
274        self.registers
275            .intenset
276            .write(INTE::STOPPED::Enable + INTE::ERROR::Enable);
277        // start the transfer
278        self.registers.tasks_starttx.write(TASK::TASK::SET);
279        self.buf.replace(data);
280        Ok(())
281    }
282
283    fn write(
284        &self,
285        addr: u8,
286        data: &'static mut [u8],
287        len: usize,
288    ) -> Result<(), (hil::i2c::Error, &'static mut [u8])> {
289        self.registers
290            .address_0
291            .write(ADDRESS::ADDRESS.val(addr as u32));
292        self.registers.txd_ptr.set(data.as_mut_ptr() as u32);
293        self.registers
294            .txd_maxcnt
295            .write(MAXCNT::MAXCNT.val(len as u32));
296        // Use the NRF52 shortcut register to switch to the STOP state once
297        // the TX is complete.
298        self.registers
299            .shorts
300            .write(SHORTS::LASTTX_STOP::EnableShortcut);
301        self.registers
302            .intenset
303            .write(INTE::STOPPED::Enable + INTE::ERROR::Enable);
304        // start the transfer
305        self.registers.tasks_starttx.write(TASK::TASK::SET);
306        self.buf.replace(data);
307        Ok(())
308    }
309
310    fn read(
311        &self,
312        addr: u8,
313        buffer: &'static mut [u8],
314        len: usize,
315    ) -> Result<(), (hil::i2c::Error, &'static mut [u8])> {
316        self.registers
317            .address_0
318            .write(ADDRESS::ADDRESS.val(addr as u32));
319        self.registers.rxd_ptr.set(buffer.as_mut_ptr() as u32);
320        self.registers
321            .rxd_maxcnt
322            .write(MAXCNT::MAXCNT.val(len as u32));
323        // Use the NRF52 shortcut register to switch to the STOP state once
324        // the RX is complete.
325        self.registers
326            .shorts
327            .write(SHORTS::LASTRX_STOP::EnableShortcut);
328        self.registers
329            .intenset
330            .write(INTE::STOPPED::Enable + INTE::ERROR::Enable);
331        // start the transfer
332        self.registers.tasks_startrx.write(TASK::TASK::SET);
333        self.buf.replace(buffer);
334        Ok(())
335    }
336}
337
338impl<'a> hil::i2c::I2CSlave<'a> for TWI<'a> {
339    fn set_slave_client(&self, client: &'a dyn hil::i2c::I2CHwSlaveClient) {
340        self.slave_client.set(client);
341    }
342
343    fn enable(&self) {
344        self.enable_slave();
345    }
346
347    fn disable(&self) {
348        self.disable();
349    }
350
351    fn set_address(&self, addr: u8) -> Result<(), hil::i2c::Error> {
352        self.registers
353            .address_0
354            .write(ADDRESS::ADDRESS.val(addr as u32));
355        self.registers.config.modify(CONFIG::ADDRESS0::Enable);
356        Ok(())
357    }
358
359    fn write_receive(
360        &self,
361        data: &'static mut [u8],
362        max_len: usize,
363    ) -> Result<(), (hil::i2c::Error, &'static mut [u8])> {
364        self.registers.rxd_ptr.set(data.as_mut_ptr() as u32);
365        self.registers
366            .rxd_maxcnt
367            .write(MAXCNT::MAXCNT.val(max_len as u32));
368
369        self.registers
370            .intenset
371            .modify(INTE::STOPPED::Enable + INTE::ERROR::Enable);
372
373        self.buf.replace(data);
374
375        self.registers.tasks_preparerx.write(TASK::TASK::SET);
376
377        Ok(())
378    }
379
380    fn read_send(
381        &self,
382        data: &'static mut [u8],
383        max_len: usize,
384    ) -> Result<(), (hil::i2c::Error, &'static mut [u8])> {
385        self.registers.txd_ptr.set(data.as_mut_ptr() as u32);
386        self.registers
387            .txd_maxcnt
388            .write(MAXCNT::MAXCNT.val(max_len as u32));
389
390        self.registers
391            .intenset
392            .modify(INTE::STOPPED::Enable + INTE::ERROR::Enable + INTE::READ::Enable);
393
394        self.slave_read_buf.replace(data);
395
396        self.registers.tasks_preparetx.write(TASK::TASK::SET);
397
398        Ok(())
399    }
400
401    fn listen(&self) {
402        self.registers.tasks_preparerx.write(TASK::TASK::SET);
403    }
404}
405
406impl<'a> hil::i2c::I2CMasterSlave<'a> for TWI<'a> {}
407
408// The SPI0_TWI0 and SPI1_TWI1 interrupts are dispatched to the
409// correct handler by the service_pending_interrupts() routine in
410// chip.rs based on which peripheral is enabled.
411
412register_structs! {
413    pub TwiRegisters {
414        /// Start TWI receive sequence
415        (0x00 => tasks_startrx: WriteOnly<u32, TASK::Register>),
416        (0x04 => _reserved0),
417        /// Start TWI transmit sequence
418        (0x08 => tasks_starttx: WriteOnly<u32, TASK::Register>),
419        (0x0C => _reserved1),
420        /// Stop TWI transaction
421        (0x14 => tasks_stop: WriteOnly<u32, TASK::Register>),
422        (0x18 => _reserved2),
423        /// Suspend TWI transaction
424        (0x1C => tasks_suspend: WriteOnly<u32, TASK::Register>),
425        /// Resume TWI transaction
426        (0x20 => tasks_resume: WriteOnly<u32, TASK::Register>),
427        (0x24 => _reserved3),
428        (0x30 => tasks_preparerx: WriteOnly<u32, TASK::Register>),
429        (0x34 => tasks_preparetx: WriteOnly<u32, TASK::Register>),
430        (0x38 => _reserved4),
431        /// TWI stopped
432        (0x104 => events_stopped: ReadWrite<u32, EVENT::Register>),
433        (0x108 => _reserved5),
434        /// TWI error
435        (0x124 => events_error: ReadWrite<u32, EVENT::Register>),
436        (0x128 => _reserved6),
437        /// Last byte has been sent out after the SUSPEND task has been issued, TWI
438        /// traffic is now suspended.
439        (0x148 => events_suspended: ReadWrite<u32, EVENT::Register>),
440        /// Receive sequence started
441        (0x14C => events_rxstarted: ReadWrite<u32, EVENT::Register>),
442        /// Transmit sequence started
443        (0x150 => events_txstarted: ReadWrite<u32, EVENT::Register>),
444        (0x154 => _reserved7),
445        /// Byte boundary, starting to receive the last byte
446        (0x15C => events_lastrx: ReadWrite<u32, EVENT::Register>),
447        /// Byte boundary, starting to transmit the last byte
448        (0x160 => events_lasttx: ReadWrite<u32, EVENT::Register>),
449        (0x164 => events_write: ReadWrite<u32, EVENT::Register>),
450        (0x168 => events_read: ReadWrite<u32, EVENT::Register>),
451        (0x16C => _reserved8),
452        /// Shortcut register
453        (0x200 => shorts: ReadWrite<u32, SHORTS::Register>),
454        (0x204 => _reserved9),
455        /// Enable or disable interrupt
456        (0x300 => inten: ReadWrite<u32, INTE::Register>),
457        /// Enable interrupt
458        (0x304 => intenset: ReadWrite<u32, INTE::Register>),
459        /// Disable interrupt
460        (0x308 => intenclr: ReadWrite<u32, INTE::Register>),
461        (0x30C => _reserved10),
462        /// Error source
463        (0x4C4 => errorsrc_master: ReadWrite<u32, ERRORSRC::Register>),
464        (0x4C8 => _reserved11),
465        (0x4D0 => errorsrc_slave: ReadWrite<u32, ERRORSRC::Register>),
466        (0x4D4 => match_reg: ReadWrite<u32>),
467        (0x4D8 => _reserved12),
468        /// Enable TWI
469        (0x500 => enable: ReadWrite<u32, ENABLE::Register>),
470        (0x504 => _reserved13),
471        /// Pin select for SCL signal
472        (0x508 => psel_scl: VolatileCell<Pinmux>),
473        /// Pin select for SDA signal
474        (0x50C => psel_sda: VolatileCell<Pinmux>),
475        (0x510 => _reserved_14),
476        /// TWI frequency
477        (0x524 => frequency: ReadWrite<u32>),
478        (0x528 => _reserved15),
479        /// Data pointer
480        (0x534 => rxd_ptr: ReadWrite<u32>),
481        /// Maximum number of bytes in receive buffer
482        (0x538 => rxd_maxcnt: ReadWrite<u32, MAXCNT::Register>),
483        /// Number of bytes transferred in the last transaction
484        (0x53C => rxd_amount: ReadWrite<u32, AMOUNT::Register>),
485        /// EasyDMA list type
486        (0x540 => rxd_list: ReadWrite<u32>),
487        /// Data pointer
488        (0x544 => txd_ptr: ReadWrite<u32>),
489        /// Maximum number of bytes in transmit buffer
490        (0x548 => txd_maxcnt: ReadWrite<u32, MAXCNT::Register>),
491        /// Number of bytes transferred in the last transaction
492        (0x54C => txd_amount: ReadWrite<u32, AMOUNT::Register>),
493        /// EasyDMA list type
494        (0x550 => txd_list: ReadWrite<u32>),
495        (0x554 => _reserved_16),
496        /// Address used in the TWI transfer
497        (0x588 => address_0: ReadWrite<u32, ADDRESS::Register>),
498        (0x58C => address_1: ReadWrite<u32, ADDRESS::Register>),
499        (0x590 => _reserved_17),
500        (0x594 => config: ReadWrite<u32, CONFIG::Register>),
501        (0x598 => _reserved_18),
502        (0x5C0 => orc: ReadWrite<u32>),
503        (0x5C4 => @END),
504    }
505}
506
507register_bitfields![u32,
508    SHORTS [
509        /// Shortcut between EVENTS_LASTTX event and TASKS_STARTRX task
510        LASTTX_STARTRX OFFSET(7) NUMBITS(1) [
511            /// Disable shortcut
512            DisableShortcut = 0,
513            /// Enable shortcut
514            EnableShortcut = 1
515        ],
516        /// Shortcut between EVENTS_LASTTX event and TASKS_SUSPEND task
517        LASTTX_SUSPEND OFFSET(8) NUMBITS(1) [
518            /// Disable shortcut
519            DisableShortcut = 0,
520            /// Enable shortcut
521            EnableShortcut = 1
522        ],
523        /// Shortcut between EVENTS_LASTTX event and TASKS_STOP task
524        LASTTX_STOP OFFSET(9) NUMBITS(1) [
525            /// Disable shortcut
526            DisableShortcut = 0,
527            /// Enable shortcut
528            EnableShortcut = 1
529        ],
530        /// Shortcut between EVENTS_LASTRX event and TASKS_STARTTX task
531        LASTRX_STARTTX OFFSET(10) NUMBITS(1) [
532            /// Disable shortcut
533            DisableShortcut = 0,
534            /// Enable shortcut
535            EnableShortcut = 1
536        ],
537        /// Shortcut between EVENTS_LASTRX event and TASKS_STOP task
538        LASTRX_STOP OFFSET(12) NUMBITS(1) [
539            /// Disable shortcut
540            DisableShortcut = 0,
541            /// Enable shortcut
542            EnableShortcut = 1
543        ]
544    ],
545    INTE [
546        /// Enable or disable interrupt on EVENTS_STOPPED event
547        STOPPED OFFSET(1) NUMBITS(1) [
548            /// Disable
549            Disable = 0,
550            /// Enable
551            Enable = 1
552        ],
553        /// Enable or disable interrupt on EVENTS_ERROR event
554        ERROR OFFSET(9) NUMBITS(1) [
555            /// Disable
556            Disable = 0,
557            /// Enable
558            Enable = 1
559        ],
560        /// Enable or disable interrupt on EVENTS_RXSTARTED event
561        RXSTARTED OFFSET(19) NUMBITS(1) [
562            /// Disable
563            Disable = 0,
564            /// Enable
565            Enable = 1
566        ],
567        /// Enable or disable interrupt on EVENTS_TXSTARTED event
568        TXSTARTED OFFSET(20) NUMBITS(1) [
569            /// Disable
570            Disable = 0,
571            /// Enable
572            Enable = 1
573        ],
574        /// Enable or disable interrupt on EVENTS_LASTRX event
575        LASTRX OFFSET(23) NUMBITS(1) [
576            /// Disable
577            Disable = 0,
578            /// Enable
579            Enable = 1
580        ],
581        /// Enable or disable interrupt on EVENTS_LASTTX event
582        LASTTX OFFSET(24) NUMBITS(1) [
583            /// Disable
584            Disable = 0,
585            /// Enable
586            Enable = 1
587        ],
588        WRITE OFFSET(25) NUMBITS(1) [
589            Disable = 0,
590            Enable = 1
591        ],
592        READ OFFSET(26) NUMBITS(1) [
593            Disable = 0,
594            Enable = 1
595        ],
596    ],
597    ERRORSRC [
598        /// NACK received after sending the address (write '1' to clear)
599        ANACK OFFSET(1) NUMBITS(1) [
600            /// Error did not occur
601            ErrorDidNotOccur = 0,
602            /// Error occurred
603            ErrorOccurred = 1
604        ],
605        /// NACK received after sending a data byte (write '1' to clear)
606        DNACK OFFSET(2) NUMBITS(1) [
607            /// Error did not occur
608            ErrorDidNotOccur = 0,
609            /// Error occurred
610            ErrorOccurred = 1
611        ]
612    ],
613    EVENT [
614        EVENT 0
615    ],
616    TASK [
617        TASK 0
618    ],
619    ENABLE [
620        /// Enable or disable TWI
621        ENABLE OFFSET(0) NUMBITS(4) [
622            Disable = 0,
623            EnableMaster = 6,
624            EnableSlave = 9,
625        ]
626    ],
627    MAXCNT [
628        /// Maximum number of bytes in buffer
629        MAXCNT OFFSET(0) NUMBITS(16)
630    ],
631    AMOUNT [
632        AMOUNT OFFSET(0) NUMBITS(16),
633    ],
634    ADDRESS [
635        /// Address used in the TWI transfer
636        ADDRESS OFFSET(0) NUMBITS(7)
637    ],
638    CONFIG [
639        /// Address used in the TWI transfer
640        ADDRESS0 OFFSET(0) NUMBITS(1) [
641            Disable = 0,
642            Enable = 1,
643        ],
644        ADDRESS1 OFFSET(1) NUMBITS(1) [
645            Disable = 0,
646            Enable = 1,
647        ]
648    ],
649];