libxr
Embedded C++ framework for bare-metal, RTOS and Linux
Loading...
Searching...
No Matches
stm32_uart.cpp
1#include "stm32_uart.hpp"
2
3#include <algorithm>
4
5#include "stm32_dcache.hpp"
6#ifdef HAL_UART_MODULE_ENABLED
7
8using namespace LibXR;
9
10namespace
11{
12
13bool Stm32DataBitsSupported(const UART::Configuration& config)
14{
15 if (config.parity == UART::Parity::NO_PARITY)
16 {
17 return config.data_bits == 8U;
18 }
19
20 return (config.parity == UART::Parity::EVEN || config.parity == UART::Parity::ODD) &&
21 (config.data_bits == 7U || config.data_bits == 8U);
22}
23
24bool Stm32StopBitsSupported(const UART::Configuration& config)
25{
26 return config.stop_bits == 1U || config.stop_bits == 2U;
27}
28
29} // namespace
30
31STM32UART* STM32UART::map[STM32_UART_NUMBER] = {nullptr};
32
33stm32_uart_id_t stm32_uart_get_id(USART_TypeDef* addr)
34{
35 if (addr == nullptr)
36 { // NOLINT
37 return stm32_uart_id_t::STM32_UART_ID_ERROR;
38 }
39#ifdef USART1
40 else if (addr == USART1) // NOLINT
41 {
42 return stm32_uart_id_t::STM32_USART1;
43 }
44#endif
45#ifdef USART2
46 else if (addr == USART2) // NOLINT
47 {
48 return stm32_uart_id_t::STM32_USART2;
49 }
50#endif
51#ifdef USART3
52 else if (addr == USART3) // NOLINT
53 {
54 return stm32_uart_id_t::STM32_USART3;
55 }
56#endif
57#ifdef USART4
58 else if (addr == USART4) // NOLINT
59 {
60 return stm32_uart_id_t::STM32_USART4;
61 }
62#endif
63#ifdef USART5
64 else if (addr == USART5) // NOLINT
65 {
66 return stm32_uart_id_t::STM32_USART5;
67 }
68#endif
69#ifdef USART6
70 else if (addr == USART6) // NOLINT
71 {
72 return stm32_uart_id_t::STM32_USART6;
73 }
74#endif
75#ifdef USART7
76 else if (addr == USART7) // NOLINT
77 {
78 return stm32_uart_id_t::STM32_USART7;
79 }
80#endif
81#ifdef USART8
82 else if (addr == USART8) // NOLINT
83 {
84 return stm32_uart_id_t::STM32_USART8;
85 }
86#endif
87#ifdef USART9
88 else if (addr == USART9) // NOLINT
89 {
90 return stm32_uart_id_t::STM32_USART9;
91 }
92#endif
93#ifdef USART10
94 else if (addr == USART10) // NOLINT
95 {
96 return stm32_uart_id_t::STM32_USART10;
97 }
98#endif
99#ifdef USART11
100 else if (addr == USART11) // NOLINT
101 {
102 return stm32_uart_id_t::STM32_USART11;
103 }
104#endif
105#ifdef USART12
106 else if (addr == USART12) // NOLINT
107 {
108 return stm32_uart_id_t::STM32_USART12;
109 }
110#endif
111#ifdef USART13
112 else if (addr == USART13) // NOLINT
113 {
114 return stm32_uart_id_t::STM32_USART13;
115 }
116#endif
117#ifdef UART1
118 else if (addr == UART1) // NOLINT
119 {
120 return stm32_uart_id_t::STM32_UART1;
121 }
122#endif
123#ifdef UART2
124 else if (addr == UART2) // NOLINT
125 {
126 return stm32_uart_id_t::STM32_UART2;
127 }
128#endif
129#ifdef UART3
130 else if (addr == UART3) // NOLINT
131 {
132 return stm32_uart_id_t::STM32_UART3;
133 }
134#endif
135#ifdef UART4
136 else if (addr == UART4) // NOLINT
137 {
138 return stm32_uart_id_t::STM32_UART4;
139 }
140#endif
141#ifdef UART5
142 else if (addr == UART5) // NOLINT
143 {
144 return stm32_uart_id_t::STM32_UART5;
145 }
146#endif
147#ifdef UART6
148 else if (addr == UART6) // NOLINT
149 {
150 return stm32_uart_id_t::STM32_UART6;
151 }
152#endif
153#ifdef UART7
154 else if (addr == UART7) // NOLINT
155 {
156 return stm32_uart_id_t::STM32_UART7;
157 }
158#endif
159#ifdef UART8
160 else if (addr == UART8) // NOLINT
161 {
162 return stm32_uart_id_t::STM32_UART8;
163 }
164#endif
165#ifdef UART9
166 else if (addr == UART9) // NOLINT
167 {
168 return stm32_uart_id_t::STM32_UART9;
169 }
170#endif
171#ifdef UART10
172 else if (addr == UART10) // NOLINT
173 {
174 return stm32_uart_id_t::STM32_UART10;
175 }
176#endif
177#ifdef UART11
178 else if (addr == UART11) // NOLINT
179 {
180 return stm32_uart_id_t::STM32_UART11;
181 }
182#endif
183#ifdef UART12
184 else if (addr == UART12) // NOLINT
185 {
186 return stm32_uart_id_t::STM32_UART12;
187 }
188#endif
189#ifdef UART13
190 else if (addr == UART13) // NOLINT
191 {
192 return stm32_uart_id_t::STM32_UART13;
193 }
194#endif
195#ifdef LPUART1
196 else if (addr == LPUART1) // NOLINT
197 {
198 return stm32_uart_id_t::STM32_LPUART1;
199 }
200#endif
201#ifdef LPUART2
202 else if (addr == LPUART2) // NOLINT
203 {
204 return stm32_uart_id_t::STM32_LPUART2;
205 }
206#endif
207#ifdef LPUART3
208 else if (addr == LPUART3) // NOLINT
209 {
210 return stm32_uart_id_t::STM32_LPUART3;
211 }
212#endif
213 else
214 {
215 return stm32_uart_id_t::STM32_UART_ID_ERROR;
216 }
217}
218
219void STM32UART::WriteFun(WritePort& port, bool in_isr)
220{
221 auto* uart = LibXR::ContainerOf(&port, &STM32UART::_write_port);
222
223 uart->tx_service_.Invoke(TX_EVENT_WRITE, in_isr,
224 [uart](uint32_t events, bool owner_in_isr)
225 { uart->HandleTxService(events, owner_in_isr); });
226}
227
228void STM32UART::HandleTxService(uint32_t events, bool in_isr)
229{
230 if ((events & TX_EVENT_CONFIG) != 0U)
231 {
232 ConfigState state = config_state_.load(std::memory_order_acquire);
233 if (state == ConfigState::RESERVED)
234 {
235 config_state_.store(ConfigState::PUBLISHED, std::memory_order_release);
236 }
237 else
238 {
239 DEV_ASSERT_FROM_CALLBACK(state == ConfigState::PUBLISHED, in_isr);
240 }
241 }
242
243 if (abort_pending_)
244 {
245#if defined(LIBXR_STM32_UART_GPDMA)
246 // HAL 自有的 RX 中止通过错误回调通知,因此按硬件状态判断是否全部停止。
247 // HAL-owned RX aborts notify through the error callback; check actual stop state.
248 if (!gpdma_adapter_.AllStopsComplete())
249 {
250 return;
251 }
252 events |= TX_EVENT_ABORT;
253 [[maybe_unused]] const auto uart_abort_result = HAL_UART_Abort(uart_handle_);
254 REQUIRE_FROM_CALLBACK(uart_abort_result == HAL_OK, in_isr);
255 if (uart_handle_->hdmatx != nullptr)
256 {
257 STM32GpdmaUartAdapter::FinalizeStopped(uart_handle_->hdmatx, in_isr);
258 }
259 if (uart_handle_->hdmarx != nullptr)
260 {
261 STM32GpdmaUartAdapter::FinalizeStopped(uart_handle_->hdmarx, in_isr);
262 }
263 HandleTxDone(in_isr);
264 if (config_state_.load(std::memory_order_acquire) == ConfigState::PUBLISHED)
265 {
266 ApplyConfig(pending_config_, in_isr);
267 config_state_.store(ConfigState::EMPTY, std::memory_order_release);
268 }
269#else
270 if ((events & TX_EVENT_ABORT) == 0U)
271 {
272 return;
273 }
274#endif
275 last_rx_pos_ = 0U;
276 SetRxDMA(in_isr);
277#if !defined(LIBXR_STM32_UART_GPDMA)
278 HandleTxDone(in_isr);
279#endif
280 abort_pending_ = false;
281 }
282 else if ((events & TX_EVENT_ERROR) != 0U)
283 {
284 // 中止可能同步完成,调用 HAL 前先记录等待状态。
285 // Record the wait before calling HAL, which may complete the abort synchronously.
286 abort_pending_ = true;
287 BeginAbort(in_isr);
288 return;
289 }
290 else if ((events & TX_EVENT_DONE) != 0U)
291 {
292 HandleTxDone(in_isr);
293 }
294
295#if defined(LIBXR_STM32_UART_GPDMA)
296 if ((events & TX_EVENT_START_RX) != 0U)
297 {
298 SetRxDMA(in_isr);
299 }
300#endif
301 if ((events & TX_EVENT_RX_WORK) != 0U)
302 {
303 HandleRxData(in_isr);
304 }
305
306 if ((events & (TX_EVENT_CONFIG | TX_EVENT_DONE | TX_EVENT_ABORT)) != 0U)
307 {
308 TryApplyConfig(in_isr);
309 }
310
311 if ((uart_handle_->Init.Mode & UART_MODE_TX) != 0U &&
312 (events & (TX_EVENT_WRITE | TX_EVENT_DONE | TX_EVENT_CONFIG | TX_EVENT_ABORT)) !=
313 0U &&
314 config_state_.load(std::memory_order_acquire) == ConfigState::EMPTY)
315 {
316 FillTx(in_isr);
317 }
318}
319
320void STM32UART::FillTx(bool in_isr)
321{
322 if (!tx_busy_.IsSet())
323 {
325 {
326 if (config_state_.load(std::memory_order_acquire) != ConfigState::EMPTY)
327 {
328 return;
329 }
330 const size_t size = dma_buff_tx_.GetPendingLength();
333 StartTxDma(in_isr);
334 }
335 else if (dma_buff_tx_.GetActiveLength() != 0U)
336 {
337 if (config_state_.load(std::memory_order_acquire) != ConfigState::EMPTY)
338 {
339 return;
340 }
341 StartTxDma(in_isr);
342 }
343 else
344 {
345 if (config_state_.load(std::memory_order_acquire) != ConfigState::EMPTY)
346 {
347 return;
348 }
349
350 size_t size = 0U;
351 {
352 auto queue = _write_port.GetWriteQueue(in_isr);
353 if (queue.Empty())
354 {
355 return;
356 }
357 size = queue.AvailableSize();
358 DEV_ASSERT_FROM_CALLBACK(size <= dma_buff_tx_.Size(), in_isr);
359 queue.PopAll(dma_buff_tx_.ActiveBuffer());
361 }
362
363 if (config_state_.load(std::memory_order_acquire) != ConfigState::EMPTY)
364 {
365 return;
366 }
367 StartTxDma(in_isr);
368 }
369 }
370
372 config_state_.load(std::memory_order_acquire) == ConfigState::EMPTY)
373 {
374 auto queue = _write_port.GetWriteQueue(in_isr);
375 if (!queue.Empty())
376 {
377 const size_t size = queue.AvailableSize();
378 DEV_ASSERT_FROM_CALLBACK(size <= dma_buff_tx_.Size(), in_isr);
379 queue.PopAll(dma_buff_tx_.PendingBuffer());
382 }
383 }
384}
385
386void STM32UART::HandleTxDone(bool in_isr)
387{
388 UNUSED(in_isr);
389 if (!tx_busy_.IsSet())
390 {
391 return;
392 }
393
394 tx_busy_.Clear();
396}
397
398STM32UART::STM32UART(UART_HandleTypeDef* uart_handle, RawData dma_buff_rx,
399 RawData dma_buff_tx, uint32_t tx_queue_size)
400 : UART(&_read_port, &_write_port),
401 _read_port(dma_buff_rx.size_),
402 _write_port(tx_queue_size, dma_buff_tx.size_ / 2),
403 dma_buff_rx_(dma_buff_rx),
404 dma_buff_tx_(dma_buff_tx),
405 uart_handle_(uart_handle),
406 id_(stm32_uart_get_id(uart_handle_->Instance))
407#if defined(LIBXR_STM32_UART_GPDMA)
408 ,
409 gpdma_adapter_(uart_handle)
410#endif
411{
412 ASSERT(id_ != STM32_UART_ID_ERROR);
413 ASSERT(dma_buff_rx.size_ == 0U || dma_buff_rx.addr_ != nullptr);
414
415 map[id_] = this;
416
417 if ((uart_handle->Init.Mode & UART_MODE_TX) == UART_MODE_TX)
418 {
419 ASSERT(tx_queue_size > 0U);
420 ASSERT(uart_handle_->hdmatx != NULL);
421#if defined(LIBXR_STM32_UART_GPDMA)
422 ASSERT(uart_handle_->hdmatx->Mode == DMA_NORMAL);
423#endif
425 }
426
427#if defined(LIBXR_STM32_UART_GPDMA)
428 tx_service_.Invoke(TX_EVENT_START_RX, false, [this](uint32_t events, bool in_isr)
429 { HandleTxService(events, in_isr); });
430#else
431 SetRxDMA(false);
432#endif
433}
434
436{
437 if (config.baudrate == 0U)
438 {
439 return ErrorCode::ARG_ERR;
440 }
441
442 switch (config.parity)
443 {
447 break;
448 default:
450 }
451
452 if (!Stm32DataBitsSupported(config))
453 {
454 return ErrorCode::ARG_ERR;
455 }
456
457 if (!Stm32StopBitsSupported(config))
458 {
459 return ErrorCode::ARG_ERR;
460 }
461
462 ConfigState expected = ConfigState::EMPTY;
463 if (!config_state_.compare_exchange_strong(expected, ConfigState::RESERVED,
464 std::memory_order_acq_rel,
465 std::memory_order_acquire))
466 {
467 return ErrorCode::BUSY;
468 }
469
470 pending_config_ = config;
471 tx_service_.Invoke(TX_EVENT_CONFIG, in_isr, [this](uint32_t events, bool owner_in_isr)
472 { HandleTxService(events, owner_in_isr); });
473 return ErrorCode::OK;
474}
475
476void STM32UART::ApplyConfig(UART::Configuration config, bool in_isr)
477{
478 uart_handle_->Init.BaudRate = config.baudrate;
479
480 switch (config.parity)
481 {
483 uart_handle_->Init.Parity = UART_PARITY_NONE;
484 uart_handle_->Init.WordLength = UART_WORDLENGTH_8B;
485 break;
487 uart_handle_->Init.Parity = UART_PARITY_EVEN;
488 uart_handle_->Init.WordLength =
489 config.data_bits == 7U ? UART_WORDLENGTH_8B : UART_WORDLENGTH_9B;
490 break;
492 uart_handle_->Init.Parity = UART_PARITY_ODD;
493 uart_handle_->Init.WordLength =
494 config.data_bits == 7U ? UART_WORDLENGTH_8B : UART_WORDLENGTH_9B;
495 break;
496 default:
497 DEV_ASSERT_FROM_CALLBACK(false, in_isr);
498 return;
499 }
500
501 switch (config.stop_bits)
502 {
503 case 1:
504 uart_handle_->Init.StopBits = UART_STOPBITS_1;
505 break;
506 case 2:
507 uart_handle_->Init.StopBits = UART_STOPBITS_2;
508 break;
509 default:
510 DEV_ASSERT_FROM_CALLBACK(false, in_isr);
511 return;
512 }
513
514#if defined(LIBXR_STM32_UART_GPDMA)
515 // 通道已停止,直接配置寄存器,避免在中断中等待 HAL tick。
516 // Channels are stopped; configure registers without waiting for HAL ticks in an ISR.
517 __HAL_UART_DISABLE(uart_handle_);
518 [[maybe_unused]] const auto uart_set_config_result = UART_SetConfig(uart_handle_);
519 REQUIRE_FROM_CALLBACK(uart_set_config_result == HAL_OK, in_isr);
520 CLEAR_BIT(uart_handle_->Instance->CR2, USART_CR2_LINEN | USART_CR2_CLKEN);
521 CLEAR_BIT(uart_handle_->Instance->CR3,
522 USART_CR3_SCEN | USART_CR3_HDSEL | USART_CR3_IREN);
523 __HAL_UART_ENABLE(uart_handle_);
524#else
525 [[maybe_unused]] const auto uart_init_result = HAL_UART_Init(uart_handle_);
526 REQUIRE_FROM_CALLBACK(uart_init_result == HAL_OK, in_isr);
527#endif
528}
529
530void STM32UART::TryApplyConfig(bool in_isr)
531{
532 if (config_state_.load(std::memory_order_acquire) != ConfigState::PUBLISHED)
533 {
534 return;
535 }
536
537 if (tx_busy_.IsSet())
538 {
539 return;
540 }
541
542#if defined(LIBXR_STM32_UART_GPDMA)
543 abort_pending_ = true;
544 BeginAbort(in_isr);
545#else
546 ApplyConfig(pending_config_, in_isr);
547 last_rx_pos_ = 0U;
548 SetRxDMA(in_isr);
549 config_state_.store(ConfigState::EMPTY, std::memory_order_release);
550#endif
551}
552
553void STM32UART::SetRxDMA(bool in_isr)
554{
555 if ((uart_handle_->Init.Mode & UART_MODE_RX) == UART_MODE_RX)
556 {
557 ASSERT(uart_handle_->hdmarx != NULL);
558
559#if defined(LIBXR_STM32_UART_GPDMA)
560 [[maybe_unused]] const auto start_linked_list_dma_rx_result =
561 gpdma_adapter_.StartLinkedListDmaRx(static_cast<uint8_t*>(dma_buff_rx_.addr_),
562 dma_buff_rx_.size_, in_isr);
563 REQUIRE_FROM_CALLBACK(start_linked_list_dma_rx_result == HAL_OK, in_isr);
564#else
565 uart_handle_->hdmarx->Init.Mode = DMA_CIRCULAR;
566 [[maybe_unused]] const auto dma_init_result = HAL_DMA_Init(uart_handle_->hdmarx);
567 REQUIRE_FROM_CALLBACK(dma_init_result == HAL_OK, in_isr);
568
569 [[maybe_unused]] const auto uart_ex_receive_to_idle_dma_result =
570 HAL_UARTEx_ReceiveToIdle_DMA(uart_handle_,
571 reinterpret_cast<uint8_t*>(dma_buff_rx_.addr_),
573 REQUIRE_FROM_CALLBACK(uart_ex_receive_to_idle_dma_result == HAL_OK, in_isr);
574#endif
575 }
576}
577
578void STM32UART::HandleRxData(bool in_isr)
579{
580 const size_t dma_size = dma_buff_rx_.size_;
581 if (dma_size == 0U)
582 {
583 return;
584 }
585
586 auto* const rx_buf = static_cast<uint8_t*>(dma_buff_rx_.addr_);
587
588#if defined(LIBXR_STM32_UART_GPDMA)
589 const uintptr_t destination =
590 reinterpret_cast<uintptr_t>(gpdma_adapter_.GetLinkedListDmaRxProducer());
591 const uintptr_t begin = reinterpret_cast<uintptr_t>(rx_buf);
592 DEV_ASSERT_FROM_CALLBACK(destination >= begin && destination - begin <= dma_size,
593 in_isr);
594 const size_t curr_pos = destination - begin;
595#else
596 const size_t remaining = __HAL_DMA_GET_COUNTER(uart_handle_->hdmarx);
597 DEV_ASSERT_FROM_CALLBACK(remaining <= dma_size, in_isr);
598 const size_t curr_pos = remaining == 0U ? dma_size : dma_size - remaining;
599#endif
600 const size_t last_pos = last_rx_pos_;
601 DEV_ASSERT_FROM_CALLBACK(last_pos < dma_size, in_isr);
602
603 STM32_InvalidateDCacheByAddr(rx_buf, dma_size);
604
605 if (curr_pos != last_pos)
606 {
607 const size_t first_size =
608 curr_pos > last_pos ? curr_pos - last_pos : dma_size - last_pos;
609 const size_t second_size = curr_pos > last_pos ? 0U : curr_pos;
610 auto queue = _read_port.GetReadQueue(in_isr);
611 size_t accepted = std::min(first_size + second_size, queue.EmptySize());
612
613 if (accepted != 0U)
614 {
615 const size_t first_accepted = std::min(first_size, accepted);
616 if (first_accepted != 0U)
617 {
618 [[maybe_unused]] const auto push_batch_result =
619 queue.PushBatch(rx_buf + last_pos, first_accepted);
620 DEV_ASSERT_FROM_CALLBACK(push_batch_result == ErrorCode::OK, in_isr);
621 accepted -= first_accepted;
622 }
623 if (accepted != 0U)
624 {
625 [[maybe_unused]] const auto push_batch_result = queue.PushBatch(rx_buf, accepted);
626 DEV_ASSERT_FROM_CALLBACK(push_batch_result == ErrorCode::OK, in_isr);
627 }
628 }
629
630 last_rx_pos_ = curr_pos == dma_size ? 0U : curr_pos;
631 queue.Publish();
632 }
633}
634
636{
637 tx_service_.Invoke(TX_EVENT_DONE, true, [this](uint32_t events, bool in_isr)
638 { HandleTxService(events, in_isr); });
639}
640
642{
643 tx_service_.Invoke(TX_EVENT_RX_WORK, true, [this](uint32_t events, bool in_isr)
644 { HandleTxService(events, in_isr); });
645}
646
648{
649 tx_service_.Invoke(TX_EVENT_ERROR, true, [this](uint32_t events, bool in_isr)
650 { HandleTxService(events, in_isr); });
651}
652
654{
655 tx_service_.Invoke(TX_EVENT_ABORT, true, [this](uint32_t events, bool in_isr)
656 { HandleTxService(events, in_isr); });
657}
658
659// HAL 在串口发送完成后调用此入口,此处只通知后端处理器。
660// HAL invokes this entry at UART transmission completion; only notify the service.
661void STM32_UART_ISR_Handler_TX_CPLT(stm32_uart_id_t id)
662{
663 auto uart = STM32UART::map[id];
664 if (uart != nullptr)
665 {
666 uart->TxCompleteIRQHandler();
667 }
668}
669
670extern "C" void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef* huart, uint16_t)
671{
672 auto uart = STM32UART::map[stm32_uart_get_id(huart->Instance)];
673 if (uart != nullptr)
674 {
675 uart->RxEventIRQHandler();
676 }
677}
678
679extern "C" void HAL_UART_TxCpltCallback(UART_HandleTypeDef* huart)
680{
681 STM32_UART_ISR_Handler_TX_CPLT(stm32_uart_get_id(huart->Instance));
682}
683
684extern "C" __attribute__((used)) void HAL_UART_ErrorCallback(UART_HandleTypeDef* huart)
685{
686 const auto id = stm32_uart_get_id(huart->Instance);
687 if (id == STM32_UART_ID_ERROR)
688 {
689 return;
690 }
691 auto* uart = STM32UART::map[id];
692 if (uart != nullptr)
693 {
694 uart->ErrorIRQHandler();
695 }
696}
697
698extern "C" void HAL_UART_AbortCpltCallback(UART_HandleTypeDef* huart)
699{
700 auto uart = STM32UART::map[stm32_uart_get_id(huart->Instance)];
701 if (uart != nullptr)
702 {
703 uart->AbortCompleteIRQHandler();
704 }
705}
706
707void STM32UART::BeginAbort(bool in_isr)
708{
709#if defined(LIBXR_STM32_UART_GPDMA)
710 gpdma_adapter_.CloseTxTerminalSource();
711 if (uart_handle_->hdmatx != nullptr)
712 {
713 [[maybe_unused]] const auto launch_stop_result =
714 gpdma_adapter_.LaunchStop(uart_handle_->hdmatx, DmaAbortCallback, in_isr);
715 REQUIRE_FROM_CALLBACK(launch_stop_result, in_isr);
716 }
717 if (uart_handle_->hdmarx != nullptr)
718 {
719 [[maybe_unused]] const auto launch_stop_result =
720 gpdma_adapter_.LaunchStop(uart_handle_->hdmarx, DmaAbortCallback, in_isr);
721 REQUIRE_FROM_CALLBACK(launch_stop_result, in_isr);
722 }
723 if (gpdma_adapter_.AllStopsComplete())
724 {
725 tx_service_.Publish(TX_EVENT_ABORT);
726 }
727#else
728 [[maybe_unused]] const auto uart_abort_it_result = HAL_UART_Abort_IT(uart_handle_);
729 REQUIRE_FROM_CALLBACK(uart_abort_it_result == HAL_OK, in_isr);
730#endif
731}
732
733#if defined(LIBXR_STM32_UART_GPDMA)
734void STM32UART::DmaAbortCallback(DMA_HandleTypeDef* dma_handle)
735{
736 auto* handle = static_cast<UART_HandleTypeDef*>(dma_handle->Parent);
737 const auto id = stm32_uart_get_id(handle->Instance);
738 if (id != STM32_UART_ID_ERROR && map[id] != nullptr)
739 {
740 map[id]->AbortCompleteIRQHandler();
741 }
742}
743#endif
744
745void STM32UART::StartTxDma(bool in_isr)
746{
747 const size_t size = dma_buff_tx_.GetActiveLength();
748 DEV_ASSERT_FROM_CALLBACK(size != 0U && size <= dma_buff_tx_.Size(), in_isr);
749
751 tx_busy_.Set();
752 const HAL_StatusTypeDef status = HAL_UART_Transmit_DMA(
753 uart_handle_, static_cast<uint8_t*>(dma_buff_tx_.ActiveBuffer()), size);
754 REQUIRE_FROM_CALLBACK(status == HAL_OK, in_isr);
755}
756
757#endif
void SetActiveLength(size_t length)
设置当前活动缓冲区的数据长度 Sets the size of the active buffer
void SetPendingLength(size_t length)
设置备用缓冲区的数据长度 Sets the size of the pending buffer
void EnablePending()
手动启用 pending 状态 Manually sets the pending state to true
bool HasPending() const
判断是否有待切换的缓冲区 Checks whether a pending buffer is ready
size_t Size() const
获取每个缓冲区的大小(单位:字节) Gets the size of each buffer in bytes
uint8_t * ActiveBuffer() const
获取当前正在使用的缓冲区指针 Returns the currently active buffer
size_t GetActiveLength() const
获取当前活动缓冲区中准备好的数据长度 Gets the size of valid data in active buffer
uint8_t * PendingBuffer() const
获取备用缓冲区的指针 Returns the pending (inactive) buffer
void Switch()
切换到备用缓冲区(若其有效) Switches to the pending buffer if it's valid
size_t GetPendingLength() const
获取 pending 缓冲区中准备好的数据长度 Gets the size of valid data in pending buffer
void Set() noexcept
置位标志 / Set the flag
Definition flag.hpp:125
bool IsSet() const noexcept
判断是否已置位 / Check whether the flag is set
Definition flag.hpp:138
void Clear() noexcept
清除标志 / Clear the flag
Definition flag.hpp:130
可写原始数据视图 / Mutable raw data view
size_t size_
数据字节数 / Data size in bytes
void * addr_
数据起始地址 / Data start address
ReadQueue GetReadQueue(bool in_isr=false)
获取后端接收入队接口 / Obtain the backend RX producer interface.
Definition read_port.cpp:14
static void FinalizeStopped(DMA_HandleTypeDef *dma_handle, bool in_isr)
在停止状态清除旧标志和链表计数 / Clear stale flags and list count while stopped.
使用循环接收 DMA 和双缓冲发送的 STM32 串口 / STM32 UART with circular RX DMA and double-buffered TX.
RawData dma_buff_rx_
调用者提供的接收 DMA 缓冲区 / Caller-provided RX DMA buffer.
void ErrorIRQHandler()
通知错误,由后端处理器启动中止 / Report an error; the service initiates the abort.
void SetRxDMA(bool in_isr=false)
初始化循环接收 DMA 并检查启动结果 / Initialize circular RX DMA and check startup.
DoubleBuffer dma_buff_tx_
当前与待发送的 DMA 半区 / Active and pending TX DMA halves.
Flag::Plain tx_busy_
发送半区是否在使用,仅后端处理器访问 / TX half in use; service-only access.
static void WriteFun(WritePort &port, bool in_isr)
通知后端处理已提交的写请求 / Notify the backend of released writes.
void AbortCompleteIRQHandler()
WritePort _write_port
写请求及发送字节队列 / Write requests and TX byte queue.
void TxCompleteIRQHandler()
通知发送完成,交给后端释放半区 / Notify TX completion to release the active half.
size_t last_rx_pos_
上次已处理的 DMA 接收位置 / Last processed RX DMA position.
STM32UART(UART_HandleTypeDef *uart_handle, RawData dma_buff_rx, RawData dma_buff_tx, uint32_t tx_queue_size=5)
构造串口并关联 DMA 缓冲区 / Construct a UART with DMA buffers.
void RxEventIRQHandler()
通知接收位置变化 / Notify RX position changes.
ErrorCode SetConfig(UART::Configuration config, bool in_isr=false) override
提交串口配置请求 / Submit a UART configuration request.
ReadPort _read_port
接收字节队列与读请求 / RX byte queue and read requests.
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
void STM32_InvalidateDCacheByAddr(const void *addr, size_t size)
失效指定内存范围覆盖的 D-Cache cache line Invalidates D-Cache lines covering the specified memory range
ErrorCode
定义错误码枚举 / Defines an enumeration for error codes
@ BUSY
忙碌 / Busy
@ NOT_SUPPORT
不支持 / Not supported
@ 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
void STM32_CleanDCacheByAddr(const void *addr, size_t size)
清理指定内存范围覆盖的 D-Cache cache line Cleans D-Cache lines covering the specified memory range
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