msp432/
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
5use crate::usci::{self, UsciBRegisters};
6use core::cell::Cell;
7use kernel::hil::i2c::{self, Error};
8use kernel::utilities::cells::{OptionalCell, TakeCell};
9use kernel::utilities::registers::interfaces::{ReadWriteable, Readable, Writeable};
10use kernel::utilities::StaticRef;
11
12#[derive(Copy, Clone, PartialEq)]
13pub enum Speed {
14    K100, // 100kHz
15    K375, // 375kHz
16}
17
18#[derive(Copy, Clone, PartialEq)]
19enum OperatingMode {
20    Unconfigured,
21    Disabled,
22    Idle,
23    Write,
24    Read,
25    WriteReadWrite,
26    WriteReadRead,
27}
28
29pub struct I2c<'a> {
30    registers: StaticRef<UsciBRegisters>,
31    mode: Cell<OperatingMode>,
32    read_len: Cell<usize>,
33    write_len: Cell<usize>,
34    buf_idx: Cell<usize>,
35    buffer: TakeCell<'static, [u8]>,
36    master_client: OptionalCell<&'a dyn i2c::I2CHwMasterClient>,
37}
38
39impl I2c<'_> {
40    pub fn new(registers: StaticRef<UsciBRegisters>) -> Self {
41        Self {
42            registers,
43            mode: Cell::new(OperatingMode::Unconfigured),
44            read_len: Cell::new(0),
45            write_len: Cell::new(0),
46            buf_idx: Cell::new(0),
47            buffer: TakeCell::empty(),
48            master_client: OptionalCell::empty(),
49        }
50    }
51
52    fn set_module_to_reset(&self) {
53        // Set USCI module to reset in order to make a certain configurations possible
54        self.registers.ctlw0.modify(usci::UCBxCTLW0::UCSWRST::SET);
55    }
56
57    fn clear_module_reset(&self) {
58        // Set USCI module to reset in order to make a certain configurations possible
59        self.registers.ctlw0.modify(usci::UCBxCTLW0::UCSWRST::CLEAR);
60
61        // Setting the module to reset clears the enabled interrupts -> enable them again
62        self.enable_interrupts();
63    }
64
65    fn set_slave_address(&self, addr: u8) {
66        self.registers.i2csa.set(addr as u16);
67    }
68
69    fn generate_start_condition(&self) {
70        self.registers
71            .ctlw0
72            .modify(usci::UCBxCTLW0::UCTXSTT::GenerateSTARTCondition);
73    }
74
75    fn generate_stop_condition(&self) {
76        self.registers
77            .ctlw0
78            .modify(usci::UCBxCTLW0::UCTXSTP::GenerateSTOP);
79    }
80
81    fn set_stop_condition_automatically(&self, val: bool) {
82        if val {
83            self.registers
84                .ctlw1
85                .modify(usci::UCBxCTLW1::UCASTP::ByteCounterStopCondition)
86        } else {
87            self.registers.ctlw1.modify(usci::UCBxCTLW1::UCASTP::Manual);
88        }
89    }
90
91    fn enable_interrupts(&self) {
92        // Enable interrupts
93        //
94        // Enable NACK interrupt
95        // Enable RX interrupt
96        // Enable Stop condition interrupt
97        // Enable Start condition interrupt
98        // Enable 'arbitration lost' interrupt
99        self.registers.ie.modify(
100            usci::UCBxIE::UCNACKIE::SET
101                + usci::UCBxIE::UCRXIE0::SET
102                + usci::UCBxIE::UCSTPIE::SET
103                + usci::UCBxIE::UCSTTIE::SET
104                + usci::UCBxIE::UCALIE::SET,
105        );
106    }
107
108    fn enable_transmit_mode(&self) {
109        self.registers
110            .ctlw0
111            .modify(usci::UCBxCTLW0::UCTR::Transmitter);
112    }
113
114    fn enable_receive_mode(&self) {
115        self.registers.ctlw0.modify(usci::UCBxCTLW0::UCTR::Receiver);
116    }
117
118    fn enable_transmit_interrupt(&self) {
119        self.registers.ie.modify(usci::UCBxIE::UCTXIE0::SET);
120    }
121
122    fn disable_transmit_interrupt(&self) {
123        self.registers.ie.modify(usci::UCBxIE::UCTXIE0::CLEAR);
124    }
125
126    fn set_byte_counter(&self, val: usize) {
127        self.registers.tbcnt.set(val as u16);
128    }
129
130    fn invoke_callback(&self, status: Result<(), Error>) {
131        // Reset buffer index and set mode to Idle in order to start a new transfer properly
132        self.buf_idx.set(0);
133        self.mode.set(OperatingMode::Idle);
134
135        self.buffer.take().map(|buf| {
136            self.master_client
137                .map(move |cl| cl.command_complete(buf, status))
138        });
139    }
140
141    fn setup(&self) {
142        self.set_module_to_reset();
143
144        // Use 7 bit addresses
145        // Setup to master mode
146        // Setup to single master environment
147        // Configure USCI module to I2C mode
148        // Enable Synchronous mode
149        // Set clock source to SMCLK (1.5MHz)
150        self.registers.ctlw0.modify(
151            usci::UCBxCTLW0::UCSLA10::AddressSlaveWith7BitAddress
152                + usci::UCBxCTLW0::UCMST::MasterMode
153                + usci::UCBxCTLW0::UCMM::SingleMasterEnvironment
154                + usci::UCBxCTLW0::UCMODE::I2CMode
155                + usci::UCBxCTLW0::UCSYNC::SynchronousMode
156                + usci::UCBxCTLW0::UCSSEL::SMCLK,
157        );
158
159        // Disable clock low timeout
160        // Send a NACK before a stop condition
161        // Generate the ACK bit by hardware
162        // Set glitch filtering to 50ns (according to I2C standard)
163        self.registers.ctlw1.modify(
164            usci::UCBxCTLW1::UCCLTO::CLEAR
165                + usci::UCBxCTLW1::UCSTPNACK::NackBeforeStop
166                + usci::UCBxCTLW1::UCSWACK::HardwareTriggered
167                + usci::UCBxCTLW1::UCGLIT::_50ns,
168        );
169
170        // Don't clear the module reset here since we set the state to Disabled
171        self.mode.set(OperatingMode::Disabled);
172    }
173
174    pub fn set_speed(&self, speed: Speed) {
175        self.set_module_to_reset();
176
177        // SMCLK is running at 1.5MHz
178        // In order to achieve a speed of 100kHz or 375kHz, it's necessary to divide the clock
179        // by either 15 (100kHz) or 4 (375kHz)
180        if speed == Speed::K100 {
181            self.registers.brw.set(15);
182        } else if speed == Speed::K375 {
183            self.registers.brw.set(4);
184        }
185
186        self.clear_module_reset();
187    }
188
189    pub fn handle_interrupt(&self) {
190        let ifg = self.registers.ifg.get();
191        let mode = self.mode.get();
192        let idx = self.buf_idx.get();
193
194        // clear all interrupts
195        self.registers.ifg.set(0);
196
197        if (ifg & (1 << usci::UCBxIFG::UCTXIFG0.shift)) > 0 {
198            // TX interrupt
199            if idx < self.write_len.get() {
200                // Transmit another byte
201                self.buffer
202                    .map(|buf| self.registers.txbuf.set(buf[idx] as u16));
203                self.buf_idx.set(idx + 1);
204            } else {
205                self.disable_transmit_interrupt();
206                if mode == OperatingMode::WriteReadWrite {
207                    // Finished write part -> switch to reading
208                    self.mode.set(OperatingMode::WriteReadRead);
209                    self.buf_idx.set(0);
210
211                    // Switch to receiving and send a restart condition
212                    self.enable_receive_mode();
213                    self.generate_start_condition();
214                    if self.read_len.get() == 1 {
215                        // In this mode the stop condition is set automatically and has to be
216                        // requested 1 byte before the last byte was received. If only one byte will
217                        // be received request the stop condition immediately after the start.
218                        self.generate_stop_condition();
219                    }
220                }
221            }
222        } else if (ifg & (1 << usci::UCBxIFG::UCRXIFG0.shift)) > 0 {
223            // RX interrupt
224            if idx < self.read_len.get() {
225                if idx == (self.read_len.get() - 1) && mode == OperatingMode::WriteReadRead {
226                    // In this mode we don't use the byte counter to generate an automatic stop
227                    // condition, further, the stop condition has to be set before the last byte was
228                    // received
229                    self.generate_stop_condition();
230                }
231                // Store received byte in buffer
232                self.buffer
233                    .map(|buf| buf[idx] = self.registers.rxbuf.get() as u8);
234                self.buf_idx.set(idx + 1);
235            } else if mode == OperatingMode::WriteReadRead {
236                // For some reason generating a stop condition manually in receive mode doesn't
237                // trigger a stop condition interrupt -> invoke the callback here when all bytes
238                // were received
239                self.invoke_callback(Ok(()));
240            }
241        } else if (ifg & (1 << usci::UCBxIFG::UCSTTIFG.shift)) > 0 {
242            // Start condition interrupt
243            if mode == OperatingMode::Write || mode == OperatingMode::WriteReadWrite {
244                self.buffer
245                    .map(|buf| self.registers.txbuf.set(buf[idx] as u16));
246                self.buf_idx.set(idx + 1);
247            }
248        } else if (ifg & (1 << usci::UCBxIFG::UCSTPIFG.shift)) > 0 {
249            // Stop condition interrupt
250
251            // This interrupt is the default indicator that a transaction finished, thus raise the
252            // callback here and prepare for another transfer
253            self.invoke_callback(Ok(()));
254        } else if (ifg & (1 << usci::UCBxIFG::UCNACKIFG.shift)) > 0 {
255            // NACK interrupt
256            // TODO: use byte counter to detect address NAK
257
258            // Cancel i2c transfer
259            self.generate_stop_condition();
260            self.invoke_callback(Err(Error::DataNak));
261        } else if (ifg & (1 << usci::UCBxIFG::UCALIFG.shift)) > 0 {
262            // Arbitration lost  interrupt
263
264            // Cancel i2c transfer
265            self.generate_stop_condition();
266            self.invoke_callback(Err(Error::Busy));
267        } else {
268            panic!("I2C: unhandled interrupt, ifg: {}", ifg);
269        }
270    }
271}
272
273impl<'a> i2c::I2CMaster<'a> for I2c<'a> {
274    fn set_master_client(&self, master_client: &'a dyn i2c::I2CHwMasterClient) {
275        self.master_client.replace(master_client);
276    }
277
278    fn enable(&self) {
279        if self.mode.get() == OperatingMode::Unconfigured {
280            self.setup();
281        }
282
283        self.clear_module_reset();
284        self.mode.set(OperatingMode::Idle);
285    }
286
287    fn disable(&self) {
288        self.set_module_to_reset();
289        self.mode.set(OperatingMode::Disabled);
290    }
291
292    fn write(
293        &self,
294        addr: u8,
295        data: &'static mut [u8],
296        len: usize,
297    ) -> Result<(), (Error, &'static mut [u8])> {
298        if self.mode.get() != OperatingMode::Idle {
299            // Module is busy or not activated
300            return Err((Error::Busy, data));
301        }
302
303        self.buffer.replace(data);
304        self.write_len.set(len);
305
306        // Set module to reset since some of the registers cannot be modified in running state
307        self.set_module_to_reset();
308
309        // Setup the byte counter in order to automatically generate a stop condition after the
310        // desired number of bytes were transmitted
311        self.set_byte_counter(len);
312
313        // Create stop condition automatically after the number of bytes in the byte counter
314        // register were transmitted
315        self.set_stop_condition_automatically(true);
316        self.clear_module_reset();
317
318        self.set_slave_address(addr);
319        self.enable_transmit_mode();
320        self.enable_transmit_interrupt();
321
322        self.mode.set(OperatingMode::Write);
323
324        // Start transfer
325        self.generate_start_condition();
326
327        Ok(())
328    }
329
330    fn read(
331        &self,
332        addr: u8,
333        buffer: &'static mut [u8],
334        len: usize,
335    ) -> Result<(), (Error, &'static mut [u8])> {
336        if self.mode.get() != OperatingMode::Idle {
337            // Module is busy or not activated
338            return Err((Error::Busy, buffer));
339        }
340
341        self.buffer.replace(buffer);
342        self.read_len.set(len);
343
344        // Set module to reset since some of the registers cannot be modified in running state
345        self.set_module_to_reset();
346
347        // Setup the byte counter in order to automatically generate a stop condition after the
348        // desired number of bytes were transmitted
349        self.set_byte_counter(len);
350
351        // Generate a stop condition automatically after the number of bytes in the byte counter
352        // register were transmitted
353        self.set_stop_condition_automatically(true);
354        self.clear_module_reset();
355
356        self.set_slave_address(addr);
357        self.enable_receive_mode();
358        self.mode.set(OperatingMode::Read);
359
360        // Start transfer
361        self.generate_start_condition();
362        Ok(())
363    }
364
365    fn write_read(
366        &self,
367        addr: u8,
368        data: &'static mut [u8],
369        write_len: usize,
370        read_len: usize,
371    ) -> Result<(), (Error, &'static mut [u8])> {
372        if self.mode.get() != OperatingMode::Idle {
373            // Module is busy or not activated
374            return Err((Error::Busy, data));
375        }
376
377        self.buffer.replace(data);
378        self.write_len.set(write_len);
379        self.read_len.set(read_len);
380
381        // Set module to reset since some of the registers cannot be modified in running state
382        self.set_module_to_reset();
383
384        // Disable generating a stop condition automatically since after the write, a repeated
385        // start condition will be generated in order to continue reading from the slave
386        self.set_stop_condition_automatically(false);
387        self.clear_module_reset();
388
389        self.set_slave_address(addr);
390        self.enable_transmit_mode();
391        self.enable_transmit_interrupt();
392        self.mode.set(OperatingMode::WriteReadWrite);
393
394        // Start transfer
395        self.generate_start_condition();
396
397        Ok(())
398    }
399}