msp432/
uart.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//! Universal Asynchronous Receiver/Transmitter (UART)
6
7use crate::dma;
8use crate::usci::{self, UsciARegisters};
9use core::cell::Cell;
10use kernel::hil;
11use kernel::utilities::cells::OptionalCell;
12use kernel::utilities::registers::interfaces::{ReadWriteable, Readable, Writeable};
13use kernel::utilities::StaticRef;
14use kernel::ErrorCode;
15
16const DEFAULT_CLOCK_FREQ_HZ: u32 = crate::cs::SMCLK_HZ;
17
18struct BaudFraction {
19    frac: f32,
20    reg_val: u8,
21}
22
23#[rustfmt::skip]
24// Table out of the datasheet to correct the baudrate
25const BAUD_FRACTIONS: &[BaudFraction; 36] = &[
26    BaudFraction { frac: 0.0000, reg_val: 0x00 },
27    BaudFraction { frac: 0.0529, reg_val: 0x01 },
28    BaudFraction { frac: 0.0715, reg_val: 0x02 },
29    BaudFraction { frac: 0.0835, reg_val: 0x04 },
30    BaudFraction { frac: 0.1001, reg_val: 0x08 },
31    BaudFraction { frac: 0.1252, reg_val: 0x10 },
32    BaudFraction { frac: 0.1430, reg_val: 0x20 },
33    BaudFraction { frac: 0.1670, reg_val: 0x11 },
34    BaudFraction { frac: 0.2147, reg_val: 0x21 },
35    BaudFraction { frac: 0.2224, reg_val: 0x22 },
36    BaudFraction { frac: 0.2503, reg_val: 0x44 },
37    BaudFraction { frac: 0.3000, reg_val: 0x25 },
38    BaudFraction { frac: 0.3335, reg_val: 0x49 },
39    BaudFraction { frac: 0.3575, reg_val: 0x4A },
40    BaudFraction { frac: 0.3753, reg_val: 0x52 },
41    BaudFraction { frac: 0.4003, reg_val: 0x92 },
42    BaudFraction { frac: 0.4286, reg_val: 0x53 },
43    BaudFraction { frac: 0.4378, reg_val: 0x55 },
44    BaudFraction { frac: 0.5002, reg_val: 0xAA },
45    BaudFraction { frac: 0.5715, reg_val: 0x6B },
46    BaudFraction { frac: 0.6003, reg_val: 0xAD },
47    BaudFraction { frac: 0.6254, reg_val: 0xB5 },
48    BaudFraction { frac: 0.6432, reg_val: 0xB6 },
49    BaudFraction { frac: 0.6667, reg_val: 0xD6 },
50    BaudFraction { frac: 0.7001, reg_val: 0xB7 },
51    BaudFraction { frac: 0.7147, reg_val: 0xBB },
52    BaudFraction { frac: 0.7503, reg_val: 0xDD },
53    BaudFraction { frac: 0.7861, reg_val: 0xED },
54    BaudFraction { frac: 0.8004, reg_val: 0xEE },
55    BaudFraction { frac: 0.8333, reg_val: 0xBF },
56    BaudFraction { frac: 0.8464, reg_val: 0xDF },
57    BaudFraction { frac: 0.8572, reg_val: 0xEF },
58    BaudFraction { frac: 0.8751, reg_val: 0xF7 },
59    BaudFraction { frac: 0.9004, reg_val: 0xFB },
60    BaudFraction { frac: 0.9170, reg_val: 0xFD },
61    BaudFraction { frac: 0.9288, reg_val: 0xFE },
62];
63
64pub struct Uart<'a> {
65    registers: StaticRef<UsciARegisters>,
66    clock_frequency: u32,
67
68    tx_client: OptionalCell<&'a dyn hil::uart::TransmitClient>,
69    tx_busy: Cell<bool>,
70    tx_dma: OptionalCell<&'a dma::DmaChannel<'a>>,
71    pub(crate) tx_dma_chan: usize,
72    tx_dma_src: u8,
73
74    rx_client: OptionalCell<&'a dyn hil::uart::ReceiveClient>,
75    rx_busy: Cell<bool>,
76    rx_dma: OptionalCell<&'a dma::DmaChannel<'a>>,
77    pub(crate) rx_dma_chan: usize,
78    rx_dma_src: u8,
79}
80
81impl<'a> Uart<'a> {
82    pub const fn new(
83        registers: StaticRef<UsciARegisters>,
84        tx_dma_chan: usize,
85        rx_dma_chan: usize,
86        tx_dma_src: u8,
87        rx_dma_src: u8,
88    ) -> Self {
89        Self {
90            registers,
91            clock_frequency: DEFAULT_CLOCK_FREQ_HZ,
92
93            tx_client: OptionalCell::empty(),
94            tx_dma: OptionalCell::empty(),
95            tx_dma_chan,
96            tx_dma_src,
97            tx_busy: Cell::new(false),
98
99            rx_client: OptionalCell::empty(),
100            rx_dma: OptionalCell::empty(),
101            rx_dma_chan,
102            rx_dma_src,
103            rx_busy: Cell::new(false),
104        }
105    }
106
107    pub fn set_dma(&self, tx_dma: &'a dma::DmaChannel<'a>, rx_dma: &'a dma::DmaChannel<'a>) {
108        self.tx_dma.replace(tx_dma);
109        self.rx_dma.replace(rx_dma);
110    }
111
112    pub fn transmit_sync(&self, data: &[u8]) {
113        for b in data.iter() {
114            while self.registers.statw.is_set(usci::UCAxSTATW::UCBUSY) {}
115            self.registers.txbuf.set(*b as u16);
116        }
117    }
118}
119
120impl dma::DmaClient for Uart<'_> {
121    fn transfer_done(
122        &self,
123        tx_buf: Option<&'static mut [u8]>,
124        rx_buf: Option<&'static mut [u8]>,
125        transmitted_bytes: usize,
126    ) {
127        if let Some(rxbuf) = rx_buf {
128            // RX-transfer done
129            self.rx_busy.set(false);
130            self.rx_client.map(|client| {
131                client.received_buffer(rxbuf, transmitted_bytes, Ok(()), hil::uart::Error::None)
132            });
133        } else if let Some(txbuf) = tx_buf {
134            // TX-transfer done
135            self.tx_busy.set(false);
136            self.tx_client
137                .map(|client| client.transmitted_buffer(txbuf, transmitted_bytes, Ok(())));
138        }
139    }
140}
141
142impl hil::uart::Configure for Uart<'_> {
143    fn configure(&self, params: hil::uart::Parameters) -> Result<(), ErrorCode> {
144        // Disable module
145        let regs = self.registers;
146        regs.ctlw0.modify(usci::UCAxCTLW0::UCSWRST::SET);
147
148        // Setup module to UART mode
149        regs.ctlw0.modify(usci::UCAxCTLW0::UCMODE::UARTMode);
150
151        // Setup clock-source to SMCLK
152        regs.ctlw0.modify(usci::UCAxCTLW0::UCSSEL::SMCLK);
153
154        // Setup word-length
155        match params.width {
156            hil::uart::Width::Eight => regs.ctlw0.modify(usci::UCAxCTLW0::UC7BIT::CLEAR),
157            hil::uart::Width::Seven => regs.ctlw0.modify(usci::UCAxCTLW0::UC7BIT::SET),
158            hil::uart::Width::Six => {
159                panic!("UART: width of 6 bit is not supported by this hardware!")
160            }
161        }
162
163        // Setup stop bits
164        if params.stop_bits == hil::uart::StopBits::One {
165            regs.ctlw0.modify(usci::UCAxCTLW0::UCSPB::CLEAR);
166        } else {
167            regs.ctlw0.modify(usci::UCAxCTLW0::UCSPB::SET);
168        }
169
170        // Setup parity
171        if params.parity == hil::uart::Parity::None {
172            regs.ctlw0.modify(usci::UCAxCTLW0::UCPEN::CLEAR);
173        } else {
174            regs.ctlw0.modify(usci::UCAxCTLW0::UCPEN::SET);
175            if params.parity == hil::uart::Parity::Even {
176                regs.ctlw0.modify(usci::UCAxCTLW0::UCPAR::SET);
177            } else {
178                regs.ctlw0.modify(usci::UCAxCTLW0::UCPAR::CLEAR);
179            }
180        }
181
182        // Setup baudrate, all the calculation from the datasheet p. 915
183        let n = (self.clock_frequency / params.baud_rate) as u16;
184        let n_float = (self.clock_frequency as f32) / (params.baud_rate as f32);
185        let frac_part = n_float - (n as f32);
186        if n > 16 {
187            // Oversampling is enabled
188            regs.brw.set(n >> 4); // equals n / 16
189            let ucbrf = (((n_float / 16.0f32) - ((n >> 4) as f32)) * 16.0f32) as u16;
190            regs.mctlw
191                .modify(usci::UCAxMCTLW::UCBRF.val(ucbrf) + usci::UCAxMCTLW::UCOS16::SET);
192        } else {
193            // No oversampling
194            regs.brw.set(n);
195            regs.mctlw.modify(usci::UCAxMCTLW::UCOS16::CLEAR);
196        }
197
198        // Look for the closest calibration value
199        // According to the datasheet not the closest value should be taken but the next smaller one
200        let mut ucbrs = BAUD_FRACTIONS[0].reg_val;
201        for val in BAUD_FRACTIONS.iter() {
202            if val.frac > frac_part {
203                break;
204            }
205            ucbrs = val.reg_val;
206        }
207        regs.mctlw.modify(usci::UCAxMCTLW::UCBRS.val(ucbrs as u16));
208
209        // Enable module
210        regs.ctlw0.modify(usci::UCAxCTLW0::UCSWRST::CLEAR);
211
212        // Configure the DMA
213        let tx_conf = dma::DmaConfig {
214            src_chan: self.tx_dma_src,
215            mode: dma::DmaMode::Basic,
216            width: dma::DmaDataWidth::Width8Bit,
217            src_incr: dma::DmaPtrIncrement::Incr8Bit,
218            dst_incr: dma::DmaPtrIncrement::NoIncr,
219        };
220
221        let rx_conf = dma::DmaConfig {
222            src_chan: self.rx_dma_src,
223            mode: dma::DmaMode::Basic,
224            width: dma::DmaDataWidth::Width8Bit,
225            src_incr: dma::DmaPtrIncrement::NoIncr,
226            dst_incr: dma::DmaPtrIncrement::Incr8Bit,
227        };
228
229        self.tx_dma.map(|dma| dma.initialize(&tx_conf));
230        self.rx_dma.map(|dma| dma.initialize(&rx_conf));
231
232        Ok(())
233    }
234}
235
236impl<'a> hil::uart::Transmit<'a> for Uart<'a> {
237    fn set_transmit_client(&self, client: &'a dyn hil::uart::TransmitClient) {
238        self.tx_client.set(client);
239    }
240
241    fn transmit_buffer(
242        &self,
243        tx_buffer: &'static mut [u8],
244        tx_len: usize,
245    ) -> Result<(), (ErrorCode, &'static mut [u8])> {
246        if (tx_len == 0) || (tx_len > tx_buffer.len()) {
247            return Err((ErrorCode::SIZE, tx_buffer));
248        }
249        if self.tx_busy.get() {
250            Err((ErrorCode::BUSY, tx_buffer))
251        } else {
252            self.tx_busy.set(true);
253            let tx_reg = core::ptr::addr_of!(self.registers.txbuf).cast::<()>();
254            self.tx_dma
255                .map(move |dma| dma.transfer_mem_to_periph(tx_reg, tx_buffer, tx_len));
256            Ok(())
257        }
258    }
259
260    fn transmit_word(&self, _word: u32) -> Result<(), ErrorCode> {
261        Err(ErrorCode::FAIL)
262    }
263
264    fn transmit_abort(&self) -> Result<(), ErrorCode> {
265        if !self.tx_busy.get() {
266            return Ok(());
267        }
268
269        self.tx_dma.map(|dma| {
270            let (nr_bytes, tx1, _rx1, _tx2, _rx2) = dma.stop();
271
272            self.tx_client.map(move |cl| {
273                if let Some(tx1_buf) = tx1 {
274                    cl.transmitted_buffer(tx1_buf, nr_bytes, Err(ErrorCode::CANCEL));
275                }
276            });
277        });
278
279        Err(ErrorCode::BUSY)
280    }
281}
282
283impl<'a> hil::uart::Receive<'a> for Uart<'a> {
284    fn set_receive_client(&self, client: &'a dyn hil::uart::ReceiveClient) {
285        self.rx_client.set(client);
286    }
287
288    fn receive_buffer(
289        &self,
290        rx_buffer: &'static mut [u8],
291        rx_len: usize,
292    ) -> Result<(), (ErrorCode, &'static mut [u8])> {
293        if (rx_len == 0) || (rx_len > rx_buffer.len()) {
294            return Err((ErrorCode::SIZE, rx_buffer));
295        }
296
297        if self.rx_busy.get() {
298            Err((ErrorCode::BUSY, rx_buffer))
299        } else {
300            self.rx_busy.set(true);
301            let rx_reg = core::ptr::addr_of!(self.registers.rxbuf).cast::<()>();
302            self.rx_dma
303                .map(move |dma| dma.transfer_periph_to_mem(rx_reg, rx_buffer, rx_len));
304            Ok(())
305        }
306    }
307
308    fn receive_word(&self) -> Result<(), ErrorCode> {
309        Err(ErrorCode::FAIL)
310    }
311
312    fn receive_abort(&self) -> Result<(), ErrorCode> {
313        if !self.rx_busy.get() {
314            return Ok(());
315        }
316
317        self.rx_dma.map(|dma| {
318            let (nr_bytes, _tx1, rx1, _tx2, _rx2) = dma.stop();
319
320            self.rx_client.map(move |cl| {
321                if let Some(rx1_buf) = rx1 {
322                    cl.received_buffer(
323                        rx1_buf,
324                        nr_bytes,
325                        Err(ErrorCode::CANCEL),
326                        hil::uart::Error::Aborted,
327                    );
328                }
329            });
330        });
331
332        Err(ErrorCode::BUSY)
333    }
334}