libxr
Embedded C++ framework for bare-metal, RTOS and Linux
Loading...
Searching...
No Matches
mspm0_uart.cpp
1#include "mspm0_uart.hpp"
2
3#include <algorithm>
4#include <cstdint>
5#include <limits>
6
7using namespace LibXR;
8
9namespace
10{
11
12constexpr uint64_t UART_UINT32_MAX = 0xFFFFFFFFULL;
13constexpr uint64_t UART_BAUD_DIVISOR_MIN = 1ULL << 6U;
14constexpr uint64_t UART_BAUD_DIVISOR_MAX = 0xFFFFULL << 6U;
15constexpr DL_DMA_Config UART_DMA_TX_CONFIG = {
16 .trigger = 0U,
17 .triggerType = DL_DMA_TRIGGER_TYPE_EXTERNAL,
18 .transferMode = DL_DMA_SINGLE_TRANSFER_MODE,
19 .extendedMode = DL_DMA_NORMAL_MODE,
20 .srcWidth = DL_DMA_WIDTH_BYTE,
21 .destWidth = DL_DMA_WIDTH_BYTE,
22 .srcIncrement = DL_DMA_ADDR_INCREMENT,
23 .destIncrement = DL_DMA_ADDR_UNCHANGED,
24};
25
26#if defined(DEVICE_HAS_DMA_FULL_CHANNEL)
27constexpr DL_DMA_Config UART_DMA_RX_CONFIG = {
28 .trigger = 0U,
29 .triggerType = DL_DMA_TRIGGER_TYPE_EXTERNAL,
30 .transferMode = DL_DMA_FULL_CH_REPEAT_SINGLE_TRANSFER_MODE,
31 .extendedMode = DL_DMA_NORMAL_MODE,
32 .srcWidth = DL_DMA_WIDTH_BYTE,
33 .destWidth = DL_DMA_WIDTH_BYTE,
34 .srcIncrement = DL_DMA_ADDR_UNCHANGED,
35 .destIncrement = DL_DMA_ADDR_INCREMENT,
36};
37#endif
38
39// 校验 DriverLib 分频算式及寄存器可表示范围 / Check divider arithmetic and register
40// range.
41bool BaudRateRepresentable(uint32_t clock_freq, uint32_t baudrate)
42{
43 if (baudrate == 0U || baudrate > (UART_UINT32_MAX / 16U))
44 {
45 return false;
46 }
47
48 const uint64_t clock = clock_freq;
49 const uint64_t baud = baudrate;
50 uint64_t divisor = 0U;
51 if ((baud * 8U) > clock)
52 {
53 if (clock > (UART_UINT32_MAX / 64U))
54 {
55 return false;
56 }
57 divisor = (clock * 64U) / (baud * 3U);
58 }
59 else if ((baud * 16U) > clock)
60 {
61 if (clock > (UART_UINT32_MAX / 8U))
62 {
63 return false;
64 }
65 const uint64_t half_baud = baud / 2U;
66 if (half_baud == 0U)
67 {
68 return false;
69 }
70 divisor = (((clock * 8U) / half_baud) + 1U) / 2U;
71 }
72 else
73 {
74 if (clock > (UART_UINT32_MAX / 8U))
75 {
76 return false;
77 }
78 divisor = (((clock * 8U) / baud) + 1U) / 2U;
79 }
80
81 return divisor >= UART_BAUD_DIVISOR_MIN && divisor <= UART_BAUD_DIVISOR_MAX;
82}
83
84// 间隔阈值覆盖最长帧内高电平和一个完整字符 / Cover the longest high span plus one
85// character.
86uint64_t GapCompare(uint32_t clock_freq, UART::Configuration config)
87{
88 if (clock_freq == 0U || config.baudrate == 0U)
89 {
90 return 0U;
91 }
92
93 const uint64_t parity_bits = config.parity == UART::Parity::NO_PARITY ? 0U : 1U;
94 const uint64_t high_bits = config.data_bits + parity_bits + config.stop_bits;
95 const uint64_t gap_bits = high_bits + (1U + high_bits);
96 const uint64_t numerator = static_cast<uint64_t>(clock_freq) * gap_bits;
97 return (numerator / config.baudrate) + ((numerator % config.baudrate) != 0U ? 1U : 0U);
98}
99
100} // namespace
101
102MSPM0UART* MSPM0UART::instance_map_[MAX_UART_INSTANCES] = {nullptr};
103
104MSPM0UART::MSPM0UART(Resources res, RawData tx_dma_storage, RawData rx_dma_storage,
105 uint32_t tx_queue_size, uint32_t rx_queue_capacity,
106 UART::Configuration config)
107 : UART(&_read_port, &_write_port),
108 _read_port(rx_queue_capacity),
109 _write_port(tx_queue_size, tx_dma_storage.size_ / 2U),
110 res_(res),
111 tx_dma_storage_(tx_dma_storage),
112 rx_dma_storage_(rx_dma_storage),
113 tx_half_size_(tx_dma_storage.size_ / 2U)
114{
115 ASSERT(res_.instance != nullptr);
116 ASSERT(res_.clock_freq > 0U);
117 ASSERT(res_.index < MAX_UART_INSTANCES);
118 ASSERT(res_.index == ResolveIndex(res_.irqn));
119 ASSERT(instance_map_[res_.index] == nullptr);
120 ASSERT(tx_dma_storage_.addr_ != nullptr);
121 ASSERT(tx_dma_storage_.size_ > 1U);
122 ASSERT((tx_dma_storage_.size_ % 2U) == 0U);
123 ASSERT((reinterpret_cast<uintptr_t>(tx_dma_storage_.addr_) % alignof(size_t)) == 0U);
124 ASSERT((tx_dma_storage_.size_ % (2U * alignof(size_t))) == 0U);
125 ASSERT(tx_half_size_ <= MSPM0_UART_DMA_MAX_TRANSFER_SIZE);
126 ASSERT(tx_queue_size > 0U);
127 ASSERT(rx_queue_capacity > 0U);
128
129 if (res_.rx_mode == RxMode::EXTEND_DMA)
130 {
131 ASSERT(rx_dma_storage_.addr_ != nullptr);
132 ASSERT(rx_dma_storage_.size_ > 1U);
133 ASSERT((rx_dma_storage_.size_ % 2U) == 0U);
134 ASSERT(rx_dma_storage_.size_ <= MSPM0_UART_DMA_MAX_TRANSFER_SIZE);
135 ASSERT(res_.dma_rx_channel < DMA_SYS_N_DMA_FULL_CHANNEL);
136 }
137 else
138 {
139 ASSERT(rx_dma_storage_.addr_ == nullptr);
140 ASSERT(rx_dma_storage_.size_ == 0U);
141 ASSERT(!res_.rx_half_interrupt);
142 ASSERT(res_.dma_rx_channel == INVALID_DMA_CHANNEL);
143 }
144
145 ASSERT(res_.dma_tx_channel < MAX_DMA_CHANNELS);
146 ASSERT(res_.dma_tx_trigger != 0U);
147 if (res_.rx_mode == RxMode::EXTEND_DMA)
148 {
149 ASSERT(res_.dma_rx_channel < MAX_DMA_CHANNELS);
150 ASSERT(res_.dma_rx_channel != res_.dma_tx_channel);
151 ASSERT(res_.dma_rx_trigger != 0U);
152 ASSERT(res_.dma_rx_trigger != res_.dma_tx_trigger);
153 ASSERT(!res_.rx_half_interrupt || res_.dma_rx_channel < 8U);
154 }
155
156 for (const MSPM0UART* other : instance_map_)
157 {
158 if (other == nullptr)
159 {
160 continue;
161 }
162
163 ASSERT(res_.dma_tx_channel != other->res_.dma_tx_channel);
164 if (other->res_.rx_mode == RxMode::EXTEND_DMA)
165 {
166 ASSERT(res_.dma_tx_channel != other->res_.dma_rx_channel);
167 }
168
169 if (res_.rx_mode == RxMode::EXTEND_DMA)
170 {
171 ASSERT(res_.dma_rx_channel != other->res_.dma_tx_channel);
172 if (other->res_.rx_mode == RxMode::EXTEND_DMA)
173 {
174 ASSERT(res_.dma_rx_channel != other->res_.dma_rx_channel);
175 }
176 }
177 }
178
179 ASSERT(ValidateConfig(config) == ErrorCode::OK);
180 _read_port.SetOwner(this);
181 _write_port = WriteFun;
182
183 NVIC_DisableIRQ(res_.irqn);
184 NVIC_ClearPendingIRQ(res_.irqn);
185 ConfigureTxDma();
186 ApplyConfig(config);
187 if (res_.rx_mode == RxMode::EXTEND_DMA)
188 {
189 ConfigureRxDma();
190 }
191 instance_map_[res_.index] = this;
192 StartDataPath();
193
194 // 优先级低于 SysTick 时基 / Below the SysTick timebase.
195 NVIC_SetPriority(res_.irqn, 1U);
196 NVIC_EnableIRQ(res_.irqn);
197}
198
199ErrorCode MSPM0UART::ValidateConfig(UART::Configuration config) const
200{
201 if (!BaudRateRepresentable(res_.clock_freq, config.baudrate) || config.data_bits < 5U ||
202 config.data_bits > 8U || (config.stop_bits != 1U && config.stop_bits != 2U))
203 {
204 return ErrorCode::ARG_ERR;
205 }
206 if (config.parity != UART::Parity::NO_PARITY && config.parity != UART::Parity::EVEN &&
207 config.parity != UART::Parity::ODD)
208 {
209 return ErrorCode::ARG_ERR;
210 }
211 if (res_.rx_mode == RxMode::EXTEND_DMA)
212 {
213 const uint64_t gap = GapCompare(res_.clock_freq, config);
214 if (gap == 0U || gap > std::numeric_limits<uint16_t>::max())
215 {
216 return ErrorCode::ARG_ERR;
217 }
218 }
219 return ErrorCode::OK;
220}
221
223 uint32_t baudrate)
224{
225 ASSERT(instance != nullptr);
226 ASSERT(baudrate > 0U);
227
228 UART::Configuration config = {baudrate, UART::Parity::NO_PARITY, 8U, 1U};
229 switch (DL_UART_getWordLength(instance))
230 {
231 case DL_UART_WORD_LENGTH_5_BITS:
232 config.data_bits = 5U;
233 break;
234 case DL_UART_WORD_LENGTH_6_BITS:
235 config.data_bits = 6U;
236 break;
237 case DL_UART_WORD_LENGTH_7_BITS:
238 config.data_bits = 7U;
239 break;
240 case DL_UART_WORD_LENGTH_8_BITS:
241 default:
242 config.data_bits = 8U;
243 break;
244 }
245
246 switch (DL_UART_getParityMode(instance))
247 {
248 case DL_UART_PARITY_NONE:
250 break;
251 case DL_UART_PARITY_EVEN:
252 config.parity = UART::Parity::EVEN;
253 break;
254 case DL_UART_PARITY_ODD:
255 config.parity = UART::Parity::ODD;
256 break;
257 default:
258 ASSERT(false);
259 break;
260 }
261 config.stop_bits = DL_UART_getStopBits(instance) == DL_UART_STOP_BITS_TWO ? 2U : 1U;
262 return config;
263}
264
266{
267 const ErrorCode validation = ValidateConfig(config);
268 if (validation != ErrorCode::OK)
269 {
270 return validation;
271 }
272
273 ConfigState expected = ConfigState::EMPTY;
274 if (!config_state_.compare_exchange_strong(expected, ConfigState::RESERVED,
275 std::memory_order_acq_rel,
276 std::memory_order_acquire))
277 {
278 return ErrorCode::BUSY;
279 }
280
281 // 配置内容通过下方事件发布,由处理器将槽标记为 PUBLISHED。
282 // Publish the payload through the event; the service marks the slot PUBLISHED.
283 pending_config_ = config;
284 service_.Invoke(EVENT_CONFIG, in_isr, [this](uint32_t events, bool owner_in_isr)
285 { HandleService(events, owner_in_isr); });
286 return ErrorCode::OK;
287}
288
289void MSPM0UART::WriteFun(WritePort& port, bool in_isr)
290{
291 auto* uart = LibXR::ContainerOf(&port, &MSPM0UART::_write_port);
292 uart->service_.Invoke(EVENT_WRITE, in_isr, [uart](uint32_t events, bool owner_in_isr)
293 { uart->HandleService(events, owner_in_isr); });
294}
295
296void MSPM0UART::NotifyReadSpace(bool in_isr)
297{
298 service_.Invoke(EVENT_RX_WORK, in_isr, [this](uint32_t events, bool owner_in_isr)
299 { HandleService(events, owner_in_isr); });
300}
301
302void MSPM0UART::HandleService(uint32_t events, bool in_isr)
303{
304 if ((events & EVENT_CONFIG) != 0U)
305 {
306 DEV_ASSERT_FROM_CALLBACK(
307 config_state_.load(std::memory_order_acquire) == ConfigState::RESERVED, in_isr);
308 config_state_.store(ConfigState::PUBLISHED, std::memory_order_release);
309 }
310
311 if ((events & EVENT_DMA_DONE_TX) != 0U)
312 {
313 HandleTxDone(in_isr);
314 }
315
316 if ((events & EVENT_RX_WORK) != 0U)
317 {
318 HandleRxWork(in_isr);
319 }
320
321 if ((events & EVENT_EOT_DONE) != 0U)
322 {
323 tx_draining_ = false;
324 DL_UART_disableInterrupt(res_.instance, EOT_INTERRUPT_MASK);
325 }
326
327 if ((events & (EVENT_CONFIG | EVENT_DMA_DONE_TX | EVENT_EOT_DONE | EVENT_RX_WORK)) !=
328 0U)
329 {
330 TryApplyPublishedConfig(in_isr);
331 }
332
333 if (events != 0U && config_state_.load(std::memory_order_acquire) == ConfigState::EMPTY)
334 {
335 if ((events & (EVENT_WRITE | EVENT_DMA_DONE_TX | EVENT_CONFIG | EVENT_EOT_DONE)) !=
336 0U)
337 {
338 FillTx(in_isr);
339 }
340 }
341}
342
343void MSPM0UART::FillTx(bool in_isr)
344{
345 while (config_state_.load(std::memory_order_acquire) == ConfigState::EMPTY)
346 {
347 if (active_half_ < 0)
348 {
349 for (uint8_t half = 0U; half < 2U; ++half)
350 {
351 if (tx_half_size_used_[half] != 0U)
352 {
353 if (config_state_.load(std::memory_order_acquire) != ConfigState::EMPTY)
354 {
355 return;
356 }
357 active_half_ = static_cast<int8_t>(half);
358 StartTxDma(half, tx_half_size_used_[half]);
359 break;
360 }
361 }
362 }
363
364 uint8_t free_half = INVALID_DMA_CHANNEL;
365 for (uint8_t i = 0U; i < 2U; ++i)
366 {
367 if (tx_half_size_used_[i] == 0U)
368 {
369 free_half = i;
370 break;
371 }
372 }
373 if (free_half == INVALID_DMA_CHANNEL)
374 {
375 return;
376 }
377
378 size_t size = 0U;
379 {
380 auto queue = _write_port.GetWriteQueue(in_isr);
381 if (queue.Empty())
382 {
383 return;
384 }
385 if (config_state_.load(std::memory_order_acquire) != ConfigState::EMPTY)
386 {
387 return;
388 }
389
390 size = queue.AvailableSize();
391 DEV_ASSERT_FROM_CALLBACK(size > 0U && size <= tx_half_size_, in_isr);
392 queue.PopAll(TxHalf(free_half));
393 tx_half_size_used_[free_half] = size;
394 }
395
396 if (active_half_ < 0 &&
397 config_state_.load(std::memory_order_acquire) == ConfigState::EMPTY)
398 {
399 active_half_ = static_cast<int8_t>(free_half);
400 StartTxDma(free_half, size);
401 }
402 }
403}
404
405void MSPM0UART::HandleTxDone(bool in_isr)
406{
407 DEV_ASSERT_FROM_CALLBACK(active_half_ >= 0 && active_half_ < 2, in_isr);
408 const uint8_t completed = static_cast<uint8_t>(active_half_);
409 tx_half_size_used_[completed] = 0U;
410 active_half_ = -1;
411
412 const uint8_t next = completed ^ 1U;
413 if (tx_half_size_used_[next] != 0U &&
414 config_state_.load(std::memory_order_acquire) == ConfigState::EMPTY)
415 {
416 active_half_ = static_cast<int8_t>(next);
417 StartTxDma(next, tx_half_size_used_[next]);
418 }
419 else
420 {
421 DL_UART_disableInterrupt(res_.instance, TX_DONE_INTERRUPT_MASK);
422 DL_UART_disableDMATransmitEvent(res_.instance);
423 }
424}
425
426void MSPM0UART::HandleRxWork(bool in_isr)
427{
428 if (res_.rx_mode == RxMode::MAIN_BYTE_IRQ)
429 {
430 HandleMainRx(in_isr);
431 }
432 else
433 {
434 HandleExtendRx(in_isr);
435 }
436}
437
438void MSPM0UART::HandleMainRx(bool in_isr)
439{
440 auto queue = _read_port.GetReadQueue(in_isr);
441 if (queue.EmptySize() != 0U)
442 {
443 DL_UART_enableInterrupt(res_.instance, RX_INTERRUPT_MASK);
444 }
445
446 while (!DL_UART_isRXFIFOEmpty(res_.instance))
447 {
448 if (queue.EmptySize() == 0U)
449 {
450 DL_UART_disableInterrupt(res_.instance, RX_INTERRUPT_MASK);
451 break;
452 }
453
454 const uint8_t byte = DL_UART_receiveData(res_.instance);
455 [[maybe_unused]] const auto push_batch_result = queue.PushBatch(&byte, 1U);
456 DEV_ASSERT_FROM_CALLBACK(push_batch_result == ErrorCode::OK, in_isr);
457 }
458 queue.Publish();
459}
460
461void MSPM0UART::HandleExtendRx(bool in_isr)
462{
463 const size_t capacity = RxCapacity();
464 DEV_ASSERT_FROM_CALLBACK(capacity > 1U, in_isr);
465
466 const uint32_t remaining = DL_DMA_getTransferSize(DMA, res_.dma_rx_channel);
467 DEV_ASSERT_FROM_CALLBACK(remaining <= capacity, in_isr);
468
469 const size_t position = remaining == 0U ? capacity : capacity - remaining;
470 const size_t cursor = rx_dma_cursor_;
471 DEV_ASSERT_FROM_CALLBACK(cursor < capacity, in_isr);
472
473 const size_t first_size = position >= cursor ? position - cursor : capacity - cursor;
474 const size_t second_size = position >= cursor ? 0U : position;
475 const size_t observed = first_size + second_size;
476
477 auto queue = _read_port.GetReadQueue(in_isr);
478 size_t accepted = std::min(observed, queue.EmptySize());
479 size_t first_accepted = std::min(first_size, accepted);
480 if (first_accepted != 0U)
481 {
482 auto* source = static_cast<const uint8_t*>(rx_dma_storage_.addr_) + cursor;
483 [[maybe_unused]] const auto push_batch_result =
484 queue.PushBatch(source, first_accepted);
485 DEV_ASSERT_FROM_CALLBACK(push_batch_result == ErrorCode::OK, in_isr);
486 accepted -= first_accepted;
487 }
488 if (accepted != 0U)
489 {
490 [[maybe_unused]] const auto push_batch_result =
491 queue.PushBatch(static_cast<const uint8_t*>(rx_dma_storage_.addr_), accepted);
492 DEV_ASSERT_FROM_CALLBACK(push_batch_result == ErrorCode::OK, in_isr);
493 }
494
495 // 超出软件容量的尾部作为溢出丢弃,回调前先推进游标。
496 // Drop excess bytes and advance the cursor before callbacks can run.
497 rx_dma_cursor_ = position == capacity ? 0U : position;
498 queue.Publish();
499}
500
501void MSPM0UART::HandleUartInterrupt()
502{
503 constexpr uint32_t MASK = RX_ERROR_INTERRUPT_MASK | RX_INTERRUPT_MASK |
504 RX_TIMEOUT_INTERRUPT_MASK | TX_DONE_INTERRUPT_MASK |
505 EOT_INTERRUPT_MASK | RX_GAP_INTERRUPT_MASK;
506 const uint32_t pending = DL_UART_getEnabledInterruptStatus(res_.instance, MASK);
507 if (pending == 0U)
508 {
509 return;
510 }
511
512 if ((pending & RX_TIMEOUT_INTERRUPT_MASK) != 0U)
513 {
514 DL_UART_disableInterrupt(res_.instance, RX_TIMEOUT_INTERRUPT_MASK);
515 }
516 DL_UART_clearInterruptStatus(res_.instance, pending & MASK);
517
518 uint32_t events = 0U;
519 if ((pending &
520 (RX_INTERRUPT_MASK | RX_TIMEOUT_INTERRUPT_MASK | RX_GAP_INTERRUPT_MASK)) != 0U)
521 {
522 events |= EVENT_RX_WORK;
523 }
524 if ((pending & TX_DONE_INTERRUPT_MASK) != 0U)
525 {
526 events |= EVENT_DMA_DONE_TX;
527 }
528 if ((pending & EOT_INTERRUPT_MASK) != 0U)
529 {
530 events |= EVENT_EOT_DONE;
531 }
532
533 if (events != 0U)
534 {
535 service_.Invoke(events, true, [this](uint32_t handled, bool in_isr)
536 { HandleService(handled, in_isr); });
537 }
538}
539
540void MSPM0UART::HandleRxDmaInterrupt()
541{
542 service_.Invoke(EVENT_RX_WORK, true, [this](uint32_t events, bool in_isr)
543 { HandleService(events, in_isr); });
544}
545
546void MSPM0UART::OnInterrupt(uint8_t index)
547{
548 if (index < MAX_UART_INSTANCES && instance_map_[index] != nullptr)
549 {
550 instance_map_[index]->HandleUartInterrupt();
551 }
552}
553
555{
556 uint32_t owned_mask = 0U;
557 for (MSPM0UART* uart : instance_map_)
558 {
559 if (uart != nullptr && uart->res_.rx_mode == RxMode::EXTEND_DMA)
560 {
561 owned_mask |= DmaRawMask(uart->res_.dma_rx_channel, uart->res_.rx_half_interrupt);
562 }
563 }
564
565 if (owned_mask == 0U)
566 {
567 return;
568 }
569
570 const uint32_t pending = DL_DMA_getEnabledInterruptStatus(DMA, owned_mask);
571 for (MSPM0UART* uart : instance_map_)
572 {
573 if (uart == nullptr || uart->res_.rx_mode != RxMode::EXTEND_DMA)
574 {
575 continue;
576 }
577
578 const uint32_t mask =
579 DmaRawMask(uart->res_.dma_rx_channel, uart->res_.rx_half_interrupt);
580 const uint32_t hit = pending & mask;
581 if (hit != 0U)
582 {
583 DL_DMA_clearInterruptStatus(DMA, hit);
584 uart->HandleRxDmaInterrupt();
585 }
586 }
587 __DSB();
588}
589
591{
592 DEV_ASSERT_FROM_CALLBACK(owner_ != nullptr, in_isr);
593 owner_->NotifyReadSpace(in_isr);
594}
595
596void MSPM0UART::ConfigureTxDma()
597{
598 DL_DMA_Config config = UART_DMA_TX_CONFIG;
599 config.trigger = res_.dma_tx_trigger;
600 DL_DMA_disableChannel(DMA, res_.dma_tx_channel);
601 DL_DMA_clearInterruptStatus(DMA, DmaCompleteMask(res_.dma_tx_channel));
602 DL_DMA_initChannel(DMA, res_.dma_tx_channel, &config);
603}
604
605void MSPM0UART::ConfigureRxDma()
606{
607#if defined(DEVICE_HAS_DMA_FULL_CHANNEL)
608 if (res_.rx_mode != RxMode::EXTEND_DMA)
609 {
610 return;
611 }
612
613 DL_DMA_Config config = UART_DMA_RX_CONFIG;
614 config.trigger = res_.dma_rx_trigger;
615 DL_DMA_disableChannel(DMA, res_.dma_rx_channel);
616 DL_DMA_initChannel(DMA, res_.dma_rx_channel, &config);
617 DL_DMA_setSrcAddr(
618 DMA, res_.dma_rx_channel,
619 static_cast<uint32_t>(reinterpret_cast<uintptr_t>(&res_.instance->RXDATA)));
620 DL_DMA_setDestAddr(
621 DMA, res_.dma_rx_channel,
622 static_cast<uint32_t>(reinterpret_cast<uintptr_t>(rx_dma_storage_.addr_)));
623 DL_DMA_setTransferSize(DMA, res_.dma_rx_channel,
624 static_cast<uint16_t>(rx_dma_storage_.size_));
625 if (res_.rx_half_interrupt)
626 {
627 DL_DMA_Full_Ch_setEarlyInterruptThreshold(DMA, res_.dma_rx_channel,
628 DL_DMA_EARLY_INTERRUPT_THRESHOLD_HALF);
629 }
630#else
631 ASSERT(false);
632#endif
633}
634
635void MSPM0UART::ApplyConfig(UART::Configuration config)
636{
637 // 调用方保证发送已结束(无发送或已收到 EOT);BUSY 也包含接收,不在这里等待。
638 // 保留 FEN,避免反复切换 FIFO 暴露旧的 RX 内容。
639 // The caller guarantees that transmission has ended (nothing sent, or EOT seen).
640 // BUSY also covers reception and is not waited on here. Keep FEN unchanged:
641 // toggling FIFO mode on G3507 can expose previously consumed RX bytes.
642 DL_UART_disable(res_.instance);
643
644 DL_UART_WORD_LENGTH word_length = DL_UART_WORD_LENGTH_8_BITS;
645 switch (config.data_bits)
646 {
647 case 5U:
648 word_length = DL_UART_WORD_LENGTH_5_BITS;
649 break;
650 case 6U:
651 word_length = DL_UART_WORD_LENGTH_6_BITS;
652 break;
653 case 7U:
654 word_length = DL_UART_WORD_LENGTH_7_BITS;
655 break;
656 case 8U:
657 break;
658 default:
659 DEV_ASSERT(false);
660 break;
661 }
662
663 DL_UART_PARITY parity = DL_UART_PARITY_NONE;
664 if (config.parity == UART::Parity::EVEN)
665 {
666 parity = DL_UART_PARITY_EVEN;
667 }
668 else if (config.parity == UART::Parity::ODD)
669 {
670 parity = DL_UART_PARITY_ODD;
671 }
672
673 DL_UART_setWordLength(res_.instance, word_length);
674 DL_UART_setParityMode(res_.instance, parity);
675 DL_UART_setStopBits(res_.instance, config.stop_bits == 2U ? DL_UART_STOP_BITS_TWO
676 : DL_UART_STOP_BITS_ONE);
677 DL_UART_setCommunicationMode(res_.instance, DL_UART_MODE_NORMAL);
678 DL_UART_setDirection(res_.instance, DL_UART_DIRECTION_TX_RX);
679 DL_UART_enableFIFOs(res_.instance);
680 DL_UART_setTXFIFOThreshold(res_.instance, DL_UART_TX_FIFO_LEVEL_ONE_ENTRY);
681 DL_UART_setRXFIFOThreshold(res_.instance, DL_UART_RX_FIFO_LEVEL_ONE_ENTRY);
682 DL_UART_setRXInterruptTimeout(res_.instance, 0U);
683 DL_UART_configBaudRate(res_.instance, res_.clock_freq, config.baudrate);
684
685 if (res_.rx_mode == RxMode::EXTEND_DMA)
686 {
687 DL_UART_setLINCounterValue(res_.instance, 0U);
688 DL_UART_setLINCounterCompareValue(
689 res_.instance, static_cast<uint16_t>(GapCompare(res_.clock_freq, config)));
690 DL_UART_enableLINCounterCompareMatch(res_.instance);
691 DL_UART_disableLINCountWhileLow(res_.instance);
692 DL_UART_enableLINCounterClearOnFallingEdge(res_.instance);
693 DL_UART_enableLINCounter(res_.instance);
694 }
695}
696
697void MSPM0UART::StartDataPath()
698{
699 DL_UART_disableInterrupt(res_.instance, 0xFFFFFFFFU);
700 DL_UART_clearInterruptStatus(res_.instance, 0xFFFFFFFFU);
701 DL_UART_clearDMATransmitEventStatus(res_.instance);
702 DL_UART_clearDMAReceiveEventStatus(res_.instance, DL_UART_DMA_INTERRUPT_RX);
703 DL_UART_disableDMAReceiveEvent(res_.instance, DL_UART_DMA_INTERRUPT_RX);
704 DL_UART_disableDMATransmitEvent(res_.instance);
705 DL_UART_enableInterrupt(res_.instance, RX_ERROR_INTERRUPT_MASK);
706
707 if (res_.rx_mode == RxMode::MAIN_BYTE_IRQ)
708 {
709 DL_UART_enableInterrupt(res_.instance, RX_INTERRUPT_MASK);
710 }
711 else
712 {
713 const uint32_t dma_mask = DmaRawMask(res_.dma_rx_channel, res_.rx_half_interrupt);
714 DL_DMA_clearInterruptStatus(DMA, dma_mask);
715 DL_DMA_enableInterrupt(DMA, dma_mask);
716 DL_DMA_enableChannel(DMA, res_.dma_rx_channel);
717 DL_UART_enableInterrupt(res_.instance, RX_GAP_INTERRUPT_MASK);
718 DL_UART_enableDMAReceiveEvent(res_.instance, DL_UART_DMA_INTERRUPT_RX);
719 rx_dma_cursor_ = 0U;
720 }
721
722 __DMB();
723 DL_UART_enable(res_.instance);
724}
725
726void MSPM0UART::StopDataPath()
727{
728 DL_UART_disableInterrupt(res_.instance, RX_ERROR_INTERRUPT_MASK | RX_INTERRUPT_MASK |
729 RX_TIMEOUT_INTERRUPT_MASK |
730 TX_DONE_INTERRUPT_MASK |
731 EOT_INTERRUPT_MASK | RX_GAP_INTERRUPT_MASK);
732 DL_UART_disableDMAReceiveEvent(res_.instance, DL_UART_DMA_INTERRUPT_RX);
733 DL_UART_disableDMATransmitEvent(res_.instance);
734 if (res_.rx_mode == RxMode::EXTEND_DMA)
735 {
736 DL_DMA_disableChannel(DMA, res_.dma_rx_channel);
737 DL_DMA_disableInterrupt(DMA, DmaRawMask(res_.dma_rx_channel, res_.rx_half_interrupt));
738 }
739 DL_UART_disable(res_.instance);
740}
741
742void MSPM0UART::DiscardRxFifo()
743{
744 while (!DL_UART_isRXFIFOEmpty(res_.instance))
745 {
746 (void)DL_UART_receiveData(res_.instance);
747 }
748}
749
750void MSPM0UART::StartTxDma(uint8_t half, size_t size)
751{
752 DEV_ASSERT(half < 2U);
753 DEV_ASSERT(size > 0U && size <= tx_half_size_);
754
755 DL_DMA_disableChannel(DMA, res_.dma_tx_channel);
756 DL_DMA_clearInterruptStatus(DMA, DmaCompleteMask(res_.dma_tx_channel));
757 DL_DMA_setSrcAddr(DMA, res_.dma_tx_channel,
758 static_cast<uint32_t>(reinterpret_cast<uintptr_t>(TxHalf(half))));
759 DL_DMA_setDestAddr(
760 DMA, res_.dma_tx_channel,
761 static_cast<uint32_t>(reinterpret_cast<uintptr_t>(&res_.instance->TXDATA)));
762 DL_DMA_setTransferSize(DMA, res_.dma_tx_channel, static_cast<uint16_t>(size));
763 DL_UART_clearInterruptStatus(res_.instance,
764 TX_DONE_INTERRUPT_MASK | EOT_INTERRUPT_MASK);
765 tx_draining_ = true;
766 DL_UART_enableInterrupt(res_.instance, TX_DONE_INTERRUPT_MASK);
767 DL_UART_enableDMATransmitEvent(res_.instance);
768 __DMB();
769 DL_DMA_enableChannel(DMA, res_.dma_tx_channel);
770}
771
772void MSPM0UART::TryApplyPublishedConfig(bool in_isr)
773{
774 if (config_state_.load(std::memory_order_acquire) != ConfigState::PUBLISHED)
775 {
776 return;
777 }
778
779 if (active_half_ >= 0)
780 {
781 return;
782 }
783
784 if (tx_draining_)
785 {
786 // DMA 已结束但最后的字节可能仍在发送;EOT 置位后(包括开中断前已置位)再配置。
787 // 接收不参与判断,进行中的字节随配置丢弃。
788 // DMA has finished but the last bytes may still be shifting out; configure once
789 // EOT is set, including when it was set before the interrupt is enabled. RX is
790 // not considered; a byte being received is dropped with the configuration.
791 DL_UART_enableInterrupt(res_.instance, EOT_INTERRUPT_MASK);
792 return;
793 }
794
795 const UART::Configuration config = pending_config_;
796 StopDataPath();
797 DiscardRxFifo();
798 ApplyConfig(config);
799 if (res_.rx_mode == RxMode::EXTEND_DMA)
800 {
801 ConfigureRxDma();
802 }
803 config_state_.store(ConfigState::EMPTY, std::memory_order_release);
804 StartDataPath();
805 // 当前处理器仍持有执行权,会在本轮结束后处理这些通知。
806 // The active service will process these hints after this pass.
807 service_.Publish(EVENT_WRITE | EVENT_RX_WORK);
808 UNUSED(in_isr);
809}
810
811#if defined(UART0_BASE)
812extern "C" void UART0_IRQHandler(void) { MSPM0UART::OnInterrupt(0U); }
813#endif
814#if defined(UART1_BASE)
815extern "C" void UART1_IRQHandler(void) { MSPM0UART::OnInterrupt(1U); }
816#endif
817#if defined(UART2_BASE)
818extern "C" void UART2_IRQHandler(void) { MSPM0UART::OnInterrupt(2U); }
819#endif
820#if defined(UART3_BASE)
821extern "C" void UART3_IRQHandler(void) { MSPM0UART::OnInterrupt(3U); }
822#endif
823#if defined(UART4_BASE)
824extern "C" void UART4_IRQHandler(void) { MSPM0UART::OnInterrupt(4U); }
825#endif
826#if defined(UART5_BASE)
827extern "C" void UART5_IRQHandler(void) { MSPM0UART::OnInterrupt(5U); }
828#endif
829#if defined(UART6_BASE)
830extern "C" void UART6_IRQHandler(void) { MSPM0UART::OnInterrupt(6U); }
831#endif
832#if defined(UART7_BASE)
833extern "C" void UART7_IRQHandler(void) { MSPM0UART::OnInterrupt(7U); }
834#endif
使用双缓冲 DMA 发送的 MSPM0 串口 / MSPM0 UART with double-buffered DMA TX.
static constexpr uint8_t ResolveIndex(IRQn_Type irqn)
根据 UART 中断号取得实例编号 / Resolve an instance index from its UART IRQ.
static void OnDmaInterrupt()
分派本驱动登记的接收 DMA 中断 / Dispatch registered UART RX DMA interrupts.
static constexpr uint8_t INVALID_DMA_CHANNEL
无 DMA 通道的标记 / Sentinel for no DMA channel.
static void WriteFun(WritePort &port, bool in_isr)
通知已提交的写请求 / Notify released write requests.
ErrorCode SetConfig(UART::Configuration config, bool in_isr=false) override
提交串口配置 / Submit a UART configuration.
static UART::Configuration BuildConfigFromSysCfg(UART_Regs *instance, uint32_t baudrate)
MSPM0UART(Resources res, RawData tx_dma_storage, RawData rx_dma_storage, uint32_t tx_queue_size=5U, uint32_t rx_queue_capacity=128U, UART::Configuration config={115200, UART::Parity::NO_PARITY, 8U, 1U})
构造串口并配置所选 DMA 路径 / Construct the UART and selected DMA paths.
@ EXTEND_DMA
扩展 UART DMA / Extend UART DMA.
@ MAIN_BYTE_IRQ
主 UART 字节中断 / Main UART byte interrupts.
static void OnInterrupt(uint8_t index)
按实例编号分派 UART 中断 / Dispatch a UART IRQ by instance index.
void OnReadQueueSpaceAvailable(bool in_isr) override
发布接收空间可用通知 / Publish RX space availability.
void SetOwner(MSPM0UART *owner)
在串口初始化时绑定后端 / Bind the backend during UART initialization.
可写原始数据视图 / Mutable raw data view
size_t size_
数据字节数 / Data size in bytes
void * addr_
数据起始地址 / Data start address
void Publish()
结束本次写入并通知挂起读 / End production and notify a pending read.
Definition read_port.cpp:42
ReadQueue GetReadQueue(bool in_isr=false)
获取后端接收入队接口 / Obtain the backend RX producer interface.
Definition read_port.cpp:14
bool Invoke(uint32_t events, bool in_isr, Handler &&handler) noexcept
发布事件并尝试取得执行权 / Publish events and attempt to claim execution.
void Publish(uint32_t events) noexcept
为已有或确定会出现的执行者发布事件 / Publish for an active or guaranteed executor.
通用异步收发传输(UART)基类 / Abstract base class for Universal Asynchronous Receiver-Transmitter (UART)
Definition uart.hpp:19
@ NO_PARITY
无校验 / No parity
@ ODD
奇校验 / Odd parity
@ EVEN
偶校验 / Even parity
size_t AvailableSize() const
获取当前队头的剩余长度 / Get the current front remainder.
基于 SPSC 字节队列的写端口 / Write endpoint backed by an SPSC byte queue.
WriteQueue GetWriteQueue(bool in_isr=false)
获取已提交队头的出队接口 / Obtain a consumer interface for the released front.
LibXR 命名空间 / LibXR namespace.
Definition ch32_can.hpp:14
ErrorCode
定义错误码枚举 / Defines an enumeration for error codes
@ BUSY
忙碌 / Busy
@ OK
操作成功 / Operation successful
@ ARG_ERR
参数错误 / Argument error
void(* WriteFun)(WritePort &port, bool in_isr)
写入进度通知函数类型 / Write progress notification function type.
OwnerType * ContainerOf(MemberType *ptr, MemberType OwnerType::*member) noexcept
通过成员指针恢复其所属对象指针 Recover the owning object pointer from a member pointer
由 BSP 提供的 UART 与 DMA 绑定 / UART and DMA bindings supplied by the BSP.
uint8_t dma_rx_channel
接收 FULL-DMA 通道,Main 使用无效编号 / RX full channel, invalid for Main.
RxMode rx_mode
选择的接收路径 / Selected RX path.
uint32_t clock_freq
UART 输入时钟频率 / UART input clock frequency.
uint8_t dma_rx_trigger
UART 接收 DMA 触发源,Main 为零 / RX DMA trigger, zero for Main.
UART_Regs * instance
UART 寄存器 / UART registers.
bool rx_half_interrupt
是否使用接收半传输中断 / Enable RX half-transfer interrupts.
IRQn_Type irqn
UART 中断号 / UART interrupt number.
uint8_t index
ResolveIndex 返回的编号 / Index returned by ResolveIndex.
uint8_t dma_tx_channel
发送 DMA 通道 / TX DMA channel.
uint8_t dma_tx_trigger
UART 发送 DMA 触发源 / UART TX DMA trigger.
UART 配置结构体 / UART configuration structure.
Definition uart.hpp:44
uint8_t stop_bits
停止位长度 / Number of stop bits
Definition uart.hpp:53
uint32_t baudrate
波特率 / Baud rate
Definition uart.hpp:45