Merge pull request #475 from UncleRus/i2c_fix2
Configurable I2C clock stretching
This commit is contained in:
commit
e0410b2c5d
6 changed files with 54 additions and 31 deletions
|
@ -41,7 +41,7 @@ void user_init(void)
|
||||||
printf("SDK version : %s\n", sdk_system_get_sdk_version());
|
printf("SDK version : %s\n", sdk_system_get_sdk_version());
|
||||||
printf("GIT version : %s\n", GITSHORTREV);
|
printf("GIT version : %s\n", GITSHORTREV);
|
||||||
|
|
||||||
i2c_init(0,scl,sda,I2C_FREQ_400K);
|
i2c_init(0, scl, sda, I2C_FREQ_400K);
|
||||||
|
|
||||||
xTaskCreate(task1, "tsk1", 256, NULL, 2, NULL);
|
xTaskCreate(task1, "tsk1", 256, NULL, 2, NULL);
|
||||||
}
|
}
|
||||||
|
|
|
@ -216,8 +216,8 @@ typedef struct
|
||||||
} bmp180_command_t;
|
} bmp180_command_t;
|
||||||
|
|
||||||
// Just works due to the fact that QueueHandle_t is a "void *"
|
// Just works due to the fact that QueueHandle_t is a "void *"
|
||||||
static QueueHandle_t bmp180_rx_queue[MAX_I2C_BUS] = { NULL };
|
static QueueHandle_t bmp180_rx_queue[I2C_MAX_BUS] = { NULL };
|
||||||
static TaskHandle_t bmp180_task_handle[MAX_I2C_BUS] = { NULL };
|
static TaskHandle_t bmp180_task_handle[I2C_MAX_BUS] = { NULL };
|
||||||
|
|
||||||
//
|
//
|
||||||
// Forward declarations
|
// Forward declarations
|
||||||
|
|
|
@ -21,9 +21,10 @@ from it.
|
||||||
Connect BMP280 or BME280 module to you ESP8266 module and initialize the I2C SCL and SDA pins:
|
Connect BMP280 or BME280 module to you ESP8266 module and initialize the I2C SCL and SDA pins:
|
||||||
|
|
||||||
```
|
```
|
||||||
|
const uint8_t bus = 0;
|
||||||
const uint8_t scl_pin = 0;
|
const uint8_t scl_pin = 0;
|
||||||
const uint8_t sda_pin = 2;
|
const uint8_t sda_pin = 2;
|
||||||
i2c_init(scl_pin, sda_pin);
|
i2c_init(bus, scl_pin, sda_pin, I2C_FREQ_100K);
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -38,7 +38,7 @@
|
||||||
#define debug(fmt, ...)
|
#define debug(fmt, ...)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define CLK_STRETCH (10)
|
//#define CLK_STRETCH (10)
|
||||||
|
|
||||||
// Following array contain delay values for different frequencies
|
// Following array contain delay values for different frequencies
|
||||||
// Warning: 1 is minimal, that mean at 80MHz clock, frequency max is 320kHz
|
// Warning: 1 is minimal, that mean at 80MHz clock, frequency max is 320kHz
|
||||||
|
@ -60,22 +60,29 @@ typedef struct i2c_bus_description
|
||||||
bool started;
|
bool started;
|
||||||
bool flag;
|
bool flag;
|
||||||
bool force;
|
bool force;
|
||||||
|
uint32_t clk_stretch;
|
||||||
} i2c_bus_description_t;
|
} i2c_bus_description_t;
|
||||||
|
|
||||||
static i2c_bus_description_t i2c_bus[MAX_I2C_BUS];
|
static i2c_bus_description_t i2c_bus[I2C_MAX_BUS];
|
||||||
|
|
||||||
inline bool i2c_status(uint8_t bus)
|
inline bool i2c_status(uint8_t bus)
|
||||||
{
|
{
|
||||||
return i2c_bus[bus].started;
|
return i2c_bus[bus].started;
|
||||||
}
|
}
|
||||||
|
|
||||||
void i2c_init(uint8_t bus, uint8_t scl_pin, uint8_t sda_pin, i2c_freq_t freq)
|
int i2c_init(uint8_t bus, uint8_t scl_pin, uint8_t sda_pin, i2c_freq_t freq)
|
||||||
{
|
{
|
||||||
|
if (bus >= I2C_MAX_BUS) {
|
||||||
|
debug("Invalid bus");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
i2c_bus[bus].started = false;
|
i2c_bus[bus].started = false;
|
||||||
i2c_bus[bus].flag = false;
|
i2c_bus[bus].flag = false;
|
||||||
i2c_bus[bus].g_scl_pin = scl_pin;
|
i2c_bus[bus].g_scl_pin = scl_pin;
|
||||||
i2c_bus[bus].g_sda_pin = sda_pin;
|
i2c_bus[bus].g_sda_pin = sda_pin;
|
||||||
i2c_bus[bus].frequency = freq;
|
i2c_bus[bus].frequency = freq;
|
||||||
|
i2c_bus[bus].clk_stretch = I2C_DEFAULT_CLK_STRETCH;
|
||||||
|
|
||||||
// Just to prevent these pins floating too much if not connected.
|
// Just to prevent these pins floating too much if not connected.
|
||||||
gpio_set_pullup(i2c_bus[bus].g_scl_pin, 1, 1);
|
gpio_set_pullup(i2c_bus[bus].g_scl_pin, 1, 1);
|
||||||
|
@ -90,16 +97,24 @@ void i2c_init(uint8_t bus, uint8_t scl_pin, uint8_t sda_pin, i2c_freq_t freq)
|
||||||
|
|
||||||
// Prevent user, if frequency is high
|
// Prevent user, if frequency is high
|
||||||
if (sdk_system_get_cpu_freq() == SYS_CPU_80MHZ)
|
if (sdk_system_get_cpu_freq() == SYS_CPU_80MHZ)
|
||||||
if (i2c_freq_array[i2c_bus[bus].frequency][1] == 1)
|
if (i2c_freq_array[i2c_bus[bus].frequency][1] == 1) {
|
||||||
debug("Max frequency is 320Khz at 80MHz");
|
debug("Max frequency is 320Khz at 80MHz");
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void i2c_frequency(uint8_t bus, i2c_freq_t freq)
|
void i2c_set_frequency(uint8_t bus, i2c_freq_t freq)
|
||||||
{
|
{
|
||||||
i2c_bus[bus].frequency = freq;
|
i2c_bus[bus].frequency = freq;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void i2c_set_clock_stretch(uint8_t bus, uint32_t clk_stretch)
|
||||||
|
{
|
||||||
|
i2c_bus[bus].clk_stretch = clk_stretch;
|
||||||
|
}
|
||||||
|
|
||||||
static inline void i2c_delay(uint8_t bus)
|
static inline void i2c_delay(uint8_t bus)
|
||||||
{
|
{
|
||||||
uint32_t delay;
|
uint32_t delay;
|
||||||
|
@ -159,7 +174,7 @@ void i2c_start(uint8_t bus)
|
||||||
// Set SDA to 1
|
// Set SDA to 1
|
||||||
(void) read_sda(bus);
|
(void) read_sda(bus);
|
||||||
i2c_delay(bus);
|
i2c_delay(bus);
|
||||||
uint32_t clk_stretch = CLK_STRETCH;
|
uint32_t clk_stretch = i2c_bus[bus].clk_stretch;
|
||||||
while (read_scl(bus) == 0 && clk_stretch--)
|
while (read_scl(bus) == 0 && clk_stretch--)
|
||||||
;
|
;
|
||||||
// Repeated start setup time, minimum 4.7us
|
// Repeated start setup time, minimum 4.7us
|
||||||
|
@ -178,7 +193,7 @@ void i2c_start(uint8_t bus)
|
||||||
// Output stop condition
|
// Output stop condition
|
||||||
bool i2c_stop(uint8_t bus)
|
bool i2c_stop(uint8_t bus)
|
||||||
{
|
{
|
||||||
uint32_t clk_stretch = CLK_STRETCH;
|
uint32_t clk_stretch = i2c_bus[bus].clk_stretch;
|
||||||
// Set SDA to 0
|
// Set SDA to 0
|
||||||
clear_sda(bus);
|
clear_sda(bus);
|
||||||
i2c_delay(bus);
|
i2c_delay(bus);
|
||||||
|
@ -203,7 +218,7 @@ bool i2c_stop(uint8_t bus)
|
||||||
// Write a bit to I2C bus
|
// Write a bit to I2C bus
|
||||||
static void i2c_write_bit(uint8_t bus, bool bit)
|
static void i2c_write_bit(uint8_t bus, bool bit)
|
||||||
{
|
{
|
||||||
uint32_t clk_stretch = CLK_STRETCH;
|
uint32_t clk_stretch = i2c_bus[bus].clk_stretch;
|
||||||
if (bit) {
|
if (bit) {
|
||||||
(void) read_sda(bus);
|
(void) read_sda(bus);
|
||||||
} else {
|
} else {
|
||||||
|
@ -225,7 +240,7 @@ static void i2c_write_bit(uint8_t bus, bool bit)
|
||||||
// Read a bit from I2C bus
|
// Read a bit from I2C bus
|
||||||
static bool i2c_read_bit(uint8_t bus)
|
static bool i2c_read_bit(uint8_t bus)
|
||||||
{
|
{
|
||||||
uint32_t clk_stretch = CLK_STRETCH;
|
uint32_t clk_stretch = i2c_bus[bus].clk_stretch;
|
||||||
bool bit;
|
bool bit;
|
||||||
// Let the slave drive data
|
// Let the slave drive data
|
||||||
(void) read_sda(bus);
|
(void) read_sda(bus);
|
||||||
|
@ -272,24 +287,20 @@ static int i2c_bus_test(uint8_t bus)
|
||||||
{
|
{
|
||||||
taskENTER_CRITICAL(); // To prevent task swaping after checking flag and before set it!
|
taskENTER_CRITICAL(); // To prevent task swaping after checking flag and before set it!
|
||||||
bool status = i2c_bus[bus].flag; // get current status
|
bool status = i2c_bus[bus].flag; // get current status
|
||||||
if(i2c_bus[bus].force)
|
if (i2c_bus[bus].force) {
|
||||||
{
|
|
||||||
i2c_bus[bus].flag = true; // force bus on
|
i2c_bus[bus].flag = true; // force bus on
|
||||||
taskEXIT_CRITICAL();
|
taskEXIT_CRITICAL();
|
||||||
if(status)
|
if (status)
|
||||||
i2c_stop(bus); //Bus was busy, stop it.
|
i2c_stop(bus); //Bus was busy, stop it.
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
{
|
if (status) {
|
||||||
if (status)
|
|
||||||
{
|
|
||||||
taskEXIT_CRITICAL();
|
taskEXIT_CRITICAL();
|
||||||
debug("busy");
|
debug("busy");
|
||||||
taskYIELD(); // If bus busy, change task to try finish last com.
|
taskYIELD(); // If bus busy, change task to try finish last com.
|
||||||
return -EBUSY; // If bus busy, inform user
|
return -EBUSY; // If bus busy, inform user
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
{
|
|
||||||
i2c_bus[bus].flag = true; // Set Bus busy
|
i2c_bus[bus].flag = true; // Set Bus busy
|
||||||
taskEXIT_CRITICAL();
|
taskEXIT_CRITICAL();
|
||||||
}
|
}
|
||||||
|
@ -299,12 +310,12 @@ static int i2c_bus_test(uint8_t bus)
|
||||||
|
|
||||||
int i2c_slave_write(uint8_t bus, uint8_t slave_addr, const uint8_t *data, const uint8_t *buf, uint32_t len)
|
int i2c_slave_write(uint8_t bus, uint8_t slave_addr, const uint8_t *data, const uint8_t *buf, uint32_t len)
|
||||||
{
|
{
|
||||||
if(i2c_bus_test(bus))
|
if (i2c_bus_test(bus))
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
i2c_start(bus);
|
i2c_start(bus);
|
||||||
if (!i2c_write(bus, slave_addr << 1))
|
if (!i2c_write(bus, slave_addr << 1))
|
||||||
goto error;
|
goto error;
|
||||||
if(data != NULL)
|
if (data != NULL)
|
||||||
if (!i2c_write(bus, *data))
|
if (!i2c_write(bus, *data))
|
||||||
goto error;
|
goto error;
|
||||||
while (len--) {
|
while (len--) {
|
||||||
|
@ -325,9 +336,9 @@ error:
|
||||||
|
|
||||||
int i2c_slave_read(uint8_t bus, uint8_t slave_addr, const uint8_t *data, uint8_t *buf, uint32_t len)
|
int i2c_slave_read(uint8_t bus, uint8_t slave_addr, const uint8_t *data, uint8_t *buf, uint32_t len)
|
||||||
{
|
{
|
||||||
if(i2c_bus_test(bus))
|
if (i2c_bus_test(bus))
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
if(data != NULL) {
|
if (data != NULL) {
|
||||||
i2c_start(bus);
|
i2c_start(bus);
|
||||||
if (!i2c_write(bus, slave_addr << 1))
|
if (!i2c_write(bus, slave_addr << 1))
|
||||||
goto error;
|
goto error;
|
||||||
|
|
|
@ -40,10 +40,12 @@ extern "C" {
|
||||||
/**
|
/**
|
||||||
* Define i2c bus max number
|
* Define i2c bus max number
|
||||||
*/
|
*/
|
||||||
#ifndef MAX_I2C_BUS
|
#ifndef I2C_MAX_BUS
|
||||||
#define MAX_I2C_BUS 2
|
#define I2C_MAX_BUS 2
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define I2C_DEFAULT_CLK_STRETCH (10)
|
||||||
|
|
||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
I2C_FREQ_80K = 0,//!< I2C_FREQ_80K
|
I2C_FREQ_80K = 0,//!< I2C_FREQ_80K
|
||||||
|
@ -69,15 +71,24 @@ typedef struct i2c_dev
|
||||||
* @param scl_pin SCL pin for I2C
|
* @param scl_pin SCL pin for I2C
|
||||||
* @param sda_pin SDA pin for I2C
|
* @param sda_pin SDA pin for I2C
|
||||||
* @param freq frequency of bus (ex : I2C_FREQ_400K)
|
* @param freq frequency of bus (ex : I2C_FREQ_400K)
|
||||||
|
* @param clk_stretch I2C clock stretch. I2C_DEFAULT_CLK_STRETCH would be good in most cases
|
||||||
|
* @return Non-zero if error occured
|
||||||
*/
|
*/
|
||||||
void i2c_init(uint8_t bus, uint8_t scl_pin, uint8_t sda_pin, i2c_freq_t freq);
|
int i2c_init(uint8_t bus, uint8_t scl_pin, uint8_t sda_pin, i2c_freq_t freq);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Change bus frequency
|
* Change bus frequency
|
||||||
* @param bus Bus i2c selection
|
* @param bus Bus i2c selection
|
||||||
* @param freq frequency of bus (ex : I2C_FREQ_400K)
|
* @param freq frequency of bus (ex : I2C_FREQ_400K)
|
||||||
*/
|
*/
|
||||||
void i2c_frequency(uint8_t bus, i2c_freq_t freq);
|
void i2c_set_frequency(uint8_t bus, i2c_freq_t freq);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Change clock stretch
|
||||||
|
* @param bus I2C bus
|
||||||
|
* @param clk_stretch I2C clock stretch. I2C_DEFAULT_CLK_STRETCH by default
|
||||||
|
*/
|
||||||
|
void i2c_set_clock_stretch(uint8_t bus, uint32_t clk_stretch);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Write a byte to I2C bus.
|
* Write a byte to I2C bus.
|
||||||
|
|
|
@ -83,7 +83,7 @@ Before using the SHT3x driver, function ```i2c_init``` needs to be called for ea
|
||||||
#define I2C_SDA_PIN GPIO_ID_PIN((4))
|
#define I2C_SDA_PIN GPIO_ID_PIN((4))
|
||||||
|
|
||||||
...
|
...
|
||||||
i2c_init(I2C_BUS, I2C_SCL_PIN, I2C_SDA_PIN, I2C_FREQ_100K))
|
i2c_init(I2C_BUS, I2C_SCL_PIN, I2C_SDA_PIN, I2C_FREQ_100K)
|
||||||
...
|
...
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue