libxr
Embedded C++ framework for bare-metal, RTOS and Linux
Loading...
Searching...
No Matches
stm32_adc_gpdma.cpp
1#include "stm32_adc_gpdma.hpp"
2
3#if defined(LIBXR_STM32_ADC_GPDMA) && defined(HAL_ADC_MODULE_ENABLED)
4
5#include <limits>
6
7#include "libxr_def.hpp"
8#include "stm32_dcache.hpp"
9
10namespace LibXR
11{
12
13HAL_StatusTypeDef STM32GpdmaAdcAdapter::Start(ADC_HandleTypeDef* adc_handle,
14 uint32_t* buffer, uint32_t sample_count,
15 size_t buffer_size)
16{
17 ASSERT(adc_handle != nullptr);
18 ASSERT(adc_handle->DMA_Handle != nullptr);
19 ASSERT(buffer != nullptr);
20 ASSERT(sample_count > 0U);
21 ASSERT(sample_count <= std::numeric_limits<size_t>::max() / sizeof(uint16_t));
22 ASSERT(buffer_size >= static_cast<size_t>(sample_count) * sizeof(uint16_t));
23 DMA_HandleTypeDef* const dma_handle = adc_handle->DMA_Handle;
24 ASSERT(dma_handle->Parent == adc_handle);
25 ASSERT(IS_GPDMA_INSTANCE(dma_handle->Instance) != 0U);
26 ASSERT(dma_handle->Mode == DMA_LINKEDLIST_CIRCULAR);
27 ASSERT(dma_handle->InitLinkedList.LinkedListMode == DMA_LINKEDLIST_CIRCULAR);
28 ASSERT(dma_handle->InitLinkedList.LinkStepMode == DMA_LSM_FULL_EXECUTION);
29 ASSERT((dma_handle->Instance->CCR & DMA_CCR_LSM) == DMA_LSM_FULL_EXECUTION);
30
31 if (state_.original_queue == nullptr)
32 {
33 BuildAndAttach(adc_handle, buffer, sample_count, buffer_size);
34 }
35 else
36 {
37 DEV_ASSERT(dma_handle->LinkedListQueue == &state_.queue);
38 DEV_ASSERT(state_.queue.Head == &state_.node);
39 DEV_ASSERT(state_.queue.FirstCircularNode == &state_.node);
40 DEV_ASSERT(state_.queue.NodeNumber == 1U);
41 }
42
43 FinalizeStopped(dma_handle);
44 STM32_CleanDCacheByAddr(&state_, sizeof(state_));
45 STM32_CleanDCacheByAddr(buffer, buffer_size);
46 STM32_InvalidateDCacheByAddr(buffer, buffer_size);
47
48 return HAL_ADC_Start_DMA(adc_handle, buffer, sample_count);
49}
50
51HAL_StatusTypeDef STM32GpdmaAdcAdapter::Stop(ADC_HandleTypeDef* adc_handle)
52{
53 ASSERT(adc_handle != nullptr);
54 ASSERT(adc_handle->DMA_Handle != nullptr);
55 DMA_HandleTypeDef* const dma_handle = adc_handle->DMA_Handle;
56 ASSERT(dma_handle->Parent == adc_handle);
57
58 const HAL_StatusTypeDef stop_status = HAL_ADC_Stop_DMA(adc_handle);
59 if (stop_status != HAL_OK)
60 {
61 return stop_status;
62 }
63
64 if (state_.original_queue == nullptr)
65 {
66 return HAL_OK;
67 }
68
69 FinalizeStopped(dma_handle);
70 DEV_ASSERT(dma_handle->LinkedListQueue == &state_.queue);
71 DEV_ASSERT(state_.queue.State == HAL_DMA_QUEUE_STATE_READY);
72 DMA_QListTypeDef* const original_queue = state_.original_queue;
73 [[maybe_unused]] const auto dma_ex_list_un_linkq_result =
74 HAL_DMAEx_List_UnLinkQ(dma_handle);
75 DEV_ASSERT(dma_ex_list_un_linkq_result == HAL_OK);
76 [[maybe_unused]] const auto dma_ex_list_linkq_result =
77 HAL_DMAEx_List_LinkQ(dma_handle, original_queue);
78 DEV_ASSERT(dma_ex_list_linkq_result == HAL_OK);
79 DEV_ASSERT(dma_handle->LinkedListQueue == original_queue);
80 state_.original_queue = nullptr;
81 return HAL_OK;
82}
83
84void STM32GpdmaAdcAdapter::FinalizeStopped(DMA_HandleTypeDef* dma_handle)
85{
86 DEV_ASSERT(dma_handle->State == HAL_DMA_STATE_READY);
87 DEV_ASSERT(dma_handle->Lock == HAL_UNLOCKED);
88 DEV_ASSERT((dma_handle->Instance->CCR & DMA_CCR_EN) == 0U);
89 DEV_ASSERT(dma_handle->LinkedListQueue != nullptr);
90 DEV_ASSERT(dma_handle->LinkedListQueue->State == HAL_DMA_QUEUE_STATE_READY);
91
92 // 错误中断可能保留块计数,清零后下次启动才会装载链表头。
93 // Error IRQs may retain the block count; clear it so the next start loads the list
94 // head.
95 __HAL_DMA_DISABLE_IT(dma_handle, DMA_IT_TC | DMA_IT_HT | DMA_IT_DTE | DMA_IT_ULE |
96 DMA_IT_USE | DMA_IT_SUSP | DMA_IT_TO);
97 dma_handle->Instance->CBR1 = 0U;
98 __HAL_DMA_CLEAR_FLAG(dma_handle, DMA_FLAG_TC | DMA_FLAG_HT | DMA_FLAG_DTE |
99 DMA_FLAG_ULE | DMA_FLAG_USE | DMA_FLAG_SUSP |
100 DMA_FLAG_TO);
101 __DSB();
102}
103
104void STM32GpdmaAdcAdapter::BuildAndAttach(ADC_HandleTypeDef* adc_handle, uint32_t* buffer,
105 uint32_t sample_count, size_t buffer_size)
106{
107 DMA_HandleTypeDef* const dma_handle = adc_handle->DMA_Handle;
108 ASSERT(dma_handle->State == HAL_DMA_STATE_READY);
109 ASSERT((dma_handle->Instance->CCR & DMA_CCR_EN) == 0U);
110 ASSERT(dma_handle->LinkedListQueue != nullptr);
111 ASSERT(dma_handle->LinkedListQueue->Head != nullptr);
112 ASSERT(dma_handle->LinkedListQueue->FirstCircularNode != nullptr);
113 ASSERT(dma_handle->LinkedListQueue->State == HAL_DMA_QUEUE_STATE_READY);
114
115 DMA_NodeConfTypeDef node_config{};
116 [[maybe_unused]] const auto dma_ex_list_get_node_config_result =
117 HAL_DMAEx_List_GetNodeConfig(&node_config, dma_handle->LinkedListQueue->Head);
118 DEV_ASSERT(dma_ex_list_get_node_config_result == HAL_OK);
119 ASSERT(node_config.Init.Direction == DMA_PERIPH_TO_MEMORY);
120 ASSERT(node_config.Init.SrcInc == DMA_SINC_FIXED);
121 ASSERT(node_config.Init.DestInc == DMA_DINC_INCREMENTED);
122 ASSERT(node_config.Init.SrcDataWidth == DMA_SRC_DATAWIDTH_HALFWORD);
123 ASSERT(node_config.Init.DestDataWidth == DMA_DEST_DATAWIDTH_HALFWORD);
124 ASSERT(node_config.Init.SrcBurstLength == 1U);
125 ASSERT(node_config.Init.DestBurstLength == 1U);
126 ASSERT(node_config.Init.BlkHWRequest == DMA_BREQ_SINGLE_BURST);
127 ASSERT(node_config.Init.Mode == DMA_NORMAL);
128 ASSERT(node_config.TriggerConfig.TriggerPolarity == DMA_TRIG_POLARITY_MASKED);
129 ASSERT(node_config.DataHandlingConfig.DataExchange == DMA_EXCHANGE_NONE);
130 ASSERT(sample_count <= std::numeric_limits<uint32_t>::max() / sizeof(uint16_t));
131
132 const uint32_t transfer_size = sample_count * sizeof(uint16_t);
133 ASSERT(buffer_size >= transfer_size);
134 ASSERT(IS_DMA_BLOCK_SIZE(transfer_size) != 0U);
135
136 node_config.NodeType = DMA_GPDMA_LINEAR_NODE;
137 node_config.SrcAddress =
138 static_cast<uint32_t>(reinterpret_cast<uintptr_t>(&adc_handle->Instance->DR));
139 node_config.DstAddress = static_cast<uint32_t>(reinterpret_cast<uintptr_t>(buffer));
140 node_config.DataSize = transfer_size;
141
142 DEV_ASSERT(state_.queue.Head == nullptr);
143 DEV_ASSERT(state_.queue.NodeNumber == 0U);
144 [[maybe_unused]] const auto dma_ex_list_build_node_result =
145 HAL_DMAEx_List_BuildNode(&node_config, &state_.node);
146 DEV_ASSERT(dma_ex_list_build_node_result == HAL_OK);
147 [[maybe_unused]] const auto dma_ex_list_insert_node_tail_result =
148 HAL_DMAEx_List_InsertNode_Tail(&state_.queue, &state_.node);
149 DEV_ASSERT(dma_ex_list_insert_node_tail_result == HAL_OK);
150 [[maybe_unused]] const auto dma_ex_list_set_circular_mode_result =
151 HAL_DMAEx_List_SetCircularMode(&state_.queue);
152 DEV_ASSERT(dma_ex_list_set_circular_mode_result == HAL_OK);
153 DEV_ASSERT(state_.queue.Head == &state_.node);
154 DEV_ASSERT(state_.queue.FirstCircularNode == &state_.node);
155 DEV_ASSERT(state_.queue.NodeNumber == 1U);
156 DEV_ASSERT(state_.queue.State == HAL_DMA_QUEUE_STATE_READY);
157
158 state_.original_queue = dma_handle->LinkedListQueue;
159 [[maybe_unused]] const auto dma_ex_list_un_linkq_result =
160 HAL_DMAEx_List_UnLinkQ(dma_handle);
161 DEV_ASSERT(dma_ex_list_un_linkq_result == HAL_OK);
162 [[maybe_unused]] const auto dma_ex_list_linkq_result =
163 HAL_DMAEx_List_LinkQ(dma_handle, &state_.queue);
164 DEV_ASSERT(dma_ex_list_linkq_result == HAL_OK);
165 DEV_ASSERT(dma_handle->LinkedListQueue == &state_.queue);
166}
167
168} // namespace LibXR
169
170#endif
HAL_StatusTypeDef Start(ADC_HandleTypeDef *adc_handle, uint32_t *buffer, uint32_t sample_count, size_t buffer_size)
挂接循环链表并启动 ADC DMA / Attach the circular list and start ADC DMA.
HAL_StatusTypeDef Stop(ADC_HandleTypeDef *adc_handle)
停止 ADC DMA 并恢复 BSP 链表 / Stop ADC DMA and restore the BSP list.
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
void STM32_CleanDCacheByAddr(const void *addr, size_t size)
清理指定内存范围覆盖的 D-Cache cache line Cleans D-Cache lines covering the specified memory range