Fix I2C timeout (#3377)

This commit is contained in:
jmdasnoy 2021-01-22 13:01:21 +01:00 committed by GitHub
parent d5f0094576
commit fb12af06e7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 270 additions and 120 deletions

View File

@ -1,4 +1,4 @@
// Module for interfacing with the I2C interface
// Module for interfacing with the ESP32 I2C interfaces
#include "module.h"
#include "lauxlib.h"
@ -8,28 +8,34 @@
#include "i2c_common.h"
// Lua: i2c.setup( id, sda, scl, speed )
// Lua: speed = i2c.setup( id, sda, scl, speed [,stretchfactor] )
static int i2c_setup( lua_State *L )
{
unsigned id = luaL_checkinteger( L, 1 );
unsigned sda = luaL_checkinteger( L, 2 );
unsigned scl = luaL_checkinteger( L, 3 );
uint32_t speed = (uint32_t)luaL_checkinteger( L, 4 );
int stretchfactor = 1;
int timeout;
luaL_argcheck( L, id < I2C_ID_MAX, 1, "invalid id" );
luaL_argcheck( L, id < I2C_ID_MAX, 1, "invalid i2c interface id" );
MOD_CHECK_ID( gpio, sda );
MOD_CHECK_ID( gpio, scl );
if (id == I2C_ID_SW) {
luaL_argcheck( L, speed <= PLATFORM_I2C_SPEED_SLOW, 4, "wrong arg range" );
luaL_argcheck( L, speed <= PLATFORM_I2C_SPEED_SLOW, 4, "i2c speed too high for i2c.SW interface" );
if (!platform_i2c_setup( id, sda, scl, (uint32_t)speed ))
luaL_error( L, "setup failed" );
lua_pushinteger(L,speed);
} else {
luaL_argcheck( L, speed <= PLATFORM_I2C_SPEED_FASTPLUS, 4, "wrong arg range" );
li2c_hw_master_setup( L, id, sda, scl, speed );
luaL_argcheck( L, speed <= PLATFORM_I2C_SPEED_FASTPLUS, 4, "i2c speed too high for i2c.HWx interfaces" );
if (lua_gettop( L ) > 4) stretchfactor = luaL_checkinteger( L, 5 );
timeout=li2c_hw_master_setup( L, id, sda, scl, speed, stretchfactor);
lua_pushinteger(L,timeout);
}
return 0;
return 1;
}
// Lua: i2c.start( id )
@ -37,11 +43,11 @@ static int i2c_start( lua_State *L )
{
unsigned id = luaL_checkinteger( L, 1 );
luaL_argcheck( L, id < I2C_ID_MAX, 1, "invalid id" );
luaL_argcheck( L, id < I2C_ID_MAX, 1, "invalid i2c interface id" );
if (id == I2C_ID_SW) {
if (!platform_i2c_send_start( id ))
luaL_error( L, "command failed");
luaL_error( L, "start command failed on i2c.SW interface");
} else {
li2c_hw_master_start( L, id );
}
@ -54,11 +60,11 @@ static int i2c_stop( lua_State *L )
{
unsigned id = luaL_checkinteger( L, 1 );
luaL_argcheck( L, id < I2C_ID_MAX, 1, "invalid id" );
luaL_argcheck( L, id < I2C_ID_MAX, 1, "invalid i2c interface id" );
if (id == I2C_ID_SW) {
if (!platform_i2c_send_stop( id ))
luaL_error( L, "command failed" );
luaL_error( L, "stop command failed on i2c.SW interface" );
} else {
li2c_hw_master_stop( L, id );
}
@ -66,22 +72,23 @@ static int i2c_stop( lua_State *L )
return 0;
}
// Lua: status = i2c.address( id, address, direction )
// Lua: status = i2c.address( id , address , direction [, ack_check_en] )
static int i2c_address( lua_State *L )
{
int stack = 0;
unsigned id = luaL_checkinteger( L, ++stack );
luaL_argcheck( L, id < I2C_ID_MAX, stack, "invalid id" );
luaL_argcheck( L, id < I2C_ID_MAX, stack, "invalid i2c interface id" );
int address = luaL_checkinteger( L, ++stack );
luaL_argcheck( L, address >= 0 && address <= 127, stack, "wrong arg range" );
luaL_argcheck( L, address >= 0 && address <= 127, stack, "i2c address out of 7-bit range" );
// *** FIX ME what about 10-bit addresses ???
int direction = luaL_checkinteger( L, ++stack );
luaL_argcheck( L,
direction == PLATFORM_I2C_DIRECTION_TRANSMITTER ||
direction == PLATFORM_I2C_DIRECTION_RECEIVER,
stack, "wrong arg range" );
stack, "invalid i2c address direction" );
bool ack_check_en = luaL_optbool( L, ++stack, true );
@ -90,18 +97,19 @@ static int i2c_address( lua_State *L )
ret = platform_i2c_send_address( id, (uint16_t)address, direction, ack_check_en ? 1 : 0 );
} else {
ret = li2c_hw_master_address( L, id, (uint16_t)address, direction, ack_check_en );
// bad parameters could cause failure to enqueue, but all have been checked, so it should always return true
}
lua_pushboolean( L, ret > 0 );
return 1;
}
// Lua: wrote = i2c.write( id, data1, [data2], ..., [datan] )
// data can be either a string, a table or an 8-bit number
// Lua: wrote = i2c.write( id, data1, [data2], ..., [datan] [, ack_check_en] )
// each of the data elements can be either a string, a table or an 8-bit number
static int i2c_write( lua_State *L )
{
unsigned id = luaL_checkinteger( L, 1 );
luaL_argcheck( L, id < I2C_ID_MAX, 1, "invalid id" );
luaL_argcheck( L, id < I2C_ID_MAX, 1, "invalid i2c interface id" );
const char *pdata;
size_t datalen, i;
@ -116,7 +124,8 @@ static int i2c_write( lua_State *L )
}
if( lua_gettop( L ) < 2 )
return luaL_error( L, "wrong arg type" );
return luaL_error( L, "not enough or wrong arg types for i2c.write" );
for( argn = 2; argn <= lua_gettop( L ); argn ++ )
{
// lua_isnumber() would silently convert a string of digits to an integer
@ -125,7 +134,7 @@ static int i2c_write( lua_State *L )
{
numdata = ( int )luaL_checkinteger( L, argn );
if( numdata < 0 || numdata > 255 )
return luaL_error( L, "wrong arg range" );
return luaL_error( L, "numeric value for i2c.write does not fit in 1 byte" );
if (id == I2C_ID_SW) {
if( platform_i2c_send_byte( id, numdata, 1) != 1 && ack_check_en )
break;
@ -143,7 +152,7 @@ static int i2c_write( lua_State *L )
numdata = ( int )luaL_checkinteger( L, -1 );
lua_pop( L, 1 );
if( numdata < 0 || numdata > 255 )
return luaL_error( L, "wrong arg range" );
return luaL_error( L, "table value for i2c.write does not fit in 1 byte" );
if (id == I2C_ID_SW) {
if( platform_i2c_send_byte( id, numdata, 1 ) == 0 && ack_check_en)
break;
@ -174,20 +183,19 @@ static int i2c_write( lua_State *L )
return 1;
}
// Lua: read = i2c.read( id, size )
// Lua: read = i2c.read( id, size ) for SW interface or i2c.read( id, size ) for HWx interfaces
static int i2c_read( lua_State *L )
{
unsigned id = luaL_checkinteger( L, 1 );
luaL_argcheck( L, id < I2C_ID_MAX, 1, "invalid id" );
luaL_argcheck( L, id < I2C_ID_MAX, 1, "invalid i2c interface id" );
uint32_t size = ( uint32_t )luaL_checkinteger( L, 2 ), i;
uint32_t size = ( uint32_t ) luaL_checkinteger( L, 2 );
luaL_argcheck( L, size > 0, 2, "i2c read size of 0 is invalid" );
if (id == I2C_ID_SW) {
luaL_Buffer b;
uint32_t i;
int data;
if( size == 0 )
return 0;
luaL_buffinit( L, &b );
for( i = 0; i < size; i ++ )
if( ( data = platform_i2c_recv_byte( id, i < size - 1 ) ) == -1 )

View File

@ -17,7 +17,7 @@ typedef enum {
// Hardware master prototypes
//
void li2c_hw_master_init( lua_State *L );
void li2c_hw_master_setup( lua_State *L, unsigned id, unsigned sda, unsigned scl, uint32_t speed );
int li2c_hw_master_setup( lua_State *L, unsigned id, unsigned sda, unsigned scl, uint32_t speed, unsigned stretchfactor );
void li2c_hw_master_start( lua_State *L, unsigned id );
void li2c_hw_master_stop( lua_State *L, unsigned id );
int li2c_hw_master_address( lua_State *L, unsigned id, uint16_t address, uint8_t direction, bool ack_check_en );

View File

@ -3,6 +3,7 @@
#include "lauxlib.h"
#include "lmem.h"
#include "driver/i2c.h"
#include "soc/i2c_reg.h"
#include "i2c_common.h"
@ -165,11 +166,11 @@ static int i2c_lua_checkerr( lua_State *L, esp_err_t err ) {
switch (err) {
case ESP_OK: return 0;
case ESP_FAIL: msg = "command failed or NACK from slave"; break;
case ESP_ERR_INVALID_ARG: msg = "parameter error"; break;
case ESP_ERR_INVALID_STATE: msg = "driver state error"; break;
case ESP_ERR_TIMEOUT: msg = "timeout"; break;
default: msg = "unknown error"; break;
case ESP_FAIL: msg = "i2c command failed or NACK from slave"; break;
case ESP_ERR_INVALID_ARG: msg = "i2c parameter error"; break;
case ESP_ERR_INVALID_STATE: msg = "i2c driver state error"; break;
case ESP_ERR_TIMEOUT: msg = "i2c timeout"; break;
default: msg = "i2c unknown error"; break;
}
return luaL_error( L, msg );
@ -191,7 +192,8 @@ static void i2c_setup_ud_transfer( lua_State *L, i2c_hw_master_ud_type *ud )
// Cares for I2C driver creation and initialization.
// Prepares an empty job descriptor and triggers setup of FreeRTOS stuff.
//
void li2c_hw_master_setup( lua_State *L, unsigned id, unsigned sda, unsigned scl, uint32_t speed )
int li2c_hw_master_setup( lua_State *L, unsigned id, unsigned sda, unsigned scl, uint32_t speed, unsigned stretchfactor )
{
get_udata(L, id);
@ -199,19 +201,27 @@ void li2c_hw_master_setup( lua_State *L, unsigned id, unsigned sda, unsigned scl
memset( &cfg, 0, sizeof( cfg ) );
cfg.mode = I2C_MODE_MASTER;
luaL_argcheck( L, GPIO_IS_VALID_OUTPUT_GPIO(sda), 1, "invalid sda pin" );
luaL_argcheck( L, GPIO_IS_VALID_OUTPUT_GPIO(sda), 2, "invalid sda pin" );
cfg.sda_io_num = sda;
cfg.sda_pullup_en = GPIO_PULLUP_ENABLE;
luaL_argcheck( L, GPIO_IS_VALID_OUTPUT_GPIO(scl), 1, "invalid scl pin" );
luaL_argcheck( L, GPIO_IS_VALID_OUTPUT_GPIO(scl), 3, "invalid scl pin" );
cfg.scl_io_num = scl;
cfg.scl_pullup_en = GPIO_PULLUP_ENABLE;
luaL_argcheck( L, speed > 0 && speed <= 1000000, 1, "invalid speed" );
luaL_argcheck( L, speed > 0 && speed <= 1000000, 4, "invalid speed" );
cfg.master.clk_speed = speed;
// init driver level
i2c_lua_checkerr( L, i2c_param_config( port, &cfg ) );
luaL_argcheck( L, stretchfactor > 0 , 5, "invalid stretch factor" );
int timeoutcycles;
i2c_lua_checkerr( L, i2c_get_timeout( port, &timeoutcycles) );
timeoutcycles = timeoutcycles * stretchfactor;
luaL_argcheck( L, timeoutcycles * stretchfactor <= I2C_TIME_OUT_REG_V, 5, "excessive stretch factor" );
i2c_lua_checkerr( L, i2c_set_timeout( port, timeoutcycles) );
i2c_lua_checkerr( L, i2c_driver_install( port, cfg.mode, 0, 0, 0 ));
job->port = port;
@ -227,6 +237,7 @@ void li2c_hw_master_setup( lua_State *L, unsigned id, unsigned sda, unsigned scl
i2c_driver_delete( port );
luaL_error( L, "rtos task creation failed" );
}
return timeoutcycles;
}
void li2c_hw_master_start( lua_State *L, unsigned id )
@ -288,9 +299,9 @@ void li2c_hw_master_read( lua_State *L, unsigned id, uint32_t len )
res->len = len;
job->result = res;
if (len > 1)
i2c_lua_checkerr( L, i2c_master_read( job->cmd, res->data, len-1, 0 ) );
i2c_lua_checkerr( L, i2c_master_read( job->cmd, res->data + len-1, 1, 1 ) );
// call i2c_master_read specifying a NACK on last byte read
i2c_lua_checkerr( L, i2c_master_read( job->cmd, res->data,len,I2C_MASTER_LAST_NACK) );
}
// Initiate the I2C transfer

View File

@ -2,102 +2,222 @@
| Since | Origin / Contributor | Maintainer | Source |
| :----- | :-------------------- | :---------- | :------ |
| 2014-12-22 | [Zeroday](https://github.com/funshine) | [Zeroday](https://github.com/funshine) | [i2c.c](../../components/modules/i2c.c)|
| 2020-01-17 | [jmdasnoy](https://github.com/jmdasnoy) | [jmdasnoy](https://github.com/jmdasnoy) | [i2c.c](../../components/modules/i2c.c)|
This module supports different interfaces for communicating via I²C protocol. All interfaces can be assigned to arbitrary GPIOs for SCL and SDA and can be operated concurrently.
- `i2c.SW` software based bitbanging, master mode only, synchronous operation
- `i2c.HW0` ESP32 hardware port 0, master or slave mode, synchronous or asynchronous operation
- `i2c.HW1` ESP32 hardware port 1, master or slave mode, synchronous or asynchronous operation
This module supports 3 different interfaces for I²C communication on a ESP-32.
The hardware master interfaces differ from the SW interface as the commands (start, stop, read, write) are queued up to an internal command list. Actual I²C communication is initiated afterwards using the `i2c.transfer()` function. Commands for the `i2c.SW` interface are immediately effective on the I²C bus and read data is also instantly available.
The interface `id` can be
- `i2c.SW` software based bitbanging, master mode only, immediate execution, synchronous operation, maximum speed 100 KHz (Standard mode)
- `i2c.HW0` ESP32 hardware bus interface 0, master or slave mode, deferred execution, synchronous or asynchronous operation, maximum speed 1 MHz (Fast-mode Plus)
- `i2c.HW1` ESP32 hardware bus interface 1, master or slave mode, deferred execution, synchronous or asynchronous operation, maximum speed 1 MHz (Fast-mode Plus)
All interfaces can be used at the same time.
Interfaces can use arbitrary GPIOs for the clock (SCL) and data (SDA) lines.
The interfaces are not suitable for multi-master configurations.
In master mode, I²C communication is performed by combinations of 5 basic I²C operations, provided by the functions `i2c.start()`,`i2c.stop()`,`i2c.address()`,`i2c.write()`,`i2c.read()`.
The behaviour of these functions is quite different according to the type of interface.
For the software interface, these functions IMMEDIATELY perform the requested I²C operation and return on completion. For slow bus speeds and multi-byte reads or writes, this can tie up the CPU for a significant time.
However, any results returned reflect the effective outcome of the operation.
For the hardware interfaces, these functions do NOT trigger any immediate I²C activity but enqueue (store) a request for later, DEFERRED execution.
These functions return immediately as they do not have to wait for any I²C operation to complete.
As a consequence, any results returned do not reflect the effective outcome of the operation.
The function `i2c.transfer()` MUST be called to effectively execute the stored requests for operations.
Execution of the stored requests is performed by the hardware interface.
If `i2c.transfer()` is provided with a call-back function, it will return before completion of the enqueued I²C operations, freeing the CPU for other tasks.
#### Example using the software interface
```lua
-- check if chip is present and functional by reading a signature/chip id
-- i2c bus setup
sda = 23 -- pins as on Adafruit Huzzah32 silkscreen
scl = 22
id = i2c.SW -- software interface
speed = i2c.SLOW
-- values for Bosch Sensortech BMP180 chip
bmpAddress = 0x77
bmpIdRegister = 0xD0
bmpChipSignature = 0x55
-- initialize i2c software interface
i2c.setup(id, sda, scl, speed)
-- attempt to read chip id and compare against expected value
function simple_check_chip(dev_address, dev_register, dev_signature)
i2c.start(id)
assert(i2c.address(id, dev_address, i2c.TRANSMITTER) , "!!i2c device did not ACK first address operation" )
i2c.write(id, dev_register)
i2c.start(id) -- repeated start condition
assert( i2c.address(id, dev_address, i2c.RECEIVER) , "!!i2c device did not ACK second address operation" )
if i2c.read(id, 1):byte() == dev_signature then
print("..chip is operational")
else
print("!!The chip does not have the expected signature")
end
i2c.stop(id)
end
--
print("Chip check, should fail because device address is wrong")
simple_check_chip(bmpAddress+1, bmpIdRegister, bmpChipSignature)
print("Chip check, should succeed if chip is present and functional")
simple_check_chip(bmpAddress, bmpIdRegister, bmpChipSignature)
```
#### Example using the hardware interfaces
```lua
sda = 23 -- pins as on Adafruit Huzzah32 silkscreen
scl = 22
id = i2c.HW1 -- hardware interface
speed = i2c.SLOW
-- values for Bosch Sensortech BMP180 chip
bmpAddress = 0x77
bmpIdRegister = 0xD0
bmpChipSignature = 0x55
-- initialize i2c software interface
i2c.setup(id, sda, scl, speed)
-- read a single byte from the chip
function read_byte(dev_address, dev_register , callback )
i2c.start(id)
i2c.address(id, dev_address, i2c.TRANSMITTER)
i2c.write(id, dev_register)
i2c.start(id) -- repeated start condition
i2c.address(id, dev_address, i2c.RECEIVER)
i2c.read(id, 1)
i2c.stop(id)
return i2c.transfer(id, callback)
end
-- check results returned
function check(value, ack)
if ack then
if value:byte() == bmpChipSignature then
print("..chip is operational")
else
print("!!The chip does not have the expected signature")
end
else
print("!!chip did not respond")
end
end
--
print("synchronous use")
print("Chip check, should fail because device address is wrong")
check(read_byte(bmpAddress+1, bmpIdRegister))
print("Chip check, should succeed if chip is present and functional")
check(read_byte(bmpAddress, bmpIdRegister))
print("asynchronous use")
print("Chip check, should fail because device address is wrong")
read_byte(bmpAddress+1, bmpIdRegister, check)
print("Chip check, should succeed if chip is present and functional")
read_byte(bmpAddress, bmpIdRegister, check)
```
## i2c.address()
Send (`SW`) or queue (`HWx`) I²C address and read/write mode for the next transfer.
Communication stops when the slave answers with NACK to the address byte. This can be avoided with parameter `ack_check_en` on `false`.
Perform (`SW`) or enqueue (`HWx`) an I²C address operation, defining data transfer direction for the next operation (read or write).
#### Syntax
`i2c.address(id, device_addr, direction[, ack_check_en])`
`i2c.address(id, device_addr, direction [, ack_check_en])`
#### Parameters
- `id` interface id
- `device_addr` device address
- `direction` `i2c.TRANSMITTER` for writing mode , `i2c.RECEIVER` for reading mode
- `ack_check_en` enable check for slave ACK with `true` (default), disable with `false`
- `device_addr` I²C device address
- `direction` `i2c.TRANSMITTER` for write mode , `i2c.RECEIVER` for read mode
- `ack_check_en` enable check for slave ACK with `true` (default), disable check with `false`
This last, optional parameter is only relevant for for hardware interfaces `i2c.HW0` and `i2c.HW1` and defaults to `true'.
The I²C `address` operation is enqueued for later execution and this parameter will be used at that later time.
At that time, if NO slave device produces an ACK to the address operation, the default assumption is that the slave at that address is absent or not functional. Any remaining I²C operations in the queue will be ignored/flushed/discarded and the communication will be stopped.
This default queue flushing behaviour on slave NACK can be overridden by specifying `false`.
#### Returns
`true` if ack received (always for ids `i2c.HW0` and `i2c.HW1`), `false` if no ack received (only possible for `i2c.SW`).
for interface `i2c.SW`: returns `true` if ack received, `false` if no ack received. This value should be checked to decide whether to continue communication.
for interfaces `i2c.HW0` and `i2c.HW1`: always returns `true`.
#### See also
[i2c.read()](#i2cread)
## i2c.read()
Read (`SW`) or queue (`HWx`) data for variable number of bytes.
Perform (`SW`) or enqueue (`HWx`) a data read operation for a variable number of bytes.
#### Syntax
`i2c.read(id, len)`
#### Parameters
- `id` interface id
- `len` number of data bytes
- `id` I²C interface id
- `len` number of data bytes to read
#### Returns
- `string` of received data for interface `i2c.SW`
- `nil` for ids `i2c.HW0` and `i2c.HW1`
- for software interface `i2c.SW` : returns `string` of received data
- for hardware interfaces id `i2c.HWx` : no value returned
#### Example
```lua
id = i2c.SW
sda = 1
scl = 2
For the hardware interfaces, any values read from the bus will be returned by the `i2c.transfer()` function or the associated callback function.
For this reason, a sequence of enqueued operations may only contain one read request.
-- initialize i2c, set pin1 as sda, set pin2 as scl
i2c.setup(id, sda, scl, i2c.SLOW)
The value returned by a read operation is a string. Refer to the slave datasheet for multibyte reads/autoincrement capability, endianness and format details.
-- user defined function: read from reg_addr content of dev_addr
function read_reg(dev_addr, reg_addr)
i2c.start(id)
i2c.address(id, dev_addr, i2c.TRANSMITTER)
i2c.write(id, reg_addr)
i2c.stop(id)
i2c.start(id)
i2c.address(id, dev_addr, i2c.RECEIVER)
c = i2c.read(id, 1)
i2c.stop(id)
return c
end
-- get content of register 0xAA of device 0x77
reg = read_reg(0x77, 0xAA)
print(string.byte(reg))
```
####See also
#### See also
[i2c.write()](#i2cwrite)
## i2c.setup()
Initialize the I²C interface for master mode.
#### Syntax
`i2c.setup(id, pinSDA, pinSCL, speed)`
`i2c.setup(id, pinSDA, pinSCL, speed [,stretchfactor])`
####Parameters
#### Parameters
- `id` interface id
- `pinSDA` IO index, see [GPIO Overview](gpio.md#gpio-overview)
- `pinSCL` IO index, see [GPIO Overview](gpio.md#gpio-overview)
- `speed` bit rate in Hz, positive integer
- `i2c.SLOW` for 100000 Hz, max for `i2c.SW`
- `i2c.FAST` for 400000 Hz
- `i2c.FASTPLUS` for 1000000 Hz
- `speed` bit rate in Hz, integer
- `i2c.SLOW` for 100000 Hz (100 KHz a.k.a Standard Mode), this is the maximum allowed value for the `i2c.SW` interface
- `i2c.FAST` for 400000 Hz (400 KHz a.k.a Fast Mode)
- `i2c.FASTPLUS` for 1000000 Hz (1 MHz, a.k.a. Fast-mode Plus), this is the maximum allowed value for `i2c.HWx`interfaces
- `stretchfactor` integer multiplier for timeout
The pins declared for SDA and SCL are configured with onchip pullup resistors. These are weak pullups.
The data sheets do not specify any specific value for the pullup resistors, but they are reported to be between 10KΩ and 100KΩ with a target value of 50 KΩ.
Additional pullups are recommended especialy for faster speeds, in doubt try 4.7 kΩ.
The `speed` constants are provided for convenience but any other integer value can be used.
The last, optional parameter `stretchfactor` is only relevant for the `HWx`interfaces and defaults to 1.
The hardware interfaces have a built-in timeout, designed to recover from abnormal I²C bus conditions.
The default timeout is defined as 8 I²C SCL clock cycles. With an 80 MHz CPU clock speed and a 100 KHz this means 8*80/0.1 = 6400 CPU clock cycles i.e. 80 µS.
A busy or slow slave device can request a temporary pause of communication by keeping the SCL line line low a.k.a. clock stretching.
This clock stretching may exceed the timeout value and cause (often intermittent) errors.
This can be avoided either by using a slower bit rate or by specifying a multiplier value for the timeout.
Calling setup on an already configured hardware interface will cause panic.
Note to wizards: The I²C specifications defines a High-Speed mode allowing communication up to 3.4 Mbits/s, with the added complexity of variable clock speed and current-source pullups. The Expressif documentation states that the I²C hardware interfaces support up to 5 MHz, constrained by SDA pull-up strength. This module will object to speeds higher than 1 MHz, but your experience and feedback is welcome !
#### Returns
`speed` the selected speed
for interface `i2c.SW`: returns `speed` the selected speed.
####See also
for interfaces `i2c.HW0` and `i2c.HW1`: returns `timeout` expressed as CPU clock cycles.
#### See also
[i2c.read()](#i2cread)
## i2c.start()
Send (`SW`) or queue (`HWx`) an I²C start condition.
Perform (`SW`) or enqueue (`HWx`) an I²C start condition.
#### Syntax
`i2c.start(id)`
@ -106,66 +226,77 @@ Send (`SW`) or queue (`HWx`) an I²C start condition.
`id` interface id
#### Returns
`nil`
no returned value
####See also
#### See also
[i2c.read()](#i2cread)
## i2c.stop()
Send (`SW`) or queue (`HWx`) an I²C stop condition.
Perform (`SW`) or enqueue (`HWx`) an I²C stop condition.
#### Syntax
`i2c.stop(id)`
####Parameters
#### Parameters
`id` interface id
#### Returns
`nil`
no returned value
####See also
#### See also
[i2c.read()](#i2cread)
## i2c.transfer()
Starts a transfer for the specified hardware module. Providing a callback function allows the transfer to be started asynchronously in the background and `i2c.transfer()` finishes immediately. Without a callback function, the transfer is executed synchronously and `i2c.transfer()` comes back when the transfer completed. Data from a read operation is returned from `i2c.transfer()` in this case.
Starts a transfer for the specified hardware module.
First argument to the callback is a string with data obtained from a read operation during the transfer or `nil`, followed by the ack flag (true = ACK received).
Providing a callback function allows the transfer to be started asynchronously in the background and `i2c.transfer()` finishes immediately, without returning any value.
Results from any data read will be provided to the callback function.
Without a callback function, the transfer is executed synchronously and `i2c.transfer()` returns when the transfer completes.
In this case, this function returns read values and an ACK flag.
#### Syntax
`i2c.transfer(id[, cb_fn][, to_ms])`
`i2c.transfer(id [, callback] [, to_ms])`
#### Parameters
- `id` interface id, `i2c.SW` not allowed
- `cb_fn(data, ack)` function to be called when transfer finished
- `to_ms` timeout for the transfer in ms, defaults to 0=infinite
- `id` hardware interface id only , `i2c.SW` not allowed
- `callback` optional callback function to be called when transfer finishes
- `to_ms` optional timeout for the synchronous transfer in ms, defaults to 0 (infinite)
The optional callback function should be defined to accept 2 arguments i.e. `function( data , ack )` where
- `data `is the string from a read operation during the transfer (`nil` if no read or failed ACK )
- `ack is a boolean (true = ACK received).
The optional timeout parameter defaults to 0 meaning infinite and is only relevant for synchronous mode. This can be used to define an upper bound to the execution time of `i2c.transfer()`.
It specifies the maximum delay in mS before `i2c.transfer()` returns, possibly before the complete I²C set of operations is executed.
This timeout should not be confused with the timeout specified in `i2c.setup`.
#### Returns
- synchronous operation:
- for synchronous operation i.e. without any callback function, two values are returned
- `data` string of received data (`nil` if no read or NACK)
- `ack` true if ACK received, false for NACK
- `nil` for asynchronous operation
- for asynchronous operation, i.e. with a callback function, no value is returned
## i2c.write()
Write (`SW`) or queue (`HWx`) data to I²C bus. Data items can be multiple numbers, strings or lua tables.
Perform (`SW`) or enqueue (`HWx`) data write to I²C bus.
Communication stops when the slave answers with NACK to a written byte. This can be avoided with parameter `ack_check_en` on `false`.
#### Syntax
`i2c.write(id, data1 [, data2[, ..., datan]] [, ack_check_en] )`
####Syntax
`i2c.write(id, data1[, data2[, ..., datan]][, ack_check_en])`
####Parameters
#### Parameters
- `id` interface id
- `data` data can be numbers, string or lua table.
- `data` data items can be numbers, strings or lua tables.
- `ack_check_en` enable check for slave ACK with `true` (default), disable with `false`
Numbers or table elements must be in range [0,255] i.e. they must fit in a single byte.
By default, communication stops when the slave does not ACK each written byte.
This can be overridden by setting parameter `ack_check_en` to `false`.
#### Returns
`number` number of bytes written
#### Example
```lua
i2c.write(0, "hello", "world")
```
#### See also
[i2c.read()](#i2cread)