imxrt10xx/
lpuart.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 core::cell::Cell;
6use kernel::utilities::cells::{OptionalCell, TakeCell};
7use kernel::utilities::registers::interfaces::{ReadWriteable, Readable, Writeable};
8use kernel::utilities::registers::{register_bitfields, ReadOnly, ReadWrite};
9
10use kernel::hil;
11use kernel::platform::chip::ClockInterface;
12use kernel::utilities::StaticRef;
13use kernel::ErrorCode;
14
15use crate::{ccm, dma};
16
17/// LP Universal asynchronous receiver transmitter
18#[repr(C)]
19struct LpuartRegisters {
20    ///  Version ID Register
21    verid: ReadOnly<u32, VERID::Register>,
22    /// Parameter Register
23    param: ReadOnly<u32, PARAM::Register>,
24    /// LPUART Global Register
25    global: ReadWrite<u32, GLOBAL::Register>,
26    /// LPUART Pin Configuration Register
27    pincfg: ReadWrite<u32, PINCFG::Register>,
28    /// LPUART Baud Rate Register
29    baud: ReadWrite<u32, BAUD::Register>,
30    /// LPUART Status Register
31    stat: ReadWrite<u32, STAT::Register>,
32    /// LPUART Control Register
33    ctrl: ReadWrite<u32, CTRL::Register>,
34    /// LPUART Data Register
35    data: ReadWrite<u32, DATA::Register>,
36    /// LPUART Match Address Register
37    r#match: ReadWrite<u32, MATCH::Register>,
38    /// LPUART Modem IrDA Register
39    modir: ReadWrite<u32, MODIR::Register>,
40    /// LPUART FIFO Register
41    fifo: ReadWrite<u32, FIFO::Register>,
42    /// LPUART Watemark Register
43    water: ReadWrite<u32, WATER::Register>,
44}
45
46register_bitfields![u32,
47    VERID [
48        /// Major Version Number
49        MAJOR OFFSET(24) NUMBITS(8) [],
50        /// Minor Version Number
51        MINOR OFFSET(16) NUMBITS(8) [],
52        /// Feature Identification Number
53        FEATURE OFFSET(0) NUMBITS(16) []
54    ],
55
56    PARAM [
57        /// Receive FIFO Size
58        RXFIFO OFFSET(8) NUMBITS(8) [],
59        /// Transmit FIFO Size
60        TXFIFO OFFSET(0) NUMBITS(8) []
61    ],
62
63    GLOBAL [
64        /// Software reset
65        RST OFFSET(1) NUMBITS(1) []
66    ],
67
68    PINCFG [
69        /// Trigger Select for input trigger usage
70        TRGSEL OFFSET(0) NUMBITS(2) []
71    ],
72
73    BAUD [
74        /// Match Address Mode Enable 1
75        MAEN1 OFFSET(31) NUMBITS(1) [],
76        /// Match Address Mode Enable 2
77        MAEN2 OFFSET(30) NUMBITS(1) [],
78        /// 10-bit Mode select
79        M10 OFFSET(29) NUMBITS(1) [],
80        /// Oversampling Ratio
81        OSR OFFSET(24) NUMBITS(5) [],
82        /// Transmitter DMA Enable
83        TDMAE OFFSET(23) NUMBITS(1) [],
84        /// Receiver Full DMA Enable
85        RDMAE OFFSET(21) NUMBITS(1) [],
86        /// Receiver Idle DMA Enable
87        RIDMAE OFFSET(20) NUMBITS(1) [],
88        /// Match Configuration
89        MATCFG OFFSET(18) NUMBITS(2) [],
90        /// Both Edge Sampling
91        BOTHEDGE OFFSET(17) NUMBITS(1) [],
92        /// Resynchronization Disable
93        RESYNCDIS OFFSET(16) NUMBITS(1) [],
94        /// LIN Break Detect Interrupt Enable
95        LBKDIE OFFSET(15) NUMBITS(1) [],
96        /// RX Input Active Edge Interrupt Enable
97        RXEDGIE OFFSET(14) NUMBITS(1) [],
98        /// Stop Bit Number Select
99        SBNS OFFSET(13) NUMBITS(1) [],
100        /// Baud Rate Modulo Divisor
101        SBR OFFSET(0) NUMBITS(13) []
102    ],
103
104    STAT [
105        /// LIN Break Detect Interrupt Flag
106        LBKDIF OFFSET(31) NUMBITS(1) [],
107        /// RXD Pin Active Edge Interrupt Flag
108        RXEDGIF OFFSET(30) NUMBITS(1) [],
109        /// MSB First
110        MSBF OFFSET(29) NUMBITS(1) [],
111        /// Receive Data Inversion
112        RXINV OFFSET(28) NUMBITS(1) [],
113        /// Receive Wake Up Idle Detect
114        RWUID OFFSET(27) NUMBITS(1) [],
115        /// Break Character Generation Length
116        BRK13 OFFSET(26) NUMBITS(1) [],
117        /// LIN Break Detection Enable
118        LBKDE OFFSET(25) NUMBITS(1) [],
119        /// Receiver Active Flag
120        RAF OFFSET(24) NUMBITS(1) [],
121        /// Transmit Data Register Empty Flag
122        TDRE OFFSET(23) NUMBITS(1) [],
123        /// Transmission Complete Flag
124        TC OFFSET(22) NUMBITS(1) [],
125        /// Receive Data Register Full Flag
126        RDRF OFFSET(21) NUMBITS(1) [],
127        /// Idle Line Flag
128        IDLE OFFSET(20) NUMBITS(1) [],
129        /// Receiver Overrun Flag
130        OR OFFSET(19) NUMBITS(1) [],
131        /// Noise Flag
132        NF OFFSET(18) NUMBITS(1) [],
133        /// Framing Error Flag
134        FE OFFSET(17) NUMBITS(1) [],
135        /// Parity Error Flag
136        PF OFFSET(16) NUMBITS(1) [],
137        /// Match 1 Flag
138        MA1F OFFSET(15) NUMBITS(1) [],
139        /// Match 2 Flag
140        MA2F OFFSET(14) NUMBITS(1) []
141    ],
142
143    CTRL [
144        /// Receive Bit 8 / Transmit Bit 9
145        R8T9 OFFSET(31) NUMBITS(1) [],
146        /// Receive Bit 9 / Transmit Bit 8
147        R9T8 OFFSET(30) NUMBITS(1) [],
148        /// TXD Pin Direction in Single-Wire Mode
149        TXDIR OFFSET(29) NUMBITS(1) [],
150        /// Transmit Data Inversion
151        TXINV OFFSET(28) NUMBITS(1) [],
152        /// Overrun Interrupt Enable
153        ORIE OFFSET(27) NUMBITS(1) [],
154        /// Noise Error Interrupt Enable
155        NEIE OFFSET(26) NUMBITS(1) [],
156        /// Framing Error Interrupt Enable
157        FEIE OFFSET(25) NUMBITS(1) [],
158        /// Parity Error Interrupt Enable
159        PEIE OFFSET(24) NUMBITS(1) [],
160        /// Transmit Interrupt Enable
161        TIE OFFSET(23) NUMBITS(1) [],
162        /// Transmission Complete Interrupt Enable for
163        TCIE OFFSET(22) NUMBITS(1) [],
164        /// Receiver Interrupt Enable
165        RIE OFFSET(21) NUMBITS(1) [],
166        /// Idle Line Interrupt Enable
167        ILIE OFFSET(20) NUMBITS(1) [],
168        /// Transmitter Enable
169        TE OFFSET(19) NUMBITS(1) [],
170        /// Receiver Enable
171        RE OFFSET(18) NUMBITS(1) [],
172        /// Receiver Wakeup Control
173        RWU OFFSET(17) NUMBITS(1) [],
174        /// Send Break
175        SBK OFFSET(16) NUMBITS(1) [],
176        /// Match 1 Interrupt Enable
177        MA1IE OFFSET(15) NUMBITS(1) [],
178        /// Match 2 Interrupt Enable
179        MA2IE OFFSET(14) NUMBITS(1) [],
180        /// 7-Bit Mode Select
181        M7 OFFSET(11) NUMBITS(1) [],
182        /// Idle Configuration
183        IDLECFG OFFSET(8) NUMBITS(3) [],
184        /// Loop Mode Select
185        LOOPS OFFSET(7) NUMBITS(1) [],
186        /// Doze Enable
187        DOZEEN OFFSET(6) NUMBITS(1) [],
188        /// Receiver Source Select
189        RSRC OFFSET(5) NUMBITS(1) [],
190        /// 9-Bit or 8-Bit Mode Select
191        M OFFSET(4) NUMBITS(1) [],
192        /// Receiver Wakeup Method Select
193        WAKE OFFSET(3) NUMBITS(1) [],
194        /// Idle Line Type Select
195        ILT OFFSET(2) NUMBITS(1) [],
196        /// Parity Enable
197        PE OFFSET(1) NUMBITS(1) [],
198        /// Parity Type
199        PT OFFSET(0) NUMBITS(1) []
200    ],
201
202    DATA [
203        /// NOISY
204        NOISY OFFSET(15) NUMBITS(8) [],
205        /// PARITYE
206        PARITYE OFFSET(14) NUMBITS(8) [],
207        /// Frame Error / Transmit Special Character
208        FRETSC OFFSET(13) NUMBITS(8) [],
209        /// Receive Buffer Empty
210        RXEMPT OFFSET(12) NUMBITS(8) [],
211        /// Idle Line
212        IDLINE OFFSET(11) NUMBITS(8) [],
213        /// R9T9
214        R9T9 OFFSET(9) NUMBITS(8) [],
215        /// R8T8
216        R8T8 OFFSET(8) NUMBITS(8) [],
217        /// R7T7
218        R7T7 OFFSET(7) NUMBITS(8) [],
219        /// R6T6
220        R6T6 OFFSET(6) NUMBITS(8) [],
221        /// R5T5
222        R5T5 OFFSET(5) NUMBITS(8) [],
223        /// R4T4
224        R4T4 OFFSET(4) NUMBITS(8) [],
225        /// R3T3
226        R3T3 OFFSET(3) NUMBITS(8) [],
227        /// R2T2
228        R2T2 OFFSET(2) NUMBITS(8) [],
229        /// R1T1
230        R1T1 OFFSET(1) NUMBITS(8) [],
231        /// R0T0
232        R0T0 OFFSET(0) NUMBITS(8) []
233    ],
234
235    MATCH [
236        /// Match Address 2
237        MA2 OFFSET(16) NUMBITS(10) [],
238        /// Match Address 1
239        MA1 OFFSET(0) NUMBITS(10) []
240    ],
241
242    MODIR [
243        /// Infrared enable
244        IREN OFFSET(18) NUMBITS(1) [],
245        /// Transmitter narrow pulse
246        TNP OFFSET(16) NUMBITS(2) [],
247        /// Receive RTS Configuration
248        RTSWATER OFFSET(8) NUMBITS(2) [],
249        /// Transmit CTS Source
250        TXCTSSRC OFFSET(5) NUMBITS(1) [],
251        /// Transmit CTS Configuration
252        TXCTSC OFFSET(4) NUMBITS(1) [],
253        /// Receiver request-to-send enable
254        RXRTSE OFFSET(3) NUMBITS(1) [],
255        /// Transmitter request-to-send polarity
256        TXRTSPOL OFFSET(2) NUMBITS(1) [],
257        /// Transmitter request-to-send enable
258        TXRTSE OFFSET(1) NUMBITS(1) [],
259        /// Transmitter clear-to-send enable
260        TXCTSE OFFSET(0) NUMBITS(1) []
261    ],
262
263    FIFO [
264        /// Transmit Buffer/FIFO Empty
265        TXEMPT OFFSET(23) NUMBITS(1) [],
266        /// Receive Buffer/FIFO Empty
267        RXEMPT OFFSET(22) NUMBITS(1) [],
268        /// Transmitter Buffer Overflow Flag
269        TXOF OFFSET(17) NUMBITS(1) [],
270        /// Receiver Buffer Underflow Flag
271        RXUF OFFSET(16) NUMBITS(1) [],
272        /// Transmit FIFO/Buffer Flush
273        TXFLUSH OFFSET(15) NUMBITS(1) [],
274        /// Receive FIFO/Buffer Flush
275        RXFLUSH OFFSET(14) NUMBITS(1) [],
276        /// Receiver Idle Empty Enable
277        RXIDEN OFFSET(10) NUMBITS(2) [],
278        /// Transmit FIFO Overflow Interrupt Enable
279        TXOFE OFFSET(9) NUMBITS(1) [],
280        /// Receive FIFO Underflow Interrupt Enable
281        RXUFE OFFSET(8) NUMBITS(1) [],
282        /// Transmit FIFO Enable
283        TXFE OFFSET(7) NUMBITS(1) [],
284        /// Transmit FIFO Buffer Depth
285        TXFIFOSIZE OFFSET(4) NUMBITS(3) [],
286        /// Receive FIFO Enable
287        RXFE OFFSET(3) NUMBITS(1) [],
288        /// Receive FIFO Buffer Depth
289        RXFIFOSIZE OFFSET(0) NUMBITS(3) []
290    ],
291
292    WATER [
293        /// Receive Counter
294        RXCOUNT OFFSET(24) NUMBITS(3) [],
295        /// Receive Watermark
296        RXWATER OFFSET(16) NUMBITS(2) [],
297        /// Transmit Counter
298        TXCOUNT OFFSET(8) NUMBITS(3) [],
299        /// Transmit Watermark
300        TXWATER OFFSET(0) NUMBITS(2) []
301    ]
302];
303
304const LPUART1_BASE: StaticRef<LpuartRegisters> =
305    unsafe { StaticRef::new(0x40184000 as *const LpuartRegisters) };
306const LPUART2_BASE: StaticRef<LpuartRegisters> =
307    unsafe { StaticRef::new(0x4018_8000 as *const LpuartRegisters) };
308
309#[derive(Copy, Clone, PartialEq)]
310enum LPUARTStateTX {
311    Idle,
312    Transmitting,
313    AbortRequested,
314}
315
316#[derive(Copy, Clone, PartialEq)]
317enum USARTStateRX {
318    Idle,
319    Receiving,
320    AbortRequested,
321}
322
323pub struct Lpuart<'a> {
324    registers: StaticRef<LpuartRegisters>,
325    clock: LpuartClock<'a>,
326
327    tx_client: OptionalCell<&'a dyn hil::uart::TransmitClient>,
328    rx_client: OptionalCell<&'a dyn hil::uart::ReceiveClient>,
329
330    tx_buffer: TakeCell<'static, [u8]>,
331    tx_position: Cell<usize>,
332    tx_len: Cell<usize>,
333    tx_status: Cell<LPUARTStateTX>,
334    tx_dma_channel: OptionalCell<&'a dma::DmaChannel>,
335    tx_dma_source: dma::DmaHardwareSource,
336
337    rx_buffer: TakeCell<'static, [u8]>,
338    rx_position: Cell<usize>,
339    rx_len: Cell<usize>,
340    rx_status: Cell<USARTStateRX>,
341    rx_dma_channel: OptionalCell<&'a dma::DmaChannel>,
342    rx_dma_source: dma::DmaHardwareSource,
343}
344
345impl<'a> Lpuart<'a> {
346    pub fn new_lpuart1(ccm: &'a ccm::Ccm) -> Self {
347        Lpuart::new(
348            LPUART1_BASE,
349            LpuartClock(ccm::PeripheralClock::ccgr5(ccm, ccm::HCLK5::LPUART1)),
350            dma::DmaHardwareSource::Lpuart1Transfer,
351            dma::DmaHardwareSource::Lpuart1Receive,
352        )
353    }
354
355    pub fn new_lpuart2(ccm: &'a ccm::Ccm) -> Self {
356        Lpuart::new(
357            LPUART2_BASE,
358            LpuartClock(ccm::PeripheralClock::ccgr0(ccm, ccm::HCLK0::LPUART2)),
359            dma::DmaHardwareSource::Lpuart2Transfer,
360            dma::DmaHardwareSource::Lpuart2Receive,
361        )
362    }
363
364    fn new(
365        base_addr: StaticRef<LpuartRegisters>,
366        clock: LpuartClock<'a>,
367        tx_dma_source: dma::DmaHardwareSource,
368        rx_dma_source: dma::DmaHardwareSource,
369    ) -> Lpuart<'a> {
370        Lpuart {
371            registers: base_addr,
372            clock,
373
374            tx_client: OptionalCell::empty(),
375            rx_client: OptionalCell::empty(),
376
377            tx_buffer: TakeCell::empty(),
378            tx_position: Cell::new(0),
379            tx_len: Cell::new(0),
380            tx_status: Cell::new(LPUARTStateTX::Idle),
381            tx_dma_channel: OptionalCell::empty(),
382            tx_dma_source,
383
384            rx_buffer: TakeCell::empty(),
385            rx_position: Cell::new(0),
386            rx_len: Cell::new(0),
387            rx_status: Cell::new(USARTStateRX::Idle),
388            rx_dma_channel: OptionalCell::empty(),
389            rx_dma_source,
390        }
391    }
392
393    /// Set the DMA channel for transferring data from this UART peripheral
394    pub fn set_tx_dma_channel(&'static self, dma_channel: &'static dma::DmaChannel) {
395        dma_channel.set_client(self, self.tx_dma_source);
396        unsafe {
397            // Safety: pointing to static memory
398            dma_channel.set_destination(core::ptr::addr_of!(self.registers.data) as *const u8);
399        }
400        dma_channel.set_interrupt_on_completion(true);
401        dma_channel.set_disable_on_completion(true);
402        self.tx_dma_channel.set(dma_channel);
403    }
404
405    /// Set the DMA channel used for receiving data from this UART peripheral
406    pub fn set_rx_dma_channel(&'static self, dma_channel: &'static dma::DmaChannel) {
407        dma_channel.set_client(self, self.rx_dma_source);
408        unsafe {
409            // Safety: pointing to static memory
410            dma_channel.set_source(core::ptr::addr_of!(self.registers.data) as *const u8);
411        }
412        dma_channel.set_interrupt_on_completion(true);
413        dma_channel.set_disable_on_completion(true);
414        self.rx_dma_channel.set(dma_channel);
415    }
416
417    pub fn is_enabled_clock(&self) -> bool {
418        self.clock.is_enabled()
419    }
420
421    pub fn enable_clock(&self) {
422        self.clock.enable();
423    }
424
425    pub fn disable_clock(&self) {
426        self.clock.disable();
427    }
428
429    pub fn set_baud(&self) {
430        // Set the Baud Rate Modulo Divisor
431        self.registers.baud.modify(BAUD::SBR.val(139_u32));
432    }
433
434    // for use by panic in io.rs
435    pub fn send_byte(&self, byte: u8) {
436        // loop until TDRE (Transmit data register empty) becomes 1
437        while !self.registers.stat.is_set(STAT::TDRE) {}
438
439        self.registers.data.set(byte.into());
440
441        while !self.registers.stat.is_set(STAT::TC) {}
442    }
443
444    /// Returns true if the transmit is enabled
445    pub fn is_transmit_enabled(&self) -> bool {
446        self.registers.ctrl.is_set(CTRL::TE)
447    }
448
449    /// Returns `true` if receive is enabled
450    pub fn is_receive_enabled(&self) -> bool {
451        self.registers.ctrl.is_set(CTRL::RE)
452    }
453
454    fn enable_transmit_complete_interrupt(&self) {
455        self.registers.ctrl.modify(CTRL::TIE::SET);
456    }
457
458    fn disable_transmit_complete_interrupt(&self) {
459        self.registers.ctrl.modify(CTRL::TIE::CLEAR);
460    }
461
462    fn clear_transmit_complete(&self) {
463        self.registers.stat.modify(STAT::TDRE::CLEAR);
464    }
465
466    fn enable_receive_interrupt(&self) {
467        self.registers.ctrl.modify(CTRL::RIE::SET);
468    }
469
470    fn disable_receive_interrupt(&self) {
471        self.registers.ctrl.modify(CTRL::RIE::CLEAR);
472    }
473
474    fn clear_overrun(&self) {
475        self.registers.ctrl.modify(CTRL::ORIE::CLEAR);
476    }
477
478    pub fn handle_interrupt(&self) {
479        if self.registers.stat.is_set(STAT::TDRE) {
480            self.clear_transmit_complete();
481            self.disable_transmit_complete_interrupt();
482
483            // ignore IRQ if not transmitting
484            if self.tx_status.get() == LPUARTStateTX::Transmitting {
485                let position = self.tx_position.get();
486                if position < self.tx_len.get() {
487                    self.tx_buffer.map(|buf| {
488                        self.registers.data.set(buf[position].into());
489                        self.tx_position.replace(self.tx_position.get() + 1);
490                        self.enable_transmit_complete_interrupt();
491                    });
492                } else {
493                    // transmission done
494                    self.tx_status.replace(LPUARTStateTX::Idle);
495                }
496                // notify client if transfer is done
497                if self.tx_status.get() == LPUARTStateTX::Idle {
498                    self.tx_client.map(|client| {
499                        if let Some(buf) = self.tx_buffer.take() {
500                            client.transmitted_buffer(buf, self.tx_len.get(), Ok(()));
501                        }
502                    });
503                }
504            } else if self.tx_status.get() == LPUARTStateTX::AbortRequested {
505                self.tx_status.replace(LPUARTStateTX::Idle);
506                self.tx_client.map(|client| {
507                    if let Some(buf) = self.tx_buffer.take() {
508                        client.transmitted_buffer(
509                            buf,
510                            self.tx_position.get(),
511                            Err(ErrorCode::CANCEL),
512                        );
513                    }
514                });
515            }
516        }
517
518        if self.registers.stat.is_set(STAT::RDRF) {
519            let byte = self.registers.data.get() as u8;
520
521            self.disable_receive_interrupt();
522
523            // ignore IRQ if not receiving
524            if self.rx_status.get() == USARTStateRX::Receiving {
525                if self.rx_position.get() < self.rx_len.get() {
526                    self.rx_buffer.map(|buf| {
527                        buf[self.rx_position.get()] = byte;
528                        self.rx_position.replace(self.rx_position.get() + 1);
529                    });
530                }
531                if self.rx_position.get() == self.rx_len.get() {
532                    // reception done
533                    self.rx_status.replace(USARTStateRX::Idle);
534                } else {
535                    self.enable_receive_interrupt();
536                }
537                // notify client if transfer is done
538                if self.rx_status.get() == USARTStateRX::Idle {
539                    self.rx_client.map(|client| {
540                        if let Some(buf) = self.rx_buffer.take() {
541                            client.received_buffer(
542                                buf,
543                                self.rx_len.get(),
544                                Ok(()),
545                                hil::uart::Error::None,
546                            );
547                        }
548                    });
549                }
550            } else if self.rx_status.get() == USARTStateRX::AbortRequested {
551                self.rx_status.replace(USARTStateRX::Idle);
552                self.rx_client.map(|client| {
553                    if let Some(buf) = self.rx_buffer.take() {
554                        client.received_buffer(
555                            buf,
556                            self.rx_position.get(),
557                            Err(ErrorCode::CANCEL),
558                            hil::uart::Error::Aborted,
559                        );
560                    }
561                });
562            }
563        }
564
565        if self.registers.stat.is_set(STAT::OR) {
566            self.clear_overrun();
567            self.rx_status.replace(USARTStateRX::Idle);
568            self.rx_client.map(|client| {
569                if let Some(buf) = self.rx_buffer.take() {
570                    client.received_buffer(
571                        buf,
572                        self.rx_position.get(),
573                        Err(ErrorCode::CANCEL),
574                        hil::uart::Error::OverrunError,
575                    );
576                }
577            });
578        }
579    }
580
581    fn check_status(&self) -> kernel::hil::uart::Error {
582        use kernel::hil::uart::Error;
583        let stat = self.registers.stat.extract();
584        if stat.is_set(STAT::PF) {
585            Error::ParityError
586        } else if stat.is_set(STAT::FE) {
587            Error::FramingError
588        } else if stat.is_set(STAT::OR) {
589            Error::OverrunError
590        } else {
591            Error::None
592        }
593    }
594
595    /// Clear all status flags
596    fn clear_status(&self) {
597        self.registers.stat.modify(
598            STAT::IDLE::SET
599                + STAT::OR::SET
600                + STAT::NF::SET
601                + STAT::FE::SET
602                + STAT::PF::SET
603                + STAT::RXEDGIF::SET
604                + STAT::MA1F::SET
605                + STAT::MA2F::SET,
606        )
607    }
608
609    /// Execute an interrupt-driven transfer.
610    fn transmit_buffer_interrupt(
611        &self,
612        tx_data: &'static mut [u8],
613        tx_len: usize,
614    ) -> Result<(), (ErrorCode, &'static mut [u8])> {
615        if self.tx_status.get() == LPUARTStateTX::Idle {
616            if tx_len <= tx_data.len() {
617                self.tx_buffer.put(Some(tx_data));
618                self.tx_position.set(0);
619                self.tx_len.set(tx_len);
620                self.tx_status.set(LPUARTStateTX::Transmitting);
621                self.enable_transmit_complete_interrupt();
622                Ok(())
623            } else {
624                Err((ErrorCode::SIZE, tx_data))
625            }
626        } else {
627            Err((ErrorCode::BUSY, tx_data))
628        }
629    }
630
631    /// Execute a transfer using a DMA channel.
632    ///
633    /// When this call returns, the transfer buffer is associated
634    /// with the internal DMA channel, and the DMA peripheral will schedule
635    /// the transfer to the serial output.
636    fn transmit_buffer_dma(
637        &self,
638        tx_buffer: &'static mut [u8],
639        tx_len: usize,
640    ) -> Result<(), (ErrorCode, &'static mut [u8])> {
641        if self.tx_buffer.is_some() {
642            return Err((ErrorCode::BUSY, tx_buffer));
643        } else if !self.is_transmit_enabled() {
644            return Err((ErrorCode::OFF, tx_buffer));
645        } else if tx_len > tx_buffer.len() {
646            return Err((ErrorCode::SIZE, tx_buffer));
647        } else if self.tx_dma_channel.is_none() {
648            return Err((ErrorCode::FAIL, tx_buffer));
649        }
650
651        self.tx_dma_channel
652            .map(move |dma_channel| unsafe {
653                dma_channel.set_source_buffer(&tx_buffer[..tx_len]);
654
655                self.tx_buffer.put(Some(tx_buffer));
656                self.tx_len.set(tx_len);
657                dma_channel.enable();
658                self.registers.baud.modify(BAUD::TDMAE::SET);
659                Ok(())
660            })
661            .unwrap() // OK: checked is_some above
662    }
663
664    /// Abort an interrupt-driven transfer.
665    fn transmit_abort_interrupt(&self) -> Result<(), ErrorCode> {
666        if self.tx_status.get() != LPUARTStateTX::Idle {
667            self.tx_status.set(LPUARTStateTX::AbortRequested);
668            Err(ErrorCode::BUSY)
669        } else {
670            Ok(())
671        }
672    }
673
674    /// Abort a DMA transfer.
675    fn transmit_abort_dma(&self) -> Result<(), ErrorCode> {
676        self.registers.baud.modify(BAUD::TDMAE::CLEAR);
677        while self.registers.baud.is_set(BAUD::TDMAE) {
678            cortexm7::support::nop();
679        }
680        self.tx_dma_channel.map(|dma_channel| {
681            while dma_channel.is_hardware_signaling() {
682                cortexm7::support::nop();
683            }
684            dma_channel.disable();
685        });
686        Ok(())
687    }
688
689    /// Schedule an interrupt-driver UART receive.
690    fn receive_buffer_interrupt(
691        &self,
692        rx_buffer: &'static mut [u8],
693        rx_len: usize,
694    ) -> Result<(), (ErrorCode, &'static mut [u8])> {
695        if self.rx_status.get() == USARTStateRX::Idle {
696            if rx_len <= rx_buffer.len() {
697                self.rx_buffer.put(Some(rx_buffer));
698                self.rx_position.set(0);
699                self.rx_len.set(rx_len);
700                self.rx_status.set(USARTStateRX::Receiving);
701                self.enable_receive_interrupt();
702                Ok(())
703            } else {
704                Err((ErrorCode::SIZE, rx_buffer))
705            }
706        } else {
707            Err((ErrorCode::BUSY, rx_buffer))
708        }
709    }
710
711    /// Execute a receive using a DMA channel.
712    ///
713    /// When this call returns, the receive buffer is associated with
714    /// the internal DMA channel, and the DMA peripheral will move bytes
715    /// from the peripheral into memory until the buffer is filled.
716    fn receive_buffer_dma(
717        &self,
718        rx_buffer: &'static mut [u8],
719        rx_size: usize,
720    ) -> Result<(), (ErrorCode, &'static mut [u8])> {
721        if self.rx_buffer.is_some() {
722            return Err((ErrorCode::BUSY, rx_buffer));
723        } else if !self.is_receive_enabled() {
724            return Err((ErrorCode::OFF, rx_buffer));
725        } else if rx_size > rx_buffer.len() {
726            return Err((ErrorCode::SIZE, rx_buffer));
727        } else if self.rx_dma_channel.is_none() {
728            return Err((ErrorCode::FAIL, rx_buffer));
729        }
730
731        self.rx_dma_channel
732            .map(move |dma_channel| unsafe {
733                dma_channel.set_destination_buffer(&mut rx_buffer[..rx_size]);
734
735                self.clear_status();
736                self.rx_buffer.put(Some(rx_buffer));
737                self.rx_len.set(rx_size);
738
739                dma_channel.enable();
740                self.registers.baud.modify(BAUD::RDMAE::SET);
741                Ok(())
742            })
743            .unwrap() // Safe: checked is_none above
744    }
745
746    /// Abort an interrupt-driven receive.
747    fn receive_abort_interrupt(&self) -> Result<(), ErrorCode> {
748        if self.rx_status.get() != USARTStateRX::Idle {
749            self.rx_status.set(USARTStateRX::AbortRequested);
750            Err(ErrorCode::BUSY)
751        } else {
752            Ok(())
753        }
754    }
755
756    /// Abort a DMA receive.
757    fn receive_abort_dma(&self) -> Result<(), ErrorCode> {
758        self.registers.baud.modify(BAUD::RDMAE::CLEAR);
759        while self.registers.baud.is_set(BAUD::RDMAE) {
760            cortexm7::support::nop();
761        }
762
763        self.rx_dma_channel.map(|dma_channel| {
764            while dma_channel.is_hardware_signaling() {
765                cortexm7::support::nop();
766            }
767            dma_channel.disable()
768        });
769        Ok(())
770    }
771}
772
773impl<'a> hil::uart::Transmit<'a> for Lpuart<'a> {
774    fn set_transmit_client(&self, client: &'a dyn hil::uart::TransmitClient) {
775        self.tx_client.set(client);
776    }
777
778    fn transmit_buffer(
779        &self,
780        tx_data: &'static mut [u8],
781        tx_len: usize,
782    ) -> Result<(), (ErrorCode, &'static mut [u8])> {
783        if self.tx_dma_channel.is_some() {
784            self.transmit_buffer_dma(tx_data, tx_len)
785        } else {
786            self.transmit_buffer_interrupt(tx_data, tx_len)
787        }
788    }
789
790    fn transmit_word(&self, _word: u32) -> Result<(), ErrorCode> {
791        // TODO implement for interrupt-, DMA-based transmits.
792        Err(ErrorCode::FAIL)
793    }
794
795    fn transmit_abort(&self) -> Result<(), ErrorCode> {
796        if self.tx_dma_channel.is_some() {
797            self.transmit_abort_dma()
798        } else {
799            self.transmit_abort_interrupt()
800        }
801    }
802}
803
804impl hil::uart::Configure for Lpuart<'_> {
805    fn configure(&self, params: hil::uart::Parameters) -> Result<(), ErrorCode> {
806        if params.baud_rate != 115200
807            || params.stop_bits != hil::uart::StopBits::One
808            || params.parity != hil::uart::Parity::None
809            || params.hw_flow_control
810            || params.width != hil::uart::Width::Eight
811        {
812            panic!(
813                "Currently we only support uart setting of 115200bps 8N1, no hardware flow control"
814            );
815        }
816
817        self.enable_clock();
818        // Reset the LPUART using software
819        self.registers.global.modify(GLOBAL::RST::SET);
820        self.registers.global.modify(GLOBAL::RST::CLEAR);
821
822        // Enable Bothedge sampling
823        self.registers.baud.modify(BAUD::BOTHEDGE::SET);
824
825        // Set Oversampling Ratio to 5 (the value written is -1)
826        self.registers.baud.modify(BAUD::OSR.val(0b100_u32));
827
828        // Set the Baud Rate Modulo Divisor
829        self.registers.baud.modify(BAUD::SBR.val(139_u32));
830
831        // Set bit count and parity mode
832        self.registers.baud.modify(BAUD::M10::CLEAR);
833
834        self.registers.ctrl.modify(CTRL::PE::CLEAR);
835        self.registers.ctrl.modify(CTRL::PT::CLEAR);
836        self.registers.ctrl.modify(CTRL::M::CLEAR);
837        self.registers.ctrl.modify(CTRL::ILT::CLEAR);
838        self.registers.ctrl.modify(CTRL::IDLECFG::CLEAR);
839
840        // Set 1 stop bit
841        self.registers.baud.modify(BAUD::SBNS::CLEAR);
842
843        // Clear RX and TX watermarks
844        self.registers.water.modify(WATER::RXWATER::CLEAR);
845        self.registers.water.modify(WATER::TXWATER::CLEAR);
846
847        // Disable TX and RX FIFO
848        self.registers.fifo.modify(FIFO::TXFE::CLEAR);
849        self.registers.fifo.modify(FIFO::RXFE::CLEAR);
850
851        // Flush RX FIFO and TX FIFO
852        self.registers.fifo.modify(FIFO::TXFLUSH::SET);
853        self.registers.fifo.modify(FIFO::RXFLUSH::SET);
854
855        self.clear_status();
856
857        // Set the CTS configuration/TX CTS source.
858        self.registers.modir.modify(MODIR::TXCTSC::CLEAR);
859        self.registers.modir.modify(MODIR::TXCTSSRC::CLEAR);
860
861        // Set as LSB
862        self.registers.stat.modify(STAT::MSBF::CLEAR);
863
864        // Enable TX and RX over LPUART
865        self.registers.ctrl.modify(CTRL::TE::SET);
866        self.registers.ctrl.modify(CTRL::RE::SET);
867
868        Ok(())
869    }
870}
871
872impl<'a> hil::uart::Receive<'a> for Lpuart<'a> {
873    fn set_receive_client(&self, client: &'a dyn hil::uart::ReceiveClient) {
874        self.rx_client.set(client);
875    }
876
877    fn receive_buffer(
878        &self,
879        rx_buffer: &'static mut [u8],
880        rx_len: usize,
881    ) -> Result<(), (ErrorCode, &'static mut [u8])> {
882        if self.rx_dma_channel.is_some() {
883            self.receive_buffer_dma(rx_buffer, rx_len)
884        } else {
885            self.receive_buffer_interrupt(rx_buffer, rx_len)
886        }
887    }
888
889    fn receive_word(&self) -> Result<(), ErrorCode> {
890        // TODO handle interrupt-/DMA-based word receives
891        Err(ErrorCode::FAIL)
892    }
893
894    fn receive_abort(&self) -> Result<(), ErrorCode> {
895        if self.rx_dma_channel.is_some() {
896            self.receive_abort_dma()
897        } else {
898            self.receive_abort_interrupt()
899        }
900    }
901}
902
903struct LpuartClock<'a>(ccm::PeripheralClock<'a>);
904
905impl ClockInterface for LpuartClock<'_> {
906    fn is_enabled(&self) -> bool {
907        self.0.is_enabled()
908    }
909
910    fn enable(&self) {
911        self.0.enable();
912    }
913
914    fn disable(&self) {
915        self.0.disable();
916    }
917}
918
919impl dma::DmaClient for Lpuart<'_> {
920    fn transfer_complete(&self, result: dma::Result) {
921        match result {
922            // Successful transfer from memory to peripheral
923            Ok(source) if source == self.tx_dma_source => {
924                self.registers.baud.modify(BAUD::TDMAE::CLEAR);
925                let result = if self.registers.fifo.is_set(FIFO::TXOF) {
926                    Err(ErrorCode::FAIL)
927                } else {
928                    Ok(())
929                };
930                self.tx_client.map(|client| {
931                    client.transmitted_buffer(
932                        self.tx_buffer.take().unwrap(),
933                        self.tx_len.take(),
934                        result,
935                    );
936                });
937            }
938            // Unsuccessful transfer from memory to peripheral
939            Err(source) if source == self.tx_dma_source => {
940                self.registers.baud.modify(BAUD::TDMAE::CLEAR);
941                self.tx_client.map(|client| {
942                    client.transmitted_buffer(
943                        self.tx_buffer.take().unwrap(),
944                        self.tx_len.take(),
945                        Err(ErrorCode::FAIL),
946                    );
947                });
948            }
949            // Successful transfer from peripheral into memory
950            Ok(source) if source == self.rx_dma_source => {
951                self.registers.baud.modify(BAUD::RDMAE::CLEAR);
952                let err = self.check_status();
953                let code = if kernel::hil::uart::Error::None == err {
954                    Ok(())
955                } else {
956                    Err(ErrorCode::FAIL)
957                };
958                self.rx_client.map(|client| {
959                    client.received_buffer(
960                        self.rx_buffer.take().unwrap(),
961                        self.rx_len.take(),
962                        code,
963                        err,
964                    );
965                });
966            }
967            // Unsuccessful transfer from peripheral into memory
968            Err(source) if source == self.rx_dma_source => {
969                self.registers.baud.modify(BAUD::RDMAE::CLEAR);
970                self.rx_client.map(|client| {
971                    client.received_buffer(
972                        self.rx_buffer.take().unwrap(),
973                        self.rx_len.take(),
974                        Err(ErrorCode::FAIL),
975                        kernel::hil::uart::Error::Aborted,
976                    );
977                });
978            }
979            _ => panic!("DMA channel has reference to the wrong DMA client"),
980        }
981    }
982}