diff --git a/bsp/novosns/ns800/libraries/HAL_Drivers/drivers/SConscript b/bsp/novosns/ns800/libraries/HAL_Drivers/drivers/SConscript index 312e99602c7..bc60d24133d 100644 --- a/bsp/novosns/ns800/libraries/HAL_Drivers/drivers/SConscript +++ b/bsp/novosns/ns800/libraries/HAL_Drivers/drivers/SConscript @@ -27,6 +27,9 @@ if GetDepend('BSP_USING_TIM'): if GetDepend('BSP_USING_SPI'): src += ['drv_spi.c'] + +if GetDepend('BSP_USING_I2C'): + src += ['drv_hard_i2c.c'] group = DefineGroup('HAL_Drivers', src, depend = [''], CPPPATH = path) diff --git a/bsp/novosns/ns800/libraries/HAL_Drivers/drivers/config/rt7/i2c_hard_config.h b/bsp/novosns/ns800/libraries/HAL_Drivers/drivers/config/rt7/i2c_hard_config.h index 7168665eba2..a9432a566a7 100644 --- a/bsp/novosns/ns800/libraries/HAL_Drivers/drivers/config/rt7/i2c_hard_config.h +++ b/bsp/novosns/ns800/libraries/HAL_Drivers/drivers/config/rt7/i2c_hard_config.h @@ -5,9 +5,7 @@ * * Change Logs: * Date Author Notes - * 2024-02-06 Dyyt587 first version - * 2024-04-23 Zeidan Add I2Cx_xx_DMA_CONFIG - * 2024-06-23 wdfk-prog Add H7 hard I2C config + * 2026-06-07 dirtwillfly first version for NS800 */ #ifndef __I2C_HARD_CONFIG_H__ #define __I2C_HARD_CONFIG_H__ @@ -18,242 +16,114 @@ extern "C" { #endif +/* I2C1 default GPIO configuration */ +/* GPIO_0 (SDA) -> GPIOA, GPIO_PIN_0 */ +/* GPIO_1 (SCL) -> GPIOA, GPIO_PIN_1 */ +#ifndef BSP_I2C1_SCL_PIN_NUM +#define BSP_I2C1_SCL_PIN_NUM 1U +#endif +#ifndef BSP_I2C1_SDA_PIN_NUM +#define BSP_I2C1_SDA_PIN_NUM 0U +#endif +#ifndef BSP_I2C1_SCL_PORT +#define BSP_I2C1_SCL_PORT GPIOA +#endif +#ifndef BSP_I2C1_SDA_PORT +#define BSP_I2C1_SDA_PORT GPIOA +#endif +#ifndef BSP_I2C1_SCL_PIN +#define BSP_I2C1_SCL_PIN GPIO_PIN_1 +#endif +#ifndef BSP_I2C1_SDA_PIN +#define BSP_I2C1_SDA_PIN GPIO_PIN_0 +#endif +#ifndef BSP_I2C1_SCL_ALT_FUNC +#define BSP_I2C1_SCL_ALT_FUNC ALT6_FUNCTION +#endif +#ifndef BSP_I2C1_SDA_ALT_FUNC +#define BSP_I2C1_SDA_ALT_FUNC ALT6_FUNCTION +#endif + +/* I2C2 default GPIO configuration */ +/* GPIO_34 (SDA) -> GPIOB, GPIO_PIN_2 */ +/* GPIO_35 (SCL) -> GPIOB, GPIO_PIN_3 */ +#ifndef BSP_I2C2_SCL_PIN_NUM +#define BSP_I2C2_SCL_PIN_NUM 35U +#endif +#ifndef BSP_I2C2_SDA_PIN_NUM +#define BSP_I2C2_SDA_PIN_NUM 34U +#endif +#ifndef BSP_I2C2_SCL_PORT +#define BSP_I2C2_SCL_PORT GPIOB +#endif +#ifndef BSP_I2C2_SDA_PORT +#define BSP_I2C2_SDA_PORT GPIOB +#endif +#ifndef BSP_I2C2_SCL_PIN +#define BSP_I2C2_SCL_PIN GPIO_PIN_3 +#endif +#ifndef BSP_I2C2_SDA_PIN +#define BSP_I2C2_SDA_PIN GPIO_PIN_2 +#endif +#ifndef BSP_I2C2_SCL_ALT_FUNC +#define BSP_I2C2_SCL_ALT_FUNC ALT6_FUNCTION +#endif +#ifndef BSP_I2C2_SDA_ALT_FUNC +#define BSP_I2C2_SDA_ALT_FUNC ALT6_FUNCTION +#endif + #ifdef BSP_USING_HARD_I2C1 +#ifndef BSP_I2C1_BAUDRATE +#define BSP_I2C1_BAUDRATE 100000 +#endif + #ifndef I2C1_BUS_CONFIG -#define I2C1_BUS_CONFIG \ - { \ - .Instance = I2C1, \ - .timing = 0x307075B1, \ - .timeout = 1000, \ - .name = "hwi2c1", \ - .evirq_type = I2C1_EV_IRQn, \ - .erirq_type = I2C1_ER_IRQn, \ +#define I2C1_BUS_CONFIG \ + { \ + .name = "hwi2c1", \ + .Instance = I2C1, \ + .baudrate = BSP_I2C1_BAUDRATE, \ + .timeout = 1000, \ + .irq_type = I2C1_MST_IRQn, \ + .scl_pin_num = BSP_I2C1_SCL_PIN_NUM, \ + .sda_pin_num = BSP_I2C1_SDA_PIN_NUM, \ + .scl_port = BSP_I2C1_SCL_PORT, \ + .sda_port = BSP_I2C1_SDA_PORT, \ + .scl_pin = BSP_I2C1_SCL_PIN, \ + .sda_pin = BSP_I2C1_SDA_PIN, \ + .scl_alt_func = BSP_I2C1_SCL_ALT_FUNC, \ + .sda_alt_func = BSP_I2C1_SDA_ALT_FUNC, \ } #endif /* I2C1_BUS_CONFIG */ #endif /* BSP_USING_HARD_I2C1 */ -#ifdef BSP_I2C1_TX_USING_DMA -#ifndef I2C1_TX_DMA_CONFIG -#if defined(SOC_SERIES_STM32F2) || defined(SOC_SERIES_STM32F4) || defined(SOC_SERIES_STM32F7) -#define I2C1_TX_DMA_CONFIG \ - { \ - .dma_rcc = I2C1_TX_DMA_RCC, \ - .Instance = I2C1_TX_DMA_INSTANCE, \ - .dma_irq = I2C1_TX_DMA_IRQ, \ - .channel = I2C1_TX_DMA_CHANNEL \ - } -#elif defined(SOC_SERIES_STM32L4) || defined(SOC_SERIES_STM32G0) || defined(SOC_SERIES_STM32MP1) || defined(SOC_SERIES_STM32WB) || defined(SOC_SERIES_STM32H7) -#define I2C1_TX_DMA_CONFIG \ - { \ - .dma_rcc = I2C1_TX_DMA_RCC, \ - .Instance = I2C1_TX_DMA_INSTANCE, \ - .dma_irq = I2C1_TX_DMA_IRQ, \ - .request = DMA_REQUEST_I2C1_TX \ - } -#endif /* defined(SOC_SERIES_STM32F2) || defined(SOC_SERIES_STM32F4) || defined(SOC_SERIES_STM32F7) */ -#endif /* I2C1_TX_DMA_CONFIG */ -#endif /* BSP_I2C1_TX_USING_DMA */ - -#ifdef BSP_I2C1_RX_USING_DMA -#ifndef I2C1_RX_DMA_CONFIG -#if defined(SOC_SERIES_STM32F2) || defined(SOC_SERIES_STM32F4) || defined(SOC_SERIES_STM32F7) -#define I2C1_RX_DMA_CONFIG \ - { \ - .dma_rcc = I2C1_RX_DMA_RCC, \ - .Instance = I2C1_RX_DMA_INSTANCE, \ - .dma_irq = I2C1_RX_DMA_IRQ, \ - .channel = I2C1_RX_DMA_CHANNEL, \ - } -#elif defined(SOC_SERIES_STM32L4) || defined(SOC_SERIES_STM32G0) || defined(SOC_SERIES_STM32MP1) || defined(SOC_SERIES_STM32WB) || defined(SOC_SERIES_STM32H7) -#define I2C1_RX_DMA_CONFIG \ - { \ - .dma_rcc = I2C1_RX_DMA_RCC, \ - .Instance = I2C1_RX_DMA_INSTANCE, \ - .dma_irq = I2C1_RX_DMA_IRQ, \ - .request = DMA_REQUEST_I2C1_RX \ - } -#endif /* defined(SOC_SERIES_STM32F2) || defined(SOC_SERIES_STM32F4) || defined(SOC_SERIES_STM32F7) */ -#endif /* I2C1_RX_DMA_CONFIG */ -#endif /* BSP_I2C1_RX_USING_DMA */ - #ifdef BSP_USING_HARD_I2C2 +#ifndef BSP_I2C2_BAUDRATE +#define BSP_I2C2_BAUDRATE 100000 +#endif + #ifndef I2C2_BUS_CONFIG -#define I2C2_BUS_CONFIG \ - { \ - .Instance = I2C2, \ - .timing = 0x307075B1, \ - .timeout = 1000, \ - .name = "hwi2c2", \ - .evirq_type = I2C2_EV_IRQn, \ - .erirq_type = I2C2_ER_IRQn, \ +#define I2C2_BUS_CONFIG \ + { \ + .name = "hwi2c2", \ + .Instance = I2C2, \ + .baudrate = BSP_I2C2_BAUDRATE, \ + .timeout = 1000, \ + .irq_type = I2C2_MST_IRQn, \ + .scl_pin_num = BSP_I2C2_SCL_PIN_NUM, \ + .sda_pin_num = BSP_I2C2_SDA_PIN_NUM, \ + .scl_port = BSP_I2C2_SCL_PORT, \ + .sda_port = BSP_I2C2_SDA_PORT, \ + .scl_pin = BSP_I2C2_SCL_PIN, \ + .sda_pin = BSP_I2C2_SDA_PIN, \ + .scl_alt_func = BSP_I2C2_SCL_ALT_FUNC, \ + .sda_alt_func = BSP_I2C2_SDA_ALT_FUNC, \ } #endif /* I2C2_BUS_CONFIG */ #endif /* BSP_USING_HARD_I2C2 */ -#ifdef BSP_I2C2_TX_USING_DMA -#ifndef I2C2_TX_DMA_CONFIG -#if defined(SOC_SERIES_STM32F2) || defined(SOC_SERIES_STM32F4) || defined(SOC_SERIES_STM32F7) -#define I2C2_TX_DMA_CONFIG \ - { \ - .dma_rcc = I2C2_TX_DMA_RCC, \ - .Instance = I2C2_TX_DMA_INSTANCE, \ - .dma_irq = I2C2_TX_DMA_IRQ, \ - .channel = I2C2_TX_DMA_CHANNEL, \ - } -#elif defined(SOC_SERIES_STM32L4) || defined(SOC_SERIES_STM32G0) || defined(SOC_SERIES_STM32MP1) || defined(SOC_SERIES_STM32WB) || defined(SOC_SERIES_STM32H7) -#define I2C2_TX_DMA_CONFIG \ - { \ - .dma_rcc = I2C2_TX_DMA_RCC, \ - .Instance = I2C2_TX_DMA_INSTANCE, \ - .dma_irq = I2C2_TX_DMA_IRQ, \ - .request = DMA_REQUEST_I2C2_TX \ - } -#endif /* defined(SOC_SERIES_STM32F2) || defined(SOC_SERIES_STM32F4) || defined(SOC_SERIES_STM32F7) */ -#endif /* I2C2_TX_DMA_CONFIG */ -#endif /* BSP_I2C2_TX_USING_DMA */ - -#ifdef BSP_I2C2_RX_USING_DMA -#ifndef I2C2_RX_DMA_CONFIG -#if defined(SOC_SERIES_STM32F2) || defined(SOC_SERIES_STM32F4) || defined(SOC_SERIES_STM32F7) -#define I2C2_RX_DMA_CONFIG \ - { \ - .dma_rcc = I2C2_RX_DMA_RCC, \ - .Instance = I2C2_RX_DMA_INSTANCE, \ - .dma_irq = I2C2_RX_DMA_IRQ, \ - .channel = I2C2_RX_DMA_CHANNEL, \ - } -#elif defined(SOC_SERIES_STM32L4) || defined(SOC_SERIES_STM32G0) || defined(SOC_SERIES_STM32MP1) || defined(SOC_SERIES_STM32WB) || defined(SOC_SERIES_STM32H7) -#define I2C2_RX_DMA_CONFIG \ - { \ - .dma_rcc = I2C2_RX_DMA_RCC, \ - .Instance = I2C2_RX_DMA_INSTANCE, \ - .dma_irq = I2C2_RX_DMA_IRQ, \ - .request = DMA_REQUEST_I2C2_RX \ - } -#endif /* defined(SOC_SERIES_STM32F2) || defined(SOC_SERIES_STM32F4) || defined(SOC_SERIES_STM32F7) */ -#endif /* I2C2_RX_DMA_CONFIG */ -#endif /* BSP_I2C2_RX_USING_DMA */ - -#ifdef BSP_USING_HARD_I2C3 -#ifndef I2C3_BUS_CONFIG -#define I2C3_BUS_CONFIG \ - { \ - .Instance = I2C3, \ - .timing = 0x307075B1, \ - .timeout = 1000, \ - .name = "hwi2c3", \ - .evirq_type = I2C3_EV_IRQn, \ - .erirq_type = I2C3_ER_IRQn, \ - } -#endif /* I2C3_BUS_CONFIG */ -#endif /* BSP_USING_HARD_I2C3 */ - -#ifdef BSP_I2C3_TX_USING_DMA -#ifndef I2C3_TX_DMA_CONFIG -#if defined(SOC_SERIES_STM32F2) || defined(SOC_SERIES_STM32F4) || defined(SOC_SERIES_STM32F7) -#define I2C3_TX_DMA_CONFIG \ - { \ - .dma_rcc = I2C3_TX_DMA_RCC, \ - .Instance = I2C3_TX_DMA_INSTANCE, \ - .dma_irq = I2C3_TX_DMA_IRQ, \ - .channel = I2C3_TX_DMA_CHANNEL, \ - } -#elif defined(SOC_SERIES_STM32L4) || defined(SOC_SERIES_STM32G0) || defined(SOC_SERIES_STM32MP1) || defined(SOC_SERIES_STM32WB) || defined(SOC_SERIES_STM32H7) -#define I2C3_TX_DMA_CONFIG \ - { \ - .dma_rcc = I2C3_TX_DMA_RCC, \ - .Instance = I2C3_TX_DMA_INSTANCE, \ - .dma_irq = I2C3_TX_DMA_IRQ, \ - .request = DMA_REQUEST_I2C3_TX \ - } -#endif /* defined(SOC_SERIES_STM32F2) || defined(SOC_SERIES_STM32F4) || defined(SOC_SERIES_STM32F7) */ -#endif /* I2C3_TX_DMA_CONFIG */ -#endif /* BSP_I2C3_TX_USING_DMA */ - -#ifdef BSP_I2C3_RX_USING_DMA -#ifndef I2C3_RX_DMA_CONFIG -#if defined(SOC_SERIES_STM32F2) || defined(SOC_SERIES_STM32F4) || defined(SOC_SERIES_STM32F7) -#define I2C3_RX_DMA_CONFIG \ - { \ - .dma_rcc = I2C3_RX_DMA_RCC, \ - .Instance = I2C3_RX_DMA_INSTANCE, \ - .dma_irq = I2C3_RX_DMA_IRQ, \ - .channel = I2C3_RX_DMA_CHANNEL, \ - } -#elif defined(SOC_SERIES_STM32L4) || defined(SOC_SERIES_STM32G0) || defined(SOC_SERIES_STM32MP1) || defined(SOC_SERIES_STM32WB) || defined(SOC_SERIES_STM32H7) -#define I2C3_RX_DMA_CONFIG \ - { \ - .dma_rcc = I2C3_RX_DMA_RCC, \ - .Instance = I2C3_RX_DMA_INSTANCE, \ - .dma_irq = I2C3_RX_DMA_IRQ, \ - .request = DMA_REQUEST_I2C3_RX \ - } -#endif /* defined(SOC_SERIES_STM32F2) || defined(SOC_SERIES_STM32F4) || defined(SOC_SERIES_STM32F7) */ -#endif /* I2C3_RX_DMA_CONFIG */ -#endif /* BSP_I2C3_RX_USING_DMA */ - -#ifdef BSP_USING_HARD_I2C4 -#ifndef I2C4_BUS_CONFIG -#define I2C4_BUS_CONFIG \ - { \ - .Instance = I2C4, \ - .timing = 0x307075B1, \ - .timeout = 1000, \ - .name = "hwi2c4", \ - .evirq_type = I2C4_EV_IRQn, \ - .erirq_type = I2C4_ER_IRQn, \ - } -#endif /* I2C4_BUS_CONFIG */ -#endif /* BSP_USING_HARD_I2C4 */ - -#ifdef BSP_I2C4_TX_USING_DMA -#ifndef I2C4_TX_DMA_CONFIG -#if defined(SOC_SERIES_STM32F2) || defined(SOC_SERIES_STM32F4) || defined(SOC_SERIES_STM32F7) -#define I2C4_TX_DMA_CONFIG \ - { \ - .dma_rcc = I2C4_TX_DMA_RCC, \ - .Instance = I2C4_TX_DMA_INSTANCE, \ - .dma_irq = I2C4_TX_DMA_IRQ, \ - .channel = I2C4_TX_DMA_CHANNEL, \ - } -#elif defined(SOC_SERIES_STM32L4) || defined(SOC_SERIES_STM32G0) || defined(SOC_SERIES_STM32MP1) || defined(SOC_SERIES_STM32WB) || defined(SOC_SERIES_STM32H7) -#define I2C4_TX_DMA_CONFIG \ - { \ - .dma_rcc = I2C4_TX_DMA_RCC, \ - .Instance = I2C4_TX_DMA_INSTANCE, \ - .dma_irq = I2C4_TX_DMA_IRQ, \ - .request = DMA_REQUEST_I2C4_TX \ - } -#endif /* defined(SOC_SERIES_STM32F2) || defined(SOC_SERIES_STM32F4) || defined(SOC_SERIES_STM32F7) */ -#endif /* I2C4_TX_DMA_CONFIG */ -#endif /* BSP_I2C4_TX_USING_DMA */ - -#ifdef BSP_I2C4_RX_USING_DMA -#ifndef I2C4_RX_DMA_CONFIG -#if defined(SOC_SERIES_STM32F2) || defined(SOC_SERIES_STM32F4) || defined(SOC_SERIES_STM32F7) -#define I2C4_RX_DMA_CONFIG \ - { \ - .dma_rcc = I2C4_RX_DMA_RCC, \ - .Instance = I2C4_RX_DMA_INSTANCE, \ - .dma_irq = I2C4_RX_DMA_IRQ, \ - .channel = I2C4_RX_DMA_CHANNEL, \ - } -#elif defined(SOC_SERIES_STM32L4) || defined(SOC_SERIES_STM32G0) || defined(SOC_SERIES_STM32MP1) || defined(SOC_SERIES_STM32WB) || defined(SOC_SERIES_STM32H7) -#define I2C4_RX_DMA_CONFIG \ - { \ - .dma_rcc = I2C4_RX_DMA_RCC, \ - .Instance = I2C4_RX_DMA_INSTANCE, \ - .dma_irq = I2C4_RX_DMA_IRQ, \ - .request = DMA_REQUEST_I2C4_RX \ - } -#endif /* defined(SOC_SERIES_STM32F2) || defined(SOC_SERIES_STM32F4) || defined(SOC_SERIES_STM32F7) */ -#endif /* I2C4_RX_DMA_CONFIG */ -#endif /* BSP_I2C4_RX_USING_DMA */ - - #ifdef __cplusplus } #endif -#endif /*__I2C_HARD_CONFIG_H__ */ - +#endif /* __I2C_HARD_CONFIG_H__ */ diff --git a/bsp/novosns/ns800/libraries/HAL_Drivers/drivers/drv_config.h b/bsp/novosns/ns800/libraries/HAL_Drivers/drivers/drv_config.h index 9907a5c283e..9111b199102 100644 --- a/bsp/novosns/ns800/libraries/HAL_Drivers/drivers/drv_config.h +++ b/bsp/novosns/ns800/libraries/HAL_Drivers/drivers/drv_config.h @@ -20,6 +20,7 @@ extern "C" { #if defined(SOC_SERIES_NS800RT7) #include "rt7/uart_config.h" +#include "rt7/i2c_hard_config.h" #endif diff --git a/bsp/novosns/ns800/libraries/HAL_Drivers/drivers/drv_hard_i2c.c b/bsp/novosns/ns800/libraries/HAL_Drivers/drivers/drv_hard_i2c.c new file mode 100644 index 00000000000..4f4e9867c66 --- /dev/null +++ b/bsp/novosns/ns800/libraries/HAL_Drivers/drivers/drv_hard_i2c.c @@ -0,0 +1,634 @@ +/* + * Copyright (c) 2006-2026, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2026-06-07 dirtwillfly first version for NS800 + */ + +#include "drv_hard_i2c.h" + +#if defined(BSP_USING_I2C) + +#define DRV_DEBUG +#define LOG_TAG "drv.i2c.hw" +#include + +#define DEFAULT_I2C_BAUDRATE (100 * 1000U) +#define I2C_TIMEOUT_MS (1000U) + +enum +{ +#ifdef BSP_USING_HARD_I2C1 + I2C1_INDEX, +#endif +#ifdef BSP_USING_HARD_I2C2 + I2C2_INDEX, +#endif +}; + +static struct ns800_i2c_config i2c_config[] = +{ +#ifdef BSP_USING_HARD_I2C1 + I2C1_BUS_CONFIG, +#endif +#ifdef BSP_USING_HARD_I2C2 + I2C2_BUS_CONFIG, +#endif +}; + +static struct ns800_i2c i2c_objs[sizeof(i2c_config) / sizeof(i2c_config[0])] = {0}; + +/** + * @brief Wait for master TX FIFO to have space available with timeout + * @param i2c I2C instance + * @param timeout_ms timeout in milliseconds + * @return I2C_STATUS_SUCCESS if ready, otherwise error status + */ +static I2C_Status I2C_waitMasterTxReadyTimeout(I2C_TypeDef *i2c, uint32_t timeout_ms) +{ + uint32_t start_tick = rt_tick_get(); + uint32_t status; + uint8_t txCount; + uint8_t txFifoSize = 16U; + + while (rt_tick_get() - start_tick < rt_tick_from_millisecond(timeout_ms)) + { + /* Get the number of words in the tx fifo and compute empty slots. */ + txCount = txFifoSize - I2C_getMasterTxFifoCounts(i2c); + + if (txCount > 0U) + { + /* Check for error flags. */ + status = I2C_getMasterStatusFlags(i2c); + return I2C_checkAndClearMasterError(i2c, status); + } + + rt_thread_mdelay(1); + } + + /* Timeout */ + LOG_E("I2C wait TX ready timeout"); + return I2C_STATUS_TIMEOUT; +} + +/** + * @brief Send STOP signal with timeout protection + * @param i2c I2C instance + * @param timeout_ms timeout in milliseconds + * @return I2C_STATUS_SUCCESS if success, otherwise error status + */ +static I2C_Status I2C_sendStopTimeout(I2C_TypeDef *i2c, uint32_t timeout_ms) +{ + uint32_t start_tick = rt_tick_get(); + uint32_t status; + + LOG_D("I2C_sendStopTimeout: entering, timeout=%dms", timeout_ms); + + /* Wait until there is room in the fifo. */ + I2C_Status result = I2C_waitMasterTxReadyTimeout(i2c, timeout_ms); + if (result != I2C_STATUS_SUCCESS) + { + LOG_E("I2C_sendStopTimeout: TxReady failed, result=%d", result); + return result; + } + + LOG_D("I2C_sendStopTimeout: TxReady OK, sending STOP"); + + /* Send the STOP signal */ + WRITE_REG(i2c->MTDR.WORDVAL, (uint32_t)I2C_COMMAND_STOP); + + /* Wait for STOP flag */ + while (rt_tick_get() - start_tick < rt_tick_from_millisecond(timeout_ms)) + { + status = I2C_getMasterStatusFlags(i2c); + LOG_D("I2C_sendStopTimeout: status=0x%x", status); + + if (status & (uint32_t)I2C_MASTER_FLAG_STOP) + { + LOG_D("I2C_sendStopTimeout: STOP flag set"); + result = I2C_checkAndClearMasterError(i2c, status); + I2C_clearMasterStatusFlags(i2c, (uint32_t)I2C_MASTER_FLAG_CLEAR); + return result; + } + + if (status & (uint32_t)I2C_MASTER_FLAG_NACK) + { + LOG_E("I2C_sendStopTimeout: NACK received, status=0x%x", status); + result = I2C_checkAndClearMasterError(i2c, status); + I2C_clearMasterStatusFlags(i2c, (uint32_t)I2C_MASTER_FLAG_CLEAR); + return result; + } + + rt_thread_mdelay(1); + } + + /* Timeout - reset to recover bus */ + status = I2C_getMasterStatusFlags(i2c); + LOG_E("I2C wait STOP timeout, status=0x%x, resetting I2C", status); + I2C_resetMaster(i2c); + I2C_enableMasterModule(i2c); + return I2C_STATUS_TIMEOUT; +} + +/** + * @brief Check if master is busy + * @param i2c I2C instance + * @return I2C_STATUS_SUCCESS if idle, otherwise I2C_STATUS_BUSY + */ +static I2C_Status I2C_checkMasterBusyTimeout(I2C_TypeDef *i2c, uint32_t timeout_ms) +{ + uint32_t start_tick = rt_tick_get(); + + while (rt_tick_get() - start_tick < rt_tick_from_millisecond(timeout_ms)) + { + __IO uint32_t status = I2C_getMasterStatusFlags(i2c); + if ((0U == (status & (uint32_t)I2C_MASTER_FLAG_BUSBUSY)) || + (0U != (status & (uint32_t)I2C_MASTER_FLAG_BUSY))) + { + return I2C_STATUS_SUCCESS; + } + rt_thread_mdelay(1); + } + + return I2C_STATUS_BUSY; +} + +/** + * @brief Reset I2C bus to recover from error state + * @param i2c I2C instance + */ +static void I2C_resetBus(I2C_TypeDef *i2c) +{ + /* Reset master module */ + I2C_resetMaster(i2c); + + /* Enable master module */ + I2C_enableMasterModule(i2c); + + /* Clear all status flags */ + I2C_clearMasterStatusFlags(i2c, (uint32_t)I2C_MASTER_FLAG_CLEAR); +} + +static void ns800_i2c_apply_default_config(struct ns800_i2c_config *cfg) +{ + RT_ASSERT(cfg != RT_NULL); + + if (cfg->baudrate == 0U) + { + cfg->baudrate = DEFAULT_I2C_BAUDRATE; + } +} + +/** + * @brief Initialize I2C GPIO pins + * @param cfg I2C configuration structure + */ +static void ns800_i2c_gpio_init(struct ns800_i2c_config *cfg) +{ + RT_ASSERT(cfg != RT_NULL); + + LOG_D("I2C[%s] GPIO init: SCL(port=0x%x, pin=%d, alt=%d), SDA(port=0x%x, pin=%d, alt=%d)", + cfg->name, cfg->scl_port, cfg->scl_pin, cfg->scl_alt_func, + cfg->sda_port, cfg->sda_pin, cfg->sda_alt_func); + + /* SCL pin configuration - follow SDK example order */ + if (cfg->scl_port != RT_NULL && cfg->scl_alt_func != 0U) + { + GPIO_setPinConfig(cfg->scl_port, cfg->scl_pin, cfg->scl_alt_func); + GPIO_setAnalogMode(cfg->scl_port, cfg->scl_pin, GPIO_ANALOG_DISABLED); + GPIO_setPadConfig(cfg->scl_port, cfg->scl_pin, GPIO_PIN_TYPE_PULLUP); + GPIO_setQualificationMode(cfg->scl_port, cfg->scl_pin, GPIO_QUAL_ASYNC); + GPIO_setDirectionMode(cfg->scl_port, cfg->scl_pin, GPIO_DIR_MODE_IN); + } + + /* SDA pin configuration - follow SDK example order */ + if (cfg->sda_port != RT_NULL && cfg->sda_alt_func != 0U) + { + GPIO_setPinConfig(cfg->sda_port, cfg->sda_pin, cfg->sda_alt_func); + GPIO_setAnalogMode(cfg->sda_port, cfg->sda_pin, GPIO_ANALOG_DISABLED); + GPIO_setPadConfig(cfg->sda_port, cfg->sda_pin, GPIO_PIN_TYPE_PULLUP); + GPIO_setQualificationMode(cfg->sda_port, cfg->sda_pin, GPIO_QUAL_ASYNC); + GPIO_setDirectionMode(cfg->sda_port, cfg->sda_pin, GPIO_DIR_MODE_IN); + } +} + +static rt_err_t ns800_i2c_init(struct ns800_i2c *i2c_drv) +{ + RT_ASSERT(i2c_drv != RT_NULL); + + I2C_TypeDef *i2c = i2c_drv->config->Instance; + struct ns800_i2c_config *cfg = i2c_drv->config; + + LOG_D("I2C[%s] init start, Instance=0x%x, baudrate=%d", + cfg->name, i2c, cfg->baudrate); + + ns800_i2c_apply_default_config(cfg); + + /* Initialize GPIO pins FIRST - follow SDK example order */ + ns800_i2c_gpio_init(cfg); + + /* Enable I2C module clock */ + if (i2c == I2C1) + { + LOG_D("I2C[%s] enabling I2C1 clock", cfg->name); + SET_BIT(RCC->PCLKEN5.WORDVAL, RCC_PCLKEN5_I2C1EN_M); + } + else if (i2c == I2C2) + { + LOG_D("I2C[%s] enabling I2C2 clock", cfg->name); + SET_BIT(RCC->PCLKEN5.WORDVAL, RCC_PCLKEN5_I2C2EN_M); + } + + LOG_D("I2C[%s] clock enabled, PCLKEN5=0x%x", cfg->name, RCC->PCLKEN5.WORDVAL); + + /* Reset module before configuring it */ + I2C_resetMaster(i2c); + LOG_D("I2C[%s] master reset done", cfg->name); + + /* Disable debug mode */ + I2C_disableMasterDebug(i2c); + + /* Set master water marks */ + I2C_setMasterWatermarks(i2c, I2C_MASTER_WATERMARK_0, I2C_MASTER_WATERMARK_0); + + /* Configure master glitch filters + And set FILTSDA to 0 disables the filter, so the min value is 1 */ + I2C_setMasterGlitchFilter(i2c, I2C_MASTER_FILTER_PCLK1, I2C_MASTER_FILTER_PCLK1); + + /* Configure baudrate after the SDA/SCL glitch filter setting */ + I2C_configMasterBaudRate(i2c, RCC_getPclk2Frequency(), cfg->baudrate); + + /* Configure bus idle timeouts after baudrate setting + The value is equal to BUSIDLE cycles of functional clock divided by prescaler + And set BUSIDLE to 0 disables the filter, so the min value is 1 */ + I2C_setMasterBusIdleTimeout(i2c, 1U); + + /* Configure pin low timeouts after baudrate setting + The value is equal to PINLOW cycles of functional clock divided by prescaler + And set PINLOW to 0 disables the filter, so the min value is 1 */ + I2C_setMasterPinLowTimeout(i2c, I2C_MASTER_PINLOW_SCLSDA, 0U); + + /* Config master data match mode, match code and rxmatchonly */ + I2C_configMasterDataMatch(i2c, I2C_MASTER_MATCHMODE_DISABLED, 0U, 0U, I2C_MASTER_RXMATCHDATAONLY_DISABLE); + + /* Enable master module */ + I2C_enableMasterModule(i2c); + LOG_D("I2C[%s] master module enabled", cfg->name); + + /* Verify I2C is properly initialized */ + uint32_t mcr = READ_REG(i2c->MCR.WORDVAL); + uint32_t msr = READ_REG(i2c->MSR.WORDVAL); + LOG_D("I2C[%s] MCR=0x%x, MSR=0x%x", cfg->name, mcr, msr); + + return RT_EOK; +} + +static rt_err_t ns800_i2c_configure(struct rt_i2c_bus_device *bus) +{ + RT_ASSERT(RT_NULL != bus); + struct ns800_i2c *i2c_drv = rt_container_of(bus, struct ns800_i2c, i2c_bus); + + return ns800_i2c_init(i2c_drv); +} + +static rt_ssize_t ns800_i2c_master_xfer(struct rt_i2c_bus_device *bus, + struct rt_i2c_msg msgs[], + rt_uint32_t num) +{ + rt_uint32_t i = 0; + rt_int32_t ret = 0; + struct rt_i2c_msg *msg = RT_NULL; + struct ns800_i2c *i2c_obj; + I2C_Status status; + rt_uint32_t timeout; + + if (num == 0) + { + return 0; + } + + RT_ASSERT((msgs != RT_NULL) && (bus != RT_NULL)); + i2c_obj = rt_container_of(bus, struct ns800_i2c, i2c_bus); + RT_ASSERT(i2c_obj != RT_NULL); + I2C_TypeDef *i2c = i2c_obj->config->Instance; + + /* Get timeout from config, default 1000ms */ + timeout = i2c_obj->config->timeout > 0 ? i2c_obj->config->timeout : I2C_TIMEOUT_MS; + + LOG_D("xfer start %d msgs", num); + + for (i = 0; i < num; i++) + { + msg = &msgs[i]; + 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); + + if (!(msg->flags & RT_I2C_NO_START)) + { + /* RT-Thread uses 7-bit address, SDK expects 8-bit address */ + /* Convert 7-bit address to 8-bit address by shifting left */ + uint8_t addr_8bit = msg->addr << 1; + + if (msg->flags & RT_I2C_RD) + { + status = I2C_sendStart(i2c, addr_8bit, I2C_DIRECTION_READ); + } + else + { + status = I2C_sendStart(i2c, addr_8bit, I2C_DIRECTION_WRITE); + } + + LOG_D("I2C[%s] SendStart status=%d, MSR=0x%x", bus->parent.parent.name, status, I2C_getMasterStatusFlags(i2c)); + + if (status != I2C_STATUS_SUCCESS) + { + LOG_E("I2C[%s] SendStart error(%d)", bus->parent.parent.name, status); + ret = -RT_EIO; + goto out; + } + + /* Wait a short time for slave to respond */ + rt_thread_mdelay(1); + + /* Check if we got ACK from slave */ + uint32_t start_msr = I2C_getMasterStatusFlags(i2c); + if (start_msr & I2C_MASTER_FLAG_NACK) + { + LOG_E("I2C[%s] SendStart got NACK from slave addr=0x%x, MSR=0x%x", + bus->parent.parent.name, msg->addr, start_msr); + /* Clear all flags and send STOP to release bus */ + I2C_clearMasterStatusFlags(i2c, I2C_MASTER_FLAG_CLEAR); + I2C_sendStopTimeout(i2c, timeout); + ret = -RT_EIO; + goto out; + } + } + else + { + /* RT-Thread uses 7-bit address, SDK expects 8-bit address */ + uint8_t addr_8bit = msg->addr << 1; + + if (msg->flags & RT_I2C_RD) + { + status = I2C_sendReStart(i2c, addr_8bit, I2C_DIRECTION_READ); + } + else + { + status = I2C_sendReStart(i2c, addr_8bit, I2C_DIRECTION_WRITE); + } + + LOG_D("I2C[%s] SendReStart status=%d, MSR=0x%x", bus->parent.parent.name, status, I2C_getMasterStatusFlags(i2c)); + + if (status != I2C_STATUS_SUCCESS) + { + LOG_E("I2C[%s] SendReStart error(%d)", bus->parent.parent.name, status); + ret = -RT_EIO; + goto out; + } + } + + if (msg->flags & RT_I2C_RD) + { + status = I2C_receiveDataMaster(i2c, msg->buf, msg->len); + if (status != I2C_STATUS_SUCCESS) + { + LOG_E("I2C[%s] Read error(%d)", bus->parent.parent.name, status); + ret = -RT_EIO; + goto out; + } + } + else + { + status = I2C_sendDataMaster(i2c, msg->buf, msg->len); + if (status != I2C_STATUS_SUCCESS) + { + LOG_E("I2C[%s] Write error(%d)", bus->parent.parent.name, status); + ret = -RT_EIO; + goto out; + } + } + + if (!(msg->flags & RT_I2C_NO_STOP)) + { + /* Use timeout protected STOP */ + status = I2C_sendStopTimeout(i2c, timeout); + if (status != I2C_STATUS_SUCCESS) + { + LOG_E("I2C[%s] SendStop error(%d), resetting bus", bus->parent.parent.name, status); + I2C_resetBus(i2c); + ret = -RT_EIO; + goto out; + } + } + } + + ret = num; + LOG_D("xfer end %d msgs", num); + return ret; + +out: + /* Safe error recovery - use timeout protected STOP or reset */ + I2C_sendStopTimeout(i2c, timeout / 2); /* Shorter timeout for recovery */ + return ret; +} + +static rt_err_t ns800_i2c_bus_control(struct rt_i2c_bus_device *bus, + int cmd, + void *args) +{ + rt_err_t result = RT_EOK; + struct ns800_i2c *i2c_obj; + + RT_ASSERT(bus != RT_NULL); + i2c_obj = rt_container_of(bus, struct ns800_i2c, i2c_bus); + RT_ASSERT(i2c_obj != RT_NULL); + + I2C_TypeDef *i2c = i2c_obj->config->Instance; + + switch (cmd) + { + case RT_I2C_DEV_CTRL_ADDR: + /* Set slave address - not typically used for master */ + result = -RT_ENOSYS; + break; + + case RT_I2C_DEV_CTRL_TIMEOUT: + /* Set timeout in milliseconds */ + i2c_obj->config->timeout = *(rt_uint32_t *)args; + break; + + case RT_I2C_CTRL_SET_MAX_HZ: + /* Change baudrate */ + if (args != RT_NULL) + { + i2c_obj->config->baudrate = *(rt_uint32_t *)args; + I2C_resetMaster(i2c); + I2C_configMasterBaudRate(i2c, RCC_getPclk2Frequency(), i2c_obj->config->baudrate); + I2C_enableMasterModule(i2c); + } + break; + + case RT_I2C_DEV_CTRL_RW: + /* Combined read/write operation */ + result = -RT_ENOSYS; + break; + + case RT_I2C_DEV_CTRL_CLK: + /* Set clock - similar to baud rate */ + if (args != RT_NULL) + { + i2c_obj->config->baudrate = *(rt_uint32_t *)args; + I2C_resetMaster(i2c); + I2C_configMasterBaudRate(i2c, RCC_getPclk2Frequency(), i2c_obj->config->baudrate); + I2C_enableMasterModule(i2c); + } + break; + + default: + result = -RT_ENOSYS; + break; + } + + return result; +} + +static const struct rt_i2c_bus_device_ops ns800_i2c_ops = +{ + .master_xfer = ns800_i2c_master_xfer, + .slave_xfer = RT_NULL, + .i2c_bus_control = ns800_i2c_bus_control, +}; + +int ns800_hw_i2c_bus_init(void) +{ + int ret = -RT_ERROR; + rt_size_t obj_num = sizeof(i2c_objs) / sizeof(i2c_objs[0]); + + for (int i = 0; i < obj_num; i++) + { + i2c_objs[i].i2c_bus.ops = &ns800_i2c_ops; + i2c_objs[i].config = &i2c_config[i]; + ns800_i2c_apply_default_config(&i2c_config[i]); + + ret = ns800_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); + 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; +} + +int rt_hw_i2c_init(void) +{ + return ns800_hw_i2c_bus_init(); +} +INIT_BOARD_EXPORT(rt_hw_i2c_init); + +#ifdef RT_USING_FINSH + +/** + * @brief Scan I2C bus for devices + * @param i2c I2C instance + * @param bus_name Bus name for logging + */ +static void ns800_i2c_scan_bus(I2C_TypeDef *i2c, const char *bus_name) +{ + uint8_t found_count = 0; + uint32_t timeout = 100; + + LOG_I("Scanning I2C bus: %s...", bus_name); + + for (uint8_t addr = 1; addr < 128; addr++) + { + I2C_Status status; + + /* RT-Thread uses 7-bit address, SDK expects 8-bit address */ + uint8_t addr_8bit = addr << 1; + + /* Send START with write direction */ + status = I2C_sendStart(i2c, addr_8bit, I2C_DIRECTION_WRITE); + + if (status == I2C_STATUS_SUCCESS) + { + uint32_t msr = I2C_getMasterStatusFlags(i2c); + + /* Check if we got ACK (no NACK) */ + if (!(msr & I2C_MASTER_FLAG_NACK)) + { + LOG_I("I2C device found at address: 0x%02X", addr); + found_count++; + } + + /* Clear any pending flags */ + I2C_clearMasterStatusFlags(i2c, I2C_MASTER_FLAG_NACK); + + /* Send STOP to release bus */ + I2C_sendStopTimeout(i2c, timeout); + } + else + { + /* Failed to send start, reset and continue */ + I2C_resetMaster(i2c); + I2C_enableMasterModule(i2c); + } + + /* Small delay between devices */ + rt_thread_mdelay(1); + } + + if (found_count == 0) + { + LOG_W("No I2C devices found on bus: %s", bus_name); + } + else + { + LOG_I("Found %d I2C device(s) on bus: %s", found_count, bus_name); + } +} + +/** + * @brief Finsh command to scan I2C buses + * @param argc Argument count + * @param argv Argument array + */ +static void i2c_scan(int argc, char **argv) +{ + const char *bus_name = RT_NULL; + + if (argc == 2) + { + bus_name = argv[1]; + } + + for (int i = 0; i < sizeof(i2c_objs) / sizeof(i2c_objs[0]); i++) + { + if (i2c_objs[i].config->name != RT_NULL) + { + if (bus_name == RT_NULL || rt_strcmp(bus_name, i2c_objs[i].config->name) == 0) + { + ns800_i2c_scan_bus(i2c_objs[i].config->Instance, i2c_objs[i].config->name); + } + } + } +} +MSH_CMD_EXPORT(i2c_scan, Scan I2C bus for devices); + +#endif /* RT_USING_FINSH */ + +#endif /* defined(BSP_USING_I2C) */ diff --git a/bsp/novosns/ns800/libraries/HAL_Drivers/drivers/drv_hard_i2c.h b/bsp/novosns/ns800/libraries/HAL_Drivers/drivers/drv_hard_i2c.h new file mode 100644 index 00000000000..7cfe09739da --- /dev/null +++ b/bsp/novosns/ns800/libraries/HAL_Drivers/drivers/drv_hard_i2c.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2006-2026, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2026-06-07 dirtwillfly first version for NS800 + */ + +#ifndef __DRV_HARD_I2C_H__ +#define __DRV_HARD_I2C_H__ + +#include "board.h" +#include "drv_config.h" +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + +#define BSP_I2C_CTRL_SET_TIMING 0x40 + +struct ns800_i2c_config +{ + const char *name; + I2C_TypeDef *Instance; + rt_uint32_t baudrate; + rt_uint32_t timeout; + IRQn_Type irq_type; + uint32_t scl_pin_num; /* SCL pin number for get_pin_info */ + uint32_t sda_pin_num; /* SDA pin number for get_pin_info */ + GPIO_TypeDef *scl_port; /* SCL GPIO port */ + GPIO_TypeDef *sda_port; /* SDA GPIO port */ + GPIO_PinNum scl_pin; /* SCL pin in the port */ + GPIO_PinNum sda_pin; /* SDA pin in the port */ + GPIO_AltFunc scl_alt_func; /* SCL alternate function */ + GPIO_AltFunc sda_alt_func; /* SDA alternate function */ +}; + +struct ns800_i2c +{ + struct ns800_i2c_config *config; + struct rt_i2c_bus_device i2c_bus; +}; + +#ifdef __cplusplus +} +#endif + +#endif /* __DRV_HARD_I2C_H__ */ diff --git a/bsp/novosns/ns800/ns800rt7p65-nssinepad/board/Kconfig b/bsp/novosns/ns800/ns800rt7p65-nssinepad/board/Kconfig index 86332fa557e..b0133d150b2 100644 --- a/bsp/novosns/ns800/ns800rt7p65-nssinepad/board/Kconfig +++ b/bsp/novosns/ns800/ns800rt7p65-nssinepad/board/Kconfig @@ -205,5 +205,29 @@ menu "On-chip Peripheral Drivers" bool "Enable SPI4" default n endif + + menuconfig BSP_USING_I2C + bool "Enable I2C" + select RT_USING_I2C + default n + if BSP_USING_I2C + menuconfig BSP_USING_HARD_I2C1 + bool "Enable Hardware I2C1" + default n + if BSP_USING_HARD_I2C1 + config BSP_I2C1_BAUDRATE + int "I2C1 baud rate (Hz)" + default 100000 + endif + + menuconfig BSP_USING_HARD_I2C2 + bool "Enable Hardware I2C2" + default n + if BSP_USING_HARD_I2C2 + config BSP_I2C2_BAUDRATE + int "I2C2 baud rate (Hz)" + default 100000 + endif + endif endmenu diff --git a/bsp/novosns/ns800/ns800rt7p65-nssinepad/rtconfig.h b/bsp/novosns/ns800/ns800rt7p65-nssinepad/rtconfig.h index 9300af36c69..351e20f8ddd 100644 --- a/bsp/novosns/ns800/ns800rt7p65-nssinepad/rtconfig.h +++ b/bsp/novosns/ns800/ns800rt7p65-nssinepad/rtconfig.h @@ -149,6 +149,8 @@ #define RT_CANSND_BOX_NUM 1 #define RT_CANSND_MSG_TIMEOUT 100 #define RT_CAN_NB_TX_FIFO_SIZE 256 +#define RT_USING_I2C +#define RT_USING_I2C_BITOPS #define RT_USING_PIN /* end of Device Drivers */ @@ -423,6 +425,9 @@ #define BSP_USING_UART1 #define BSP_USING_CAN #define BSP_USING_CANFD1 +#define BSP_USING_I2C +#define BSP_USING_HARD_I2C2 +#define BSP_I2C2_BAUDRATE 100000 /* end of On-chip Peripheral Drivers */ #endif