libxr  1.0
Want to be the best embedded framework
Loading...
Searching...
No Matches
stm32_i2c.cpp
1#include "stm32_i2c.hpp"
2
3#ifdef HAL_I2C_MODULE_ENABLED
4
5using namespace LibXR;
6
7STM32I2C* STM32I2C::map[STM32_I2C_NUMBER] = {nullptr};
8
9stm32_i2c_id_t STM32_I2C_GetID(I2C_TypeDef* hi2c)
10{ // NOLINT
11 if (hi2c == nullptr)
12 {
13 return stm32_i2c_id_t::STM32_I2C_ID_ERROR;
14 }
15#ifdef I2C1
16 else if (hi2c == I2C1)
17 { // NOLINT
18 return stm32_i2c_id_t::STM32_I2C1;
19 }
20#endif
21#ifdef I2C2
22 else if (hi2c == I2C2)
23 { // NOLINT
24 return stm32_i2c_id_t::STM32_I2C2;
25 }
26#endif
27#ifdef I2C3
28 else if (hi2c == I2C3)
29 { // NOLINT
30 return stm32_i2c_id_t::STM32_I2C3;
31 }
32#endif
33#ifdef I2C4
34 else if (hi2c == I2C4)
35 { // NOLINT
36 return stm32_i2c_id_t::STM32_I2C4;
37 }
38#endif
39#ifdef I2C5
40 else if (hi2c == I2C5)
41 { // NOLINT
42 return stm32_i2c_id_t::STM32_I2C5;
43 }
44#endif
45#ifdef I2C6
46 else if (hi2c == I2C6)
47 { // NOLINT
48 return stm32_i2c_id_t::STM32_I2C6;
49 }
50#endif
51#ifdef I2C7
52 else if (hi2c == I2C7)
53 { // NOLINT
54 return stm32_i2c_id_t::STM32_I2C7;
55 }
56#endif
57#ifdef I2C8
58 else if (hi2c == I2C8)
59 { // NOLINT
60 return stm32_i2c_id_t::STM32_I2C8;
61 }
62#endif
63 return stm32_i2c_id_t::STM32_I2C_ID_ERROR;
64}
65
66namespace
67{
68
69// 统一输入:
70// - 7-bit 模式:传 0x00~0x7F(不带 R/W 位),内部左移 1 给 HAL
71// - 10-bit 模式:传 0x000~0x3FF(不带 R/W 位),内部直接给 HAL
72static inline uint16_t EncodeHalDevAddress(const I2C_HandleTypeDef* hi2c,
73 uint16_t slave_addr)
74{
75 ASSERT(hi2c != nullptr);
76
77#if defined(I2C_ADDRESSINGMODE_10BIT)
78 if (hi2c->Init.AddressingMode == I2C_ADDRESSINGMODE_10BIT)
79 {
80 ASSERT(slave_addr <= 0x03FF);
81 return static_cast<uint16_t>(slave_addr & 0x03FF);
82 }
83#endif
84
85 // 默认按 7-bit
86 ASSERT(slave_addr <= 0x007F);
87 return static_cast<uint16_t>((slave_addr & 0x007F) << 1);
88}
89
90} // namespace
91
92STM32I2C::STM32I2C(I2C_HandleTypeDef* hi2c, RawData dma_buff,
93 uint32_t dma_enable_min_size)
94 : I2C(),
95 id_(STM32_I2C_GetID(hi2c->Instance)),
96 i2c_handle_(hi2c),
97 dma_enable_min_size_(dma_enable_min_size),
98 dma_buff_(dma_buff)
99{
100 map[id_] = this;
101}
102
103ErrorCode STM32I2C::Read(uint16_t slave_addr, RawData read_data, ReadOperation& op,
104 bool in_isr)
105{
106 if (i2c_handle_->State != HAL_I2C_STATE_READY)
107 {
108 return ErrorCode::BUSY;
109 }
110
111 read_ = true;
112
113 const uint16_t dev_addr = EncodeHalDevAddress(i2c_handle_, slave_addr);
114
115 if (read_data.size_ > dma_enable_min_size_)
116 {
117 read_op_ = op;
118 HAL_I2C_Master_Receive_DMA(i2c_handle_, dev_addr,
119 reinterpret_cast<uint8_t*>(dma_buff_.addr_),
120 read_data.size_);
121 read_buff_ = read_data;
122 op.MarkAsRunning();
123 if (op.type == ReadOperation::OperationType::BLOCK)
124 {
125 return op.data.sem_info.sem->Wait(op.data.sem_info.timeout);
126 }
127 return ErrorCode::OK;
128 }
129 else
130 {
131 auto ans = HAL_I2C_Master_Receive(i2c_handle_, dev_addr,
132 reinterpret_cast<uint8_t*>(read_data.addr_),
133 read_data.size_, 20) == HAL_OK
134 ? ErrorCode::OK
135 : ErrorCode::BUSY;
136 // BLOCK 模式下沿用统一状态更新路径。
137 // Reuse the same status update path for BLOCK mode.
138 op.UpdateStatus(in_isr, ans);
139 if (op.type == ReadOperation::OperationType::BLOCK)
140 {
141 return op.data.sem_info.sem->Wait(op.data.sem_info.timeout);
142 }
143 return ans;
144 }
145}
146
147ErrorCode STM32I2C::Write(uint16_t slave_addr, ConstRawData write_data,
148 WriteOperation& op, bool in_isr)
149{
150 if (i2c_handle_->State != HAL_I2C_STATE_READY)
151 {
152 return ErrorCode::BUSY;
153 }
154
155 read_ = false;
156
157 const uint16_t dev_addr = EncodeHalDevAddress(i2c_handle_, slave_addr);
158
159 Memory::FastCopy(dma_buff_.addr_, write_data.addr_, write_data.size_);
160
161 if (write_data.size_ > dma_enable_min_size_)
162 {
163 write_op_ = op;
164#if defined(__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U)
165 SCB_CleanDCache_by_Addr(reinterpret_cast<uint32_t*>(dma_buff_.addr_),
166 write_data.size_);
167#endif
168 HAL_I2C_Master_Transmit_DMA(i2c_handle_, dev_addr,
169 reinterpret_cast<uint8_t*>(dma_buff_.addr_),
170 write_data.size_);
171 op.MarkAsRunning();
172 if (op.type == WriteOperation::OperationType::BLOCK)
173 {
174 return op.data.sem_info.sem->Wait(op.data.sem_info.timeout);
175 }
176 return ErrorCode::OK;
177 }
178 else
179 {
180 auto ans = HAL_I2C_Master_Transmit(i2c_handle_, dev_addr,
181 reinterpret_cast<uint8_t*>(dma_buff_.addr_),
182 write_data.size_, 20) == HAL_OK
183 ? ErrorCode::OK
184 : ErrorCode::BUSY;
185 op.UpdateStatus(in_isr, ans);
186 if (op.type == WriteOperation::OperationType::BLOCK)
187 {
188 return op.data.sem_info.sem->Wait(op.data.sem_info.timeout);
189 }
190 return ans;
191 }
192}
193
194ErrorCode STM32I2C::MemRead(uint16_t slave_addr, uint16_t mem_addr, RawData read_data,
195 ReadOperation& op, MemAddrLength mem_addr_size, bool in_isr)
196{
197 ASSERT(read_data.size_ <= dma_buff_.size_);
198
199 if (i2c_handle_->State != HAL_I2C_STATE_READY)
200 {
201 return ErrorCode::BUSY;
202 }
203
204 read_ = true;
205
206 const uint16_t dev_addr = EncodeHalDevAddress(i2c_handle_, slave_addr);
207
208 if (read_data.size_ > dma_enable_min_size_)
209 {
210 read_op_ = op;
211 HAL_I2C_Mem_Read_DMA(i2c_handle_, dev_addr, mem_addr,
212 mem_addr_size == MemAddrLength::BYTE_8 ? I2C_MEMADD_SIZE_8BIT
213 : I2C_MEMADD_SIZE_16BIT,
214 reinterpret_cast<uint8_t*>(dma_buff_.addr_), read_data.size_);
215 read_buff_ = read_data;
216 op.MarkAsRunning();
217 if (op.type == ReadOperation::OperationType::BLOCK)
218 {
219 return op.data.sem_info.sem->Wait(op.data.sem_info.timeout);
220 }
221 return ErrorCode::OK;
222 }
223 else
224 {
225 auto ans =
226 HAL_I2C_Mem_Read(i2c_handle_, dev_addr, mem_addr,
227 mem_addr_size == MemAddrLength::BYTE_8 ? I2C_MEMADD_SIZE_8BIT
228 : I2C_MEMADD_SIZE_16BIT,
229 reinterpret_cast<uint8_t*>(read_data.addr_), read_data.size_,
230 20) == HAL_OK
231 ? ErrorCode::OK
232 : ErrorCode::BUSY;
233
234 op.UpdateStatus(in_isr, ans);
235 if (op.type == ReadOperation::OperationType::BLOCK)
236 {
237 return op.data.sem_info.sem->Wait(op.data.sem_info.timeout);
238 }
239 return ans;
240 }
241}
242
243ErrorCode STM32I2C::MemWrite(uint16_t slave_addr, uint16_t mem_addr,
244 ConstRawData write_data, WriteOperation& op,
245 MemAddrLength mem_addr_size, bool in_isr)
246{
247 ASSERT(write_data.size_ <= dma_buff_.size_);
248
249 if (i2c_handle_->State != HAL_I2C_STATE_READY)
250 {
251 return ErrorCode::BUSY;
252 }
253
254 read_ = false;
255
256 const uint16_t dev_addr = EncodeHalDevAddress(i2c_handle_, slave_addr);
257
258 Memory::FastCopy(dma_buff_.addr_, write_data.addr_, write_data.size_);
259
260 if (write_data.size_ > dma_enable_min_size_)
261 {
262 write_op_ = op;
263#if defined(__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U)
264 SCB_CleanDCache_by_Addr(reinterpret_cast<uint32_t*>(dma_buff_.addr_),
265 write_data.size_);
266#endif
267 HAL_I2C_Mem_Write_DMA(i2c_handle_, dev_addr, mem_addr,
268 mem_addr_size == MemAddrLength::BYTE_8 ? I2C_MEMADD_SIZE_8BIT
269 : I2C_MEMADD_SIZE_16BIT,
270 reinterpret_cast<uint8_t*>(dma_buff_.addr_), write_data.size_);
271 op.MarkAsRunning();
272 if (op.type == WriteOperation::OperationType::BLOCK)
273 {
274 return op.data.sem_info.sem->Wait(op.data.sem_info.timeout);
275 }
276 return ErrorCode::OK;
277 }
278 else
279 {
280 auto ans =
281 HAL_I2C_Mem_Write(i2c_handle_, dev_addr, mem_addr,
282 mem_addr_size == MemAddrLength::BYTE_8 ? I2C_MEMADD_SIZE_8BIT
283 : I2C_MEMADD_SIZE_16BIT,
284 reinterpret_cast<uint8_t*>(dma_buff_.addr_), write_data.size_,
285 20) == HAL_OK
286 ? ErrorCode::OK
287 : ErrorCode::BUSY;
288
289 op.UpdateStatus(in_isr, ans);
290 if (op.type == WriteOperation::OperationType::BLOCK)
291 {
292 return op.data.sem_info.sem->Wait(op.data.sem_info.timeout);
293 }
294 return ans;
295 }
296}
297
299{
300 if (HasClockSpeed<decltype(i2c_handle_)>::value)
301 {
302 SetClockSpeed<decltype(i2c_handle_)>(i2c_handle_, config);
303 }
304 else
305 {
306 return ErrorCode::NOT_SUPPORT;
307 }
308
309 if (HAL_I2C_Init(i2c_handle_) != HAL_OK)
310 {
311 return ErrorCode::INIT_ERR;
312 }
313 return ErrorCode::OK;
314}
315
316extern "C" void HAL_I2C_MasterRxCpltCallback(I2C_HandleTypeDef* hi2c)
317{
318 STM32I2C* i2c = STM32I2C::map[STM32_I2C_GetID(hi2c->Instance)];
319 if (i2c)
320 {
321#if defined(__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U)
322 SCB_InvalidateDCache_by_Addr(i2c->dma_buff_.addr_, i2c->read_buff_.size_);
323#endif
324 Memory::FastCopy(i2c->read_buff_.addr_, i2c->dma_buff_.addr_, i2c->read_buff_.size_);
325 i2c->read_op_.UpdateStatus(true, ErrorCode::OK);
326 }
327}
328
329extern "C" void HAL_I2C_MasterTxCpltCallback(I2C_HandleTypeDef* hi2c)
330{
331 STM32I2C* i2c = STM32I2C::map[STM32_I2C_GetID(hi2c->Instance)];
332 if (i2c)
333 {
334 i2c->write_op_.UpdateStatus(true, ErrorCode::OK);
335 }
336}
337
338extern "C" void HAL_I2C_MemTxCpltCallback(I2C_HandleTypeDef* hi2c)
339{
340 STM32I2C* i2c = STM32I2C::map[STM32_I2C_GetID(hi2c->Instance)];
341 if (i2c)
342 {
343 i2c->write_op_.UpdateStatus(true, ErrorCode::OK);
344 }
345}
346
347extern "C" void HAL_I2C_MemRxCpltCallback(I2C_HandleTypeDef* hi2c)
348{
349 STM32I2C* i2c = STM32I2C::map[STM32_I2C_GetID(hi2c->Instance)];
350 if (i2c)
351 {
352#if defined(__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U)
353 SCB_InvalidateDCache_by_Addr(i2c->dma_buff_.addr_, i2c->read_buff_.size_);
354#endif
355 Memory::FastCopy(i2c->read_buff_.addr_, i2c->dma_buff_.addr_, i2c->read_buff_.size_);
356 i2c->read_op_.UpdateStatus(true, ErrorCode::OK);
357 }
358}
359
360extern "C" void HAL_I2C_ErrorCallback(I2C_HandleTypeDef* hi2c)
361{
362 STM32I2C* i2c = STM32I2C::map[STM32_I2C_GetID(hi2c->Instance)];
363
364 if (i2c)
365 {
366 if (i2c->read_)
367 {
368 i2c->read_op_.UpdateStatus(true, ErrorCode::FAILED);
369 }
370 else
371 {
372 i2c->write_op_.UpdateStatus(true, ErrorCode::FAILED);
373 }
374 }
375}
376
377#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).
I2C(Inter-Integrated Circuit)接口类。 I2C (Inter-Integrated Circuit) interface class.
Definition i2c.hpp:17
static void FastCopy(void *dst, const void *src, size_t size)
快速内存拷贝 / Fast memory copy
Definition libxr_mem.cpp:3
union LibXR::Operation::@5 data
void UpdateStatus(bool in_isr, Status &&status)
Updates operation status based on type.
Definition libxr_rw.hpp:172
void MarkAsRunning()
标记操作为运行状态。 Marks the operation as running.
Definition libxr_rw.hpp:205
OperationType type
Definition libxr_rw.hpp:229
原始数据封装类。 A class for encapsulating raw data.
size_t size_
数据大小(字节)。 The size of the data (in bytes).
void * addr_
数据存储地址。 The storage address of the data.
STM32 I2C 驱动实现 / STM32 I2C driver implementation.
Definition stm32_i2c.hpp:52
ErrorCode SetConfig(Configuration config) override
配置 I2C 设备参数。 Configures the I2C device settings.
ErrorCode MemRead(uint16_t slave_addr, uint16_t mem_addr, RawData read_data, ReadOperation &op, MemAddrLength mem_addr_size, bool in_isr) override
从 I2C 设备指定寄存器读取数据。 Reads data from a specific register of an I2C device.
ErrorCode MemWrite(uint16_t slave_addr, uint16_t mem_addr, ConstRawData write_data, WriteOperation &op, MemAddrLength mem_addr_size, bool in_isr) override
向 I2C 设备指定寄存器写入数据。 Writes data to a specific register of an I2C device.
ErrorCode Write(uint16_t slave_addr, ConstRawData write_data, WriteOperation &op, bool in_isr) override
向 I2C 设备写入数据。 Writes data to an I2C device.
ErrorCode Read(uint16_t slave_addr, RawData read_data, ReadOperation &op, bool in_isr) override
读取 I2C 设备的数据。 Reads data from an I2C device.
STM32I2C(I2C_HandleTypeDef *hi2c, RawData dma_buff, uint32_t dma_enable_min_size=3)
构造 I2C 对象 / Construct I2C object
Definition stm32_i2c.cpp:92
ErrorCode Wait(uint32_t timeout=UINT32_MAX)
等待(减少)信号量 Waits (decrements) the semaphore
Definition semaphore.cpp:25
LibXR 命名空间
Definition ch32_can.hpp:14
I2C 设备的配置信息结构体。 Configuration structure for an I2C device.
Definition i2c.hpp:24