Fix I2C timeout (#3377)
This commit is contained in:
parent
d5f0094576
commit
fb12af06e7
|
@ -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 )
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
Loading…
Reference in New Issue