From 721b596a4ebffde932e3879af8190538658ea65d Mon Sep 17 00:00:00 2001 From: wdfk-prog <1425075683@qq.com> Date: Sat, 14 Mar 2026 15:08:57 +0800 Subject: [PATCH 1/2] feat[stm32][i2c]: support poll/int/dma transfer paths and i2c4 --- .../HAL_Drivers/drivers/drv_hard_i2c.c | 448 +++++++++++++----- .../HAL_Drivers/drivers/drv_hard_i2c.h | 124 ++++- 2 files changed, 440 insertions(+), 132 deletions(-) diff --git a/bsp/stm32/libraries/HAL_Drivers/drivers/drv_hard_i2c.c b/bsp/stm32/libraries/HAL_Drivers/drivers/drv_hard_i2c.c index 424adaf0c4e..b6db90e5006 100644 --- a/bsp/stm32/libraries/HAL_Drivers/drivers/drv_hard_i2c.c +++ b/bsp/stm32/libraries/HAL_Drivers/drivers/drv_hard_i2c.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006-2023, RT-Thread Development Team + * Copyright (c) 2006-2024, RT-Thread Development Team * * SPDX-License-Identifier: Apache-2.0 * @@ -8,18 +8,18 @@ * 2024-02-17 Dyyt587 first version * 2024-04-23 Zeidan fix bugs, test on STM32F429IGTx * 2024-12-10 zzk597 add support for STM32F1 series + * 2024-06-23 wdfk-prog Add blocking modes and distinguish POLL,INT,DMA modes */ #include "drv_hard_i2c.h" -/* not fully support for I2C4 */ -#if defined(BSP_USING_HARD_I2C1) || defined(BSP_USING_HARD_I2C2) || defined(BSP_USING_HARD_I2C3) +#if defined(BSP_HARDWARE_I2C) -//#define DRV_DEBUG +// #define DRV_DEBUG #define LOG_TAG "drv.i2c.hw" #include -enum +typedef enum { #ifdef BSP_USING_HARD_I2C1 I2C1_INDEX, @@ -30,7 +30,10 @@ enum #ifdef BSP_USING_HARD_I2C3 I2C3_INDEX, #endif /* BSP_USING_HARD_I2C3 */ -}; +#ifdef BSP_USING_HARD_I2C4 + I2C4_INDEX, +#endif /* BSP_USING_HARD_I2C4 */ +}i2c_index_t; static struct stm32_i2c_config i2c_config[] = { @@ -43,6 +46,9 @@ static struct stm32_i2c_config i2c_config[] = #ifdef BSP_USING_HARD_I2C3 I2C3_BUS_CONFIG, #endif /* BSP_USING_HARD_I2C3 */ +#ifdef BSP_USING_HARD_I2C4 + I2C4_BUS_CONFIG, +#endif /* BSP_USING_HARD_I2C4 */ }; static struct stm32_i2c i2c_objs[sizeof(i2c_config) / sizeof(i2c_config[0])] = {0}; @@ -55,21 +61,23 @@ static rt_err_t stm32_i2c_init(struct stm32_i2c *i2c_drv) struct stm32_i2c_config *cfg = i2c_drv->config; rt_memset(i2c_handle, 0, sizeof(I2C_HandleTypeDef)); - i2c_handle->Instance = cfg->Instance; #if defined(SOC_SERIES_STM32H7) i2c_handle->Init.Timing = cfg->timing; -#endif /* defined(SOC_SERIES_STM32H7) */ -#if defined(SOC_SERIES_STM32F1) || defined(SOC_SERIES_STM32F4) +#else i2c_handle->Init.ClockSpeed = 100000; i2c_handle->Init.DutyCycle = I2C_DUTYCYCLE_2; -#endif /* defined(SOC_SERIES_STM32F1) || defined(SOC_SERIES_STM32F4) */ +#endif /* defined(SOC_SERIES_STM32H7) */ i2c_handle->Init.OwnAddress1 = 0; i2c_handle->Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT; i2c_handle->Init.DualAddressMode = I2C_DUALADDRESS_DISABLE; i2c_handle->Init.OwnAddress2 = 0; i2c_handle->Init.GeneralCallMode = I2C_GENERALCALL_DISABLE; i2c_handle->Init.NoStretchMode = I2C_NOSTRETCH_DISABLE; +#if defined(SOC_SERIES_STM32H7) + i2c_handle->Init.OwnAddress2Masks = I2C_OA2_NOMASK; +#endif /* defined(SOC_SERIES_STM32H7) */ + if (HAL_I2C_DeInit(i2c_handle) != HAL_OK) { return -RT_EFAULT; @@ -92,8 +100,9 @@ static rt_err_t stm32_i2c_init(struct stm32_i2c *i2c_drv) return -RT_EFAULT; } #endif /* defined(SOC_SERIES_STM32H7) */ +#if defined(BSP_I2C_RX_USING_DMA) /* I2C2 DMA Init */ - if (i2c_drv->i2c_dma_flag & I2C_USING_RX_DMA_FLAG) + if (i2c_drv->i2c_dma_flag & RT_DEVICE_FLAG_DMA_RX) { HAL_DMA_Init(&i2c_drv->dma.handle_rx); @@ -103,8 +112,9 @@ static rt_err_t stm32_i2c_init(struct stm32_i2c *i2c_drv) HAL_NVIC_SetPriority(i2c_drv->config->dma_rx->dma_irq, 0, 0); HAL_NVIC_EnableIRQ(i2c_drv->config->dma_rx->dma_irq); } - - if (i2c_drv->i2c_dma_flag & I2C_USING_TX_DMA_FLAG) +#endif /* defined(BSP_I2C_RX_USING_DMA) */ +#if defined(BSP_I2C_TX_USING_DMA) + if (i2c_drv->i2c_dma_flag & RT_DEVICE_FLAG_DMA_TX) { HAL_DMA_Init(&i2c_drv->dma.handle_tx); @@ -114,13 +124,19 @@ static rt_err_t stm32_i2c_init(struct stm32_i2c *i2c_drv) HAL_NVIC_SetPriority(i2c_drv->config->dma_tx->dma_irq, 1, 0); HAL_NVIC_EnableIRQ(i2c_drv->config->dma_tx->dma_irq); } - - /* In the data transfer function stm32_i2c_master_xfer(), the IT transfer function - HAL_I2C_Master_Seq_Transmit_IT() is used when DMA is not used, so the IT interrupt - must be enable anyway, regardless of the DMA configuration, otherwise - the rt_completion_wait() will always timeout. */ - HAL_NVIC_SetPriority(i2c_drv->config->evirq_type, 2, 0); - HAL_NVIC_EnableIRQ(i2c_drv->config->evirq_type); +#endif /* defined(BSP_I2C_TX_USING_DMA) */ +#if defined(BSP_I2C_USING_IRQ) + if ((i2c_drv->i2c_dma_flag & RT_DEVICE_FLAG_DMA_TX || i2c_drv->i2c_dma_flag & RT_DEVICE_FLAG_DMA_RX) + || (i2c_drv->i2c_dma_flag & RT_DEVICE_FLAG_INT_TX || i2c_drv->i2c_dma_flag & RT_DEVICE_FLAG_INT_RX)) + { + /* In the data transfer function stm32_i2c_master_xfer(), the IT transfer function + HAL_I2C_Master_Seq_Transmit_IT() is used when DMA is not used, so the IT interrupt + must be enable anyway, regardless of the DMA configuration, otherwise + the rt_completion_wait() will always timeout. */ + HAL_NVIC_SetPriority(i2c_drv->config->evirq_type, 2, 0); + HAL_NVIC_EnableIRQ(i2c_drv->config->evirq_type); + } +#endif /* defined(BSP_I2C_USING_IRQ) */ return RT_EOK; } @@ -148,13 +164,13 @@ static rt_ssize_t stm32_i2c_master_xfer(struct rt_i2c_bus_device *bus, #define DMA_TRANS_MIN_LEN 2 /* only buffer length >= DMA_TRANS_MIN_LEN will use DMA mode */ #define TRANS_TIMEOUT_PERSEC 8 /* per ms will trans nums bytes */ - rt_int32_t i, ret; + rt_int32_t i, ret = 0; struct rt_i2c_msg *msg = msgs; struct rt_i2c_msg *next_msg = 0; struct stm32_i2c *i2c_obj; uint32_t mode = 0; + RT_UNUSED(mode); uint8_t next_flag = 0; - struct rt_completion *completion; rt_uint32_t timeout; if (num == 0) @@ -165,9 +181,13 @@ static rt_ssize_t stm32_i2c_master_xfer(struct rt_i2c_bus_device *bus, RT_ASSERT((msgs != RT_NULL) && (bus != RT_NULL)); i2c_obj = rt_container_of(bus, struct stm32_i2c, i2c_bus); - completion = &i2c_obj->completion; + RT_ASSERT(i2c_obj != RT_NULL); I2C_HandleTypeDef *handle = &i2c_obj->handle; - + RT_ASSERT(handle != RT_NULL); +#if defined(BSP_I2C_USING_IRQ) + struct rt_completion *completion; + completion = &i2c_obj->completion; +#endif /* defined(BSP_I2C_USING_IRQ) */ LOG_D("xfer start %d mags", num); for (i = 0; i < (num - 1); i++) { @@ -176,7 +196,7 @@ static rt_ssize_t stm32_i2c_master_xfer(struct rt_i2c_bus_device *bus, LOG_D("xfer msgs[%d] addr=0x%2x buf=0x%x len= 0x%x flags= 0x%x", i, msg->addr, msg->buf, msg->len, msg->flags); next_msg = &msgs[i + 1]; next_flag = next_msg->flags; - timeout = msg->len/TRANS_TIMEOUT_PERSEC + 5; + timeout = msg->len / TRANS_TIMEOUT_PERSEC + 5; if (next_flag & RT_I2C_NO_START) { if ((next_flag & RT_I2C_RD) == (msg->flags & RT_I2C_RD)) @@ -200,56 +220,82 @@ static rt_ssize_t stm32_i2c_master_xfer(struct rt_i2c_bus_device *bus, LOG_D("xfer rec msgs[%d] hal mode = %s", i, mode == I2C_FIRST_AND_NEXT_FRAME ? "I2C_FIRST_AND_NEXT_FRAME" : mode == I2C_LAST_FRAME_NO_STOP ? "I2C_FIRST_FRAME/I2C_LAST_FRAME_NO_STOP" : mode == I2C_LAST_FRAME ? "I2C_LAST_FRAME" : "nuknown mode"); - if ((i2c_obj->i2c_dma_flag & I2C_USING_RX_DMA_FLAG) && (msg->len >= DMA_TRANS_MIN_LEN)) +#if defined(BSP_I2C_RX_USING_DMA) + if ((i2c_obj->i2c_dma_flag & RT_DEVICE_FLAG_DMA_RX) && (msg->len >= DMA_TRANS_MIN_LEN)) { ret = HAL_I2C_Master_Seq_Receive_DMA(handle, (msg->addr<<1), msg->buf, msg->len, mode); } else +#endif /* defined(BSP_I2C_RX_USING_DMA) */ +#if defined(BSP_I2C_RX_USING_INT) + if(i2c_obj->i2c_dma_flag & RT_DEVICE_FLAG_INT_RX) { ret = HAL_I2C_Master_Seq_Receive_IT(handle, (msg->addr<<1), msg->buf, msg->len, mode); } - if (ret != RT_EOK) + else +#endif /* defined(BSP_I2C_RX_USING_INT) */ +#if defined(BSP_I2C_RX_USING_POLL) + { + ret = HAL_I2C_Master_Receive(handle, (msg->addr<<1), msg->buf, msg->len, timeout); + } +#endif /* defined(BSP_I2C_RX_USING_POLL) */ + if (ret != HAL_OK) { LOG_E("[%s:%d]I2C Read error(%d)!\n", __func__, __LINE__, ret); goto out; } - if (rt_completion_wait(completion, timeout) != RT_EOK) +#if defined(BSP_I2C_USING_IRQ) + ret = rt_completion_wait(completion, timeout); + if (ret != RT_EOK) { - LOG_D("receive time out"); - goto out; - + LOG_W("receive error %d, timeout %d", ret, timeout); + goto out; } +#endif /* defined(BSP_I2C_USING_IRQ) */ } else { LOG_D("xfer trans msgs[%d] hal mode = %s", i, mode == I2C_FIRST_AND_NEXT_FRAME ? "I2C_FIRST_AND_NEXT_FRAME" : mode == I2C_LAST_FRAME_NO_STOP ? "I2C_FIRST_FRAME/I2C_LAST_FRAME_NO_STOP" : mode == I2C_LAST_FRAME ? "I2C_LAST_FRAME" : "nuknown mode"); - if ((i2c_obj->i2c_dma_flag & I2C_USING_TX_DMA_FLAG) && (msg->len >= DMA_TRANS_MIN_LEN)) +#if defined(BSP_I2C_TX_USING_DMA) + if ((i2c_obj->i2c_dma_flag & RT_DEVICE_FLAG_DMA_TX) && (msg->len >= DMA_TRANS_MIN_LEN)) { ret = HAL_I2C_Master_Seq_Transmit_DMA(handle, (msg->addr<<1), msg->buf, msg->len, mode); } else +#endif /* defined(BSP_I2C_TX_USING_DMA) */ +#if defined(BSP_I2C_TX_USING_INT) + if(i2c_obj->i2c_dma_flag & RT_DEVICE_FLAG_INT_TX) { ret = HAL_I2C_Master_Seq_Transmit_IT(handle, (msg->addr<<1), msg->buf, msg->len, mode); } - if (ret != RT_EOK) + else +#endif /* defined(BSP_I2C_TX_USING_INT) */ +#if defined(BSP_I2C_TX_USING_POLL) + { + ret = HAL_I2C_Master_Transmit(handle, (msg->addr<<1), msg->buf, msg->len, timeout); + } +#endif /* defined(BSP_I2C_TX_USING_POLL) */ + if (ret != HAL_OK) { - LOG_D("[%s:%d]I2C Write error(%d)!\n", __func__, __LINE__, ret); + LOG_E("[%s:%d]I2C Write error(%d)!\n", __func__, __LINE__, ret); goto out; } - if (rt_completion_wait(completion, timeout) != RT_EOK) +#if defined(BSP_I2C_USING_IRQ) + ret = rt_completion_wait(completion, timeout); + if (ret != RT_EOK) { - LOG_D("transmit time out"); - goto out; - + LOG_W("receive error %d, timeout %d", ret, timeout); + goto out; } +#endif /* defined(BSP_I2C_USING_IRQ) */ } LOG_D("xfer next msgs[%d] addr=0x%2x buf= 0x%x len= 0x%x flags = 0x%x\r\n", i + 1, next_msg->addr, next_msg->buf, next_msg->len, next_msg->flags); } /* last msg */ msg = &msgs[i]; - timeout = msg->len/TRANS_TIMEOUT_PERSEC + 5; + timeout = msg->len / TRANS_TIMEOUT_PERSEC + 5; if (msg->flags & RT_I2C_NO_STOP) mode = I2C_LAST_FRAME_NO_STOP; else @@ -260,49 +306,76 @@ static rt_ssize_t stm32_i2c_master_xfer(struct rt_i2c_bus_device *bus, LOG_D("xfer rec msgs[%d] hal mode=%s", i, mode == I2C_FIRST_AND_NEXT_FRAME ? "I2C_FIRST_AND_NEXT_FRAME" : mode == I2C_LAST_FRAME_NO_STOP ? "I2C_FIRST_FRAME/I2C_LAST_FRAME_NO_STOP" : mode == I2C_LAST_FRAME ? "I2C_LAST_FRAME" : "nuknown mode"); - if ((i2c_obj->i2c_dma_flag & I2C_USING_RX_DMA_FLAG) && (msg->len >= DMA_TRANS_MIN_LEN)) +#if defined(BSP_I2C_RX_USING_DMA) + if ((i2c_obj->i2c_dma_flag & RT_DEVICE_FLAG_DMA_RX) && (msg->len >= DMA_TRANS_MIN_LEN)) { ret = HAL_I2C_Master_Seq_Receive_DMA(handle, (msg->addr<<1), msg->buf, msg->len, mode); } else +#endif /* defined(BSP_I2C_RX_USING_DMA) */ +#if defined(BSP_I2C_RX_USING_INT) + if(i2c_obj->i2c_dma_flag & RT_DEVICE_FLAG_INT_RX) { ret = HAL_I2C_Master_Seq_Receive_IT(handle,(msg->addr<<1), msg->buf, msg->len, mode); } - if (ret != RT_EOK) + else +#endif /* defined(BSP_I2C_RX_USING_INT) */ +#if defined(BSP_I2C_RX_USING_POLL) { - LOG_D("[%s:%d]I2C Read error(%d)!\n", __func__, __LINE__, ret); + ret = HAL_I2C_Master_Receive(handle, (msg->addr<<1), msg->buf, msg->len, timeout); + } +#endif /* defined(BSP_I2C_RX_USING_POLL) */ + if (ret != HAL_OK) + { + LOG_E("[%s:%d]I2C Read error(%d)!\n", __func__, __LINE__, ret); goto out; } - if (rt_completion_wait(completion, timeout) != RT_EOK) +#if defined(BSP_I2C_USING_IRQ) + ret = rt_completion_wait(completion, timeout); + if (ret != RT_EOK) { - LOG_D("receive time out"); + LOG_W("receive error %d, timeout %d", ret, timeout); goto out; } +#endif /* defined(BSP_I2C_USING_IRQ) */ } else { LOG_D("xfer trans msgs[%d] hal mode = %s", i, mode == I2C_FIRST_AND_NEXT_FRAME ? "I2C_FIRST_AND_NEXT_FRAME" : mode == I2C_LAST_FRAME ? "I2C_LAST_FRAME" : mode == I2C_LAST_FRAME_NO_STOP ? "I2C_FIRST_FRAME/I2C_LAST_FRAME_NO_STOP" : "nuknown mode"); - if ((i2c_obj->i2c_dma_flag & I2C_USING_TX_DMA_FLAG) && (msg->len >= DMA_TRANS_MIN_LEN)) +#if defined(BSP_I2C_TX_USING_DMA) + if ((i2c_obj->i2c_dma_flag & RT_DEVICE_FLAG_DMA_TX) && (msg->len >= DMA_TRANS_MIN_LEN)) { ret = HAL_I2C_Master_Seq_Transmit_DMA(handle, (msg->addr<<1), msg->buf, msg->len, mode); } else +#endif /* defined(BSP_I2C_TX_USING_DMA) */ +#if defined(BSP_I2C_TX_USING_INT) + if(i2c_obj->i2c_dma_flag & RT_DEVICE_FLAG_INT_TX) { ret = HAL_I2C_Master_Seq_Transmit_IT(handle, (msg->addr<<1), msg->buf, msg->len, mode); } - if (ret != RT_EOK) + else +#endif /* defined(BSP_I2C_TX_USING_INT) */ +#if defined(BSP_I2C_TX_USING_POLL) { - LOG_D("[%s:%d]I2C Write error(%d)!\n", __func__, __LINE__, ret); + ret = HAL_I2C_Master_Transmit(handle, (msg->addr<<1), msg->buf, msg->len, timeout); + } +#endif /* defined(BSP_I2C_TX_USING_POLL) */ + if (ret != HAL_OK) + { + LOG_E("[%s:%d]I2C Write error(%d)!\n", __func__, __LINE__, ret); goto out; } - if (rt_completion_wait(completion, timeout) != RT_EOK) +#if defined(BSP_I2C_USING_IRQ) + ret = rt_completion_wait(completion, timeout); + if (ret != RT_EOK) { - LOG_D("transmit time out"); + LOG_W("transmit error %d, timeout %d", ret, timeout); goto out; - } +#endif /* defined(BSP_I2C_USING_IRQ) */ } ret = num; LOG_D("xfer end %d mags\r\n", num); @@ -311,7 +384,7 @@ static rt_ssize_t stm32_i2c_master_xfer(struct rt_i2c_bus_device *bus, out: if (handle->ErrorCode == HAL_I2C_ERROR_AF) { - LOG_D("I2C NACK Error now stoped"); + LOG_W("I2C NACK Error now stoped"); /* Send stop signal to prevent bus lock-up */ #if defined(SOC_SERIES_STM32H7) handle->Instance->CR1 |= I2C_IT_STOPI; @@ -319,8 +392,12 @@ static rt_ssize_t stm32_i2c_master_xfer(struct rt_i2c_bus_device *bus, } if (handle->ErrorCode == HAL_I2C_ERROR_BERR) { - LOG_D("I2C BUS Error now stoped"); + LOG_W("I2C BUS Error now stoped"); +#if defined(SOC_SERIES_STM32H7) + handle->Instance->CR1 |= I2C_IT_STOPI; +#else handle->Instance->CR1 |= I2C_CR1_STOP; +#endif /* defined(SOC_SERIES_STM32H7) */ ret=i-1; } return ret; @@ -330,7 +407,7 @@ static const struct rt_i2c_bus_device_ops stm32_i2c_ops = { .master_xfer = stm32_i2c_master_xfer, RT_NULL, - RT_NULL + RT_NULL, }; int RT_hw_i2c_bus_init(void) @@ -343,8 +420,8 @@ int RT_hw_i2c_bus_init(void) i2c_objs[i].i2c_bus.ops = &stm32_i2c_ops; i2c_objs[i].config = &i2c_config[i]; i2c_objs[i].i2c_bus.timeout = i2c_config[i].timeout; - - if ((i2c_objs[i].i2c_dma_flag & I2C_USING_RX_DMA_FLAG)) +#ifdef BSP_I2C_USING_DMA + if ((i2c_objs[i].i2c_dma_flag & RT_DEVICE_FLAG_DMA_RX)) { i2c_objs[i].dma.handle_rx.Instance = i2c_config[i].dma_rx->Instance; #if defined(SOC_SERIES_STM32F2) || defined(SOC_SERIES_STM32F4) || defined(SOC_SERIES_STM32F7) @@ -386,7 +463,8 @@ int RT_hw_i2c_bus_init(void) } } - if (i2c_objs[i].i2c_dma_flag & I2C_USING_TX_DMA_FLAG) +#ifdef BSP_I2C_USING_DMA + if (i2c_objs[i].i2c_dma_flag & RT_DEVICE_FLAG_DMA_TX) { i2c_objs[i].dma.handle_tx.Instance = i2c_config[i].dma_tx->Instance; #if defined(SOC_SERIES_STM32F2) || defined(SOC_SERIES_STM32F4) || defined(SOC_SERIES_STM32F7) @@ -405,10 +483,10 @@ int RT_hw_i2c_bus_init(void) #endif #if defined(SOC_SERIES_STM32F2) || defined(SOC_SERIES_STM32F4) || defined(SOC_SERIES_STM32F7) || defined(SOC_SERIES_STM32MP1) || defined(SOC_SERIES_STM32H7) - i2c_objs[i].dma.handle_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE; - i2c_objs[i].dma.handle_tx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; - i2c_objs[i].dma.handle_tx.Init.MemBurst = DMA_MBURST_INC4; - i2c_objs[i].dma.handle_tx.Init.PeriphBurst = DMA_PBURST_INC4; + i2c_objs[i].dma.handle_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE; + i2c_objs[i].dma.handle_tx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; + i2c_objs[i].dma.handle_tx.Init.MemBurst = DMA_MBURST_INC4; + i2c_objs[i].dma.handle_tx.Init.PeriphBurst = DMA_PBURST_INC4; #endif /* defined(SOC_SERIES_STM32F2) || defined(SOC_SERIES_STM32F4) || defined(SOC_SERIES_STM32F7) || defined(SOC_SERIES_STM32MP1) || defined(SOC_SERIES_STM32H7) */ { rt_uint32_t tmpreg = 0x00U; @@ -429,109 +507,182 @@ int RT_hw_i2c_bus_init(void) } } +#endif /* BSP_I2C_USING_DMA */ +#if defined(BSP_I2C_USING_IRQ) rt_completion_init(&i2c_objs[i].completion); - stm32_i2c_configure(&i2c_objs[i].i2c_bus); +#endif /* defined(BSP_I2C_USING_IRQ) */ + ret = stm32_i2c_configure(&i2c_objs[i].i2c_bus); + if (ret != RT_EOK) + { + LOG_E("%s bus configure failed %d", i2c_config[i].name, ret); + return -RT_ERROR; + } ret = rt_i2c_bus_device_register(&i2c_objs[i].i2c_bus, i2c_objs[i].config->name); - RT_ASSERT(ret == RT_EOK); - LOG_D("%s bus init done", i2c_config[i].name); + if(ret != RT_EOK) + { + LOG_E("%s bus init failed %d", i2c_config[i].name, ret); + } + else + { + LOG_D("%s bus init done", i2c_config[i].name); + } } return ret; } -static void stm32_get_dma_info(void) +static void stm32_get_info(void) { -#ifdef BSP_I2C1_RX_USING_DMA - i2c_objs[I2C1_INDEX].i2c_dma_flag |= I2C_USING_RX_DMA_FLAG; - static struct dma_config I2C1_dma_rx = I2C1_RX_DMA_CONFIG; - i2c_config[I2C1_INDEX].dma_rx = &I2C1_dma_rx; -#endif /* BSP_I2C1_RX_USING_DMA */ -#ifdef BSP_I2C1_TX_USING_DMA - i2c_objs[I2C1_INDEX].i2c_dma_flag |= I2C_USING_TX_DMA_FLAG; +#if defined(BSP_USING_HARD_I2C1) + i2c_objs[I2C1_INDEX].i2c_dma_flag = 0; + +#if defined (BSP_I2C1_TX_USING_INT) + i2c_objs[I2C1_INDEX].i2c_dma_flag |= RT_DEVICE_FLAG_INT_TX; +#elif defined(BSP_I2C1_TX_USING_DMA) + i2c_objs[I2C1_INDEX].i2c_dma_flag |= RT_DEVICE_FLAG_DMA_TX; static struct dma_config I2C1_dma_tx = I2C1_TX_DMA_CONFIG; i2c_config[I2C1_INDEX].dma_tx = &I2C1_dma_tx; -#endif /* BSP_I2C1_TX_USING_DMA */ +#endif /* defined (BSP_I2C1_TX_USING_INT) */ -#ifdef BSP_I2C2_RX_USING_DMA - i2c_objs[I2C2_INDEX].i2c_dma_flag |= I2C_USING_RX_DMA_FLAG; - static struct dma_config I2C2_dma_rx = I2C2_RX_DMA_CONFIG; - i2c_config[I2C2_INDEX].dma_rx = &I2C2_dma_rx; -#endif /* BSP_I2C2_RX_USING_DMA */ -#ifdef BSP_I2C2_TX_USING_DMA - i2c_objs[I2C2_INDEX].i2c_dma_flag |= I2C_USING_TX_DMA_FLAG; +#if defined (BSP_I2C1_RX_USING_INT) + i2c_objs[I2C1_INDEX].i2c_dma_flag |= RT_DEVICE_FLAG_INT_RX; +#elif defined(BSP_I2C1_RX_USING_DMA) + i2c_objs[I2C1_INDEX].i2c_dma_flag |= RT_DEVICE_FLAG_DMA_RX; + static struct dma_config I2C1_dma_rx = I2C1_RX_DMA_CONFIG; + i2c_config[I2C1_INDEX].dma_rx = &I2C1_dma_rx; +#endif /* defined (BSP_I2C1_RX_USING_INT) */ + +#endif /* defined(BSP_USING_HARD_I2C1) */ + +#if defined(BSP_USING_HARD_I2C2) + i2c_objs[I2C2_INDEX].i2c_dma_flag = 0; + +#if defined (BSP_I2C2_TX_USING_INT) + i2c_objs[I2C2_INDEX].i2c_dma_flag |= RT_DEVICE_FLAG_INT_TX; +#elif defined(BSP_I2C2_TX_USING_DMA) + i2c_objs[I2C2_INDEX].i2c_dma_flag |= RT_DEVICE_FLAG_DMA_TX; static struct dma_config I2C2_dma_tx = I2C2_TX_DMA_CONFIG; i2c_config[I2C2_INDEX].dma_tx = &I2C2_dma_tx; -#endif /* BSP_I2C2_TX_USING_DMA */ +#endif /* defined (BSP_I2C2_TX_USING_INT) */ -#ifdef BSP_I2C3_RX_USING_DMA - i2c_objs[I2C3_INDEX].i2c_dma_flag |= I2C_USING_RX_DMA_FLAG; - static struct dma_config I2C3_dma_rx = I2C3_RX_DMA_CONFIG; - i2c_config[I2C3_INDEX].dma_rx = &I2C3_dma_rx; -#endif /* BSP_I2C3_RX_USING_DMA */ -#ifdef BSP_I2C3_TX_USING_DMA - i2c_objs[I2C3_INDEX].i2c_dma_flag |= I2C_USING_TX_DMA_FLAG; +#if defined (BSP_I2C2_RX_USING_INT) + i2c_objs[I2C2_INDEX].i2c_dma_flag |= RT_DEVICE_FLAG_INT_RX; +#elif defined(BSP_I2C2_RX_USING_DMA) + i2c_objs[I2C2_INDEX].i2c_dma_flag |= RT_DEVICE_FLAG_DMA_RX; + static struct dma_config I2C2_dma_rx = I2C2_RX_DMA_CONFIG; + i2c_config[I2C2_INDEX].dma_rx = &I2C2_dma_rx; +#endif /* defined (BSP_I2C2_RX_USING_INT) */ + +#endif /* defined(BSP_USING_HARD_I2C2) */ + +#if defined(BSP_USING_HARD_I2C3) + i2c_objs[I2C3_INDEX].i2c_dma_flag = 0; + +#if defined (BSP_I2C3_TX_USING_INT) + i2c_objs[I2C3_INDEX].i2c_dma_flag |= RT_DEVICE_FLAG_INT_TX; +#elif defined(BSP_I2C3_TX_USING_DMA) + i2c_objs[I2C3_INDEX].i2c_dma_flag |= RT_DEVICE_FLAG_DMA_TX; static struct dma_config I2C3_dma_tx = I2C3_TX_DMA_CONFIG; i2c_config[I2C3_INDEX].dma_tx = &I2C3_dma_tx; -#endif /* BSP_I2C3_TX_USING_DMA */ +#endif /* defined (BSP_I2C3_TX_USING_INT) */ + +#if defined (BSP_I2C3_RX_USING_INT) + i2c_objs[I2C3_INDEX].i2c_dma_flag |= RT_DEVICE_FLAG_INT_RX; +#elif defined(BSP_I2C3_RX_USING_DMA) + i2c_objs[I2C3_INDEX].i2c_dma_flag |= RT_DEVICE_FLAG_DMA_RX; + static struct dma_config I2C3_dma_rx = I2C3_RX_DMA_CONFIG; + i2c_config[I2C3_INDEX].dma_rx = &I2C3_dma_rx; +#endif /* defined (BSP_I2C3_RX_USING_INT) */ + +#endif /* defined(BSP_USING_HARD_I2C3) */ + +#if defined(BSP_USING_HARD_I2C4) + i2c_objs[I2C4_INDEX].i2c_dma_flag = 0; + +#if defined (BSP_I2C4_TX_USING_INT) + i2c_objs[I2C4_INDEX].i2c_dma_flag |= RT_DEVICE_FLAG_INT_TX; +#elif defined(BSP_I2C4_TX_USING_DMA) + i2c_objs[I2C4_INDEX].i2c_dma_flag |= RT_DEVICE_FLAG_DMA_TX; + static struct dma_config I2C4_dma_tx = I2C4_TX_DMA_CONFIG; + i2c_config[I2C4_INDEX].dma_tx = &I2C4_dma_tx; +#endif /* defined (BSP_I2C4_TX_USING_INT) */ + +#if defined (BSP_I2C4_RX_USING_INT) + i2c_objs[I2C4_INDEX].i2c_dma_flag |= RT_DEVICE_FLAG_INT_RX; +#elif defined(BSP_I2C4_RX_USING_DMA) + i2c_objs[I2C4_INDEX].i2c_dma_flag |= RT_DEVICE_FLAG_DMA_RX; + static struct dma_config I2C4_dma_rx = I2C4_RX_DMA_CONFIG; + i2c_config[I2C4_INDEX].dma_rx = &I2C4_dma_rx; +#endif /* defined (BSP_I2C4_RX_USING_INT) */ + +#endif /* defined(BSP_USING_HARD_I2C4) */ } +#ifdef BSP_I2C_USING_IRQ void HAL_I2C_MasterTxCpltCallback(I2C_HandleTypeDef *hi2c) { struct stm32_i2c *i2c_drv = rt_container_of(hi2c, struct stm32_i2c, handle); rt_completion_done(&i2c_drv->completion); } + void HAL_I2C_MasterRxCpltCallback(I2C_HandleTypeDef *hi2c) { struct stm32_i2c *i2c_drv = rt_container_of(hi2c, struct stm32_i2c, handle); rt_completion_done(&i2c_drv->completion); } + void HAL_I2C_ErrorCallback(I2C_HandleTypeDef *hi2c) { + LOG_W("%s error code %d", hi2c->Instance == I2C1 ? "I2C1" + : hi2c->Instance == I2C2 ? "I2C2" + : hi2c->Instance == I2C3 ? "I2C3" + : "unknown", + hi2c->ErrorCode); #if defined(SOC_SERIES_STM32H7) /* Send stop signal to prevent bus lock-up */ if (hi2c->ErrorCode == HAL_I2C_ERROR_AF) { - LOG_D("I2C NACK Error now stoped"); + LOG_W("I2C NACK Error now stoped"); hi2c->Instance->CR1 |= I2C_IT_STOPI; } if (hi2c->ErrorCode == HAL_I2C_ERROR_BERR) { - LOG_D("I2C BUS Error now stoped"); + LOG_W("I2C BUS Error now stoped"); hi2c->Instance->CR1 |= I2C_IT_STOPI; } #endif /* defined(SOC_SERIES_STM32H7) */ - } + #ifdef BSP_USING_HARD_I2C1 /** - * @brief This function handles I2C2 event interrupt. + * @brief This function handles I2C1 event interrupt. */ void I2C1_EV_IRQHandler(void) { - /* USER CODE BEGIN I2C2_EV_IRQn 0 */ + /* USER CODE BEGIN I2C1_EV_IRQn 0 */ /* enter interrupt */ rt_interrupt_enter(); - /* USER CODE END I2C2_EV_IRQn 0 */ + /* USER CODE END I2C1_EV_IRQn 0 */ HAL_I2C_EV_IRQHandler(&i2c_objs[I2C1_INDEX].handle); - /* USER CODE BEGIN I2C2_EV_IRQn 1 */ + /* USER CODE BEGIN I2C1_EV_IRQn 1 */ /* leave interrupt */ rt_interrupt_leave(); - /* USER CODE END I2C2_EV_IRQn 1 */ + /* USER CODE END I2C1_EV_IRQn 1 */ } /** - * @brief This function handles I2C2 error interrupt. + * @brief This function handles I2C1 error interrupt. */ void I2C1_ER_IRQHandler(void) { - /* USER CODE BEGIN I2C2_ER_IRQn 0 */ + /* USER CODE BEGIN I2C1_ER_IRQn 0 */ /* enter interrupt */ rt_interrupt_enter(); - /* USER CODE END I2C2_ER_IRQn 0 */ + /* USER CODE END I2C1_ER_IRQn 0 */ HAL_I2C_ER_IRQHandler(&i2c_objs[I2C1_INDEX].handle); - /* USER CODE BEGIN I2C2_ER_IRQn 1 */ + /* USER CODE BEGIN I2C1_ER_IRQn 1 */ /* leave interrupt */ rt_interrupt_leave(); - /* USER CODE END I2C2_ER_IRQn 1 */ + /* USER CODE END I2C1_ER_IRQn 1 */ } #endif /* BSP_USING_HARD_I2C1 */ @@ -571,38 +722,74 @@ void I2C2_ER_IRQHandler(void) #ifdef BSP_USING_HARD_I2C3 /** - * @brief This function handles I2C2 event interrupt. + * @brief This function handles I2C3 event interrupt. */ void I2C3_EV_IRQHandler(void) { - /* USER CODE BEGIN I2C2_EV_IRQn 0 */ + /* USER CODE BEGIN I2C3_EV_IRQn 0 */ /* enter interrupt */ rt_interrupt_enter(); - /* USER CODE END I2C2_EV_IRQn 0 */ + /* USER CODE END I2C3_EV_IRQn 0 */ HAL_I2C_EV_IRQHandler(&i2c_objs[I2C3_INDEX].handle); - /* USER CODE BEGIN I2C2_EV_IRQn 1 */ + /* USER CODE BEGIN I2C3_EV_IRQn 1 */ /* leave interrupt */ rt_interrupt_leave(); - /* USER CODE END I2C2_EV_IRQn 1 */ + /* USER CODE END I2C3_EV_IRQn 1 */ } /** - * @brief This function handles I2C2 error interrupt. + * @brief This function handles I2C3 error interrupt. */ void I2C3_ER_IRQHandler(void) { - /* USER CODE BEGIN I2C2_ER_IRQn 0 */ + /* USER CODE BEGIN I2C3_ER_IRQn 0 */ /* enter interrupt */ rt_interrupt_enter(); - /* USER CODE END I2C2_ER_IRQn 0 */ + /* USER CODE END I2C3_ER_IRQn 0 */ HAL_I2C_ER_IRQHandler(&i2c_objs[I2C3_INDEX].handle); - /* USER CODE BEGIN I2C2_ER_IRQn 1 */ + /* USER CODE BEGIN I2C3_ER_IRQn 1 */ /* leave interrupt */ rt_interrupt_leave(); /* USER CODE END I2C2_ER_IRQn 1 */ } #endif /* BSP_USING_HARD_I2C3 */ +#ifdef BSP_USING_HARD_I2C4 +/** + * @brief This function handles I2C4 event interrupt. + */ +void I2C4_EV_IRQHandler(void) +{ + /* USER CODE BEGIN I2C4_EV_IRQn 0 */ + /* enter interrupt */ + rt_interrupt_enter(); + /* USER CODE END I2C4_EV_IRQn 0 */ + HAL_I2C_EV_IRQHandler(&i2c_objs[I2C4_INDEX].handle); + /* USER CODE BEGIN I2C4_EV_IRQn 1 */ + /* leave interrupt */ + rt_interrupt_leave(); + /* USER CODE END I2C4_EV_IRQn 1 */ +} + +/** + * @brief This function handles I2C4 error interrupt. + */ +void I2C4_ER_IRQHandler(void) +{ + /* USER CODE BEGIN I2C4_ER_IRQn 0 */ + /* enter interrupt */ + rt_interrupt_enter(); + /* USER CODE END I2C4_ER_IRQn 0 */ + HAL_I2C_ER_IRQHandler(&i2c_objs[I2C4_INDEX].handle); + /* USER CODE BEGIN I2C4_ER_IRQn 1 */ + /* leave interrupt */ + rt_interrupt_leave(); + /* USER CODE END I2C4_ER_IRQn 1 */ +} +#endif /* BSP_USING_HARD_I2C4 */ +#endif /* BSP_I2C_USING_IRQ */ + +#ifdef BSP_I2C_USING_DMA #if defined(BSP_USING_HARD_I2C1) && defined(BSP_I2C1_RX_USING_DMA) /** * @brief This function handles DMA Rx interrupt request. @@ -711,11 +898,48 @@ void I2C3_DMA_TX_IRQHandler(void) } #endif /* defined(BSP_USING_HARD_I2C3) && defined(BSP_I2C3_TX_USING_DMA) */ +#if defined(BSP_USING_HARD_I2C4) && defined(BSP_I2C4_RX_USING_DMA) +/** + * @brief This function handles DMA Rx interrupt request. + * @param None + * @retval None + */ +void I2C4_DMA_RX_IRQHandler(void) +{ + /* enter interrupt */ + rt_interrupt_enter(); + + HAL_DMA_IRQHandler(&i2c_objs[I2C4_INDEX].dma.handle_rx); + + /* leave interrupt */ + rt_interrupt_leave(); +} +#endif /* defined(BSP_USING_HARD_I2C4) && defined(BSP_I2C4_RX_USING_DMA) */ + +#if defined(BSP_USING_HARD_I2C4) && defined(BSP_I2C4_TX_USING_DMA) +/** + * @brief This function handles DMA Rx interrupt request. + * @param None + * @retval None + */ +void I2C4_DMA_TX_IRQHandler(void) +{ + /* enter interrupt */ + rt_interrupt_enter(); + + HAL_DMA_IRQHandler(&i2c_objs[I2C4_INDEX].dma.handle_tx); + + /* leave interrupt */ + rt_interrupt_leave(); +} +#endif /* defined(BSP_USING_HARD_I2C4) && defined(BSP_I2C4_TX_USING_DMA) */ +#endif /* BSP_I2C_USING_DMA */ + int rt_hw_hw_i2c_init(void) { - stm32_get_dma_info(); + stm32_get_info(); return RT_hw_i2c_bus_init(); } INIT_BOARD_EXPORT(rt_hw_hw_i2c_init); -#endif /* defined(BSP_USING_HARD_I2C1) || defined(BSP_USING_HARD_I2C2) || defined(BSP_USING_HARD_I2C3) */ +#endif /* defined(BSP_HARDWARE_I2C) */ diff --git a/bsp/stm32/libraries/HAL_Drivers/drivers/drv_hard_i2c.h b/bsp/stm32/libraries/HAL_Drivers/drivers/drv_hard_i2c.h index 06046512965..89a88b00459 100644 --- a/bsp/stm32/libraries/HAL_Drivers/drivers/drv_hard_i2c.h +++ b/bsp/stm32/libraries/HAL_Drivers/drivers/drv_hard_i2c.h @@ -1,11 +1,12 @@ /* - * Copyright (c) 2006-2023, RT-Thread Development Team + * Copyright (c) 2006-2024, RT-Thread Development Team * * SPDX-License-Identifier: Apache-2.0 * * Change Logs: * Date Author Notes - * 2024-02-17 Dyyt587 first version + * 2024-02-17 Dyyt587 first version + * 2024-06-23 wdfk-prog Add mode selection scaffolding */ #ifndef __DRV_HARD_I2C_H__ @@ -22,35 +23,118 @@ extern "C" { #endif +/* hardware bus */ +#if defined(BSP_USING_HARD_I2C1) \ + || defined(BSP_USING_HARD_I2C2) \ + || defined(BSP_USING_HARD_I2C3) \ + || defined(BSP_USING_HARD_I2C4) +#define BSP_HARDWARE_I2C +#endif + +/* poll */ +#if defined(BSP_I2C1_TX_USING_POLL) \ + || defined(BSP_I2C2_TX_USING_POLL) \ + || defined(BSP_I2C3_TX_USING_POLL) \ + || defined(BSP_I2C4_TX_USING_POLL) +#define BSP_I2C_TX_USING_POLL +#endif + +#if defined(BSP_I2C1_RX_USING_POLL) \ + || defined(BSP_I2C2_RX_USING_POLL) \ + || defined(BSP_I2C3_RX_USING_POLL) \ + || defined(BSP_I2C4_RX_USING_POLL) +#define BSP_I2C_RX_USING_POLL +#endif + +#if defined (BSP_I2C_TX_USING_POLL) \ + || defined (BSP_I2C_RX_USING_POLL) +#define BSP_I2C_USING_POLL +#endif + +/* DMA */ +#if defined(BSP_I2C1_TX_USING_DMA) \ + || defined(BSP_I2C2_TX_USING_DMA) \ + || defined(BSP_I2C3_TX_USING_DMA) \ + || defined(BSP_I2C4_TX_USING_DMA) +#define BSP_I2C_TX_USING_DMA +#endif + +#if defined(BSP_I2C1_RX_USING_DMA) \ + || defined(BSP_I2C2_RX_USING_DMA) \ + || defined(BSP_I2C3_RX_USING_DMA) \ + || defined(BSP_I2C4_RX_USING_DMA) +#define BSP_I2C_RX_USING_DMA +#endif + +#if defined (BSP_I2C_TX_USING_DMA) \ + || defined (BSP_I2C_RX_USING_DMA) +#define BSP_I2C_USING_DMA +#endif + +/* INT */ +#if defined(BSP_I2C1_TX_USING_INT) \ + || defined(BSP_I2C2_TX_USING_INT) \ + || defined(BSP_I2C3_TX_USING_INT) \ + || defined(BSP_I2C4_TX_USING_INT) +#define BSP_I2C_TX_USING_INT +#endif + +#if defined(BSP_I2C1_RX_USING_INT) \ + || defined(BSP_I2C2_RX_USING_INT) \ + || defined(BSP_I2C3_RX_USING_INT) \ + || defined(BSP_I2C4_RX_USING_INT) +#define BSP_I2C_RX_USING_INT +#endif + +#if defined (BSP_I2C_TX_USING_INT) \ + || defined (BSP_I2C_RX_USING_INT) +#define BSP_I2C_USING_INT +#endif + +/* IRQ */ +#if defined (BSP_I2C_USING_DMA) \ + || defined (BSP_I2C_USING_INT) +#define BSP_I2C_USING_IRQ +#endif + struct stm32_i2c_config { - const char *name; - I2C_TypeDef *Instance; - rt_uint32_t timing; - rt_uint32_t timeout; - IRQn_Type evirq_type; - IRQn_Type erirq_type; - struct dma_config *dma_rx; - struct dma_config *dma_tx; + const char *name; + I2C_TypeDef *Instance; + rt_uint32_t timing; + rt_uint32_t timeout; + IRQn_Type evirq_type; + IRQn_Type erirq_type; +#ifdef BSP_I2C_RX_USING_DMA + struct dma_config *dma_rx; +#endif /* BSP_I2C_RX_USING_DMA */ +#ifdef BSP_I2C_TX_USING_DMA + struct dma_config *dma_tx; +#endif /* BSP_I2C_TX_USING_DMA */ }; struct stm32_i2c { - I2C_HandleTypeDef handle; - struct stm32_i2c_config *config; + I2C_HandleTypeDef handle; + struct stm32_i2c_config *config; + struct rt_i2c_bus_device i2c_bus; + rt_uint16_t i2c_dma_flag; +#ifdef BSP_I2C_USING_IRQ + struct rt_completion completion; +#endif /* BSP_I2C_USING_IRQ */ +#ifdef BSP_I2C_USING_DMA struct { - DMA_HandleTypeDef handle_rx; - DMA_HandleTypeDef handle_tx; +#ifdef BSP_I2C_RX_USING_DMA + DMA_HandleTypeDef handle_rx; +#endif /* BSP_I2C_RX_USING_DMA */ +#ifdef BSP_I2C_TX_USING_DMA + DMA_HandleTypeDef handle_tx; +#endif /* BSP_I2C_TX_USING_DMA */ } dma; - rt_uint8_t i2c_dma_flag; - struct rt_i2c_bus_device i2c_bus; - struct rt_completion completion; +#endif /* BSP_I2C_USING_DMA */ }; -#define I2C_USING_TX_DMA_FLAG (1U) -#define I2C_USING_RX_DMA_FLAG (1U << 1) - #ifdef __cplusplus } #endif From ecb3677c1a289b4ab64834dc65b035ba9e46a2ca Mon Sep 17 00:00:00 2001 From: wdfk-prog <1425075683@qq.com> Date: Mon, 16 Mar 2026 10:23:04 +0800 Subject: [PATCH 2/2] refactor[stm32][i2c]: restructure transfer flow and error handling --- .../HAL_Drivers/drivers/drv_hard_i2c.c | 418 ++++++++++-------- 1 file changed, 233 insertions(+), 185 deletions(-) diff --git a/bsp/stm32/libraries/HAL_Drivers/drivers/drv_hard_i2c.c b/bsp/stm32/libraries/HAL_Drivers/drivers/drv_hard_i2c.c index b6db90e5006..7f571945ff5 100644 --- a/bsp/stm32/libraries/HAL_Drivers/drivers/drv_hard_i2c.c +++ b/bsp/stm32/libraries/HAL_Drivers/drivers/drv_hard_i2c.c @@ -19,6 +19,9 @@ #define LOG_TAG "drv.i2c.hw" #include +/* only buffer length >= DMA_TRANS_MIN_LEN will use DMA mode */ +#define DMA_TRANS_MIN_LEN 2 + typedef enum { #ifdef BSP_USING_HARD_I2C1 @@ -64,6 +67,7 @@ static rt_err_t stm32_i2c_init(struct stm32_i2c *i2c_drv) i2c_handle->Instance = cfg->Instance; #if defined(SOC_SERIES_STM32H7) i2c_handle->Init.Timing = cfg->timing; + i2c_handle->Init.OwnAddress2Masks = I2C_OA2_NOMASK; #else i2c_handle->Init.ClockSpeed = 100000; i2c_handle->Init.DutyCycle = I2C_DUTYCYCLE_2; @@ -74,10 +78,6 @@ static rt_err_t stm32_i2c_init(struct stm32_i2c *i2c_drv) i2c_handle->Init.OwnAddress2 = 0; i2c_handle->Init.GeneralCallMode = I2C_GENERALCALL_DISABLE; i2c_handle->Init.NoStretchMode = I2C_NOSTRETCH_DISABLE; -#if defined(SOC_SERIES_STM32H7) - i2c_handle->Init.OwnAddress2Masks = I2C_OA2_NOMASK; -#endif /* defined(SOC_SERIES_STM32H7) */ - if (HAL_I2C_DeInit(i2c_handle) != HAL_OK) { return -RT_EFAULT; @@ -148,6 +148,171 @@ static rt_err_t stm32_i2c_configure(struct rt_i2c_bus_device *bus) return stm32_i2c_init(i2c_drv); } + +/** + * @brief Start one master receive transfer and report whether wait is required. + * @param i2c_obj Pointer to the STM32 I2C driver object. + * @param handle Pointer to the HAL I2C handle. + * @param msg Pointer to the RT-Thread I2C message descriptor. + * @param mode HAL sequential transfer mode. + * @param timeout Timeout in RT-Thread ticks for polling transfer. + * @param need_wait Output flag set to RT_TRUE when IT/DMA path is used. + * @return HAL status returned by the selected HAL receive API. + * @retval HAL_OK Transfer start succeeded. + * @retval HAL_ERROR Transfer start failed or no receive backend is enabled. + */ +static HAL_StatusTypeDef stm32_i2c_master_receive_start(struct stm32_i2c *i2c_obj, + I2C_HandleTypeDef *handle, + struct rt_i2c_msg *msg, + uint32_t mode, + rt_uint32_t timeout, + rt_bool_t *need_wait) +{ + RT_UNUSED(i2c_obj); + RT_UNUSED(mode); + RT_UNUSED(timeout); + RT_ASSERT(i2c_obj != RT_NULL); + RT_ASSERT(handle != RT_NULL); + RT_ASSERT(msg != RT_NULL); + RT_ASSERT(need_wait != RT_NULL); + + *need_wait = RT_FALSE; + +#if defined(BSP_I2C_RX_USING_DMA) + if ((i2c_obj->i2c_dma_flag & RT_DEVICE_FLAG_DMA_RX) && (msg->len >= DMA_TRANS_MIN_LEN)) + { + *need_wait = RT_TRUE; + return HAL_I2C_Master_Seq_Receive_DMA(handle, (msg->addr << 1), msg->buf, msg->len, mode); + } +#endif /* defined(BSP_I2C_RX_USING_DMA) */ + +#if defined(BSP_I2C_RX_USING_INT) + if (i2c_obj->i2c_dma_flag & RT_DEVICE_FLAG_INT_RX) + { + *need_wait = RT_TRUE; + return HAL_I2C_Master_Seq_Receive_IT(handle, (msg->addr << 1), msg->buf, msg->len, mode); + } +#endif /* defined(BSP_I2C_RX_USING_INT) */ + +#if defined(BSP_I2C_RX_USING_POLL) + return HAL_I2C_Master_Receive(handle, (msg->addr << 1), msg->buf, msg->len, timeout); +#else + return HAL_ERROR; +#endif /* defined(BSP_I2C_RX_USING_POLL) */ +} + +/** + * @brief Start one master transmit transfer and report whether wait is required. + * @param i2c_obj Pointer to the STM32 I2C driver object. + * @param handle Pointer to the HAL I2C handle. + * @param msg Pointer to the RT-Thread I2C message descriptor. + * @param mode HAL sequential transfer mode. + * @param timeout Timeout in RT-Thread ticks for polling transfer. + * @param need_wait Output flag set to RT_TRUE when IT/DMA path is used. + * @return HAL status returned by the selected HAL transmit API. + * @retval HAL_OK Transfer start succeeded. + * @retval HAL_ERROR Transfer start failed or no transmit backend is enabled. + */ +static HAL_StatusTypeDef stm32_i2c_master_transmit_start(struct stm32_i2c *i2c_obj, + I2C_HandleTypeDef *handle, + struct rt_i2c_msg *msg, + uint32_t mode, + rt_uint32_t timeout, + rt_bool_t *need_wait) +{ + RT_UNUSED(i2c_obj); + RT_UNUSED(mode); + RT_UNUSED(timeout); + RT_ASSERT(i2c_obj != RT_NULL); + RT_ASSERT(handle != RT_NULL); + RT_ASSERT(msg != RT_NULL); + RT_ASSERT(need_wait != RT_NULL); + + *need_wait = RT_FALSE; + +#if defined(BSP_I2C_TX_USING_DMA) + if ((i2c_obj->i2c_dma_flag & RT_DEVICE_FLAG_DMA_TX) && (msg->len >= DMA_TRANS_MIN_LEN)) + { + *need_wait = RT_TRUE; + return HAL_I2C_Master_Seq_Transmit_DMA(handle, (msg->addr << 1), msg->buf, msg->len, mode); + } +#endif /* defined(BSP_I2C_TX_USING_DMA) */ + +#if defined(BSP_I2C_TX_USING_INT) + if (i2c_obj->i2c_dma_flag & RT_DEVICE_FLAG_INT_TX) + { + *need_wait = RT_TRUE; + return HAL_I2C_Master_Seq_Transmit_IT(handle, (msg->addr << 1), msg->buf, msg->len, mode); + } +#endif /* defined(BSP_I2C_TX_USING_INT) */ + +#if defined(BSP_I2C_TX_USING_POLL) + return HAL_I2C_Master_Transmit(handle, (msg->addr << 1), msg->buf, msg->len, timeout); +#else + return HAL_ERROR; +#endif /* defined(BSP_I2C_TX_USING_POLL) */ +} + +/** + * @brief Compute HAL transfer mode for the current message in a sequence. + * @param index Index of the current message. + * @param msg Pointer to the current I2C message. + * @param next_msg Pointer to the next I2C message, or RT_NULL for the last one. + * @param is_last RT_TRUE when the current message is the last frame. + * @return HAL sequential transfer option used by the message. + * @retval I2C_FIRST_AND_NEXT_FRAME Continue transfer without repeated start. + * @retval I2C_LAST_FRAME_NO_STOP Keep bus active for following frame semantics. + * @retval I2C_LAST_FRAME End transfer with the last frame behavior. + */ +static uint32_t stm32_i2c_get_xfer_mode(rt_int32_t index, + struct rt_i2c_msg *msg, + struct rt_i2c_msg *next_msg, + rt_bool_t is_last) +{ + if (is_last) + { + if (msg->flags & RT_I2C_NO_STOP) + { + return I2C_LAST_FRAME_NO_STOP; + } + + return I2C_LAST_FRAME; + } + + if (next_msg->flags & RT_I2C_NO_START) + { + if ((next_msg->flags & RT_I2C_RD) == (msg->flags & RT_I2C_RD)) + { + /* The same mode, can use no start */ + return I2C_FIRST_AND_NEXT_FRAME; + } + + /* Not allowed to use no start, sending address is required when changing direction, user setting error */ + LOG_W("user set flags error msg[%d] flags RT_I2C_NO_START has canceled", index + 1); + } + + return I2C_LAST_FRAME_NO_STOP; +} + +/** + * @brief Convert HAL transfer mode value to a readable log string. + * @param mode HAL sequential transfer option. + * @return Constant string for logging. + */ +const char *stm32_i2c_mode_name(uint32_t mode) +{ + switch (mode) + { + case I2C_FIRST_AND_NEXT_FRAME: + return "I2C_FIRST_AND_NEXT_FRAME"; + case I2C_LAST_FRAME_NO_STOP: + return "I2C_FIRST_FRAME/I2C_LAST_FRAME_NO_STOP"; + case I2C_LAST_FRAME: + return "I2C_LAST_FRAME"; + default: + return "unknown mode"; + } +} /** * @brief Hardware I2C driver transfer * @@ -160,26 +325,20 @@ static rt_ssize_t stm32_i2c_master_xfer(struct rt_i2c_bus_device *bus, struct rt_i2c_msg msgs[], rt_uint32_t num) { - /* for stm32 dma may more stability */ -#define DMA_TRANS_MIN_LEN 2 /* only buffer length >= DMA_TRANS_MIN_LEN will use DMA mode */ -#define TRANS_TIMEOUT_PERSEC 8 /* per ms will trans nums bytes */ - - rt_int32_t i, ret = 0; - struct rt_i2c_msg *msg = msgs; - struct rt_i2c_msg *next_msg = 0; + rt_uint32_t i = 0; + rt_int32_t ret = 0; + struct rt_i2c_msg *msg = RT_NULL; + struct rt_i2c_msg *next_msg = RT_NULL; struct stm32_i2c *i2c_obj; + rt_bool_t is_last = RT_FALSE; uint32_t mode = 0; - RT_UNUSED(mode); - uint8_t next_flag = 0; rt_uint32_t timeout; - if (num == 0) { return 0; } RT_ASSERT((msgs != RT_NULL) && (bus != RT_NULL)); - i2c_obj = rt_container_of(bus, struct stm32_i2c, i2c_bus); RT_ASSERT(i2c_obj != RT_NULL); I2C_HandleTypeDef *handle = &i2c_obj->handle; @@ -188,218 +347,104 @@ static rt_ssize_t stm32_i2c_master_xfer(struct rt_i2c_bus_device *bus, struct rt_completion *completion; completion = &i2c_obj->completion; #endif /* defined(BSP_I2C_USING_IRQ) */ - LOG_D("xfer start %d mags", num); - for (i = 0; i < (num - 1); i++) + LOG_D("xfer start %d megs", num); + + rt_uint32_t freq_khz = bus->config.usage_freq / 1000; + if (freq_khz == 0) { - mode = 0; + freq_khz = 1; + } + + for (i = 0; i < num; i++) + { + rt_bool_t need_wait = RT_FALSE; msg = &msgs[i]; + is_last = (i == (num - 1)); + next_msg = is_last ? RT_NULL : &msgs[i + 1]; + mode = stm32_i2c_get_xfer_mode(i, msg, next_msg, is_last); LOG_D("xfer msgs[%d] addr=0x%2x buf=0x%x len= 0x%x flags= 0x%x", i, msg->addr, msg->buf, msg->len, msg->flags); - next_msg = &msgs[i + 1]; - next_flag = next_msg->flags; - timeout = msg->len / TRANS_TIMEOUT_PERSEC + 5; - if (next_flag & RT_I2C_NO_START) - { - if ((next_flag & RT_I2C_RD) == (msg->flags & RT_I2C_RD)) - { /* The same mode, can use no start */ - mode = I2C_FIRST_AND_NEXT_FRAME; - } - else - { - /* Not allowed to use no start, sending address is required when changing direction, user setting error */ - LOG_W("user set flags error msg[%d] flags RT_I2C_NO_START has canceled", i + 1); - mode = I2C_LAST_FRAME_NO_STOP; - } - } - else - { - mode = I2C_LAST_FRAME_NO_STOP; - } + + // timeout= data_time + dev_addr_time + reserve_time + timeout = (msg->len * 8) / freq_khz + 1 + 5; if (msg->flags & RT_I2C_RD) { - LOG_D("xfer rec msgs[%d] hal mode = %s", i, mode == I2C_FIRST_AND_NEXT_FRAME ? "I2C_FIRST_AND_NEXT_FRAME" : mode == I2C_LAST_FRAME_NO_STOP ? "I2C_FIRST_FRAME/I2C_LAST_FRAME_NO_STOP" - : mode == I2C_LAST_FRAME ? "I2C_LAST_FRAME" - : "nuknown mode"); -#if defined(BSP_I2C_RX_USING_DMA) - if ((i2c_obj->i2c_dma_flag & RT_DEVICE_FLAG_DMA_RX) && (msg->len >= DMA_TRANS_MIN_LEN)) - { - ret = HAL_I2C_Master_Seq_Receive_DMA(handle, (msg->addr<<1), msg->buf, msg->len, mode); - } - else -#endif /* defined(BSP_I2C_RX_USING_DMA) */ -#if defined(BSP_I2C_RX_USING_INT) - if(i2c_obj->i2c_dma_flag & RT_DEVICE_FLAG_INT_RX) - { - ret = HAL_I2C_Master_Seq_Receive_IT(handle, (msg->addr<<1), msg->buf, msg->len, mode); - } - else -#endif /* defined(BSP_I2C_RX_USING_INT) */ -#if defined(BSP_I2C_RX_USING_POLL) - { - ret = HAL_I2C_Master_Receive(handle, (msg->addr<<1), msg->buf, msg->len, timeout); - } -#endif /* defined(BSP_I2C_RX_USING_POLL) */ - if (ret != HAL_OK) + LOG_D("xfer rec msgs[%d] hal mode = %s", i, stm32_i2c_mode_name(mode)); + ret = stm32_i2c_master_receive_start(i2c_obj, handle, msg, mode, timeout, &need_wait); + if (ret != HAL_OK) { - LOG_E("[%s:%d]I2C Read error(%d)!\n", __func__, __LINE__, ret); + LOG_E("I2C[%s] Read error(%d)!\n", bus->parent.parent.name, ret); goto out; } #if defined(BSP_I2C_USING_IRQ) - ret = rt_completion_wait(completion, timeout); - if (ret != RT_EOK) + if (need_wait) { - LOG_W("receive error %d, timeout %d", ret, timeout); - goto out; + ret = rt_completion_wait(completion, timeout); + if (ret != RT_EOK) + { + LOG_W("I2C[%s] receive wait failed %d, timeout %d", bus->parent.parent.name, ret, timeout); + goto out; + } } #endif /* defined(BSP_I2C_USING_IRQ) */ } else { - LOG_D("xfer trans msgs[%d] hal mode = %s", i, mode == I2C_FIRST_AND_NEXT_FRAME ? "I2C_FIRST_AND_NEXT_FRAME" : mode == I2C_LAST_FRAME_NO_STOP ? "I2C_FIRST_FRAME/I2C_LAST_FRAME_NO_STOP" - : mode == I2C_LAST_FRAME ? "I2C_LAST_FRAME" - : "nuknown mode"); -#if defined(BSP_I2C_TX_USING_DMA) - if ((i2c_obj->i2c_dma_flag & RT_DEVICE_FLAG_DMA_TX) && (msg->len >= DMA_TRANS_MIN_LEN)) - { - ret = HAL_I2C_Master_Seq_Transmit_DMA(handle, (msg->addr<<1), msg->buf, msg->len, mode); - } - else -#endif /* defined(BSP_I2C_TX_USING_DMA) */ -#if defined(BSP_I2C_TX_USING_INT) - if(i2c_obj->i2c_dma_flag & RT_DEVICE_FLAG_INT_TX) - { - ret = HAL_I2C_Master_Seq_Transmit_IT(handle, (msg->addr<<1), msg->buf, msg->len, mode); - } - else -#endif /* defined(BSP_I2C_TX_USING_INT) */ -#if defined(BSP_I2C_TX_USING_POLL) - { - ret = HAL_I2C_Master_Transmit(handle, (msg->addr<<1), msg->buf, msg->len, timeout); - } -#endif /* defined(BSP_I2C_TX_USING_POLL) */ + LOG_D("xfer trans msgs[%d] hal mode = %s", i, stm32_i2c_mode_name(mode)); + ret = stm32_i2c_master_transmit_start(i2c_obj, handle, msg, mode, timeout, &need_wait); if (ret != HAL_OK) { - LOG_E("[%s:%d]I2C Write error(%d)!\n", __func__, __LINE__, ret); + LOG_E("I2C[%s] Write error(%d)!\n", bus->parent.parent.name, ret); goto out; } #if defined(BSP_I2C_USING_IRQ) - ret = rt_completion_wait(completion, timeout); - if (ret != RT_EOK) + if (need_wait) { - LOG_W("receive error %d, timeout %d", ret, timeout); - goto out; + ret = rt_completion_wait(completion, timeout); + if (ret != RT_EOK) + { + LOG_W("I2C[%s] transmit wait failed %d, timeout %d", bus->parent.parent.name, ret, timeout); + goto out; + } } #endif /* defined(BSP_I2C_USING_IRQ) */ } - LOG_D("xfer next msgs[%d] addr=0x%2x buf= 0x%x len= 0x%x flags = 0x%x\r\n", i + 1, next_msg->addr, next_msg->buf, next_msg->len, next_msg->flags); - } - /* last msg */ - msg = &msgs[i]; - timeout = msg->len / TRANS_TIMEOUT_PERSEC + 5; - if (msg->flags & RT_I2C_NO_STOP) - mode = I2C_LAST_FRAME_NO_STOP; - else - mode = I2C_LAST_FRAME; - LOG_D("xfer last msgs[%d] addr=0x%2x buf= 0x%x len= 0x%x flags = 0x%x", i, msg->addr, msg->buf, msg->len, msg->flags); - if (msg->flags & RT_I2C_RD) - { - LOG_D("xfer rec msgs[%d] hal mode=%s", i, mode == I2C_FIRST_AND_NEXT_FRAME ? "I2C_FIRST_AND_NEXT_FRAME" : mode == I2C_LAST_FRAME_NO_STOP ? "I2C_FIRST_FRAME/I2C_LAST_FRAME_NO_STOP" - : mode == I2C_LAST_FRAME ? "I2C_LAST_FRAME" - : "nuknown mode"); -#if defined(BSP_I2C_RX_USING_DMA) - if ((i2c_obj->i2c_dma_flag & RT_DEVICE_FLAG_DMA_RX) && (msg->len >= DMA_TRANS_MIN_LEN)) - { - ret = HAL_I2C_Master_Seq_Receive_DMA(handle, (msg->addr<<1), msg->buf, msg->len, mode); - } - else -#endif /* defined(BSP_I2C_RX_USING_DMA) */ -#if defined(BSP_I2C_RX_USING_INT) - if(i2c_obj->i2c_dma_flag & RT_DEVICE_FLAG_INT_RX) - { - ret = HAL_I2C_Master_Seq_Receive_IT(handle,(msg->addr<<1), msg->buf, msg->len, mode); - } - else -#endif /* defined(BSP_I2C_RX_USING_INT) */ -#if defined(BSP_I2C_RX_USING_POLL) - { - ret = HAL_I2C_Master_Receive(handle, (msg->addr<<1), msg->buf, msg->len, timeout); - } -#endif /* defined(BSP_I2C_RX_USING_POLL) */ - if (ret != HAL_OK) - { - LOG_E("[%s:%d]I2C Read error(%d)!\n", __func__, __LINE__, ret); - goto out; - } -#if defined(BSP_I2C_USING_IRQ) - ret = rt_completion_wait(completion, timeout); - if (ret != RT_EOK) - { - LOG_W("receive error %d, timeout %d", ret, timeout); - goto out; - } -#endif /* defined(BSP_I2C_USING_IRQ) */ - } - else - { - LOG_D("xfer trans msgs[%d] hal mode = %s", i, mode == I2C_FIRST_AND_NEXT_FRAME ? "I2C_FIRST_AND_NEXT_FRAME" : mode == I2C_LAST_FRAME ? "I2C_LAST_FRAME" - : mode == I2C_LAST_FRAME_NO_STOP ? "I2C_FIRST_FRAME/I2C_LAST_FRAME_NO_STOP" - : "nuknown mode"); -#if defined(BSP_I2C_TX_USING_DMA) - if ((i2c_obj->i2c_dma_flag & RT_DEVICE_FLAG_DMA_TX) && (msg->len >= DMA_TRANS_MIN_LEN)) - { - ret = HAL_I2C_Master_Seq_Transmit_DMA(handle, (msg->addr<<1), msg->buf, msg->len, mode); - } - else -#endif /* defined(BSP_I2C_TX_USING_DMA) */ -#if defined(BSP_I2C_TX_USING_INT) - if(i2c_obj->i2c_dma_flag & RT_DEVICE_FLAG_INT_TX) - { - ret = HAL_I2C_Master_Seq_Transmit_IT(handle, (msg->addr<<1), msg->buf, msg->len, mode); - } - else -#endif /* defined(BSP_I2C_TX_USING_INT) */ -#if defined(BSP_I2C_TX_USING_POLL) - { - ret = HAL_I2C_Master_Transmit(handle, (msg->addr<<1), msg->buf, msg->len, timeout); - } -#endif /* defined(BSP_I2C_TX_USING_POLL) */ - if (ret != HAL_OK) + if (!is_last) { - LOG_E("[%s:%d]I2C Write error(%d)!\n", __func__, __LINE__, ret); - goto out; + LOG_D("xfer next msgs[%d] addr=0x%2x buf= 0x%x len= 0x%x flags = 0x%x\r\n", i + 1, next_msg->addr, next_msg->buf, next_msg->len, next_msg->flags); } -#if defined(BSP_I2C_USING_IRQ) - ret = rt_completion_wait(completion, timeout); - if (ret != RT_EOK) - { - LOG_W("transmit error %d, timeout %d", ret, timeout); - goto out; - } -#endif /* defined(BSP_I2C_USING_IRQ) */ } ret = num; - LOG_D("xfer end %d mags\r\n", num); + LOG_D("xfer end %d megs\r\n", num); return ret; out: - if (handle->ErrorCode == HAL_I2C_ERROR_AF) + ret = i; + /* + * On STM32H7, STOPI only enables STOP-event interrupt handling. + * It does not actively generate a STOP condition on the bus. + * + * For non-H7 STM32 series, the legacy HAL error handler already + * generates a STOP condition on AF in master/memory modes, so + * this driver does not manually issue another STOP in the AF path. + */ + if (handle->ErrorCode & HAL_I2C_ERROR_AF) { - LOG_W("I2C NACK Error now stoped"); - /* Send stop signal to prevent bus lock-up */ + LOG_W("I2C[%s] NACK Error", bus->parent.parent.name); #if defined(SOC_SERIES_STM32H7) handle->Instance->CR1 |= I2C_IT_STOPI; -#endif /* defined(SOC_SERIES_STM32H7) */ +#endif /* defined(SOC_SERIES_STM32H7) */ } - if (handle->ErrorCode == HAL_I2C_ERROR_BERR) + if (handle->ErrorCode & HAL_I2C_ERROR_BERR) { - LOG_W("I2C BUS Error now stoped"); + LOG_W("I2C[%s] BUS Error", bus->parent.parent.name); #if defined(SOC_SERIES_STM32H7) handle->Instance->CR1 |= I2C_IT_STOPI; #else handle->Instance->CR1 |= I2C_CR1_STOP; -#endif /* defined(SOC_SERIES_STM32H7) */ - ret=i-1; +#endif /* defined(SOC_SERIES_STM32H7) */ } + return ret; } @@ -635,6 +680,9 @@ void HAL_I2C_ErrorCallback(I2C_HandleTypeDef *hi2c) LOG_W("%s error code %d", hi2c->Instance == I2C1 ? "I2C1" : hi2c->Instance == I2C2 ? "I2C2" : hi2c->Instance == I2C3 ? "I2C3" +#ifdef I2C4 + : hi2c->Instance == I2C4 ? "I2C4" +#endif /* I2C4 */ : "unknown", hi2c->ErrorCode); #if defined(SOC_SERIES_STM32H7)