lpc55s6x/
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 2025.
4
5//! Universal Asynchronous Receiver/Transmitter (UART) driver for the LPC55S6x family.
6//!
7//! The UART peripheral provides full‑duplex asynchronous serial communication,
8//! typically used for console I/O, debugging, or external device interfaces.
9//! On the LPC55S6x, UART functionality is implemented through the Flexcomm
10//! blocks when configured in USART mode.
11//!
12//! Features supported:
13//! - Standard 8‑N‑1 asynchronous communication
14//! - Configurable baud rate generation via fractional rate generator (FRG)
15//! - Interrupts for transmit, receive, and error conditions
16//! - FIFO support for buffered TX/RX
17//!
18//! Reference: *LPC55S6x/LPC55S2x/LPC552x User Manual* (NXP).
19
20use core::cell::Cell;
21use enum_primitive::cast::FromPrimitive;
22use kernel::hil::uart::ReceiveClient;
23use kernel::hil::uart::{
24    Configure, Parameters, Parity, Receive, StopBits, Transmit, TransmitClient, Width,
25};
26use kernel::utilities::cells::{OptionalCell, TakeCell};
27use kernel::utilities::registers::interfaces::{ReadWriteable, Readable, Writeable};
28use kernel::utilities::registers::{
29    register_bitfields, register_structs, ReadOnly, ReadWrite, WriteOnly,
30};
31use kernel::utilities::StaticRef;
32use kernel::{hil, ErrorCode};
33
34use crate::clocks::FrgId;
35use crate::clocks::{Clock, FrgClockSource};
36use crate::flexcomm::Flexcomm;
37
38register_structs! {
39    /// USARTs
40    pub UsartRegisters {
41        /// USART Configuration register. Basic USART configuration settings that typically
42        (0x000 => cfg: ReadWrite<u32, CFG::Register>),
43        /// USART Control register. USART control settings that are more likely to change du
44        (0x004 => ctl: ReadWrite<u32, CTL::Register>),
45        /// USART Status register. The complete status value can be read here. Writing ones
46        (0x008 => stat: ReadWrite<u32, STAT::Register>),
47        /// Interrupt Enable read and Set register for USART (not FIFO) status. Contains ind
48        (0x00C => intenset: ReadWrite<u32, INTENSET::Register>),
49        /// Interrupt Enable Clear register. Allows clearing any combination of bits in the
50        (0x010 => intenclr: WriteOnly<u32, INTENCLR::Register>),
51        (0x014 => _reserved0),
52        /// Baud Rate Generator register. 16-bit integer baud rate divisor value.
53        (0x020 => brg: ReadWrite<u32>),
54        /// Interrupt status register. Reflects interrupts that are currently enabled.
55        (0x024 => intstat: ReadOnly<u32, INTSTAT::Register>),
56        /// Oversample selection register for asynchronous communication.
57        (0x028 => osr: ReadWrite<u32>),
58        /// Address register for automatic address matching.
59        (0x02C => addr: ReadWrite<u32>),
60        (0x030 => _reserved1),
61        /// FIFO configuration and enable register.
62        (0xE00 => fifocfg: ReadWrite<u32, FIFOCFG::Register>),
63        /// FIFO status register.
64        (0xE04 => fifostat: ReadWrite<u32, FIFOSTAT::Register>),
65        /// FIFO trigger settings for interrupt and DMA request.
66        (0xE08 => fifotrig: ReadWrite<u32, FIFOTRIG::Register>),
67        (0xE0C => _reserved2),
68        /// FIFO interrupt enable set (enable) and read register.
69        (0xE10 => fifointenset: ReadWrite<u32, FIFOINTENSET::Register>),
70        /// FIFO interrupt enable clear (disable) and read register.
71        (0xE14 => fifointenclr: ReadWrite<u32, FIFOINTENCLR::Register>),
72        /// FIFO interrupt status register.
73        (0xE18 => fifointstat: ReadOnly<u32, FIFOINTSTAT::Register>),
74        (0xE1C => _reserved3),
75        /// FIFO write data.
76        (0xE20 => fifowr: WriteOnly<u32>),
77        (0xE24 => _reserved4),
78        /// FIFO read data.
79        (0xE30 => fiford: ReadOnly<u32, FIFORD::Register>),
80        (0xE34 => _reserved5),
81        /// FIFO data read with no FIFO pop.
82        (0xE40 => fifordnopop: ReadOnly<u32, FIFORDNOPOP::Register>),
83        (0xE44 => _reserved6),
84        /// FIFO size register
85        (0xE48 => fifosize: ReadWrite<u32>),
86        (0xE4C => _reserved7),
87        /// Peripheral identification register.
88        (0xFFC => id: ReadOnly<u32, ID::Register>),
89        (0x1000 => @END),
90    }
91}
92register_bitfields![u32,
93CFG [
94    /// USART Enable.
95    ENABLE OFFSET(0) NUMBITS(1) [
96        /// Disabled. The USART is disabled and the internal state machine and counters are
97        DISABLED = 0,
98        /// Enabled. The USART is enabled for operation.
99        EnabledTheUSARTIsEnabledForOperation = 1
100    ],
101    /// Selects the data size for the USART.
102    DATALEN OFFSET(2) NUMBITS(2) [
103        /// 7 bit Data length.
104        _7BitDataLength = 0,
105        /// 8 bit Data length.
106        _8BitDataLength = 1,
107        /// 9 bit data length. The 9th bit is commonly used for addressing in multidrop mode
108        _9BitDataLength = 2
109    ],
110    /// Selects what type of parity is used by the USART.
111    PARITYSEL OFFSET(4) NUMBITS(2) [
112        /// No parity.
113        NO_PARITY = 0,
114        /// Even parity. Adds a bit to each character such that the number of 1s in a transm
115        EVEN_PARITY = 2,
116        /// Odd parity. Adds a bit to each character such that the number of 1s in a transmi
117        ODD_PARITY = 3
118    ],
119    /// Number of stop bits appended to transmitted data. Only a single stop bit is requ
120    STOPLEN OFFSET(6) NUMBITS(1) [
121        /// 1 stop bit.
122        _1StopBit = 0,
123        /// 2 stop bits. This setting should only be used for asynchronous communication.
124        _2StopBits = 1
125    ],
126    /// Selects standard or 32 kHz clocking mode.
127    MODE32K OFFSET(7) NUMBITS(1) [
128        /// Disabled. USART uses standard clocking.
129        DisabledUSARTUsesStandardClocking = 0,
130        /// Enabled. USART uses the 32 kHz clock from the RTC oscillator as the clock source
131        ENABLED = 1
132    ],
133    /// LIN break mode enable.
134    LINMODE OFFSET(8) NUMBITS(1) [
135        /// Disabled. Break detect and generate is configured for normal operation.
136        DisabledBreakDetectAndGenerateIsConfiguredForNormalOperation = 0,
137        /// Enabled. Break detect and generate is configured for LIN bus operation.
138        EnabledBreakDetectAndGenerateIsConfiguredForLINBusOperation = 1
139    ],
140    /// CTS Enable. Determines whether CTS is used for flow control. CTS can be from the
141    CTSEN OFFSET(9) NUMBITS(1) [
142        /// No flow control. The transmitter does not receive any automatic flow control sig
143        NoFlowControlTheTransmitterDoesNotReceiveAnyAutomaticFlowControlSignal = 0,
144        /// Flow control enabled. The transmitter uses the CTS input (or RTS output in loopb
145        ENABLED = 1
146    ],
147    /// Selects synchronous or asynchronous operation.
148    SYNCEN OFFSET(11) NUMBITS(1) [
149        /// Asynchronous mode.
150        AsynchronousMode = 0,
151        /// Synchronous mode.
152        SynchronousMode = 1
153    ],
154    /// Selects the clock polarity and sampling edge of received data in synchronous mod
155    CLKPOL OFFSET(12) NUMBITS(1) [
156        /// Falling edge. Un_RXD is sampled on the falling edge of SCLK.
157        FallingEdgeUn_RXDIsSampledOnTheFallingEdgeOfSCLK = 0,
158        /// Rising edge. Un_RXD is sampled on the rising edge of SCLK.
159        RisingEdgeUn_RXDIsSampledOnTheRisingEdgeOfSCLK = 1
160    ],
161    /// Synchronous mode Master select.
162    SYNCMST OFFSET(14) NUMBITS(1) [
163        /// Slave. When synchronous mode is enabled, the USART is a slave.
164        SlaveWhenSynchronousModeIsEnabledTheUSARTIsASlave = 0,
165        /// Master. When synchronous mode is enabled, the USART is a master.
166        MasterWhenSynchronousModeIsEnabledTheUSARTIsAMaster = 1
167    ],
168    /// Selects data loopback mode.
169    LOOP OFFSET(15) NUMBITS(1) [
170        /// Normal operation.
171        NormalOperation = 0,
172        /// Loopback mode. This provides a mechanism to perform diagnostic loopback testing
173        LOOPBACK = 1
174    ],
175    /// Output Enable Turnaround time enable for RS-485 operation.
176    OETA OFFSET(18) NUMBITS(1) [
177        /// Disabled. If selected by OESEL, the Output Enable signal deasserted at the end o
178        DISABLED = 0,
179        /// Enabled. If selected by OESEL, the Output Enable signal remains asserted for one
180        ENABLED = 1
181    ],
182    /// Automatic Address matching enable.
183    AUTOADDR OFFSET(19) NUMBITS(1) [
184        /// Disabled. When addressing is enabled by ADDRDET, address matching is done by sof
185        DISABLED = 0,
186        /// Enabled. When addressing is enabled by ADDRDET, address matching is done by hard
187        ENABLED = 1
188    ],
189    /// Output Enable Select.
190    OESEL OFFSET(20) NUMBITS(1) [
191        /// Standard. The RTS signal is used as the standard flow control function.
192        StandardTheRTSSignalIsUsedAsTheStandardFlowControlFunction = 0,
193        /// RS-485. The RTS signal configured to provide an output enable signal to control
194        RS_485 = 1
195    ],
196    /// Output Enable Polarity.
197    OEPOL OFFSET(21) NUMBITS(1) [
198        /// Low. If selected by OESEL, the output enable is active low.
199        LowIfSelectedByOESELTheOutputEnableIsActiveLow = 0,
200        /// High. If selected by OESEL, the output enable is active high.
201        HighIfSelectedByOESELTheOutputEnableIsActiveHigh = 1
202    ],
203    /// Receive data polarity.
204    RXPOL OFFSET(22) NUMBITS(1) [
205        /// Standard. The RX signal is used as it arrives from the pin. This means that the
206        STANDARD = 0,
207        /// Inverted. The RX signal is inverted before being used by the USART. This means t
208        INVERTED = 1
209    ],
210    /// Transmit data polarity.
211    TXPOL OFFSET(23) NUMBITS(1) [
212        /// Standard. The TX signal is sent out without change. This means that the TX rest
213        STANDARD = 0,
214        /// Inverted. The TX signal is inverted by the USART before being sent out. This mea
215        INVERTED = 1
216    ]
217],
218CTL [
219    /// Break Enable.
220    TXBRKEN OFFSET(1) NUMBITS(1) [
221        /// Normal operation.
222        NormalOperation = 0,
223        /// Continuous break. Continuous break is sent immediately when this bit is set, and
224        CONTINOUS = 1
225    ],
226    /// Enable address detect mode.
227    ADDRDET OFFSET(2) NUMBITS(1) [
228        /// Disabled. The USART presents all incoming data.
229        DisabledTheUSARTPresentsAllIncomingData = 0,
230        /// Enabled. The USART receiver ignores incoming data that does not have the most si
231        ENABLED = 1
232    ],
233    /// Transmit Disable.
234    TXDIS OFFSET(6) NUMBITS(1) [
235        /// Not disabled. USART transmitter is not disabled.
236        NotDisabledUSARTTransmitterIsNotDisabled = 0,
237        /// Disabled. USART transmitter is disabled after any character currently being tran
238        DISABLED = 1
239    ],
240    /// Continuous Clock generation. By default, SCLK is only output while data is being
241    CC OFFSET(8) NUMBITS(1) [
242        /// Clock on character. In synchronous mode, SCLK cycles only when characters are be
243        CLOCK_ON_CHARACTER = 0,
244        /// Continuous clock. SCLK runs continuously in synchronous mode, allowing character
245        CONTINOUS_CLOCK = 1
246    ],
247    /// Clear Continuous Clock.
248    CLRCCONRX OFFSET(9) NUMBITS(1) [
249        /// No effect. No effect on the CC bit.
250        NoEffectNoEffectOnTheCCBit = 0,
251        /// Auto-clear. The CC bit is automatically cleared when a complete character has be
252        AUTO_CLEAR = 1
253    ],
254    /// Autobaud enable.
255    AUTOBAUD OFFSET(16) NUMBITS(1) [
256        /// Disabled. USART is in normal operating mode.
257        DisabledUSARTIsInNormalOperatingMode = 0,
258        /// Enabled. USART is in autobaud mode. This bit should only be set when the USART r
259        ENABLED = 1
260    ]
261],
262STAT [
263    /// Receiver Idle. When 0, indicates that the receiver is currently in the process o
264    RXIDLE OFFSET(1) NUMBITS(1) [],
265    /// Transmitter Idle. When 0, indicates that the transmitter is currently in the pro
266    TXIDLE OFFSET(3) NUMBITS(1) [],
267    /// This bit reflects the current state of the CTS signal, regardless of the setting
268    CTS OFFSET(4) NUMBITS(1) [],
269    /// This bit is set when a change in the state is detected for the CTS flag above. T
270    DELTACTS OFFSET(5) NUMBITS(1) [],
271    /// Transmitter Disabled Status flag. When 1, this bit indicates that the USART tran
272    TXDISSTAT OFFSET(6) NUMBITS(1) [],
273    /// Received Break. This bit reflects the current state of the receiver break detect
274    RXBRK OFFSET(10) NUMBITS(1) [],
275    /// This bit is set when a change in the state of receiver break detection occurs. C
276    DELTARXBRK OFFSET(11) NUMBITS(1) [],
277    /// This bit is set when a start is detected on the receiver input. Its purpose is p
278    START OFFSET(12) NUMBITS(1) [],
279    /// Framing Error interrupt flag. This flag is set when a character is received with
280    FRAMERRINT OFFSET(13) NUMBITS(1) [],
281    /// Parity Error interrupt flag. This flag is set when a parity error is detected in
282    PARITYERRINT OFFSET(14) NUMBITS(1) [],
283    /// Received Noise interrupt flag. Three samples of received data are taken in order
284    RXNOISEINT OFFSET(15) NUMBITS(1) [],
285    /// Auto baud Error. An auto baud error can occur if the BRG counts to its limit bef
286    ABERR OFFSET(16) NUMBITS(1) []
287],
288INTENSET [
289    /// When 1, enables an interrupt when the transmitter becomes idle (TXIDLE = 1).
290    TXIDLEEN OFFSET(3) NUMBITS(1) [],
291    /// When 1, enables an interrupt when there is a change in the state of the CTS inpu
292    DELTACTSEN OFFSET(5) NUMBITS(1) [],
293    /// When 1, enables an interrupt when the transmitter is fully disabled as indicated
294    TXDISEN OFFSET(6) NUMBITS(1) [],
295    /// When 1, enables an interrupt when a change of state has occurred in the detectio
296    DELTARXBRKEN OFFSET(11) NUMBITS(1) [],
297    /// When 1, enables an interrupt when a received start bit has been detected.
298    STARTEN OFFSET(12) NUMBITS(1) [],
299    /// When 1, enables an interrupt when a framing error has been detected.
300    FRAMERREN OFFSET(13) NUMBITS(1) [],
301    /// When 1, enables an interrupt when a parity error has been detected.
302    PARITYERREN OFFSET(14) NUMBITS(1) [],
303    /// When 1, enables an interrupt when noise is detected. See description of the RXNO
304    RXNOISEEN OFFSET(15) NUMBITS(1) [],
305    /// When 1, enables an interrupt when an auto baud error occurs.
306    ABERREN OFFSET(16) NUMBITS(1) []
307],
308INTENCLR [
309    /// Writing 1 clears the corresponding bit in the INTENSET register.
310    TXIDLECLR OFFSET(3) NUMBITS(1) [],
311    /// Writing 1 clears the corresponding bit in the INTENSET register.
312    DELTACTSCLR OFFSET(5) NUMBITS(1) [],
313    /// Writing 1 clears the corresponding bit in the INTENSET register.
314    TXDISCLR OFFSET(6) NUMBITS(1) [],
315    /// Writing 1 clears the corresponding bit in the INTENSET register.
316    DELTARXBRKCLR OFFSET(11) NUMBITS(1) [],
317    /// Writing 1 clears the corresponding bit in the INTENSET register.
318    STARTCLR OFFSET(12) NUMBITS(1) [],
319    /// Writing 1 clears the corresponding bit in the INTENSET register.
320    FRAMERRCLR OFFSET(13) NUMBITS(1) [],
321    /// Writing 1 clears the corresponding bit in the INTENSET register.
322    PARITYERRCLR OFFSET(14) NUMBITS(1) [],
323    /// Writing 1 clears the corresponding bit in the INTENSET register.
324    RXNOISECLR OFFSET(15) NUMBITS(1) [],
325    /// Writing 1 clears the corresponding bit in the INTENSET register.
326    ABERRCLR OFFSET(16) NUMBITS(1) []
327],
328BRG [
329    /// This value is used to divide the USART input clock to determine the baud rate, b
330    BRGVAL OFFSET(0) NUMBITS(16) []
331],
332INTSTAT [
333    /// Transmitter Idle status.
334    TXIDLE OFFSET(3) NUMBITS(1) [],
335    /// This bit is set when a change in the state of the CTS input is detected.
336    DELTACTS OFFSET(5) NUMBITS(1) [],
337    /// Transmitter Disabled Interrupt flag.
338    TXDISINT OFFSET(6) NUMBITS(1) [],
339    /// This bit is set when a change in the state of receiver break detection occurs.
340    DELTARXBRK OFFSET(11) NUMBITS(1) [],
341    /// This bit is set when a start is detected on the receiver input.
342    START OFFSET(12) NUMBITS(1) [],
343    /// Framing Error interrupt flag.
344    FRAMERRINT OFFSET(13) NUMBITS(1) [],
345    /// Parity Error interrupt flag.
346    PARITYERRINT OFFSET(14) NUMBITS(1) [],
347    /// Received Noise interrupt flag.
348    RXNOISEINT OFFSET(15) NUMBITS(1) [],
349    /// Auto baud Error Interrupt flag.
350    ABERRINT OFFSET(16) NUMBITS(1) []
351],
352OSR [
353    /// Oversample Selection Value. 0 to 3 = not supported 0x4 = 5 function clocks are u
354    OSRVAL OFFSET(0) NUMBITS(4) []
355],
356ADDR [
357    /// 8-bit address used with automatic address matching. Used when address detection
358    ADDRESS OFFSET(0) NUMBITS(8) []
359],
360FIFOCFG [
361    /// Enable the transmit FIFO.
362    ENABLETX OFFSET(0) NUMBITS(1) [
363        /// The transmit FIFO is not enabled.
364        TheTransmitFIFOIsNotEnabled = 0,
365        /// The transmit FIFO is enabled.
366        TheTransmitFIFOIsEnabled = 1
367    ],
368    /// Enable the receive FIFO.
369    ENABLERX OFFSET(1) NUMBITS(1) [
370        /// The receive FIFO is not enabled.
371        TheReceiveFIFOIsNotEnabled = 0,
372        /// The receive FIFO is enabled.
373        TheReceiveFIFOIsEnabled = 1
374    ],
375    /// FIFO size configuration. This is a read-only field. 0x0 = FIFO is configured as
376    SIZE OFFSET(4) NUMBITS(2) [],
377    /// DMA configuration for transmit.
378    DMATX OFFSET(12) NUMBITS(1) [
379        /// DMA is not used for the transmit function.
380        DMAIsNotUsedForTheTransmitFunction = 0,
381        /// Trigger DMA for the transmit function if the FIFO is not full. Generally, data i
382        ENABLED = 1
383    ],
384    /// DMA configuration for receive.
385    DMARX OFFSET(13) NUMBITS(1) [
386        /// DMA is not used for the receive function.
387        DMAIsNotUsedForTheReceiveFunction = 0,
388        /// Trigger DMA for the receive function if the FIFO is not empty. Generally, data i
389        ENABLED = 1
390    ],
391    /// Wake-up for transmit FIFO level. This allows the device to be woken from reduced
392    WAKETX OFFSET(14) NUMBITS(1) [
393        /// Only enabled interrupts will wake up the device form reduced power modes.
394        OnlyEnabledInterruptsWillWakeUpTheDeviceFormReducedPowerModes = 0,
395        /// A device wake-up for DMA will occur if the transmit FIFO level reaches the value
396        ENABLED = 1
397    ],
398    /// Wake-up for receive FIFO level. This allows the device to be woken from reduced
399    WAKERX OFFSET(15) NUMBITS(1) [
400        /// Only enabled interrupts will wake up the device form reduced power modes.
401        OnlyEnabledInterruptsWillWakeUpTheDeviceFormReducedPowerModes = 0,
402        /// A device wake-up for DMA will occur if the receive FIFO level reaches the value
403        ENABLED = 1
404    ],
405    /// Empty command for the transmit FIFO. When a 1 is written to this bit, the TX FIF
406    EMPTYTX OFFSET(16) NUMBITS(1) [],
407    /// Empty command for the receive FIFO. When a 1 is written to this bit, the RX FIFO
408    EMPTYRX OFFSET(17) NUMBITS(1) []
409],
410FIFOSTAT [
411    /// TX FIFO error. Will be set if a transmit FIFO error occurs. This could be an ove
412    TXERR OFFSET(0) NUMBITS(1) [],
413    /// RX FIFO error. Will be set if a receive FIFO overflow occurs, caused by software
414    RXERR OFFSET(1) NUMBITS(1) [],
415    /// Peripheral interrupt. When 1, this indicates that the peripheral function has as
416    PERINT OFFSET(3) NUMBITS(1) [],
417    /// Transmit FIFO empty. When 1, the transmit FIFO is empty. The peripheral may stil
418    TXEMPTY OFFSET(4) NUMBITS(1) [],
419    /// Transmit FIFO not full. When 1, the transmit FIFO is not full, so more data can
420    TXNOTFULL OFFSET(5) NUMBITS(1) [],
421    /// Receive FIFO not empty. When 1, the receive FIFO is not empty, so data can be re
422    RXNOTEMPTY OFFSET(6) NUMBITS(1) [],
423    /// Receive FIFO full. When 1, the receive FIFO is full. Data needs to be read out t
424    RXFULL OFFSET(7) NUMBITS(1) [],
425    /// Transmit FIFO current level. A 0 means the TX FIFO is currently empty, and the T
426    TXLVL OFFSET(8) NUMBITS(5) [],
427    /// Receive FIFO current level. A 0 means the RX FIFO is currently empty, and the RX
428    RXLVL OFFSET(16) NUMBITS(5) []
429],
430FIFOTRIG [
431    /// Transmit FIFO level trigger enable. This trigger will become an interrupt if ena
432    TXLVLENA OFFSET(0) NUMBITS(1) [
433        /// Transmit FIFO level does not generate a FIFO level trigger.
434        TransmitFIFOLevelDoesNotGenerateAFIFOLevelTrigger = 0,
435        /// An trigger will be generated if the transmit FIFO level reaches the value specif
436        ENABLED = 1
437    ],
438    /// Receive FIFO level trigger enable. This trigger will become an interrupt if enab
439    RXLVLENA OFFSET(1) NUMBITS(1) [
440        /// Receive FIFO level does not generate a FIFO level trigger.
441        ReceiveFIFOLevelDoesNotGenerateAFIFOLevelTrigger = 0,
442        /// An trigger will be generated if the receive FIFO level reaches the value specifi
443        ENABLED = 1
444    ],
445    /// Transmit FIFO level trigger point. This field is used only when TXLVLENA = 1. If
446    TXLVL OFFSET(8) NUMBITS(4) [],
447    /// Receive FIFO level trigger point. The RX FIFO level is checked when a new piece
448    RXLVL OFFSET(16) NUMBITS(4) []
449],
450FIFOINTENSET [
451    /// Determines whether an interrupt occurs when a transmit error occurs, based on th
452    TXERR OFFSET(0) NUMBITS(1) [
453        /// No interrupt will be generated for a transmit error.
454        NoInterruptWillBeGeneratedForATransmitError = 0,
455        /// An interrupt will be generated when a transmit error occurs.
456        AnInterruptWillBeGeneratedWhenATransmitErrorOccurs = 1
457    ],
458    /// Determines whether an interrupt occurs when a receive error occurs, based on the
459    RXERR OFFSET(1) NUMBITS(1) [
460        /// No interrupt will be generated for a receive error.
461        NoInterruptWillBeGeneratedForAReceiveError = 0,
462        /// An interrupt will be generated when a receive error occurs.
463        AnInterruptWillBeGeneratedWhenAReceiveErrorOccurs = 1
464    ],
465    /// Determines whether an interrupt occurs when a the transmit FIFO reaches the leve
466    TXLVL OFFSET(2) NUMBITS(1) [
467        /// No interrupt will be generated based on the TX FIFO level.
468        NoInterruptWillBeGeneratedBasedOnTheTXFIFOLevel = 0,
469        /// If TXLVLENA in the FIFOTRIG register = 1, an interrupt will be generated when th
470        ENABLED = 1
471    ],
472    /// Determines whether an interrupt occurs when a the receive FIFO reaches the level
473    RXLVL OFFSET(3) NUMBITS(1) [
474        /// No interrupt will be generated based on the RX FIFO level.
475        NoInterruptWillBeGeneratedBasedOnTheRXFIFOLevel = 0,
476        /// If RXLVLENA in the FIFOTRIG register = 1, an interrupt will be generated when th
477        ENABLED = 1
478    ]
479],
480FIFOINTENCLR [
481    /// Writing one clears the corresponding bits in the FIFOINTENSET register.
482    TXERR OFFSET(0) NUMBITS(1) [],
483    /// Writing one clears the corresponding bits in the FIFOINTENSET register.
484    RXERR OFFSET(1) NUMBITS(1) [],
485    /// Writing one clears the corresponding bits in the FIFOINTENSET register.
486    TXLVL OFFSET(2) NUMBITS(1) [],
487    /// Writing one clears the corresponding bits in the FIFOINTENSET register.
488    RXLVL OFFSET(3) NUMBITS(1) []
489],
490FIFOINTSTAT [
491    /// TX FIFO error.
492    TXERR OFFSET(0) NUMBITS(1) [],
493    /// RX FIFO error.
494    RXERR OFFSET(1) NUMBITS(1) [],
495    /// Transmit FIFO level interrupt.
496    TXLVL OFFSET(2) NUMBITS(1) [],
497    /// Receive FIFO level interrupt.
498    RXLVL OFFSET(3) NUMBITS(1) [],
499    /// Peripheral interrupt.
500    PERINT OFFSET(4) NUMBITS(1) []
501],
502FIFOWR [
503    /// Transmit data to the FIFO.
504    TXDATA OFFSET(0) NUMBITS(9) []
505],
506FIFORD [
507    /// Received data from the FIFO. The number of bits used depends on the DATALEN and
508    RXDATA OFFSET(0) NUMBITS(9) [],
509    /// Framing Error status flag. This bit reflects the status for the data it is read
510    FRAMERR OFFSET(13) NUMBITS(1) [],
511    /// Parity Error status flag. This bit reflects the status for the data it is read a
512    PARITYERR OFFSET(14) NUMBITS(1) [],
513    /// Received Noise flag. See description of the RxNoiseInt bit in Table 354.
514    RXNOISE OFFSET(15) NUMBITS(1) []
515],
516FIFORDNOPOP [
517    /// Received data from the FIFO. The number of bits used depends on the DATALEN and
518    RXDATA OFFSET(0) NUMBITS(9) [],
519    /// Framing Error status flag. This bit reflects the status for the data it is read
520    FRAMERR OFFSET(13) NUMBITS(1) [],
521    /// Parity Error status flag. This bit reflects the status for the data it is read a
522    PARITYERR OFFSET(14) NUMBITS(1) [],
523    /// Received Noise flag. See description of the RxNoiseInt bit in Table 354.
524    RXNOISE OFFSET(15) NUMBITS(1) []
525],
526FIFOSIZE [
527    /// Provides the size of the FIFO for software. The size of the SPI FIFO is 8 entrie
528    FIFOSIZE OFFSET(0) NUMBITS(5) []
529],
530ID [
531    /// Aperture: encoded as (aperture size/4K) -1, so 0x00 means a 4K aperture.
532    APERTURE OFFSET(0) NUMBITS(8) [],
533    /// Minor revision of module implementation.
534    MINOR_REV OFFSET(8) NUMBITS(4) [],
535    /// Major revision of module implementation.
536    MAJOR_REV OFFSET(12) NUMBITS(4) [],
537    /// Module identifier for the selected function.
538    ID OFFSET(16) NUMBITS(16) []
539]
540];
541
542#[derive(Copy, Clone, PartialEq)]
543enum UARTStateTX {
544    Idle,
545    Transmitting,
546    AbortRequested,
547}
548
549#[derive(Copy, Clone, PartialEq)]
550enum UARTStateRX {
551    Idle,
552    Receiving,
553    AbortRequested,
554}
555
556const USART0_BASE: StaticRef<UsartRegisters> =
557    unsafe { StaticRef::new(0x40086000 as *const UsartRegisters) };
558
559const USART4_BASE: StaticRef<UsartRegisters> =
560    unsafe { StaticRef::new(0x4008A000 as *const UsartRegisters) };
561
562pub struct Uart<'a> {
563    registers: StaticRef<UsartRegisters>,
564    instance: u8,
565    clocks: OptionalCell<&'a Clock>,
566    flexcomm: OptionalCell<&'a Flexcomm>,
567
568    uart_clock_source: Cell<FrgClockSource>,
569
570    tx_client: OptionalCell<&'a dyn TransmitClient>,
571    rx_client: OptionalCell<&'a dyn ReceiveClient>,
572
573    tx_buffer: TakeCell<'static, [u8]>,
574    tx_position: Cell<usize>,
575    tx_len: Cell<usize>,
576    tx_status: Cell<UARTStateTX>,
577
578    rx_buffer: TakeCell<'static, [u8]>,
579    rx_position: Cell<usize>,
580    rx_len: Cell<usize>,
581    rx_status: Cell<UARTStateRX>,
582}
583
584impl<'a> Uart<'a> {
585    pub fn new(registers: StaticRef<UsartRegisters>, instance: u8) -> Self {
586        Self {
587            registers,
588            instance,
589            clocks: OptionalCell::empty(),
590            flexcomm: OptionalCell::empty(),
591
592            uart_clock_source: Cell::new(FrgClockSource::Fro12Mhz),
593
594            tx_client: OptionalCell::empty(),
595            rx_client: OptionalCell::empty(),
596
597            tx_buffer: TakeCell::empty(),
598            tx_position: Cell::new(0),
599            tx_len: Cell::new(0),
600            tx_status: Cell::new(UARTStateTX::Idle),
601
602            rx_buffer: TakeCell::empty(),
603            rx_position: Cell::new(0),
604            rx_len: Cell::new(0),
605            rx_status: Cell::new(UARTStateRX::Idle),
606        }
607    }
608    pub fn new_uart0() -> Self {
609        Self::new(USART0_BASE, 0)
610    }
611
612    pub fn new_uart4() -> Self {
613        Self::new(USART4_BASE, 4)
614    }
615
616    pub fn set_clocks(&self, clocks: &'a Clock) {
617        self.clocks.set(clocks);
618    }
619
620    pub fn set_flexcomm(&self, flexcomm: &'a Flexcomm) {
621        self.flexcomm.set(flexcomm);
622    }
623
624    pub fn set_clock_source(&self, source: FrgClockSource) {
625        self.uart_clock_source.set(source);
626    }
627
628    pub fn enable(&self) {
629        self.registers.cfg.modify(CFG::ENABLE::SET);
630    }
631
632    pub fn disable(&self) {
633        self.registers.cfg.modify(CFG::ENABLE::CLEAR);
634    }
635
636    fn set_interrupts_for_transmitting(&self) {
637        // We want to know when the FIFO has space.
638        self.registers
639            .fifointenset
640            .write(FIFOINTENSET::TXLVL::SET + FIFOINTENSET::TXERR::SET);
641        // We do NOT care about the final TXIDLE state yet.
642        self.registers.intenclr.write(INTENCLR::TXIDLECLR::SET);
643    }
644
645    fn set_interrupts_for_finishing(&self) {
646        // We no longer care if the FIFO has space.
647        self.registers.fifointenclr.write(FIFOINTENCLR::TXLVL::SET);
648        // We ONLY care about when the transmission is truly complete.
649        self.registers.intenset.write(INTENSET::TXIDLEEN::SET);
650    }
651
652    /// Disables all UART transmit-related interrupts.
653    fn disable_all_tx_interrupts(&self) {
654        self.registers
655            .fifointenclr
656            .write(FIFOINTENCLR::TXLVL::SET + FIFOINTENCLR::TXERR::SET);
657        self.registers.intenclr.write(INTENCLR::TXIDLECLR::SET);
658    }
659
660    pub fn is_transmitting(&self) -> bool {
661        self.tx_status.get() == UARTStateTX::Transmitting
662    }
663
664    pub fn enable_receive_interrupt(&self) {
665        self.registers
666            .fifointenset
667            .modify(FIFOINTENSET::RXLVL::SET + FIFOINTENSET::RXERR::SET);
668
669        self.registers
670            .intenset
671            .modify(INTENSET::FRAMERREN::SET + INTENSET::PARITYERREN::SET);
672    }
673
674    pub fn disable_receive_interrupt(&self) {
675        self.registers
676            .fifointenclr
677            .modify(FIFOINTENCLR::RXLVL::SET + FIFOINTENCLR::RXERR::SET);
678
679        self.registers
680            .intenclr
681            .write(INTENCLR::FRAMERRCLR::SET + INTENCLR::PARITYERRCLR::SET);
682    }
683    pub fn uart_is_writable(&self) -> bool {
684        self.registers.fifostat.is_set(FIFOSTAT::TXNOTFULL)
685    }
686
687    pub fn uart_is_readable(&self) -> bool {
688        self.registers.fifostat.is_set(FIFOSTAT::RXNOTEMPTY)
689    }
690
691    pub fn send_byte(&self, data: u8) {
692        self.registers.fifowr.set(data as u32);
693    }
694
695    pub fn receive_byte(&self) -> u8 {
696        (self.registers.fiford.get() & 0xFF) as u8
697    }
698
699    pub fn handle_interrupt(&self) {
700        // --- Handle Errors (RX-only clears) ---
701        let framing_error = self.registers.stat.is_set(STAT::FRAMERRINT);
702        let parity_error = self.registers.stat.is_set(STAT::PARITYERRINT);
703        let rx_fifo_error = self.registers.fifostat.is_set(FIFOSTAT::RXERR);
704
705        if framing_error || parity_error || rx_fifo_error {
706            // Clear RX-related status bits; DO NOT touch TX FIFO or TX interrupts here.
707            self.registers.stat.write(
708                STAT::FRAMERRINT::SET
709                    + STAT::PARITYERRINT::SET
710                    + STAT::RXBRK::SET
711                    + STAT::DELTACTS::SET,
712            );
713            self.registers.fifostat.write(FIFOSTAT::RXERR::SET);
714
715            // If no receive is active, turn off RX interrupts; otherwise leave them on.
716            if self.rx_status.get() != UARTStateRX::Receiving {
717                self.disable_receive_interrupt();
718            }
719            // Return; TX remains untouched so the process console can still print.
720            return;
721        }
722
723        // --- Handle Transmit ---
724        let tx_level_triggered = self.registers.fifointstat.is_set(FIFOINTSTAT::TXLVL);
725        let tx_idle_triggered = self.registers.intstat.is_set(INTSTAT::TXIDLE);
726
727        if self.tx_status.get() == UARTStateTX::Transmitting {
728            if tx_level_triggered {
729                // Fill TX FIFO from software buffer
730                self.fill_fifo();
731
732                // If we finished sending the software buffer, wait for TXIDLE to signal completion.
733                if self.tx_position.get() == self.tx_len.get() {
734                    self.set_interrupts_for_finishing(); // enable INTENSET::TXIDLEEN, disable FIFO TXLVL
735                }
736            }
737            if tx_idle_triggered {
738                // Acknowledge TXIDLE and finish TX operation.
739                self.registers.stat.write(STAT::TXIDLE::SET);
740                self.disable_all_tx_interrupts();
741                self.tx_status.set(UARTStateTX::Idle);
742
743                // Notify the TX client (console/process_console expects this)
744                self.tx_client.map(|client| {
745                    self.tx_buffer.take().map(|buf| {
746                        client.transmitted_buffer(buf, self.tx_position.get(), Ok(()));
747                    });
748                });
749            }
750        }
751
752        // --- Handle Receive ---
753        if self.registers.fifointstat.is_set(FIFOINTSTAT::RXLVL) {
754            if self.rx_status.get() == UARTStateRX::Receiving {
755                if self.uart_is_readable() && self.rx_position.get() < self.rx_len.get() {
756                    let byte = self.receive_byte();
757                    let pos = self.rx_position.get();
758
759                    self.rx_buffer.map(|buf| {
760                        buf[pos] = byte;
761                    });
762                    self.rx_position.set(pos + 1);
763
764                    // If buffer is complete, finish and notify client.
765                    if self.rx_position.get() == self.rx_len.get() {
766                        self.disable_receive_interrupt();
767                        self.rx_status.set(UARTStateRX::Idle);
768
769                        self.rx_client.map(|client| {
770                            if let Some(buf) = self.rx_buffer.take() {
771                                client.received_buffer(
772                                    buf,
773                                    self.rx_position.get(),
774                                    Ok(()),
775                                    hil::uart::Error::None,
776                                );
777                            }
778                        });
779                    }
780                }
781            }
782            // If no receive is active, ignore spurious RX level interrupts.
783        }
784    }
785
786    fn fill_fifo(&self) {
787        self.tx_buffer.map(|buf| {
788            while self.uart_is_writable() && self.tx_position.get() < self.tx_len.get() {
789                let byte = buf[self.tx_position.get()];
790                self.send_byte(byte);
791                self.tx_position.set(self.tx_position.get() + 1);
792            }
793        });
794    }
795
796    pub fn is_configured(&self) -> bool {
797        self.registers.cfg.is_set(CFG::ENABLE)
798            && (self.registers.fifocfg.is_set(FIFOCFG::ENABLERX)
799                || self.registers.fifocfg.is_set(FIFOCFG::ENABLETX))
800    }
801
802    pub fn get_stat_raw(&self) -> u32 {
803        self.registers.stat.get()
804    }
805
806    pub fn get_fifostat_raw(&self) -> u32 {
807        self.registers.fifostat.get()
808    }
809
810    pub fn clear_fifo_errors(&self) {
811        self.registers
812            .fifostat
813            .write(FIFOSTAT::TXERR::SET + FIFOSTAT::RXERR::SET);
814
815        self.registers.stat.write(
816            STAT::DELTACTS::SET
817                + STAT::FRAMERRINT::SET
818                + STAT::PARITYERRINT::SET
819                + STAT::RXBRK::SET,
820        );
821    }
822
823    pub fn clear_status_flags_and_fifos(&self) {
824        self.registers.stat.write(
825            STAT::DELTACTS::SET
826                + STAT::FRAMERRINT::SET
827                + STAT::PARITYERRINT::SET
828                + STAT::RXBRK::SET,
829        );
830
831        self.registers
832            .fifocfg
833            .modify(FIFOCFG::EMPTYTX::SET + FIFOCFG::EMPTYRX::SET);
834    }
835}
836
837impl Configure for Uart<'_> {
838    fn configure(&self, params: Parameters) -> Result<(), ErrorCode> {
839        let clocks = self.clocks.get().ok_or(ErrorCode::OFF)?;
840        let flexcomm = self.flexcomm.get().ok_or(ErrorCode::OFF)?;
841        let clock_source = self.uart_clock_source.get();
842        let frg_id = FrgId::from_u32(self.instance.into()).ok_or(ErrorCode::INVAL)?;
843        clocks.setup_uart_clock(frg_id, clock_source);
844        flexcomm.configure_for_uart();
845
846        // --- Disable USART before configuration ---
847        self.registers.cfg.modify(CFG::ENABLE::CLEAR);
848
849        let clk = clocks.get_frg_clock_frequency(clock_source);
850        let brg_val = (clk / (16 * params.baud_rate)).saturating_sub(1);
851        if brg_val > 0xFFFF {
852            return Err(ErrorCode::INVAL); // Baud rate not possible
853        }
854
855        self.registers.osr.set(15);
856        self.registers.brg.set(51);
857
858        // --- Configure Frame Format (width, parity, stop bits) ---
859        let datalen = match params.width {
860            Width::Seven => CFG::DATALEN::_7BitDataLength,
861            Width::Eight => CFG::DATALEN::_8BitDataLength,
862            _ => return Err(ErrorCode::NOSUPPORT), // 6 and 9 bit not handled here
863        };
864
865        let paritysel = match params.parity {
866            Parity::None => CFG::PARITYSEL::NO_PARITY,
867            Parity::Odd => CFG::PARITYSEL::ODD_PARITY,
868            Parity::Even => CFG::PARITYSEL::EVEN_PARITY,
869        };
870
871        let stoplen = match params.stop_bits {
872            StopBits::One => CFG::STOPLEN::_1StopBit,
873            StopBits::Two => CFG::STOPLEN::_2StopBits,
874        };
875
876        // Write all configuration bits at once
877        self.registers.cfg.write(datalen + paritysel + stoplen);
878
879        // --- Configure and Enable FIFOs ---
880        // Clear any old data
881        self.registers
882            .fifocfg
883            .modify(FIFOCFG::EMPTYTX::SET + FIFOCFG::EMPTYRX::SET);
884        // Enable both TX and RX FIFOs
885        self.registers
886            .fifocfg
887            .modify(FIFOCFG::ENABLETX::SET + FIFOCFG::ENABLERX::SET);
888        // Set interrupt trigger levels.
889        self.registers
890            .fifotrig
891            .write(FIFOTRIG::TXLVL.val(1) + FIFOTRIG::RXLVL.val(0));
892
893        // --- Re-enable USART ---
894        self.registers.cfg.modify(CFG::ENABLE::SET);
895
896        // A short busy-wait loop is required to allow the peripheral clock
897        // to propagate and the internal logic to settle after being re-enabled
898        for _ in 0..1500 {
899            cortexm33::support::nop();
900        }
901
902        Ok(())
903    }
904}
905
906impl<'a> Transmit<'a> for Uart<'a> {
907    fn set_transmit_client(&self, client: &'a dyn TransmitClient) {
908        self.tx_client.set(client);
909    }
910
911    fn transmit_buffer(
912        &self,
913        tx_buffer: &'static mut [u8],
914        tx_len: usize,
915    ) -> Result<(), (ErrorCode, &'static mut [u8])> {
916        if self.tx_status.get() == UARTStateTX::Idle {
917            if tx_len <= tx_buffer.len() {
918                self.tx_buffer.replace(tx_buffer);
919                self.tx_position.set(0);
920                self.tx_len.set(tx_len);
921                self.tx_status.set(UARTStateTX::Transmitting);
922
923                self.fill_fifo();
924
925                if self.tx_position.get() == self.tx_len.get() {
926                    // The entire message fit in the FIFO at once.
927                    // Move directly to the "finishing" state.
928                    self.set_interrupts_for_finishing();
929                } else {
930                    // There's more data to send.
931                    // Go to the "transmitting" state.
932                    self.set_interrupts_for_transmitting();
933                }
934                Ok(())
935            } else {
936                Err((ErrorCode::SIZE, tx_buffer))
937            }
938        } else {
939            Err((ErrorCode::BUSY, tx_buffer))
940        }
941    }
942
943    fn transmit_word(&self, _word: u32) -> Result<(), ErrorCode> {
944        Err(ErrorCode::FAIL)
945    }
946
947    fn transmit_abort(&self) -> Result<(), ErrorCode> {
948        if self.tx_status.get() != UARTStateTX::Idle {
949            self.disable_all_tx_interrupts();
950            self.tx_status.set(UARTStateTX::AbortRequested);
951
952            Err(ErrorCode::BUSY)
953        } else {
954            Ok(())
955        }
956    }
957}
958
959impl<'a> Receive<'a> for Uart<'a> {
960    fn set_receive_client(&self, client: &'a dyn ReceiveClient) {
961        self.rx_client.set(client);
962    }
963
964    fn receive_buffer(
965        &self,
966        rx_buffer: &'static mut [u8],
967        rx_len: usize,
968    ) -> Result<(), (ErrorCode, &'static mut [u8])> {
969        // Check if we are already in the middle of a receive operation.
970        if self.rx_status.get() != UARTStateRX::Idle {
971            return Err((ErrorCode::BUSY, rx_buffer));
972        }
973
974        // Check if the requested length is valid for the provided buffer.
975        if rx_len > rx_buffer.len() {
976            return Err((ErrorCode::SIZE, rx_buffer));
977        }
978
979        self.rx_buffer.replace(rx_buffer);
980
981        // Set up the state for the interrupt handler.
982        self.rx_position.set(0);
983        self.rx_len.set(rx_len);
984        self.rx_status.set(UARTStateRX::Receiving);
985
986        // Enable the hardware interrupt that fires when data arrives.
987        self.enable_receive_interrupt();
988
989        Ok(())
990    }
991
992    fn receive_word(&self) -> Result<(), ErrorCode> {
993        Err(ErrorCode::FAIL)
994    }
995
996    fn receive_abort(&self) -> Result<(), ErrorCode> {
997        if self.rx_status.get() != UARTStateRX::Idle {
998            self.disable_receive_interrupt();
999            self.rx_status.set(UARTStateRX::AbortRequested);
1000
1001            Err(ErrorCode::BUSY)
1002        } else {
1003            Ok(())
1004        }
1005    }
1006}