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}