Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

I2C sw driver with support of multiple buses, Slow, Fast, FastPlus, and user-defined speed selection #2465

Merged
merged 7 commits into from
Apr 5, 2019
601 changes: 461 additions & 140 deletions app/driver/i2c_master.c

Large diffs are not rendered by default.

80 changes: 9 additions & 71 deletions app/include/driver/i2c_master.h
Original file line number Diff line number Diff line change
@@ -1,74 +1,12 @@
#ifndef __I2C_MASTER_H__
#define __I2C_MASTER_H__

#define I2C_MASTER_SDA_MUX (pin_mux[sda])
#define I2C_MASTER_SCL_MUX (pin_mux[scl])
#define I2C_MASTER_SDA_GPIO (pinSDA)
#define I2C_MASTER_SCL_GPIO (pinSCL)
#define I2C_MASTER_SDA_FUNC (pin_func[sda])
#define I2C_MASTER_SCL_FUNC (pin_func[scl])

// #define I2C_MASTER_SDA_MUX PERIPHS_IO_MUX_GPIO2_U
// #define I2C_MASTER_SCL_MUX PERIPHS_IO_MUX_MTDO_U
// #define I2C_MASTER_SDA_GPIO 2
// #define I2C_MASTER_SCL_GPIO 15
// #define I2C_MASTER_SDA_FUNC FUNC_GPIO2
// #define I2C_MASTER_SCL_FUNC FUNC_GPIO15

// #define I2C_MASTER_SDA_MUX PERIPHS_IO_MUX_GPIO2_U
// #define I2C_MASTER_SCL_MUX PERIPHS_IO_MUX_MTMS_U
// #define I2C_MASTER_SDA_GPIO 2
// #define I2C_MASTER_SCL_GPIO 14
// #define I2C_MASTER_SDA_FUNC FUNC_GPIO2
// #define I2C_MASTER_SCL_FUNC FUNC_GPIO14

//#define I2C_MASTER_SDA_MUX PERIPHS_IO_MUX_GPIO2_U
//#define I2C_MASTER_SCL_MUX PERIPHS_IO_MUX_GPIO0_U
//#define I2C_MASTER_SDA_GPIO 2
//#define I2C_MASTER_SCL_GPIO 0
//#define I2C_MASTER_SDA_FUNC FUNC_GPIO2
//#define I2C_MASTER_SCL_FUNC FUNC_GPIO0

#if 0
#define I2C_MASTER_GPIO_SET(pin) \
gpio_output_set(1<<pin,0,1<<pin,0)

#define I2C_MASTER_GPIO_CLR(pin) \
gpio_output_set(0,1<<pin,1<<pin,0)

#define I2C_MASTER_GPIO_OUT(pin,val) \
if(val) I2C_MASTER_GPIO_SET(pin);\
else I2C_MASTER_GPIO_CLR(pin)
#endif

#define I2C_MASTER_SDA_HIGH_SCL_HIGH() \
gpio_output_set(1<<I2C_MASTER_SDA_GPIO | 1<<I2C_MASTER_SCL_GPIO, 0, 1<<I2C_MASTER_SDA_GPIO | 1<<I2C_MASTER_SCL_GPIO, 0)

#define I2C_MASTER_SDA_HIGH_SCL_LOW() \
gpio_output_set(1<<I2C_MASTER_SDA_GPIO, 1<<I2C_MASTER_SCL_GPIO, 1<<I2C_MASTER_SDA_GPIO | 1<<I2C_MASTER_SCL_GPIO, 0)

#define I2C_MASTER_SDA_LOW_SCL_HIGH() \
gpio_output_set(1<<I2C_MASTER_SCL_GPIO, 1<<I2C_MASTER_SDA_GPIO, 1<<I2C_MASTER_SDA_GPIO | 1<<I2C_MASTER_SCL_GPIO, 0)

#define I2C_MASTER_SDA_LOW_SCL_LOW() \
gpio_output_set(0, 1<<I2C_MASTER_SDA_GPIO | 1<<I2C_MASTER_SCL_GPIO, 1<<I2C_MASTER_SDA_GPIO | 1<<I2C_MASTER_SCL_GPIO, 0)

void i2c_master_gpio_init(uint8 sda, uint8 scl);
void i2c_master_init(void);

#define i2c_master_wait os_delay_us
void i2c_master_stop(void);
void i2c_master_start(void);
void i2c_master_setAck(uint8 level);
uint8 i2c_master_getAck(void);
uint8 i2c_master_readByte(void);
void i2c_master_writeByte(uint8 wrdata);

bool i2c_master_checkAck(void);
void i2c_master_send_ack(void);
void i2c_master_send_nack(void);

uint8 i2c_master_get_pinSDA();
uint8 i2c_master_get_pinSCL();

#endif
uint32 i2c_master_setup(uint16 id, uint8 sda, uint8 scl, uint32 speed);
void i2c_master_init(uint16 id);
bool i2c_master_configured(uint16 id);
void i2c_master_stop(uint16 id);
void i2c_master_start(uint16 id);
uint8 i2c_master_readByte(uint16 id, sint16 ack);
uint8 i2c_master_writeByte(uint16 id, uint8 wrdata);

#endif //__I2C_MASTER_H__
16 changes: 16 additions & 0 deletions app/include/user_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,22 @@
#define ENDUSER_SETUP_AP_SSID "SetupGadget"


// I2C software driver partially supports use of GPIO16 (D0) pin for SCL line.
// GPIO16 does not support open-drain mode and works in push-pull mode,
// so clock stretching will not be possible, because circuit in slave device that
// supposed to drive SCL low during stretching will not be capable to hold SCL low.
// Also I2C speed will be limited to no more than 400000 Hz (FAST mode).
// This define is does not have an effect on an old driver (see I2C_MASTER_OLD_VERSION).

//#define I2C_MASTER_GPIO16_ENABLE

// For compatibility reasons you can switch to old version of I2C software driver.
// It does not support changing speed, have only one bus id = 0, does not support GPIO16
// and works only in Standard(slow) mode with clock speed around 50kHz.

#define I2C_MASTER_OLD_VERSION


// The following sections are only relevent for those developers who are
// developing modules or core Lua changes and configure how extra diagnostics
// are enabled in the firmware. These should only be configured if you are
Expand Down
19 changes: 13 additions & 6 deletions app/modules/i2c.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,16 @@ static int i2c_setup( lua_State *L )
MOD_CHECK_ID( gpio, sda );
MOD_CHECK_ID( gpio, scl );

if(scl==0 || sda==0)
return luaL_error( L, "no i2c for D0" );
if ( sda == 0 )
return luaL_error( L, "i2c SDA on D0 is not supported" );

s32 speed = ( s32 )luaL_checkinteger( L, 4 );
if (speed <= 0)
if ( speed <= 0 )
return luaL_error( L, "wrong arg range" );
lua_pushinteger( L, platform_i2c_setup( id, sda, scl, (u32)speed ) );
speed = platform_i2c_setup( id, sda, scl, (u32)speed );
if ( speed == 0 )
return luaL_error( L, "failed to initialize i2c %d", id );
lua_pushinteger( L, speed );
return 1;
}

Expand All @@ -31,7 +34,10 @@ static int i2c_start( lua_State *L )
unsigned id = luaL_checkinteger( L, 1 );

MOD_CHECK_ID( i2c, id );
platform_i2c_send_start( id );
if (platform_i2c_configured( id ) )
platform_i2c_send_start( id );
else
luaL_error( L, "i2c %d is not configured", id );
return 0;
}

Expand Down Expand Up @@ -147,7 +153,8 @@ static const LUA_REG_TYPE i2c_map[] = {
{ LSTRKEY( "address" ), LFUNCVAL( i2c_address ) },
{ LSTRKEY( "write" ), LFUNCVAL( i2c_write ) },
{ LSTRKEY( "read" ), LFUNCVAL( i2c_read ) },
//{ LSTRKEY( "FAST" ), LNUMVAL( PLATFORM_I2C_SPEED_FAST ) },
{ LSTRKEY( "FASTPLUS" ), LNUMVAL( PLATFORM_I2C_SPEED_FASTPLUS ) },
{ LSTRKEY( "FAST" ), LNUMVAL( PLATFORM_I2C_SPEED_FAST ) },
{ LSTRKEY( "SLOW" ), LNUMVAL( PLATFORM_I2C_SPEED_SLOW ) },
{ LSTRKEY( "TRANSMITTER" ), LNUMVAL( PLATFORM_I2C_DIRECTION_TRANSMITTER ) },
{ LSTRKEY( "RECEIVER" ), LNUMVAL( PLATFORM_I2C_DIRECTION_RECEIVER ) },
Expand Down
6 changes: 6 additions & 0 deletions app/platform/cpu_esp8266.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,13 @@
#define NUM_PWM GPIO_PIN_NUM
#define NUM_ADC 1
#define NUM_CAN 0

#ifndef I2C_MASTER_OLD_VERSION
#define NUM_I2C 10
sonaux marked this conversation as resolved.
Show resolved Hide resolved
#else
#define NUM_I2C 1
#endif //I2C_MASTER_OLD_VERSION

#define NUM_OW GPIO_PIN_NUM
#define NUM_TMR 7

Expand Down
28 changes: 13 additions & 15 deletions app/platform/platform.c
Original file line number Diff line number Diff line change
Expand Up @@ -735,16 +735,19 @@ uint32_t platform_i2c_setup( unsigned id, uint8_t sda, uint8_t scl, uint32_t spe
platform_gpio_mode(sda, PLATFORM_GPIO_INPUT, PLATFORM_GPIO_PULLUP); // inside this func call platform_pwm_close
platform_gpio_mode(scl, PLATFORM_GPIO_INPUT, PLATFORM_GPIO_PULLUP); // disable gpio interrupt first

i2c_master_gpio_init(sda, scl);
return PLATFORM_I2C_SPEED_SLOW;
return i2c_master_setup(id, sda, scl, speed);
}

bool platform_i2c_configured( unsigned id ){
return i2c_master_configured(id);
}

void platform_i2c_send_start( unsigned id ){
i2c_master_start();
i2c_master_start(id);
}

void platform_i2c_send_stop( unsigned id ){
i2c_master_stop();
i2c_master_stop(id);
}

int platform_i2c_send_address( unsigned id, uint16_t address, int direction ){
Expand All @@ -754,22 +757,17 @@ int platform_i2c_send_address( unsigned id, uint16_t address, int direction ){
PLATFORM_I2C_DIRECTION_RECEIVER == 1 ) ) {
direction = ( direction == PLATFORM_I2C_DIRECTION_TRANSMITTER ) ? 0 : 1;
}

i2c_master_writeByte( (uint8_t) ((address << 1) | direction ));
// Low-level returns nack (0=acked); we return ack (1=acked).
return ! i2c_master_getAck();
return i2c_master_writeByte(id,
(uint8_t) ((address << 1) + (direction == PLATFORM_I2C_DIRECTION_TRANSMITTER ? 0 : 1))
);
}

int platform_i2c_send_byte( unsigned id, uint8_t data ){
i2c_master_writeByte(data);
// Low-level returns nack (0=acked); we return ack (1=acked).
return ! i2c_master_getAck();
int platform_i2c_send_byte(unsigned id, uint8_t data ){
return i2c_master_writeByte(id, data);
}

int platform_i2c_recv_byte( unsigned id, int ack ){
uint8_t r = i2c_master_readByte();
i2c_master_setAck( !ack );
return r;
return i2c_master_readByte(id, ack);
}

// *****************************************************************************
Expand Down
4 changes: 3 additions & 1 deletion app/platform/platform.h
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,8 @@ void platform_sigma_delta_set_target( uint8_t target );
enum
{
PLATFORM_I2C_SPEED_SLOW = 100000,
PLATFORM_I2C_SPEED_FAST = 400000
PLATFORM_I2C_SPEED_FAST = 400000,
PLATFORM_I2C_SPEED_FASTPLUS = 1000000
};

// I2C direction
Expand All @@ -251,6 +252,7 @@ static inline int platform_i2c_exists( unsigned id ) { return id < NUM_I2C; }
static inline int platform_i2c_exists( unsigned id ) { return 0; }
#endif
uint32_t platform_i2c_setup( unsigned id, uint8_t sda, uint8_t scl, uint32_t speed );
bool platform_i2c_configured( unsigned id );
void platform_i2c_send_start( unsigned id );
void platform_i2c_send_stop( unsigned id );
int platform_i2c_send_address( unsigned id, uint16_t address, int direction );
Expand Down
Loading