Merge pull request #475 from UncleRus/i2c_fix2

Configurable I2C clock stretching
This commit is contained in:
Ruslan V. Uss 2017-10-29 19:13:48 +05:00 committed by GitHub
commit e0410b2c5d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 54 additions and 31 deletions

View file

@ -216,8 +216,8 @@ typedef struct
} bmp180_command_t;
// Just works due to the fact that QueueHandle_t is a "void *"
static QueueHandle_t bmp180_rx_queue[MAX_I2C_BUS] = { NULL };
static TaskHandle_t bmp180_task_handle[MAX_I2C_BUS] = { NULL };
static QueueHandle_t bmp180_rx_queue[I2C_MAX_BUS] = { NULL };
static TaskHandle_t bmp180_task_handle[I2C_MAX_BUS] = { NULL };
//
// Forward declarations

View file

@ -21,9 +21,10 @@ from it.
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 sda_pin = 2;
i2c_init(scl_pin, sda_pin);
i2c_init(bus, scl_pin, sda_pin, I2C_FREQ_100K);
```

View file

@ -38,7 +38,7 @@
#define debug(fmt, ...)
#endif
#define CLK_STRETCH (10)
//#define CLK_STRETCH (10)
// Following array contain delay values for different frequencies
// 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 flag;
bool force;
uint32_t clk_stretch;
} 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)
{
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].flag = false;
i2c_bus[bus].g_scl_pin = scl_pin;
i2c_bus[bus].g_sda_pin = sda_pin;
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.
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
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");
return -ENOTSUP;
}
void i2c_frequency(uint8_t bus, i2c_freq_t freq)
return 0;
}
void i2c_set_frequency(uint8_t bus, i2c_freq_t 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)
{
uint32_t delay;
@ -159,7 +174,7 @@ void i2c_start(uint8_t bus)
// Set SDA to 1
(void) read_sda(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--)
;
// Repeated start setup time, minimum 4.7us
@ -178,7 +193,7 @@ void i2c_start(uint8_t bus)
// Output stop condition
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
clear_sda(bus);
i2c_delay(bus);
@ -203,7 +218,7 @@ bool i2c_stop(uint8_t bus)
// Write a bit to I2C bus
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) {
(void) read_sda(bus);
} else {
@ -225,7 +240,7 @@ static void i2c_write_bit(uint8_t bus, bool bit)
// Read a bit from I2C 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;
// Let the slave drive data
(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!
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
taskEXIT_CRITICAL();
if (status)
i2c_stop(bus); //Bus was busy, stop it.
}
else
{
if (status)
{
else {
if (status) {
taskEXIT_CRITICAL();
debug("busy");
taskYIELD(); // If bus busy, change task to try finish last com.
return -EBUSY; // If bus busy, inform user
}
else
{
else {
i2c_bus[bus].flag = true; // Set Bus busy
taskEXIT_CRITICAL();
}

View file

@ -40,10 +40,12 @@ extern "C" {
/**
* Define i2c bus max number
*/
#ifndef MAX_I2C_BUS
#define MAX_I2C_BUS 2
#ifndef I2C_MAX_BUS
#define I2C_MAX_BUS 2
#endif
#define I2C_DEFAULT_CLK_STRETCH (10)
typedef enum
{
I2C_FREQ_80K = 0,//!< I2C_FREQ_80K
@ -69,15 +71,24 @@ typedef struct i2c_dev
* @param scl_pin SCL pin for I2C
* @param sda_pin SDA pin for I2C
* @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
* @param bus Bus i2c selection
* @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.

View file

@ -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))
...
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)
...
```