1#include "stm32_uart_gpdma.hpp"
3#if defined(LIBXR_STM32_UART_GPDMA) && defined(HAL_UART_MODULE_ENABLED)
5#include "libxr_assert.hpp"
6#include "stm32_dcache.hpp"
13IRQn_Type GetGpdmaIrq(DMA_Channel_TypeDef* instance)
15#define LIBXR_GPDMA_IRQ_CASE(DMA, CHANNEL) \
16 if (instance == DMA##_Channel##CHANNEL) \
18 return DMA##_Channel##CHANNEL##_IRQn; \
23#if defined(GPDMA1_Channel0)
24 LIBXR_GPDMA_IRQ_CASE(GPDMA1, 0)
25 LIBXR_GPDMA_IRQ_CASE(GPDMA1, 1)
26 LIBXR_GPDMA_IRQ_CASE(GPDMA1, 2)
27 LIBXR_GPDMA_IRQ_CASE(GPDMA1, 3)
28 LIBXR_GPDMA_IRQ_CASE(GPDMA1, 4)
29 LIBXR_GPDMA_IRQ_CASE(GPDMA1, 5)
30 LIBXR_GPDMA_IRQ_CASE(GPDMA1, 6)
31 LIBXR_GPDMA_IRQ_CASE(GPDMA1, 7)
33#if defined(GPDMA1_Channel8)
34 LIBXR_GPDMA_IRQ_CASE(GPDMA1, 8)
35 LIBXR_GPDMA_IRQ_CASE(GPDMA1, 9)
36 LIBXR_GPDMA_IRQ_CASE(GPDMA1, 10)
37 LIBXR_GPDMA_IRQ_CASE(GPDMA1, 11)
39#if defined(GPDMA1_Channel12)
40 LIBXR_GPDMA_IRQ_CASE(GPDMA1, 12)
41 LIBXR_GPDMA_IRQ_CASE(GPDMA1, 13)
42 LIBXR_GPDMA_IRQ_CASE(GPDMA1, 14)
43 LIBXR_GPDMA_IRQ_CASE(GPDMA1, 15)
45#if defined(GPDMA2_Channel0)
46 LIBXR_GPDMA_IRQ_CASE(GPDMA2, 0)
47 LIBXR_GPDMA_IRQ_CASE(GPDMA2, 1)
48 LIBXR_GPDMA_IRQ_CASE(GPDMA2, 2)
49 LIBXR_GPDMA_IRQ_CASE(GPDMA2, 3)
50 LIBXR_GPDMA_IRQ_CASE(GPDMA2, 4)
51 LIBXR_GPDMA_IRQ_CASE(GPDMA2, 5)
52 LIBXR_GPDMA_IRQ_CASE(GPDMA2, 6)
53 LIBXR_GPDMA_IRQ_CASE(GPDMA2, 7)
55#if defined(GPDMA2_Channel8)
56 LIBXR_GPDMA_IRQ_CASE(GPDMA2, 8)
57 LIBXR_GPDMA_IRQ_CASE(GPDMA2, 9)
58 LIBXR_GPDMA_IRQ_CASE(GPDMA2, 10)
59 LIBXR_GPDMA_IRQ_CASE(GPDMA2, 11)
61#if defined(GPDMA2_Channel12)
62 LIBXR_GPDMA_IRQ_CASE(GPDMA2, 12)
63 LIBXR_GPDMA_IRQ_CASE(GPDMA2, 13)
64 LIBXR_GPDMA_IRQ_CASE(GPDMA2, 14)
65 LIBXR_GPDMA_IRQ_CASE(GPDMA2, 15)
68#undef LIBXR_GPDMA_IRQ_CASE
70 return NonMaskableInt_IRQn;
73class GpdmaNvicMaskGuard
76 explicit GpdmaNvicMaskGuard(DMA_HandleTypeDef* dma_handle)
77 : irq_(GetGpdmaIrq(dma_handle->Instance)),
78 valid_(static_cast<int32_t>(irq_) >= 0),
79 was_enabled_(valid_ && (NVIC_GetEnableIRQ(irq_) != 0U))
88 NVIC_DisableIRQ(irq_);
96 if (valid_ && was_enabled_)
104 GpdmaNvicMaskGuard(
const GpdmaNvicMaskGuard&) =
delete;
105 GpdmaNvicMaskGuard& operator=(
const GpdmaNvicMaskGuard&) =
delete;
107 [[nodiscard]]
bool Valid()
const {
return valid_; }
108 [[nodiscard]]
bool WasEnabled()
const {
return was_enabled_; }
120 ASSERT(uart_handle !=
nullptr);
121 ASSERT((uart_handle->hdmatx ==
nullptr) ||
122 (IS_GPDMA_INSTANCE(uart_handle->hdmatx->Instance) != 0U));
123 ASSERT((uart_handle->hdmarx ==
nullptr) ||
124 (IS_GPDMA_INSTANCE(uart_handle->hdmarx->Instance) != 0U));
125 state_.uart_handle_ = uart_handle;
132 DMA_HandleTypeDef*
const dma_handle = state_.uart_handle_->hdmarx;
133 ASSERT_FROM_CALLBACK(dma_handle !=
nullptr, in_isr);
134 ASSERT_FROM_CALLBACK(buffer !=
nullptr, in_isr);
135 ASSERT_FROM_CALLBACK(total_size >= RX_NODE_COUNT, in_isr);
136 ASSERT_FROM_CALLBACK((total_size % RX_NODE_COUNT) == 0U, in_isr);
137 ASSERT_FROM_CALLBACK((total_size / RX_NODE_COUNT) <= UINT16_MAX, in_isr);
138 ASSERT_FROM_CALLBACK(IS_DMA_BLOCK_SIZE(total_size / RX_NODE_COUNT) != 0U, in_isr);
139 ASSERT_FROM_CALLBACK(dma_handle->Parent == state_.uart_handle_ &&
140 IS_GPDMA_INSTANCE(dma_handle->Instance) != 0U,
142 ASSERT_FROM_CALLBACK(
143 dma_handle->InitLinkedList.LinkStepMode == DMA_LSM_FULL_EXECUTION &&
144 dma_handle->InitLinkedList.LinkedListMode == DMA_LINKEDLIST_CIRCULAR &&
145 dma_handle->Mode == DMA_LINKEDLIST_CIRCULAR,
148 if (!state_.rx_queue_built_)
150 BuildRxQueue(buffer, total_size, in_isr);
154 ASSERT_FROM_CALLBACK(buffer == state_.rx_buffer_, in_isr);
155 ASSERT_FROM_CALLBACK(total_size == state_.rx_total_size_, in_isr);
156 DEV_ASSERT_FROM_CALLBACK(dma_handle->LinkedListQueue == &state_.rx_queue_, in_isr);
159 DEV_ASSERT_FROM_CALLBACK(
StopComplete(dma_handle), in_isr);
167 return HAL_UARTEx_ReceiveToIdle_DMA(state_.uart_handle_, buffer,
168 static_cast<uint16_t
>(state_.rx_node_size_));
173 DEV_ASSERT(state_.uart_handle_->hdmarx !=
nullptr);
174 const uintptr_t destination = state_.uart_handle_->hdmarx->Instance->CDAR;
175 return reinterpret_cast<uint8_t*
>(destination);
180 ATOMIC_CLEAR_BIT(state_.uart_handle_->Instance->CR1, USART_CR1_TCIE);
181 const volatile uint32_t cr1 = state_.uart_handle_->Instance->CR1;
187 AbortCallback callback,
188 [[maybe_unused]]
bool in_isr)
190 ASSERT(dma_handle !=
nullptr);
191 ASSERT(dma_handle->Parent == state_.uart_handle_);
192 ASSERT(callback !=
nullptr);
194 const auto abort_is_joinable = [&]()
196 if (dma_handle->XferAbortCallback == callback)
203 return (dma_handle == state_.uart_handle_->hdmarx) &&
204 (state_.uart_handle_->ErrorCode != HAL_UART_ERROR_NONE) &&
205 (dma_handle->XferAbortCallback !=
nullptr);
213 GpdmaNvicMaskGuard irq_guard(dma_handle);
214 if (!irq_guard.Valid() || !irq_guard.WasEnabled())
225 if (dma_handle->State == HAL_DMA_STATE_ABORT)
227 return abort_is_joinable();
229 if (dma_handle->State == HAL_DMA_STATE_READY && IsStopped(dma_handle) &&
230 dma_handle->Lock == HAL_LOCKED)
236 if (dma_handle->State != HAL_DMA_STATE_BUSY)
241 AbortCallback
const previous_callback = dma_handle->XferAbortCallback;
242 const HAL_StatusTypeDef result = HAL_DMA_Abort_IT(dma_handle);
243 if (result == HAL_OK)
247 if (dma_handle->XferAbortCallback == previous_callback)
249 dma_handle->XferAbortCallback = callback;
253 return abort_is_joinable();
256 return ((dma_handle->State == HAL_DMA_STATE_ABORT) && abort_is_joinable()) ||
262 if ((dma_handle ==
nullptr) || !IsStopped(dma_handle) ||
263 (dma_handle->State != HAL_DMA_STATE_READY) || (dma_handle->Lock != HAL_UNLOCKED))
267 if ((dma_handle->Mode & DMA_LINKEDLIST) == DMA_LINKEDLIST)
269 return (dma_handle->LinkedListQueue !=
nullptr) &&
270 (dma_handle->LinkedListQueue->State == HAL_DMA_QUEUE_STATE_READY);
277 return ((state_.uart_handle_->hdmatx ==
nullptr) ||
279 ((state_.uart_handle_->hdmarx ==
nullptr) ||
285 DEV_ASSERT_FROM_CALLBACK(
StopComplete(dma_handle), in_isr);
286 DEV_ASSERT_FROM_CALLBACK(dma_handle->Lock == HAL_UNLOCKED, in_isr);
288 DisableInterrupts(dma_handle);
289 if ((dma_handle->Mode & DMA_LINKEDLIST) == DMA_LINKEDLIST)
293 dma_handle->Instance->CBR1 = 0U;
295 const volatile uint32_t ccr = dma_handle->Instance->CCR;
298 ClearFlags(dma_handle);
302bool STM32GpdmaUartAdapter::IsStopped(DMA_HandleTypeDef* dma_handle)
304 const uint32_t ccr = dma_handle->Instance->CCR;
305 return (ccr & DMA_CCR_EN) == 0U;
308void STM32GpdmaUartAdapter::DisableInterrupts(DMA_HandleTypeDef* dma_handle)
310 __HAL_DMA_DISABLE_IT(dma_handle, DMA_IT_TC | DMA_IT_HT | DMA_IT_DTE | DMA_IT_ULE |
311 DMA_IT_USE | DMA_IT_SUSP | DMA_IT_TO);
314void STM32GpdmaUartAdapter::ClearFlags(DMA_HandleTypeDef* dma_handle)
316 __HAL_DMA_CLEAR_FLAG(dma_handle, DMA_FLAG_TC | DMA_FLAG_HT | DMA_FLAG_DTE |
317 DMA_FLAG_ULE | DMA_FLAG_USE | DMA_FLAG_SUSP |
321void STM32GpdmaUartAdapter::BuildRxQueue(uint8_t* buffer,
size_t total_size,
bool in_isr)
323 DMA_HandleTypeDef*
const dma_handle = state_.uart_handle_->hdmarx;
324 DEV_ASSERT_FROM_CALLBACK(
StopComplete(dma_handle), in_isr);
325 ASSERT_FROM_CALLBACK(dma_handle->LinkedListQueue !=
nullptr, in_isr);
326 ASSERT_FROM_CALLBACK(dma_handle->LinkedListQueue->Head !=
nullptr, in_isr);
328 DMA_NodeConfTypeDef node_config{};
329 [[maybe_unused]]
const auto dma_ex_list_get_node_config_result =
330 HAL_DMAEx_List_GetNodeConfig(&node_config, dma_handle->LinkedListQueue->Head);
331 DEV_ASSERT_FROM_CALLBACK(dma_ex_list_get_node_config_result == HAL_OK, in_isr);
335 node_config.NodeType = DMA_GPDMA_LINEAR_NODE;
336 node_config.Init.BlkHWRequest = DMA_BREQ_SINGLE_BURST;
337 node_config.Init.Direction = DMA_PERIPH_TO_MEMORY;
338 node_config.Init.SrcInc = DMA_SINC_FIXED;
339 node_config.Init.DestInc = DMA_DINC_INCREMENTED;
340 node_config.Init.SrcDataWidth = DMA_SRC_DATAWIDTH_BYTE;
341 node_config.Init.DestDataWidth = DMA_DEST_DATAWIDTH_BYTE;
342 node_config.Init.SrcBurstLength = 1U;
343 node_config.Init.DestBurstLength = 1U;
344 node_config.Init.TransferEventMode = DMA_TCEM_BLOCK_TRANSFER;
345 node_config.Init.Mode = DMA_NORMAL;
346 node_config.DataHandlingConfig.DataExchange = DMA_EXCHANGE_NONE;
347 node_config.DataHandlingConfig.DataAlignment = DMA_DATA_RIGHTALIGN_ZEROPADDED;
348 node_config.TriggerConfig.TriggerMode = DMA_TRIGM_BLOCK_TRANSFER;
349 node_config.TriggerConfig.TriggerPolarity = DMA_TRIG_POLARITY_MASKED;
350 node_config.TriggerConfig.TriggerSelection = 0U;
351 node_config.RepeatBlockConfig = {};
353 const size_t node_size = total_size / RX_NODE_COUNT;
354 node_config.SrcAddress =
static_cast<uint32_t
>(
355 reinterpret_cast<uintptr_t
>(&state_.uart_handle_->Instance->RDR));
356 node_config.DataSize =
static_cast<uint32_t
>(node_size);
358 for (
size_t i = 0U; i < RX_NODE_COUNT; ++i)
360 node_config.DstAddress =
361 static_cast<uint32_t
>(
reinterpret_cast<uintptr_t
>(&buffer[i * node_size]));
362 [[maybe_unused]]
const auto dma_ex_list_build_node_result =
363 HAL_DMAEx_List_BuildNode(&node_config, &state_.nodes_[i]);
364 DEV_ASSERT_FROM_CALLBACK(dma_ex_list_build_node_result == HAL_OK, in_isr);
365 [[maybe_unused]]
const auto dma_ex_list_insert_node_tail_result =
366 HAL_DMAEx_List_InsertNode_Tail(&state_.rx_queue_, &state_.nodes_[i]);
367 DEV_ASSERT_FROM_CALLBACK(dma_ex_list_insert_node_tail_result == HAL_OK, in_isr);
370 [[maybe_unused]]
const auto dma_ex_list_set_circular_mode_result =
371 HAL_DMAEx_List_SetCircularMode(&state_.rx_queue_);
372 DEV_ASSERT_FROM_CALLBACK(dma_ex_list_set_circular_mode_result == HAL_OK, in_isr);
373 [[maybe_unused]]
const auto dma_ex_list_un_linkq_result =
374 HAL_DMAEx_List_UnLinkQ(dma_handle);
375 DEV_ASSERT_FROM_CALLBACK(dma_ex_list_un_linkq_result == HAL_OK, in_isr);
376 [[maybe_unused]]
const auto dma_ex_list_linkq_result =
377 HAL_DMAEx_List_LinkQ(dma_handle, &state_.rx_queue_);
378 DEV_ASSERT_FROM_CALLBACK(dma_ex_list_linkq_result == HAL_OK, in_isr);
379 DEV_ASSERT_FROM_CALLBACK(dma_handle->LinkedListQueue == &state_.rx_queue_, in_isr);
381 state_.rx_buffer_ = buffer;
382 state_.rx_total_size_ = total_size;
383 state_.rx_node_size_ = node_size;
384 state_.rx_queue_built_ =
true;
static void FinalizeStopped(DMA_HandleTypeDef *dma_handle, bool in_isr)
在停止状态清除旧标志和链表计数 / Clear stale flags and list count while stopped.
static bool StopComplete(DMA_HandleTypeDef *dma_handle)
检查通道及 HAL 链表均已停止 / Check that the channel and HAL list have stopped.
bool AllStopsComplete() const
检查所有已配置的 DMA 通道均已停止 / Check all configured DMA channels have stopped.
bool LaunchStop(DMA_HandleTypeDef *dma_handle, AbortCallback callback, bool in_isr)
启动异步中止或接续已有中止 / Start an asynchronous abort or join an existing abort.
uint8_t * GetLinkedListDmaRxProducer() const
读取一次当前 DMA 写入地址 / Read the current DMA destination address once.
HAL_StatusTypeDef StartLinkedListDmaRx(uint8_t *buffer, size_t total_size, bool in_isr)
构建或复用四节点循环链表并启动 RX / Build or reuse the four-node ring and start RX.
STM32GpdmaUartAdapter(UART_HandleTypeDef *uart_handle)
绑定已初始化的 UART 句柄 / Bind an initialized UART handle.
void CloseTxTerminalSource() const
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
void STM32_CleanDCacheByAddr(const void *addr, size_t size)
清理指定内存范围覆盖的 D-Cache cache line Cleans D-Cache lines covering the specified memory range