diff --git a/software_i2c/bsp_soft_i2c.c b/software_i2c/bsp_soft_i2c.c index f8018eb..1ce566a 100644 --- a/software_i2c/bsp_soft_i2c.c +++ b/software_i2c/bsp_soft_i2c.c @@ -45,10 +45,8 @@ SOFT_I2C_STATIC_INLINE void soft_i2c_gpio_clk_enable(P_SOFT_I2C_GPIO_COMM_T p_gp */ static void soft_i2c_set_od_mode(P_SOFT_I2C_GPIO_COMM_T p_gpio) { #if defined(SOFT_I2C_GD32F3_USED) - // GD32F30x芯片 gpio_init(p_gpio->gpioPort, GPIO_MODE_OUT_OD, GPIO_OSPEED_50MHZ, p_gpio->gpioPin); #elif defined(SOFT_I2C_STM32F1_USED) - // STM32F10x芯片 GPIO_InitTypeDef initStruct; initStruct.GPIO_Pin = (uint16_t)p_gpio->gpioPin; initStruct.GPIO_Mode = GPIO_Mode_Out_OD; @@ -170,6 +168,10 @@ static void soft_i2c_start(P_SOFT_I2C_T p_i2c) { soft_i2c_delay_800ns(); soft_i2c_write_gpio(&p_i2c->sda, SOFT_I2C_LEVEL_HIGH); soft_i2c_write_gpio(&p_i2c->scl, SOFT_I2C_LEVEL_HIGH); +#if defined(__SOFT_I2C_CLOCK_STRECH_EN__) + uint32_t waitCnt = p_i2c->waitCnt; ///< 等待计数 + SOFT_I2C_WAIT_SCL_RELEASE(p_i2c, waitCnt); // 等待SCL释放 +#endif soft_i2c_delay_us(); soft_i2c_write_gpio(&p_i2c->sda, SOFT_I2C_LEVEL_LOW); soft_i2c_delay_us(); @@ -181,29 +183,23 @@ static void soft_i2c_start(P_SOFT_I2C_T p_i2c) { * * @param [in] p_i2c I2C结构体指针 * - * @return soft_i2c_err_t - * @retval 0 成功, 其他值 失败 @ref SOFT_I2C_ERR_CODE * @details 特殊说明: * @par eg: * @code * * @endcode */ -static soft_i2c_err_t soft_i2c_stop(P_SOFT_I2C_T p_i2c) { +static void soft_i2c_stop(P_SOFT_I2C_T p_i2c) { soft_i2c_write_gpio(&p_i2c->scl, SOFT_I2C_LEVEL_LOW); soft_i2c_write_gpio(&p_i2c->sda, SOFT_I2C_LEVEL_LOW); soft_i2c_delay_us(); soft_i2c_write_gpio(&p_i2c->scl, SOFT_I2C_LEVEL_HIGH); #if defined(__SOFT_I2C_CLOCK_STRECH_EN__) - uint32_t waitCnt = SOFT_I2C_WAIT_CNT; ///< 等待计数 + uint32_t waitCnt = p_i2c->waitCnt; ///< 等待计数 SOFT_I2C_WAIT_SCL_RELEASE(p_i2c, waitCnt); // 等待SCL释放 - if (waitCnt == 0) { - return SOFT_I2C_ERR_TIMEOUT; - } #endif soft_i2c_delay_us(); soft_i2c_write_gpio(&p_i2c->sda, SOFT_I2C_LEVEL_HIGH); - return SOFT_I2C_ERR_OK; } /** @@ -220,10 +216,11 @@ static soft_i2c_err_t soft_i2c_stop(P_SOFT_I2C_T p_i2c) { * @endcode */ static soft_i2c_err_t soft_i2c_wait_ack(P_SOFT_I2C_T p_i2c) { - uint32_t waitCnt = SOFT_I2C_WAIT_CNT; ///< 等待计数 + uint32_t waitCnt = 100; soft_i2c_write_gpio(&p_i2c->sda, SOFT_I2C_LEVEL_HIGH); // 开启线与 soft_i2c_write_gpio(&p_i2c->scl, SOFT_I2C_LEVEL_HIGH); // 拉起SCL #if defined(__SOFT_I2C_CLOCK_STRECH_EN__) + waitCnt = p_i2c->waitCnt; ///< 等待计数 SOFT_I2C_WAIT_SCL_RELEASE(p_i2c, waitCnt); // 等待SCL释放 if (waitCnt == 0) { return SOFT_I2C_ERR_TIMEOUT; @@ -281,8 +278,8 @@ static void soft_i2c_ack_respond(P_SOFT_I2C_T p_i2c, uint8_t ackVal) { static soft_i2c_err_t soft_i2c_send_byte(P_SOFT_I2C_T p_i2c, uint8_t byte) { uint8_t loopCnt = 0; ///< 循环计数 #if defined(__SOFT_I2C_CLOCK_STRECH_EN__) - uint32_t waitCnt = SOFT_I2C_WAIT_CNT; ///< 等待计数 - bool isFirstBit = true; ///< 是否第一位 + uint32_t waitCnt = p_i2c->waitCnt; ///< 等待计数 + bool isFirstBit = true; ///< 是否第一位 #endif for (loopCnt = 0; loopCnt < 8; loopCnt++) { soft_i2c_write_gpio(&p_i2c->sda, SOFT_I2C_GET_MSB_BIT(byte)); // 写入数据 @@ -322,8 +319,8 @@ static soft_i2c_err_t soft_i2c_send_byte(P_SOFT_I2C_T p_i2c, uint8_t byte) { static soft_i2c_err_t soft_i2c_read_byte(P_SOFT_I2C_T p_i2c, uint8_t *p_data) { uint8_t loopCnt = 0; ///< 循环计数 #if defined(__SOFT_I2C_CLOCK_STRECH_EN__) - uint32_t waitCnt = SOFT_I2C_WAIT_CNT; ///< 等待计数 - bool isFirstBit = true; ///< 是否第一位 + uint32_t waitCnt = p_i2c->waitCnt; ///< 等待计数 + bool isFirstBit = true; ///< 是否第一位 #endif soft_i2c_write_gpio(&p_i2c->sda, SOFT_I2C_LEVEL_HIGH); // 开启线与 for (loopCnt = 0; loopCnt < 8; loopCnt++) { @@ -368,6 +365,7 @@ static soft_i2c_err_t soft_i2c_comm(P_SOFT_I2C_T p_i2c, P_SOFT_I2C_MSG_T p_msg) // 1. 判忙 if (soft_i2c_is_busy(p_i2c)) { p_i2c->i2cSta = SOFT_I2C_BUSY; + soft_i2c_stop(p_i2c); return SOFT_I2C_ERR_BUSY; } // 2. 发送开始信号 @@ -435,6 +433,7 @@ static soft_i2c_err_t soft_i2c_comm(P_SOFT_I2C_T p_i2c, P_SOFT_I2C_MSG_T p_msg) * @brief 软件模拟 I2C 初始化 * * @param [in] p_i2c I2C结构体指针 + * @param [in] waitCnt 超时计数(时钟延展使能时有意义) * * @return uint32_t * @retval 0 成功, 其他值 失败 @ref SOFT_I2C_ERR_CODE @@ -444,7 +443,7 @@ static soft_i2c_err_t soft_i2c_comm(P_SOFT_I2C_T p_i2c, P_SOFT_I2C_MSG_T p_msg) * * @endcode */ -soft_i2c_err_t soft_i2c_init(P_SOFT_I2C_T p_i2c) { +soft_i2c_err_t soft_i2c_init(P_SOFT_I2C_T p_i2c, uint32_t waitCnt) { // 1. 参数检查 if (p_i2c == NULL) { return SOFT_I2C_ERR_PARAM; @@ -467,6 +466,10 @@ soft_i2c_err_t soft_i2c_init(P_SOFT_I2C_T p_i2c) { soft_i2c_set_od_mode(&p_i2c->sda); soft_i2c_write_gpio(&p_i2c->scl, SOFT_I2C_LEVEL_HIGH); soft_i2c_write_gpio(&p_i2c->sda, SOFT_I2C_LEVEL_HIGH); +#if defined(__SOFT_I2C_CLOCK_STRECH_EN__) + // 4. 修改超时计数 + p_i2c->waitCnt = waitCnt; +#endif p_i2c->isInit = true; return SOFT_I2C_ERR_OK; } diff --git a/software_i2c/bsp_soft_i2c.h b/software_i2c/bsp_soft_i2c.h index 76db70c..acaa96b 100644 --- a/software_i2c/bsp_soft_i2c.h +++ b/software_i2c/bsp_soft_i2c.h @@ -63,6 +63,16 @@ typedef uint32_t soft_i2c_err_t; ///< 返回值类型 * @} */ +/** + * @brief 软件模拟 I2C 默认超时计数 + * @addtogroup SOFT_I2C_WAITCNT + * @{ + */ +#define SOFT_I2C_DEFAULT_WAITCNT (0xFFFFU) ///< 默认超时计数 +/** + * @} + */ + /** * @brief 软件模拟 I2C 寄存器地址长度 * @addtogroup SOFT_I2C_REG_ADDR_LEN @@ -87,6 +97,26 @@ typedef uint32_t soft_i2c_err_t; ///< 返回值类型 #endif #if defined(SOFT_I2C_GD32F3_USED) +#if defined(__SOFT_I2C_CLOCK_STRECH_EN__) +/** + * @brief 软件模拟 I2C 定义结构体 + * + * @param [in] name I2C结构体名称 + * @param [in] scl_port 时钟线端口, A ~ G + * @param [in] scl_pin 时钟线引脚, 0 ~ 15 + * @param [in] sda_port 数据线端口, A ~ G + * @param [in] sda_pin 数据线引脚, 0 ~ 15 + */ +#define SOFT_I2C_DEF(name, scl_port, scl_pin, sda_port, sda_pin) \ + SOFT_I2C_T soft_i2c_##name = { \ + false, false, SOFT_I2C_DEFAULT_WAITCNT, \ + {GPIO##scl_port, GPIO_PIN_##scl_pin, SOFT_I2C_GPIO##scl_port##_CLK}, \ + {GPIO##sda_port, GPIO_PIN_##sda_pin, SOFT_I2C_GPIO##sda_port##_CLK}, \ + SOFT_I2C_IDLE \ + }; \ + void *const name = &soft_i2c_##name \ + +#else /** * @brief 软件模拟 I2C 定义结构体 * @@ -105,7 +135,28 @@ typedef uint32_t soft_i2c_err_t; ///< 返回值类型 }; \ void *const name = &soft_i2c_##name \ +#endif #elif defined(SOFT_I2C_STM32F1_USED) +#if defined(__SOFT_I2C_CLOCK_STRECH_EN__) +/** + * @brief 软件模拟 I2C 定义结构体 + * + * @param [in] name I2C结构体名称 + * @param [in] scl_port 时钟线端口, A ~ G + * @param [in] scl_pin 时钟线引脚, 0 ~ 15 + * @param [in] sda_port 数据线端口, A ~ G + * @param [in] sda_pin 数据线引脚, 0 ~ 15 + */ +#define SOFT_I2C_DEF(name, scl_port, scl_pin, sda_port, sda_pin) \ + SOFT_I2C_T soft_i2c_##name = { \ + false, false, SOFT_I2C_DEFAULT_WAITCNT, \ + {GPIO##scl_port##_BASE, GPIO_Pin_##scl_pin, SOFT_I2C_GPIO##scl_port##_CLK}, \ + {GPIO##sda_port##_BASE, GPIO_Pin_##sda_pin, SOFT_I2C_GPIO##sda_port##_CLK}, \ + SOFT_I2C_IDLE \ + }; \ + void *const name = &soft_i2c_##name \ + +#else /** * @brief 软件模拟 I2C 定义结构体 * @@ -124,6 +175,7 @@ typedef uint32_t soft_i2c_err_t; ///< 返回值类型 }; \ void *const name = &soft_i2c_##name \ +#endif #else #define SOFT_I2C_DEF(name, scl_port, scl_pin, sda_port, sda_pin) #endif @@ -172,6 +224,9 @@ typedef struct _SOFT_I2C_GPIO_COMM_T { typedef struct _SOFT_I2C_T { bool isValid; ///< 芯片是否有效 bool isInit; ///< 是否初始化 +#if defined(__SOFT_I2C_CLOCK_STRECH_EN__) + uint32_t waitCnt; ///< 超时计数(时钟延展使用) +#endif SOFT_I2C_GPIO_COMM_T scl; ///< 时钟线 SOFT_I2C_GPIO_COMM_T sda; ///< 数据线 SOFT_I2C_STA_E i2cSta; ///< I2C监控状态 @@ -203,16 +258,30 @@ SOFT_I2C_STATIC_INLINE SOFT_I2C_STA_E soft_i2c_get_sta(P_SOFT_I2C_T p_i2c) { * @brief 软件模拟 I2C 初始化 * * @param [in] p_i2c I2C结构体指针 + * @param [in] waitCnt 超时计数(时钟延展使能时有意义) * * @return uint32_t * @retval 0 成功, 其他值 失败 @ref SOFT_I2C_ERR_CODE * @details 特殊说明: * @par eg: * @code - * + * // 注册I2C驱动 + * SOFT_I2C_DEF(I2C_DEV, A, 8, A, 9); + * + * // 如果跨文件注册, 则需要在其头文件中声明驱动, 并在使用驱动的文件中包含其头文件 + * SOFT_I2C_EXT(I2C_DEV); + * + * // 开启时钟延展初始化时, 设置延展的超时计数为1000, 该传参会修改默认计数值 + * soft_i2c_init(I2C_DEV, 1000); + * + * // 开启时钟延展初始化时, 如果第二个传参为 SOFT_I2C_DEFAULT_WAITCNT, 则不会修改默认计数值 + * soft_i2c_init(I2C_DEV, SOFT_I2C_DEFAULT_WAITCNT); + * + * // 未开启时钟延展时, 传参waitCnt不会起作用 + * soft_i2c_init(I2C_DEV, 1000); * @endcode */ -extern soft_i2c_err_t soft_i2c_init(P_SOFT_I2C_T p_i2c); +extern soft_i2c_err_t soft_i2c_init(P_SOFT_I2C_T p_i2c, uint32_t waitCnt); /** * @brief 软件模拟 I2C 写数据 diff --git a/software_i2c/bsp_soft_i2c_private.h b/software_i2c/bsp_soft_i2c_private.h index 1516b83..be6000d 100644 --- a/software_i2c/bsp_soft_i2c_private.h +++ b/software_i2c/bsp_soft_i2c_private.h @@ -44,7 +44,6 @@ #define SOFT_I2C_NACK SOFT_I2C_LEVEL_HIGH ///< I2C非应答信号(高电平) #define SOFT_I2C_WRITE (0U) ///< 写操作 #define SOFT_I2C_READ (1U) ///< 读操作 -#define SOFT_I2C_WAIT_CNT (0xFFFU) ///< 等待计数(用于时钟延展) /* * @} */ diff --git a/test_project/GD32F303_PRJ/main.c b/test_project/GD32F303_PRJ/main.c index 9e8ec31..7914ae7 100644 --- a/test_project/GD32F303_PRJ/main.c +++ b/test_project/GD32F303_PRJ/main.c @@ -38,7 +38,7 @@ int main(void) { led_on(); // 初始化结构体对象 - ret = soft_i2c_init(I2C_DEV); + ret = soft_i2c_init(I2C_DEV, SOFT_I2C_DEFAULT_WAITCNT); while (1) { /* turn on LED1 */ diff --git a/test_project/STM32F1_PRJ/main.c b/test_project/STM32F1_PRJ/main.c index c9ab23c..a1527b4 100644 --- a/test_project/STM32F1_PRJ/main.c +++ b/test_project/STM32F1_PRJ/main.c @@ -71,13 +71,14 @@ int main(void) { led_init(); led_on(); - ret = soft_i2c_init(I2C_DEV); + ret = soft_i2c_init(I2C_DEV, SOFT_I2C_DEFAULT_WAITCNT); while (1) { led_on(); block_delay(); { memset(r_buf, 0, 8); + if (flag) { ret = soft_i2c_write(I2C_DEV, SLAVE_ADDR, REG_ADDR, 1, w_buf, 8); // if (ret != SOFT_I2C_ERR_OK) {