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

@ -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);
} }

View file

@ -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

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: 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);
``` ```

View file

@ -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;

View file

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

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