1#include "stm32_uart.hpp"
5#include "stm32_dcache.hpp"
6#ifdef HAL_UART_MODULE_ENABLED
15 if (config.
parity == UART::Parity::NO_PARITY)
20 return (config.
parity == UART::Parity::EVEN || config.
parity == UART::Parity::ODD) &&
31STM32UART* STM32UART::map[STM32_UART_NUMBER] = {
nullptr};
33stm32_uart_id_t stm32_uart_get_id(USART_TypeDef* addr)
37 return stm32_uart_id_t::STM32_UART_ID_ERROR;
40 else if (addr == USART1)
42 return stm32_uart_id_t::STM32_USART1;
46 else if (addr == USART2)
48 return stm32_uart_id_t::STM32_USART2;
52 else if (addr == USART3)
54 return stm32_uart_id_t::STM32_USART3;
58 else if (addr == USART4)
60 return stm32_uart_id_t::STM32_USART4;
64 else if (addr == USART5)
66 return stm32_uart_id_t::STM32_USART5;
70 else if (addr == USART6)
72 return stm32_uart_id_t::STM32_USART6;
76 else if (addr == USART7)
78 return stm32_uart_id_t::STM32_USART7;
82 else if (addr == USART8)
84 return stm32_uart_id_t::STM32_USART8;
88 else if (addr == USART9)
90 return stm32_uart_id_t::STM32_USART9;
94 else if (addr == USART10)
96 return stm32_uart_id_t::STM32_USART10;
100 else if (addr == USART11)
102 return stm32_uart_id_t::STM32_USART11;
106 else if (addr == USART12)
108 return stm32_uart_id_t::STM32_USART12;
112 else if (addr == USART13)
114 return stm32_uart_id_t::STM32_USART13;
118 else if (addr == UART1)
120 return stm32_uart_id_t::STM32_UART1;
124 else if (addr == UART2)
126 return stm32_uart_id_t::STM32_UART2;
130 else if (addr == UART3)
132 return stm32_uart_id_t::STM32_UART3;
136 else if (addr == UART4)
138 return stm32_uart_id_t::STM32_UART4;
142 else if (addr == UART5)
144 return stm32_uart_id_t::STM32_UART5;
148 else if (addr == UART6)
150 return stm32_uart_id_t::STM32_UART6;
154 else if (addr == UART7)
156 return stm32_uart_id_t::STM32_UART7;
160 else if (addr == UART8)
162 return stm32_uart_id_t::STM32_UART8;
166 else if (addr == UART9)
168 return stm32_uart_id_t::STM32_UART9;
172 else if (addr == UART10)
174 return stm32_uart_id_t::STM32_UART10;
178 else if (addr == UART11)
180 return stm32_uart_id_t::STM32_UART11;
184 else if (addr == UART12)
186 return stm32_uart_id_t::STM32_UART12;
190 else if (addr == UART13)
192 return stm32_uart_id_t::STM32_UART13;
196 else if (addr == LPUART1)
198 return stm32_uart_id_t::STM32_LPUART1;
202 else if (addr == LPUART2)
204 return stm32_uart_id_t::STM32_LPUART2;
208 else if (addr == LPUART3)
210 return stm32_uart_id_t::STM32_LPUART3;
215 return stm32_uart_id_t::STM32_UART_ID_ERROR;
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); });
228void STM32UART::HandleTxService(uint32_t events,
bool in_isr)
230 if ((events & TX_EVENT_CONFIG) != 0U)
232 ConfigState state = config_state_.load(std::memory_order_acquire);
233 if (state == ConfigState::RESERVED)
235 config_state_.store(ConfigState::PUBLISHED, std::memory_order_release);
239 DEV_ASSERT_FROM_CALLBACK(state == ConfigState::PUBLISHED, in_isr);
245#if defined(LIBXR_STM32_UART_GPDMA)
248 if (!gpdma_adapter_.AllStopsComplete())
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)
259 if (uart_handle_->hdmarx !=
nullptr)
263 HandleTxDone(in_isr);
264 if (config_state_.load(std::memory_order_acquire) == ConfigState::PUBLISHED)
266 ApplyConfig(pending_config_, in_isr);
267 config_state_.store(ConfigState::EMPTY, std::memory_order_release);
270 if ((events & TX_EVENT_ABORT) == 0U)
277#if !defined(LIBXR_STM32_UART_GPDMA)
278 HandleTxDone(in_isr);
280 abort_pending_ =
false;
282 else if ((events & TX_EVENT_ERROR) != 0U)
286 abort_pending_ =
true;
290 else if ((events & TX_EVENT_DONE) != 0U)
292 HandleTxDone(in_isr);
295#if defined(LIBXR_STM32_UART_GPDMA)
296 if ((events & TX_EVENT_START_RX) != 0U)
301 if ((events & TX_EVENT_RX_WORK) != 0U)
303 HandleRxData(in_isr);
306 if ((events & (TX_EVENT_CONFIG | TX_EVENT_DONE | TX_EVENT_ABORT)) != 0U)
308 TryApplyConfig(in_isr);
311 if ((uart_handle_->Init.Mode & UART_MODE_TX) != 0U &&
312 (events & (TX_EVENT_WRITE | TX_EVENT_DONE | TX_EVENT_CONFIG | TX_EVENT_ABORT)) !=
314 config_state_.load(std::memory_order_acquire) == ConfigState::EMPTY)
320void STM32UART::FillTx(
bool in_isr)
326 if (config_state_.load(std::memory_order_acquire) != ConfigState::EMPTY)
337 if (config_state_.load(std::memory_order_acquire) != ConfigState::EMPTY)
345 if (config_state_.load(std::memory_order_acquire) != ConfigState::EMPTY)
363 if (config_state_.load(std::memory_order_acquire) != ConfigState::EMPTY)
372 config_state_.load(std::memory_order_acquire) == ConfigState::EMPTY)
377 const size_t size = queue.AvailableSize();
386void STM32UART::HandleTxDone(
bool in_isr)
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)
409 gpdma_adapter_(uart_handle)
412 ASSERT(id_ != STM32_UART_ID_ERROR);
413 ASSERT(dma_buff_rx.
size_ == 0U || dma_buff_rx.
addr_ !=
nullptr);
417 if ((uart_handle->Init.Mode & UART_MODE_TX) == UART_MODE_TX)
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);
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); });
452 if (!Stm32DataBitsSupported(config))
457 if (!Stm32StopBitsSupported(config))
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))
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); });
478 uart_handle_->Init.BaudRate = config.
baudrate;
483 uart_handle_->Init.Parity = UART_PARITY_NONE;
484 uart_handle_->Init.WordLength = UART_WORDLENGTH_8B;
487 uart_handle_->Init.Parity = UART_PARITY_EVEN;
488 uart_handle_->Init.WordLength =
489 config.
data_bits == 7U ? UART_WORDLENGTH_8B : UART_WORDLENGTH_9B;
492 uart_handle_->Init.Parity = UART_PARITY_ODD;
493 uart_handle_->Init.WordLength =
494 config.
data_bits == 7U ? UART_WORDLENGTH_8B : UART_WORDLENGTH_9B;
497 DEV_ASSERT_FROM_CALLBACK(
false, in_isr);
504 uart_handle_->Init.StopBits = UART_STOPBITS_1;
507 uart_handle_->Init.StopBits = UART_STOPBITS_2;
510 DEV_ASSERT_FROM_CALLBACK(
false, in_isr);
514#if defined(LIBXR_STM32_UART_GPDMA)
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_);
525 [[maybe_unused]]
const auto uart_init_result = HAL_UART_Init(uart_handle_);
526 REQUIRE_FROM_CALLBACK(uart_init_result == HAL_OK, in_isr);
530void STM32UART::TryApplyConfig(
bool in_isr)
532 if (config_state_.load(std::memory_order_acquire) != ConfigState::PUBLISHED)
542#if defined(LIBXR_STM32_UART_GPDMA)
543 abort_pending_ =
true;
546 ApplyConfig(pending_config_, in_isr);
549 config_state_.store(ConfigState::EMPTY, std::memory_order_release);
555 if ((uart_handle_->Init.Mode & UART_MODE_RX) == UART_MODE_RX)
557 ASSERT(uart_handle_->hdmarx != NULL);
559#if defined(LIBXR_STM32_UART_GPDMA)
560 [[maybe_unused]]
const auto start_linked_list_dma_rx_result =
563 REQUIRE_FROM_CALLBACK(start_linked_list_dma_rx_result == HAL_OK, in_isr);
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);
569 [[maybe_unused]]
const auto uart_ex_receive_to_idle_dma_result =
570 HAL_UARTEx_ReceiveToIdle_DMA(uart_handle_,
573 REQUIRE_FROM_CALLBACK(uart_ex_receive_to_idle_dma_result == HAL_OK, in_isr);
578void STM32UART::HandleRxData(
bool in_isr)
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,
594 const size_t curr_pos = destination - begin;
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;
601 DEV_ASSERT_FROM_CALLBACK(last_pos < dma_size, in_isr);
605 if (curr_pos != last_pos)
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;
611 size_t accepted = std::min(first_size + second_size, queue.EmptySize());
615 const size_t first_accepted = std::min(first_size, accepted);
616 if (first_accepted != 0U)
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;
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);
637 tx_service_.
Invoke(TX_EVENT_DONE,
true, [
this](uint32_t events,
bool in_isr)
638 { HandleTxService(events, in_isr); });
643 tx_service_.
Invoke(TX_EVENT_RX_WORK,
true, [
this](uint32_t events,
bool in_isr)
644 { HandleTxService(events, in_isr); });
649 tx_service_.
Invoke(TX_EVENT_ERROR,
true, [
this](uint32_t events,
bool in_isr)
650 { HandleTxService(events, in_isr); });
655 tx_service_.
Invoke(TX_EVENT_ABORT,
true, [
this](uint32_t events,
bool in_isr)
656 { HandleTxService(events, in_isr); });
661void STM32_UART_ISR_Handler_TX_CPLT(stm32_uart_id_t
id)
663 auto uart = STM32UART::map[id];
666 uart->TxCompleteIRQHandler();
670extern "C" void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef* huart, uint16_t)
672 auto uart = STM32UART::map[stm32_uart_get_id(huart->Instance)];
675 uart->RxEventIRQHandler();
679extern "C" void HAL_UART_TxCpltCallback(UART_HandleTypeDef* huart)
681 STM32_UART_ISR_Handler_TX_CPLT(stm32_uart_get_id(huart->Instance));
684extern "C" __attribute__((used))
void HAL_UART_ErrorCallback(UART_HandleTypeDef* huart)
686 const auto id = stm32_uart_get_id(huart->Instance);
687 if (
id == STM32_UART_ID_ERROR)
691 auto* uart = STM32UART::map[id];
694 uart->ErrorIRQHandler();
698extern "C" void HAL_UART_AbortCpltCallback(UART_HandleTypeDef* huart)
700 auto uart = STM32UART::map[stm32_uart_get_id(huart->Instance)];
703 uart->AbortCompleteIRQHandler();
707void STM32UART::BeginAbort(
bool in_isr)
709#if defined(LIBXR_STM32_UART_GPDMA)
710 gpdma_adapter_.CloseTxTerminalSource();
711 if (uart_handle_->hdmatx !=
nullptr)
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);
717 if (uart_handle_->hdmarx !=
nullptr)
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);
723 if (gpdma_adapter_.AllStopsComplete())
725 tx_service_.
Publish(TX_EVENT_ABORT);
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);
733#if defined(LIBXR_STM32_UART_GPDMA)
734void STM32UART::DmaAbortCallback(DMA_HandleTypeDef* dma_handle)
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)
745void STM32UART::StartTxDma(
bool in_isr)
748 DEV_ASSERT_FROM_CALLBACK(size != 0U && size <=
dma_buff_tx_.
Size(), in_isr);
752 const HAL_StatusTypeDef status = HAL_UART_Transmit_DMA(
754 REQUIRE_FROM_CALLBACK(status == HAL_OK, in_isr);
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
bool IsSet() const noexcept
判断是否已置位 / Check whether the flag is set
void Clear() noexcept
清除标志 / Clear the flag
可写原始数据视图 / 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.
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)
@ NO_PARITY
无校验 / No 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.
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
@ 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.
uint8_t stop_bits
停止位长度 / Number of stop bits
uint32_t baudrate
波特率 / Baud rate