Skip to main content

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: &'a Clock,
566    flexcomm: &'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(
586        registers: StaticRef<UsartRegisters>,
587        instance: u8,
588        clocks: &'a Clock,
589        flexcomm: &'a Flexcomm,
590    ) -> Self {
591        Self {
592            registers,
593            instance,
594            clocks,
595            flexcomm,
596
597            uart_clock_source: Cell::new(FrgClockSource::Fro12Mhz),
598
599            tx_client: OptionalCell::empty(),
600            rx_client: OptionalCell::empty(),
601
602            tx_buffer: TakeCell::empty(),
603            tx_position: Cell::new(0),
604            tx_len: Cell::new(0),
605            tx_status: Cell::new(UARTStateTX::Idle),
606
607            rx_buffer: TakeCell::empty(),
608            rx_position: Cell::new(0),
609            rx_len: Cell::new(0),
610            rx_status: Cell::new(UARTStateRX::Idle),
611        }
612    }
613    pub fn new_uart0(clocks: &'a Clock, flexcomm: &'a Flexcomm) -> Self {
614        Self::new(USART0_BASE, 0, clocks, flexcomm)
615    }
616
617    pub fn new_uart4(clocks: &'a Clock, flexcomm: &'a Flexcomm) -> Self {
618        Self::new(USART4_BASE, 4, clocks, flexcomm)
619    }
620
621    pub fn set_clock_source(&self, source: FrgClockSource) {
622        self.uart_clock_source.set(source);
623    }
624
625    pub fn enable(&self) {
626        self.registers.cfg.modify(CFG::ENABLE::SET);
627    }
628
629    pub fn disable(&self) {
630        self.registers.cfg.modify(CFG::ENABLE::CLEAR);
631    }
632
633    fn set_interrupts_for_transmitting(&self) {
634        // We want to know when the FIFO has space.
635        self.registers
636            .fifointenset
637            .write(FIFOINTENSET::TXLVL::SET + FIFOINTENSET::TXERR::SET);
638        // We do NOT care about the final TXIDLE state yet.
639        self.registers.intenclr.write(INTENCLR::TXIDLECLR::SET);
640    }
641
642    fn set_interrupts_for_finishing(&self) {
643        // We no longer care if the FIFO has space.
644        self.registers.fifointenclr.write(FIFOINTENCLR::TXLVL::SET);
645        // We ONLY care about when the transmission is truly complete.
646        self.registers.intenset.write(INTENSET::TXIDLEEN::SET);
647    }
648
649    /// Disables all UART transmit-related interrupts.
650    fn disable_all_tx_interrupts(&self) {
651        self.registers
652            .fifointenclr
653            .write(FIFOINTENCLR::TXLVL::SET + FIFOINTENCLR::TXERR::SET);
654        self.registers.intenclr.write(INTENCLR::TXIDLECLR::SET);
655    }
656
657    pub fn is_transmitting(&self) -> bool {
658        self.tx_status.get() == UARTStateTX::Transmitting
659    }
660
661    pub fn enable_receive_interrupt(&self) {
662        self.registers
663            .fifointenset
664            .modify(FIFOINTENSET::RXLVL::SET + FIFOINTENSET::RXERR::SET);
665
666        self.registers
667            .intenset
668            .modify(INTENSET::FRAMERREN::SET + INTENSET::PARITYERREN::SET);
669    }
670
671    pub fn disable_receive_interrupt(&self) {
672        self.registers
673            .fifointenclr
674            .modify(FIFOINTENCLR::RXLVL::SET + FIFOINTENCLR::RXERR::SET);
675
676        self.registers
677            .intenclr
678            .write(INTENCLR::FRAMERRCLR::SET + INTENCLR::PARITYERRCLR::SET);
679    }
680    pub fn uart_is_writable(&self) -> bool {
681        self.registers.fifostat.is_set(FIFOSTAT::TXNOTFULL)
682    }
683
684    pub fn uart_is_readable(&self) -> bool {
685        self.registers.fifostat.is_set(FIFOSTAT::RXNOTEMPTY)
686    }
687
688    pub fn send_byte(&self, data: u8) {
689        self.registers.fifowr.set(data as u32);
690    }
691
692    pub fn receive_byte(&self) -> u8 {
693        (self.registers.fiford.get() & 0xFF) as u8
694    }
695
696    pub fn handle_interrupt(&self) {
697        // --- Handle Errors (RX-only clears) ---
698        let framing_error = self.registers.stat.is_set(STAT::FRAMERRINT);
699        let parity_error = self.registers.stat.is_set(STAT::PARITYERRINT);
700        let rx_fifo_error = self.registers.fifostat.is_set(FIFOSTAT::RXERR);
701
702        if framing_error || parity_error || rx_fifo_error {
703            // Clear RX-related status bits; DO NOT touch TX FIFO or TX interrupts here.
704            self.registers.stat.write(
705                STAT::FRAMERRINT::SET
706                    + STAT::PARITYERRINT::SET
707                    + STAT::RXBRK::SET
708                    + STAT::DELTACTS::SET,
709            );
710            self.registers.fifostat.write(FIFOSTAT::RXERR::SET);
711
712            // If no receive is active, turn off RX interrupts; otherwise leave them on.
713            if self.rx_status.get() != UARTStateRX::Receiving {
714                self.disable_receive_interrupt();
715            }
716            // Return; TX remains untouched so the process console can still print.
717            return;
718        }
719
720        // --- Handle Transmit ---
721        let tx_level_triggered = self.registers.fifointstat.is_set(FIFOINTSTAT::TXLVL);
722        let tx_idle_triggered = self.registers.intstat.is_set(INTSTAT::TXIDLE);
723
724        if self.tx_status.get() == UARTStateTX::Transmitting {
725            if tx_level_triggered {
726                // Fill TX FIFO from software buffer
727                self.fill_fifo();
728
729                // If we finished sending the software buffer, wait for TXIDLE to signal completion.
730                if self.tx_position.get() == self.tx_len.get() {
731                    self.set_interrupts_for_finishing(); // enable INTENSET::TXIDLEEN, disable FIFO TXLVL
732                }
733            }
734            if tx_idle_triggered {
735                // Acknowledge TXIDLE and finish TX operation.
736                self.registers.stat.write(STAT::TXIDLE::SET);
737                self.disable_all_tx_interrupts();
738                self.tx_status.set(UARTStateTX::Idle);
739
740                // Notify the TX client (console/process_console expects this)
741                self.tx_client.map(|client| {
742                    self.tx_buffer.take().map(|buf| {
743                        client.transmitted_buffer(buf, self.tx_position.get(), Ok(()));
744                    });
745                });
746            }
747        }
748
749        // --- Handle Receive ---
750        if self.registers.fifointstat.is_set(FIFOINTSTAT::RXLVL) {
751            if self.rx_status.get() == UARTStateRX::Receiving {
752                if self.uart_is_readable() && self.rx_position.get() < self.rx_len.get() {
753                    let byte = self.receive_byte();
754                    let pos = self.rx_position.get();
755
756                    self.rx_buffer.map(|buf| {
757                        buf[pos] = byte;
758                    });
759                    self.rx_position.set(pos + 1);
760
761                    // If buffer is complete, finish and notify client.
762                    if self.rx_position.get() == self.rx_len.get() {
763                        self.disable_receive_interrupt();
764                        self.rx_status.set(UARTStateRX::Idle);
765
766                        self.rx_client.map(|client| {
767                            if let Some(buf) = self.rx_buffer.take() {
768                                client.received_buffer(
769                                    buf,
770                                    self.rx_position.get(),
771                                    Ok(()),
772                                    hil::uart::Error::None,
773                                );
774                            }
775                        });
776                    }
777                }
778            }
779            // If no receive is active, ignore spurious RX level interrupts.
780        }
781    }
782
783    fn fill_fifo(&self) {
784        self.tx_buffer.map(|buf| {
785            while self.uart_is_writable() && self.tx_position.get() < self.tx_len.get() {
786                let byte = buf[self.tx_position.get()];
787                self.send_byte(byte);
788                self.tx_position.set(self.tx_position.get() + 1);
789            }
790        });
791    }
792
793    pub fn is_configured(&self) -> bool {
794        self.registers.cfg.is_set(CFG::ENABLE)
795            && (self.registers.fifocfg.is_set(FIFOCFG::ENABLERX)
796                || self.registers.fifocfg.is_set(FIFOCFG::ENABLETX))
797    }
798
799    pub fn get_stat_raw(&self) -> u32 {
800        self.registers.stat.get()
801    }
802
803    pub fn get_fifostat_raw(&self) -> u32 {
804        self.registers.fifostat.get()
805    }
806
807    pub fn clear_fifo_errors(&self) {
808        self.registers
809            .fifostat
810            .write(FIFOSTAT::TXERR::SET + FIFOSTAT::RXERR::SET);
811
812        self.registers.stat.write(
813            STAT::DELTACTS::SET
814                + STAT::FRAMERRINT::SET
815                + STAT::PARITYERRINT::SET
816                + STAT::RXBRK::SET,
817        );
818    }
819
820    pub fn clear_status_flags_and_fifos(&self) {
821        self.registers.stat.write(
822            STAT::DELTACTS::SET
823                + STAT::FRAMERRINT::SET
824                + STAT::PARITYERRINT::SET
825                + STAT::RXBRK::SET,
826        );
827
828        self.registers
829            .fifocfg
830            .modify(FIFOCFG::EMPTYTX::SET + FIFOCFG::EMPTYRX::SET);
831    }
832}
833
834impl Configure for Uart<'_> {
835    fn configure(&self, params: Parameters) -> Result<(), ErrorCode> {
836        let clock_source = self.uart_clock_source.get();
837        let frg_id = FrgId::from_u32(self.instance.into()).ok_or(ErrorCode::INVAL)?;
838        self.clocks.setup_uart_clock(frg_id, clock_source);
839        self.flexcomm.configure_for_uart();
840
841        // --- Disable USART before configuration ---
842        self.registers.cfg.modify(CFG::ENABLE::CLEAR);
843
844        let clk = self.clocks.get_frg_clock_frequency(clock_source);
845        let brg_val = (clk / (16 * params.baud_rate)).saturating_sub(1);
846        if brg_val > 0xFFFF {
847            return Err(ErrorCode::INVAL); // Baud rate not possible
848        }
849
850        self.registers.osr.set(15);
851        self.registers.brg.set(51);
852
853        // --- Configure Frame Format (width, parity, stop bits) ---
854        let datalen = match params.width {
855            Width::Seven => CFG::DATALEN::_7BitDataLength,
856            Width::Eight => CFG::DATALEN::_8BitDataLength,
857            _ => return Err(ErrorCode::NOSUPPORT), // 6 and 9 bit not handled here
858        };
859
860        let paritysel = match params.parity {
861            Parity::None => CFG::PARITYSEL::NO_PARITY,
862            Parity::Odd => CFG::PARITYSEL::ODD_PARITY,
863            Parity::Even => CFG::PARITYSEL::EVEN_PARITY,
864        };
865
866        let stoplen = match params.stop_bits {
867            StopBits::One => CFG::STOPLEN::_1StopBit,
868            StopBits::Two => CFG::STOPLEN::_2StopBits,
869        };
870
871        // Write all configuration bits at once
872        self.registers.cfg.write(datalen + paritysel + stoplen);
873
874        // --- Configure and Enable FIFOs ---
875        // Clear any old data
876        self.registers
877            .fifocfg
878            .modify(FIFOCFG::EMPTYTX::SET + FIFOCFG::EMPTYRX::SET);
879        // Enable both TX and RX FIFOs
880        self.registers
881            .fifocfg
882            .modify(FIFOCFG::ENABLETX::SET + FIFOCFG::ENABLERX::SET);
883        // Set interrupt trigger levels.
884        self.registers
885            .fifotrig
886            .write(FIFOTRIG::TXLVL.val(1) + FIFOTRIG::RXLVL.val(0));
887
888        // --- Re-enable USART ---
889        self.registers.cfg.modify(CFG::ENABLE::SET);
890
891        // A short busy-wait loop is required to allow the peripheral clock
892        // to propagate and the internal logic to settle after being re-enabled
893        for _ in 0..1500 {
894            cortexm33::support::nop();
895        }
896
897        Ok(())
898    }
899}
900
901impl<'a> Transmit<'a> for Uart<'a> {
902    fn set_transmit_client(&self, client: &'a dyn TransmitClient) {
903        self.tx_client.set(client);
904    }
905
906    fn transmit_buffer(
907        &self,
908        tx_buffer: &'static mut [u8],
909        tx_len: usize,
910    ) -> Result<(), (ErrorCode, &'static mut [u8])> {
911        if self.tx_status.get() == UARTStateTX::Idle {
912            if tx_len <= tx_buffer.len() {
913                self.tx_buffer.replace(tx_buffer);
914                self.tx_position.set(0);
915                self.tx_len.set(tx_len);
916                self.tx_status.set(UARTStateTX::Transmitting);
917
918                self.fill_fifo();
919
920                if self.tx_position.get() == self.tx_len.get() {
921                    // The entire message fit in the FIFO at once.
922                    // Move directly to the "finishing" state.
923                    self.set_interrupts_for_finishing();
924                } else {
925                    // There's more data to send.
926                    // Go to the "transmitting" state.
927                    self.set_interrupts_for_transmitting();
928                }
929                Ok(())
930            } else {
931                Err((ErrorCode::SIZE, tx_buffer))
932            }
933        } else {
934            Err((ErrorCode::BUSY, tx_buffer))
935        }
936    }
937
938    fn transmit_word(&self, _word: u32) -> Result<(), ErrorCode> {
939        Err(ErrorCode::FAIL)
940    }
941
942    fn transmit_abort(&self) -> Result<(), ErrorCode> {
943        if self.tx_status.get() != UARTStateTX::Idle {
944            self.disable_all_tx_interrupts();
945            self.tx_status.set(UARTStateTX::AbortRequested);
946
947            Err(ErrorCode::BUSY)
948        } else {
949            Ok(())
950        }
951    }
952}
953
954impl<'a> Receive<'a> for Uart<'a> {
955    fn set_receive_client(&self, client: &'a dyn ReceiveClient) {
956        self.rx_client.set(client);
957    }
958
959    fn receive_buffer(
960        &self,
961        rx_buffer: &'static mut [u8],
962        rx_len: usize,
963    ) -> Result<(), (ErrorCode, &'static mut [u8])> {
964        // Check if we are already in the middle of a receive operation.
965        if self.rx_status.get() != UARTStateRX::Idle {
966            return Err((ErrorCode::BUSY, rx_buffer));
967        }
968
969        // Check if the requested length is valid for the provided buffer.
970        if rx_len > rx_buffer.len() {
971            return Err((ErrorCode::SIZE, rx_buffer));
972        }
973
974        self.rx_buffer.replace(rx_buffer);
975
976        // Set up the state for the interrupt handler.
977        self.rx_position.set(0);
978        self.rx_len.set(rx_len);
979        self.rx_status.set(UARTStateRX::Receiving);
980
981        // Enable the hardware interrupt that fires when data arrives.
982        self.enable_receive_interrupt();
983
984        Ok(())
985    }
986
987    fn receive_word(&self) -> Result<(), ErrorCode> {
988        Err(ErrorCode::FAIL)
989    }
990
991    fn receive_abort(&self) -> Result<(), ErrorCode> {
992        if self.rx_status.get() != UARTStateRX::Idle {
993            self.disable_receive_interrupt();
994            self.rx_status.set(UARTStateRX::AbortRequested);
995
996            Err(ErrorCode::BUSY)
997        } else {
998            Ok(())
999        }
1000    }
1001}