From a2e6cb94c6b4e731ae621f3ba8020f8e0de65bf6 Mon Sep 17 00:00:00 2001 From: Dimitris Mantzouranis Date: Mon, 29 May 2023 20:36:51 +0300 Subject: [PATCH] i2c master: add i2c fallback support --- docs/i2c_driver.md | 25 +++++++++++++++++++++ platforms/chibios/drivers/i2c_master.c | 31 +++++++++++++++++++++++++- 2 files changed, 55 insertions(+), 1 deletion(-) diff --git a/docs/i2c_driver.md b/docs/i2c_driver.md index faff0a1d7bf..2efce83efe8 100644 --- a/docs/i2c_driver.md +++ b/docs/i2c_driver.md @@ -117,6 +117,31 @@ See [this page](https://www.playembedded.org/blog/stm32-i2c-chibios/#8_I2Cv2_I2C |`I2C1_TIMINGR_SCLH` |`38U` | |`I2C1_TIMINGR_SCLL` |`129U` | +### I2C Fallback :id=arm-configuration-i2cfallback + +ChibiOS provides a software solution through the I2C Fallback driver for cases where hardware I2C is not available. +To enable it, modify your board's `halconf.h` to enable the first I2C Fallback driver( assuming selected I2C peripheral is `I2CD1`). +```c +#define SW_I2C_USE_I2C1 +``` +By default, the delay required for I2C communication is calculated automatically with a target frequency of 100kHz, through the ChibiOS OSAL layer. If you wish to override this behavior, further modify your board's `halconf.h` +```c +#define SW_I2C_USE_OSAL_DELAY FALSE +``` +and provide the following function in your board's files +```c +void i2c_sw_delay(void) { + // custom delay goes here +} +``` +The I2C Fallback configuration structure is as follows +|`config.h` Override |Default | +|-----------------------|--------| +|`I2C_CLOCK_FREQUENCY` |`100000`| +|`SW_I2C_USE_OSAL_DELAY`|`TRUE` | + +Note that `I2C_CLOCK_FREQUENCY` is target I2C speed in `Hz` and is only respected if `SW_I2C_USE_OSAL_DELAY` is `TRUE`. + ## API :id=api ### `void i2c_init(void)` :id=api-i2c-init diff --git a/platforms/chibios/drivers/i2c_master.c b/platforms/chibios/drivers/i2c_master.c index 7c49f9d0059..ad149d45407 100644 --- a/platforms/chibios/drivers/i2c_master.c +++ b/platforms/chibios/drivers/i2c_master.c @@ -90,10 +90,39 @@ # endif #endif +#ifdef SW_I2C_USE_I2C1 +# ifndef I2C1_SCL_PAL_MODE +# define I2C1_SCL_PAL_MODE PAL_MODE_ALTERNATE_OPENDRAIN +# endif +# ifndef I2C1_SDA_PAL_MODE +# define I2C1_SDA_PAL_MODE PAL_MODE_ALTERNATE_OPENDRAIN +# endif +# ifndef I2C_CLOCK_FREQUENCY +# define I2C_CLOCK_FREQUENCY 100000 +# endif +# ifndef SW_I2C_DELAY +# define SW_I2C_DELAY ceil((CH_CFG_ST_FREQUENCY / I2C_CLOCK_FREQUENCY) / 2) +# endif +# ifndef SW_I2C_USE_OSAL_DELAY +# define SW_I2C_USE_OSAL_DELAY TRUE +# endif +# if (SW_I2C_USE_OSAL_DELAY == FALSE) +__attribute__((weak)) void i2c_sw_delay(void) {} +# endif +#endif static uint8_t i2c_address; static const I2CConfig i2cconfig = { -#if defined(USE_I2CV1_CONTRIB) +#if defined(SW_I2C_USE_I2C1) + 0, + I2C1_SCL_PIN, + I2C1_SDA_PIN, +# if (SW_I2C_USE_OSAL_DELAY == FALSE) + &i2c_sw_delay, +# else + SW_I2C_DELAY, +# endif +#elif defined(USE_I2CV1_CONTRIB) I2C1_CLOCK_SPEED, #elif defined(USE_I2CV1) I2C1_OPMODE,