1#include "stm32_i2c.hpp"
3#include "stm32_dcache.hpp"
4#ifdef HAL_I2C_MODULE_ENABLED
8STM32I2C* STM32I2C::map[STM32_I2C_NUMBER] = {
nullptr};
10stm32_i2c_id_t STM32_I2C_GetID(I2C_TypeDef* hi2c)
14 return stm32_i2c_id_t::STM32_I2C_ID_ERROR;
17 else if (hi2c == I2C1)
19 return stm32_i2c_id_t::STM32_I2C1;
23 else if (hi2c == I2C2)
25 return stm32_i2c_id_t::STM32_I2C2;
29 else if (hi2c == I2C3)
31 return stm32_i2c_id_t::STM32_I2C3;
35 else if (hi2c == I2C4)
37 return stm32_i2c_id_t::STM32_I2C4;
41 else if (hi2c == I2C5)
43 return stm32_i2c_id_t::STM32_I2C5;
47 else if (hi2c == I2C6)
49 return stm32_i2c_id_t::STM32_I2C6;
53 else if (hi2c == I2C7)
55 return stm32_i2c_id_t::STM32_I2C7;
59 else if (hi2c == I2C8)
61 return stm32_i2c_id_t::STM32_I2C8;
64 return stm32_i2c_id_t::STM32_I2C_ID_ERROR;
73static inline uint16_t EncodeHalDevAddress(
const I2C_HandleTypeDef* hi2c,
76 ASSERT(hi2c !=
nullptr);
78#if defined(I2C_ADDRESSINGMODE_10BIT)
79 if (hi2c->Init.AddressingMode == I2C_ADDRESSINGMODE_10BIT)
81 ASSERT(slave_addr <= 0x03FF);
82 return static_cast<uint16_t
>(slave_addr & 0x03FF);
87 ASSERT(slave_addr <= 0x007F);
88 return static_cast<uint16_t
>((slave_addr & 0x007F) << 1);
91static inline ErrorCode MapHalStartFailure(
const I2C_HandleTypeDef* hi2c,
96#ifdef HAL_I2C_ERROR_NONE
97 const uint32_t err = hi2c->ErrorCode;
98#ifdef HAL_I2C_WRONG_START
99 if ((err & (HAL_I2C_ERROR_TIMEOUT | HAL_I2C_WRONG_START)) != 0U)
101 if ((err & HAL_I2C_ERROR_TIMEOUT) != 0U)
104 return ErrorCode::TIMEOUT;
106 if (err != HAL_I2C_ERROR_NONE)
108 return ErrorCode::FAILED;
113 return (st == HAL_BUSY) ? ErrorCode::BUSY : ErrorCode::FAILED;
116static void RecoverAfterBlockTimeout(
STM32I2C* i2c)
118 ASSERT(i2c !=
nullptr);
120 auto* hi2c = i2c->i2c_handle_;
121 i2c->recovering_ =
true;
122 if (hi2c->hdmarx !=
nullptr)
124 (void)HAL_DMA_Abort(hi2c->hdmarx);
126 if (hi2c->hdmatx !=
nullptr)
128 (void)HAL_DMA_Abort(hi2c->hdmatx);
133 (void)HAL_I2C_DeInit(hi2c);
134 (void)HAL_I2C_Init(hi2c);
139 i2c->read_buff_ = {
nullptr, 0};
140 i2c->recovering_ =
false;
143static inline ErrorCode WaitBlockResultAndRecoverTimeout(
STM32I2C* i2c, uint32_t timeout)
145 ASSERT(i2c !=
nullptr);
146 const ErrorCode ans = i2c->block_wait_.Wait(timeout);
147 if (ans == ErrorCode::TIMEOUT)
149 RecoverAfterBlockTimeout(i2c);
157 uint32_t dma_enable_min_size)
159 id_(STM32_I2C_GetID(hi2c->Instance)),
161 dma_enable_min_size_(dma_enable_min_size),
170 if (i2c_handle_->State != HAL_I2C_STATE_READY)
177 const uint16_t dev_addr = EncodeHalDevAddress(i2c_handle_, slave_addr);
179 if (read_data.
size_ > dma_enable_min_size_)
182 read_buff_ = read_data;
183 if (op.
type == ReadOperation::OperationType::BLOCK)
186 block_wait_.Start(*op.
data.sem_info.sem);
188 const HAL_StatusTypeDef st = HAL_I2C_Master_Receive_DMA(
189 i2c_handle_, dev_addr,
reinterpret_cast<uint8_t*
>(dma_buff_.
addr_),
193 if (op.
type == ReadOperation::OperationType::BLOCK)
195 block_wait_.Cancel();
196 return MapHalStartFailure(i2c_handle_, st);
201 if (op.
type == ReadOperation::OperationType::BLOCK)
203 return WaitBlockResultAndRecoverTimeout(
this, op.
data.sem_info.timeout);
209 auto ans = HAL_I2C_Master_Receive(i2c_handle_, dev_addr,
210 reinterpret_cast<uint8_t*
>(read_data.
addr_),
211 read_data.
size_, 20) == HAL_OK
216 if (op.
type != ReadOperation::OperationType::BLOCK)
227 if (i2c_handle_->State != HAL_I2C_STATE_READY)
234 const uint16_t dev_addr = EncodeHalDevAddress(i2c_handle_, slave_addr);
238 if (write_data.
size_ > dma_enable_min_size_)
241 if (op.
type == WriteOperation::OperationType::BLOCK)
244 block_wait_.Start(*op.
data.sem_info.sem);
247 const HAL_StatusTypeDef st = HAL_I2C_Master_Transmit_DMA(
248 i2c_handle_, dev_addr,
reinterpret_cast<uint8_t*
>(dma_buff_.
addr_),
252 if (op.
type == WriteOperation::OperationType::BLOCK)
254 block_wait_.Cancel();
255 return MapHalStartFailure(i2c_handle_, st);
260 if (op.
type == WriteOperation::OperationType::BLOCK)
262 return WaitBlockResultAndRecoverTimeout(
this, op.
data.sem_info.timeout);
268 auto ans = HAL_I2C_Master_Transmit(i2c_handle_, dev_addr,
269 reinterpret_cast<uint8_t*
>(dma_buff_.
addr_),
270 write_data.
size_, 20) == HAL_OK
273 if (op.
type != WriteOperation::OperationType::BLOCK)
286 if (i2c_handle_->State != HAL_I2C_STATE_READY)
293 const uint16_t dev_addr = EncodeHalDevAddress(i2c_handle_, slave_addr);
295 if (read_data.
size_ > dma_enable_min_size_)
298 read_buff_ = read_data;
299 if (op.
type == ReadOperation::OperationType::BLOCK)
302 block_wait_.Start(*op.
data.sem_info.sem);
304 const HAL_StatusTypeDef st = HAL_I2C_Mem_Read_DMA(
305 i2c_handle_, dev_addr, mem_addr,
306 mem_addr_size == MemAddrLength::BYTE_8 ? I2C_MEMADD_SIZE_8BIT
307 : I2C_MEMADD_SIZE_16BIT,
308 reinterpret_cast<uint8_t*
>(dma_buff_.
addr_), read_data.
size_);
311 if (op.
type == ReadOperation::OperationType::BLOCK)
313 block_wait_.Cancel();
314 return MapHalStartFailure(i2c_handle_, st);
319 if (op.
type == ReadOperation::OperationType::BLOCK)
321 return WaitBlockResultAndRecoverTimeout(
this, op.
data.sem_info.timeout);
328 HAL_I2C_Mem_Read(i2c_handle_, dev_addr, mem_addr,
329 mem_addr_size == MemAddrLength::BYTE_8 ? I2C_MEMADD_SIZE_8BIT
330 : I2C_MEMADD_SIZE_16BIT,
331 reinterpret_cast<uint8_t*
>(read_data.
addr_), read_data.
size_,
336 if (op.
type != ReadOperation::OperationType::BLOCK)
346 MemAddrLength mem_addr_size,
bool in_isr)
350 if (i2c_handle_->State != HAL_I2C_STATE_READY)
357 const uint16_t dev_addr = EncodeHalDevAddress(i2c_handle_, slave_addr);
361 if (write_data.
size_ > dma_enable_min_size_)
364 if (op.
type == WriteOperation::OperationType::BLOCK)
367 block_wait_.Start(*op.
data.sem_info.sem);
370 const HAL_StatusTypeDef st = HAL_I2C_Mem_Write_DMA(
371 i2c_handle_, dev_addr, mem_addr,
372 mem_addr_size == MemAddrLength::BYTE_8 ? I2C_MEMADD_SIZE_8BIT
373 : I2C_MEMADD_SIZE_16BIT,
374 reinterpret_cast<uint8_t*
>(dma_buff_.
addr_), write_data.
size_);
377 if (op.
type == WriteOperation::OperationType::BLOCK)
379 block_wait_.Cancel();
380 return MapHalStartFailure(i2c_handle_, st);
385 if (op.
type == WriteOperation::OperationType::BLOCK)
387 return WaitBlockResultAndRecoverTimeout(
this, op.
data.sem_info.timeout);
394 HAL_I2C_Mem_Write(i2c_handle_, dev_addr, mem_addr,
395 mem_addr_size == MemAddrLength::BYTE_8 ? I2C_MEMADD_SIZE_8BIT
396 : I2C_MEMADD_SIZE_16BIT,
397 reinterpret_cast<uint8_t*
>(dma_buff_.
addr_), write_data.
size_,
402 if (op.
type != WriteOperation::OperationType::BLOCK)
414 SetClockSpeed<decltype(i2c_handle_)>(i2c_handle_, config);
421 if (HAL_I2C_Init(i2c_handle_) != HAL_OK)
428extern "C" void HAL_I2C_MasterRxCpltCallback(I2C_HandleTypeDef* hi2c)
430 STM32I2C* i2c = STM32I2C::map[STM32_I2C_GetID(hi2c->Instance)];
431 if (i2c && !i2c->recovering_ &&
432 (i2c->read_op_.
type != ReadOperation::OperationType::NONE))
435#ifdef HAL_I2C_ERROR_NONE
442 i2c->read_buff_.
size_);
444 if (i2c->read_op_.
type == ReadOperation::OperationType::BLOCK)
446 (void)i2c->block_wait_.TryPost(
true, ec);
455extern "C" void HAL_I2C_MasterTxCpltCallback(I2C_HandleTypeDef* hi2c)
457 STM32I2C* i2c = STM32I2C::map[STM32_I2C_GetID(hi2c->Instance)];
458 if (i2c && !i2c->recovering_ &&
459 (i2c->write_op_.
type != WriteOperation::OperationType::NONE))
462#ifdef HAL_I2C_ERROR_NONE
465 if (i2c->write_op_.
type == WriteOperation::OperationType::BLOCK)
467 (void)i2c->block_wait_.TryPost(
true, ec);
476extern "C" void HAL_I2C_MemTxCpltCallback(I2C_HandleTypeDef* hi2c)
478 STM32I2C* i2c = STM32I2C::map[STM32_I2C_GetID(hi2c->Instance)];
479 if (i2c && !i2c->recovering_ &&
480 (i2c->write_op_.
type != WriteOperation::OperationType::NONE))
483#ifdef HAL_I2C_ERROR_NONE
486 if (i2c->write_op_.
type == WriteOperation::OperationType::BLOCK)
488 (void)i2c->block_wait_.TryPost(
true, ec);
497extern "C" void HAL_I2C_MemRxCpltCallback(I2C_HandleTypeDef* hi2c)
499 STM32I2C* i2c = STM32I2C::map[STM32_I2C_GetID(hi2c->Instance)];
500 if (i2c && !i2c->recovering_ &&
501 (i2c->read_op_.
type != ReadOperation::OperationType::NONE))
504#ifdef HAL_I2C_ERROR_NONE
511 i2c->read_buff_.
size_);
513 if (i2c->read_op_.
type == ReadOperation::OperationType::BLOCK)
515 (void)i2c->block_wait_.TryPost(
true, ec);
524extern "C" void HAL_I2C_ErrorCallback(I2C_HandleTypeDef* hi2c)
526 STM32I2C* i2c = STM32I2C::map[STM32_I2C_GetID(hi2c->Instance)];
528 if (i2c && !i2c->recovering_)
532 if (i2c->read_op_.
type == ReadOperation::OperationType::BLOCK)
543 if (i2c->write_op_.
type == WriteOperation::OperationType::BLOCK)
只读原始数据视图 / Immutable raw data view
size_t size_
数据字节数 / Data size in bytes
const void * addr_
数据起始地址 / Data start address
I2C(Inter-Integrated Circuit)接口类。 I2C (Inter-Integrated Circuit) interface class.
static void FastCopy(void *dst, const void *src, size_t size)
快速内存拷贝 / Fast memory copy
union LibXR::Operation::@5 data
void UpdateStatus(bool in_isr, Status &&status)
Updates operation status based on type.
void MarkAsRunning()
标记操作为运行状态。 Marks the operation as running.
可写原始数据视图 / Mutable raw data view
size_t size_
数据字节数 / Data size in bytes
void * addr_
数据起始地址 / Data start address
STM32 I2C 驱动实现 / STM32 I2C driver implementation.
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
void STM32_InvalidateDCacheByAddr(const void *addr, size_t size)
Invalidates D-Cache lines covering the specified memory range.
@ INIT_ERR
初始化错误 | Initialization error
@ NOT_SUPPORT
不支持 | Not supported
@ FAILED
操作失败 | Operation failed
@ OK
操作成功 | Operation successful
void STM32_CleanDCacheByAddr(const void *addr, size_t size)
Cleans D-Cache lines covering the specified memory range.
I2C 设备的配置信息结构体。 Configuration structure for an I2C device.