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}