libxr  1.0
Want to be the best embedded framework
Loading...
Searching...
No Matches
stm32_spi.cpp
1#include "stm32_spi.hpp"
2
3#include "libxr_def.hpp"
4
5#ifdef HAL_SPI_MODULE_ENABLED
6
7using namespace LibXR;
8
9STM32SPI *STM32SPI::map[STM32_SPI_NUMBER] = {nullptr};
10
11stm32_spi_id_t STM32_SPI_GetID(SPI_TypeDef *addr)
12{
13 if (addr == nullptr)
14 { // NOLINT
15 return stm32_spi_id_t::STM32_SPI_ID_ERROR;
16 }
17#ifdef SPI1
18 else if (addr == SPI1)
19 { // NOLINT
20 return stm32_spi_id_t::STM32_SPI1;
21 }
22#endif
23#ifdef SPI2
24 else if (addr == SPI2)
25 { // NOLINT
26 return stm32_spi_id_t::STM32_SPI2;
27 }
28#endif
29#ifdef SPI3
30 else if (addr == SPI3)
31 { // NOLINT
32 return stm32_spi_id_t::STM32_SPI3;
33 }
34#endif
35#ifdef SPI4
36 else if (addr == SPI4)
37 { // NOLINT
38 return stm32_spi_id_t::STM32_SPI4;
39 }
40#endif
41#ifdef SPI5
42 else if (addr == SPI5)
43 { // NOLINT
44 return stm32_spi_id_t::STM32_SPI5;
45 }
46#endif
47#ifdef SPI6
48 else if (addr == SPI6)
49 { // NOLINT
50 return stm32_spi_id_t::STM32_SPI6;
51 }
52#endif
53#ifdef SPI7
54 else if (addr == SPI7)
55 { // NOLINT
56 return stm32_spi_id_t::STM32_SPI7;
57 }
58#endif
59#ifdef SPI8
60 else if (addr == SPI8)
61 { // NOLINT
62 return stm32_spi_id_t::STM32_SPI8;
63 }
64#endif
65 else
66 {
67 return stm32_spi_id_t::STM32_SPI_ID_ERROR;
68 }
69}
70
71STM32SPI::STM32SPI(SPI_HandleTypeDef *spi_handle, RawData dma_buff_rx,
72 RawData dma_buff_tx, uint32_t dma_enable_min_size)
73 : SPI(),
74 dma_buff_rx_(dma_buff_rx),
75 dma_buff_tx_(dma_buff_tx),
76 spi_handle_(spi_handle),
77 id_(STM32_SPI_GetID(spi_handle_->Instance)),
78 dma_enable_min_size_(dma_enable_min_size)
79{
80 ASSERT(id_ != STM32_SPI_ID_ERROR);
81
82 map[id_] = this;
83}
84
85ErrorCode STM32SPI::ReadAndWrite(RawData read_data, ConstRawData write_data,
86 OperationRW &op)
87{
88 uint32_t need_write = max(write_data.size_, read_data.size_);
89
90 if (dma_buff_rx_.size_ > 0)
91 {
92 ASSERT(need_write <= dma_buff_rx_.size_);
93 }
94
95 if (dma_buff_tx_.size_ > 0)
96 {
97 ASSERT(need_write <= dma_buff_tx_.size_);
98 }
99
100 if (spi_handle_->State != HAL_SPI_STATE_READY)
101 {
102 return ErrorCode::BUSY;
103 }
104
105 mem_read_ = false;
106
107 if (need_write > dma_enable_min_size_)
108 {
109 rw_op_ = op;
110
111 if (write_data.size_ > 0)
112 {
113 memcpy(dma_buff_tx_.addr_, write_data.addr_, need_write);
114
115#if __DCACHE_PRESENT
116 SCB_CleanDCache_by_Addr(static_cast<uint32_t *>(dma_buff_tx_.addr_),
117 static_cast<int32_t>(write_data.size_));
118#endif
119 }
120 if (read_data.size_ > 0)
121 {
122 read_buff_ = read_data;
123 }
124
125 if (write_data.size_ > 0 && read_data.size_ > 0)
126 {
127 HAL_SPI_TransmitReceive_DMA(spi_handle_, static_cast<uint8_t *>(dma_buff_tx_.addr_),
128 static_cast<uint8_t *>(dma_buff_rx_.addr_), need_write);
129 }
130 else if (write_data.size_ > 0)
131 {
132 HAL_SPI_Transmit_DMA(spi_handle_, static_cast<uint8_t *>(dma_buff_tx_.addr_),
133 need_write);
134 }
135 else if (read_data.size_ > 0)
136 {
137 HAL_SPI_Receive_DMA(spi_handle_, static_cast<uint8_t *>(dma_buff_rx_.addr_),
138 need_write);
139 }
140 else
141 {
142 if (op.type != OperationRW::OperationType::BLOCK)
143 {
144 op.UpdateStatus(false, ErrorCode::OK);
145 }
146 return ErrorCode::OK;
147 }
148
149 op.MarkAsRunning();
150 if (op.type == OperationRW::OperationType::BLOCK)
151 {
152 return op.data.sem_info.sem->Wait(op.data.sem_info.timeout);
153 }
154 return ErrorCode::OK;
155 }
156 else
157 {
158 if (write_data.size_ > 0)
159 {
160 memcpy(dma_buff_tx_.addr_, write_data.addr_, write_data.size_);
161 }
162
163 ErrorCode ans = ErrorCode::OK;
164 if (read_data.size_ > 0 && write_data.size_ > 0)
165 {
166 ans = HAL_SPI_TransmitReceive(
167 spi_handle_, static_cast<uint8_t *>(dma_buff_tx_.addr_),
168 static_cast<uint8_t *>(dma_buff_rx_.addr_), need_write, 20) == HAL_OK
169 ? ErrorCode::OK
170 : ErrorCode::BUSY;
171 }
172 else if (read_data.size_ > 0)
173 {
174 ans = HAL_SPI_Receive(spi_handle_, static_cast<uint8_t *>(dma_buff_rx_.addr_),
175 need_write, 20) == HAL_OK
176 ? ErrorCode::OK
177 : ErrorCode::BUSY;
178 }
179 else if (write_data.size_ > 0)
180 {
181 ans = HAL_SPI_Transmit(spi_handle_, static_cast<uint8_t *>(dma_buff_tx_.addr_),
182 need_write, 20) == HAL_OK
183 ? ErrorCode::OK
184 : ErrorCode::BUSY;
185 }
186 else
187 {
188 if (op.type != OperationRW::OperationType::BLOCK)
189 {
190 op.UpdateStatus(false, ErrorCode::OK);
191 }
192 return ErrorCode::OK;
193 }
194
195 memcpy(read_data.addr_, dma_buff_rx_.addr_, read_data.size_);
196
197 op.UpdateStatus(false, std::forward<ErrorCode>(ans));
198
199 if (op.type == OperationRW::OperationType::BLOCK)
200 {
201 return op.data.sem_info.sem->Wait(op.data.sem_info.timeout);
202 }
203
204 return ans;
205 }
206}
207
209{
210 switch (config.clock_polarity)
211 {
213 spi_handle_->Init.CLKPolarity = SPI_POLARITY_LOW;
214 break;
216 spi_handle_->Init.CLKPolarity = SPI_POLARITY_HIGH;
217 break;
218 }
219
220 switch (config.clock_phase)
221 {
223 spi_handle_->Init.CLKPhase = SPI_PHASE_1EDGE;
224 break;
226 spi_handle_->Init.CLKPhase = SPI_PHASE_2EDGE;
227 break;
228 }
229
230 return HAL_SPI_Init(spi_handle_) == HAL_OK ? ErrorCode::OK : ErrorCode::BUSY;
231}
232
233ErrorCode STM32SPI::MemRead(uint16_t reg, RawData read_data, OperationRW &op)
234{
235 uint32_t need_read = read_data.size_;
236
237 if (spi_handle_->State != HAL_SPI_STATE_READY)
238 {
239 return ErrorCode::BUSY;
240 }
241
242 ASSERT(dma_buff_rx_.size_ >= need_read + 1);
243 ASSERT(dma_buff_tx_.size_ >= need_read + 1);
244
245 uint8_t *dma_buffer_rx = reinterpret_cast<uint8_t *>(dma_buff_rx_.addr_);
246 uint8_t *dma_buffer_tx = reinterpret_cast<uint8_t *>(dma_buff_tx_.addr_);
247
248 if (need_read + 1 > dma_enable_min_size_)
249 {
250 mem_read_ = true;
251 memset(dma_buff_tx_.addr_, 0, need_read + 1);
252 dma_buffer_tx[0] = reg | 0x80;
253 rw_op_ = op;
254 read_buff_ = read_data;
255
256 HAL_SPI_TransmitReceive_DMA(spi_handle_, static_cast<uint8_t *>(dma_buff_tx_.addr_),
257 static_cast<uint8_t *>(dma_buff_rx_.addr_),
258 need_read + 1);
259
260 op.MarkAsRunning();
261 if (op.type == OperationRW::OperationType::BLOCK)
262 {
263 return op.data.sem_info.sem->Wait(op.data.sem_info.timeout);
264 }
265 return ErrorCode::OK;
266 }
267 else
268 {
269 mem_read_ = false;
270 memset(dma_buff_tx_.addr_, 0, need_read + 1);
271 dma_buffer_tx[0] = reg | 0x80;
272 ErrorCode ans =
273 HAL_SPI_TransmitReceive(spi_handle_, static_cast<uint8_t *>(dma_buff_tx_.addr_),
274 static_cast<uint8_t *>(dma_buff_rx_.addr_), need_read + 1,
275 20) == HAL_OK
276 ? ErrorCode::OK
277 : ErrorCode::BUSY;
278
279 memcpy(read_data.addr_, dma_buffer_rx + 1, read_data.size_);
280
281 op.UpdateStatus(false, std::forward<ErrorCode>(ans));
282
283 if (op.type == OperationRW::OperationType::BLOCK)
284 {
285 return op.data.sem_info.sem->Wait(op.data.sem_info.timeout);
286 }
287
288 return ans;
289 }
290}
291
292ErrorCode STM32SPI::MemWrite(uint16_t reg, ConstRawData write_data, OperationRW &op)
293{
294 uint32_t need_write = write_data.size_;
295
296 if (spi_handle_->State != HAL_SPI_STATE_READY)
297 {
298 return ErrorCode::BUSY;
299 }
300
301 mem_read_ = false;
302
303 ASSERT(dma_buff_tx_.size_ >= need_write + 1);
304
305 uint8_t *dma_buffer_tx = reinterpret_cast<uint8_t *>(dma_buff_tx_.addr_);
306
307 if (need_write + 1 > dma_enable_min_size_)
308 {
309 memcpy(dma_buffer_tx + 1, write_data.addr_, need_write);
310 *dma_buffer_tx = reg & 0x7f;
311
312 rw_op_ = op;
313 read_buff_ = {nullptr, 0};
314
315 HAL_SPI_Transmit_DMA(spi_handle_, dma_buffer_tx, need_write + 1);
316
317 op.MarkAsRunning();
318 if (op.type == OperationRW::OperationType::BLOCK)
319 {
320 return op.data.sem_info.sem->Wait(op.data.sem_info.timeout);
321 }
322 return ErrorCode::OK;
323 }
324 else
325 {
326 memcpy(dma_buffer_tx + 1, write_data.addr_, need_write);
327 *dma_buffer_tx = reg & 0x7f;
328 ErrorCode ans =
329 HAL_SPI_Transmit(spi_handle_, dma_buffer_tx, need_write + 1, 20) == HAL_OK
330 ? ErrorCode::OK
331 : ErrorCode::BUSY;
332
333 op.UpdateStatus(false, std::forward<ErrorCode>(ans));
334
335 if (op.type == OperationRW::OperationType::BLOCK)
336 {
337 return op.data.sem_info.sem->Wait(op.data.sem_info.timeout);
338 }
339
340 return ans;
341 }
342}
343
344extern "C" void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi)
345{
346 STM32SPI *spi = STM32SPI::map[STM32_SPI_GetID(hspi->Instance)];
347 spi->rw_op_.UpdateStatus(true, ErrorCode::OK);
348}
349
350extern "C" void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi)
351{
352 STM32SPI *spi = STM32SPI::map[STM32_SPI_GetID(hspi->Instance)];
353
354 if (spi->read_buff_.size_ > 0)
355 {
356#if __DCACHE_PRESENT
357 SCB_InvalidateDCache_by_Addr(spi->dma_buff_rx_.addr_, spi->read_buff_.size_);
358#endif
359 if (!spi->mem_read_)
360 {
361 memcpy(spi->read_buff_.addr_, spi->dma_buff_rx_.addr_, spi->read_buff_.size_);
362 }
363 else
364 {
365 uint8_t *rx_dma_buff = reinterpret_cast<uint8_t *>(spi->dma_buff_rx_.addr_);
366 memcpy(spi->read_buff_.addr_, rx_dma_buff + 1, spi->read_buff_.size_);
367 }
368 }
369
370 spi->rw_op_.UpdateStatus(true, ErrorCode::OK);
371}
372
373extern "C" void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi)
374{
375 HAL_SPI_RxCpltCallback(hspi);
376}
377
378extern "C" void HAL_SPI_ErrorCallback(SPI_HandleTypeDef *hspi)
379{
380 STM32SPI *spi = STM32SPI::map[STM32_SPI_GetID(hspi->Instance)];
381 spi->rw_op_.UpdateStatus(false, ErrorCode::FAILED);
382}
383
384#endif
常量原始数据封装类。 A class for encapsulating constant raw data.
size_t size_
数据大小(字节)。 The size of the data (in bytes).
const void * addr_
数据存储地址(常量)。 The storage address of the data (constant).
void MarkAsRunning()
标记操作为运行状态。 Marks the operation as running.
Definition libxr_rw.hpp:202
void UpdateStatus(bool in_isr, Status &&...status)
Updates operation status based on type.
Definition libxr_rw.hpp:171
union LibXR::Operation::@4 data
OperationType type
Definition libxr_rw.hpp:225
原始数据封装类。 A class for encapsulating raw data.
size_t size_
数据大小(字节)。 The size of the data (in bytes).
void * addr_
数据存储地址。 The storage address of the data.
串行外设接口(SPI)抽象类。Abstract class for Serial Peripheral Interface (SPI).
Definition spi.hpp:13
@ EDGE_2
在第二个时钟边沿采样数据。Data sampled on the second clock edge.
@ EDGE_1
在第一个时钟边沿采样数据。Data sampled on the first clock edge.
@ LOW
时钟空闲时为低电平。Clock idle low.
@ HIGH
时钟空闲时为高电平。Clock idle high.
ErrorCode ReadAndWrite(RawData read_data, ConstRawData write_data, OperationRW &op) override
进行 SPI 读写操作。Performs SPI read and write operations.
Definition stm32_spi.cpp:85
ErrorCode MemRead(uint16_t reg, RawData read_data, OperationRW &op) override
从 SPI 设备的寄存器读取数据。 Reads data from a specific register of the SPI device.
ErrorCode MemWrite(uint16_t reg, ConstRawData write_data, OperationRW &op) override
向 SPI 设备的寄存器写入数据。 Writes data to a specific register of the SPI device.
ErrorCode SetConfig(SPI::Configuration config) override
设置 SPI 配置参数。Sets SPI configuration parameters.
ErrorCode Wait(uint32_t timeout=UINT32_MAX)
等待(减少)信号量 Waits (decrements) the semaphore
Definition semaphore.cpp:25
LibXR 命名空间
Definition ch32_gpio.hpp:9
constexpr auto max(T1 a, T2 b) -> typename std::common_type< T1, T2 >::type
计算两个数的最大值
存储 SPI 配置参数的结构体。Structure for storing SPI configuration parameters.
Definition spi.hpp:46
ClockPhase clock_phase
SPI 时钟相位。SPI clock phase.
Definition spi.hpp:48
ClockPolarity clock_polarity
SPI 时钟极性。SPI clock polarity.
Definition spi.hpp:47