From 36faa15760643691baa47babd47dd021485443f7 Mon Sep 17 00:00:00 2001 From: Natalia Sorokina Date: Thu, 23 Aug 2018 02:22:46 +0300 Subject: [PATCH 1/7] I2C driver speed-up, i2c.SLOW, i2c.FAST and user-defined speed selection --- app/driver/i2c_master.c | 101 +++++++++++++------------------- app/include/driver/i2c_master.h | 2 +- app/modules/i2c.c | 2 +- app/platform/platform.c | 3 +- docs/modules/i2c.md | 28 ++++++--- 5 files changed, 64 insertions(+), 72 deletions(-) diff --git a/app/driver/i2c_master.c b/app/driver/i2c_master.c index f8de4bc49b..7fb5d14218 100644 --- a/app/driver/i2c_master.c +++ b/app/driver/i2c_master.c @@ -11,6 +11,7 @@ #include "ets_sys.h" #include "osapi.h" #include "gpio.h" +#include "user_interface.h" #include "driver/i2c_master.h" @@ -22,6 +23,25 @@ LOCAL uint8 m_nLastSCL; LOCAL uint8 pinSDA = 2; LOCAL uint8 pinSCL = 15; +LOCAL uint32 i2c_speed = 0; +LOCAL int cycles_delay = 0; + +/****************************************************************************** + * FunctionName : i2c_master_set_DC_delay + * Description : Internal used function - calculate delay for setDC + * Parameters : NONE + * Returns : NONE +*******************************************************************************/ +LOCAL int ICACHE_FLASH_ATTR +i2c_master_set_DC_delay(void) +{ + // [cpu cycles per half SCL clock period] - [cpu cycles that code takes to run] + cycles_delay = system_get_cpu_freq() * 500000 / i2c_speed - 130; + if(cycles_delay < 0){ + cycles_delay = 0; + } +} + /****************************************************************************** * FunctionName : i2c_master_setDC * Description : Internal used function - @@ -33,13 +53,21 @@ LOCAL uint8 pinSCL = 15; LOCAL void ICACHE_FLASH_ATTR i2c_master_setDC(uint8 SDA, uint8 SCL) { - uint8 sclLevel; + uint32 cycles_start; + uint32 cycles_curr; SDA &= 0x01; SCL &= 0x01; m_nLastSDA = SDA; m_nLastSCL = SCL; + if(cycles_delay > 0){ + asm volatile("rsr %0, ccount":"=a"(cycles_start)); //Cycle count register + do{ + asm volatile("rsr %0, ccount":"=a"(cycles_curr)); + } while (cycles_curr - cycles_start < cycles_delay); + } + if ((0 == SDA) && (0 == SCL)) { I2C_MASTER_SDA_LOW_SCL_LOW(); } else if ((0 == SDA) && (1 == SCL)) { @@ -49,10 +77,9 @@ i2c_master_setDC(uint8 SDA, uint8 SCL) } else { I2C_MASTER_SDA_HIGH_SCL_HIGH(); } - if(1 == SCL) { + if(1 == SCL) { //clock stretching do { - sclLevel = GPIO_INPUT_GET(GPIO_ID_PIN(I2C_MASTER_SCL_GPIO)); - } while(sclLevel == 0); + } while(0 == GPIO_INPUT_GET(GPIO_ID_PIN(I2C_MASTER_SCL_GPIO))); } } @@ -83,20 +110,15 @@ i2c_master_init(void) uint8 i; i2c_master_setDC(1, 0); - i2c_master_wait(5); // when SCL = 0, toggle SDA to clear up i2c_master_setDC(0, 0) ; - i2c_master_wait(5); i2c_master_setDC(1, 0) ; - i2c_master_wait(5); // set data_cnt to max value for (i = 0; i < 28; i++) { i2c_master_setDC(1, 0); - i2c_master_wait(5); // sda 1, scl 0 i2c_master_setDC(1, 1); - i2c_master_wait(5); // sda 1, scl 1 } // reset all @@ -119,12 +141,19 @@ uint8 i2c_master_get_pinSCL(){ * Parameters : NONE * Returns : NONE *******************************************************************************/ -void ICACHE_FLASH_ATTR -i2c_master_gpio_init(uint8 sda, uint8 scl) +uint32 ICACHE_FLASH_ATTR +i2c_master_gpio_init(uint8 sda, uint8 scl, uint32 speed) { pinSDA = pin_num[sda]; pinSCL = pin_num[scl]; + if(speed < 1000){ // lowest clock speed + i2c_speed = 1000; + } else{ + i2c_speed = speed; + } + i2c_master_set_DC_delay(); // recalibrate clock + ETS_GPIO_INTR_DISABLE() ; // ETS_INTR_LOCK(); @@ -142,6 +171,7 @@ i2c_master_gpio_init(uint8 sda, uint8 scl) // ETS_INTR_UNLOCK(); i2c_master_init(); + return i2c_speed; } /****************************************************************************** @@ -153,12 +183,10 @@ i2c_master_gpio_init(uint8 sda, uint8 scl) void ICACHE_FLASH_ATTR i2c_master_start(void) { + i2c_master_set_DC_delay(); // recalibrate clock i2c_master_setDC(1, m_nLastSCL); - i2c_master_wait(5); i2c_master_setDC(1, 1); - i2c_master_wait(5); // sda 1, scl 1 i2c_master_setDC(0, 1); - i2c_master_wait(5); // sda 0, scl 1 } /****************************************************************************** @@ -170,14 +198,9 @@ i2c_master_start(void) void ICACHE_FLASH_ATTR i2c_master_stop(void) { - i2c_master_wait(5); - i2c_master_setDC(0, m_nLastSCL); - i2c_master_wait(5); // sda 0 i2c_master_setDC(0, 1); - i2c_master_wait(5); // sda 0, scl 1 i2c_master_setDC(1, 1); - i2c_master_wait(5); // sda 1, scl 1 } /****************************************************************************** @@ -190,15 +213,10 @@ void ICACHE_FLASH_ATTR i2c_master_setAck(uint8 level) { i2c_master_setDC(m_nLastSDA, 0); - i2c_master_wait(5); i2c_master_setDC(level, 0); - i2c_master_wait(5); // sda level, scl 0 i2c_master_setDC(level, 1); - i2c_master_wait(8); // sda level, scl 1 i2c_master_setDC(level, 0); - i2c_master_wait(5); // sda level, scl 0 i2c_master_setDC(1, 0); - i2c_master_wait(5); } /****************************************************************************** @@ -212,17 +230,10 @@ i2c_master_getAck(void) { uint8 retVal; i2c_master_setDC(m_nLastSDA, 0); - i2c_master_wait(5); i2c_master_setDC(1, 0); - i2c_master_wait(5); i2c_master_setDC(1, 1); - i2c_master_wait(5); - retVal = i2c_master_getDC(); - i2c_master_wait(5); i2c_master_setDC(1, 0); - i2c_master_wait(5); - return retVal; } @@ -277,31 +288,17 @@ i2c_master_readByte(void) uint8 retVal = 0; uint8 k, i; - i2c_master_wait(5); i2c_master_setDC(m_nLastSDA, 0); - i2c_master_wait(5); // sda 1, scl 0 for (i = 0; i < 8; i++) { - i2c_master_wait(5); i2c_master_setDC(1, 0); - i2c_master_wait(5); // sda 1, scl 0 i2c_master_setDC(1, 1); - i2c_master_wait(5); // sda 1, scl 1 - k = i2c_master_getDC(); - i2c_master_wait(5); - - if (i == 7) { - i2c_master_wait(3); //// - } - k <<= (7 - i); retVal |= k; } i2c_master_setDC(1, 0); - i2c_master_wait(5); // sda 1, scl 0 - return retVal; } @@ -317,23 +314,9 @@ i2c_master_writeByte(uint8 wrdata) uint8 dat; sint8 i; - i2c_master_wait(5); - - i2c_master_setDC(m_nLastSDA, 0); - i2c_master_wait(5); - for (i = 7; i >= 0; i--) { dat = wrdata >> i; i2c_master_setDC(dat, 0); - i2c_master_wait(5); i2c_master_setDC(dat, 1); - i2c_master_wait(5); - - if (i == 0) { - i2c_master_wait(3); //// - } - - i2c_master_setDC(dat, 0); - i2c_master_wait(5); } } diff --git a/app/include/driver/i2c_master.h b/app/include/driver/i2c_master.h index 18635d5f23..b08213e961 100644 --- a/app/include/driver/i2c_master.h +++ b/app/include/driver/i2c_master.h @@ -53,7 +53,7 @@ #define I2C_MASTER_SDA_LOW_SCL_LOW() \ gpio_output_set(0, 1< Date: Sat, 1 Sep 2018 07:56:30 +0300 Subject: [PATCH 2/7] =?UTF-8?q?-=20Multiple=20buses=20(up=20to=2010)=20wit?= =?UTF-8?q?h=20different=20speeds=20on=20each=20bus=20-=20Standard(Slow,?= =?UTF-8?q?=20100kHz),=20Fast(400kHz)=20and=20FastPlus(1MHz)=20modes=20or?= =?UTF-8?q?=20an=20arbitrary=20clock=20speed=20-=20Sharing=20SDA=20line=20?= =?UTF-8?q?over=20multiple=20I=C2=B2C=20buses=20to=20save=20available=20pi?= =?UTF-8?q?ns=20-=20GPIO16=20pin=20can=20be=20used=20as=20SCL=20pin,=20but?= =?UTF-8?q?=20it=20does=20not=20support=20clock=20stretching=20and=20selec?= =?UTF-8?q?ted=20bus=20will=20be=20limited=20to=20FAST=20speed.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/driver/i2c_master.c | 335 +++++++++++++++++++++----------- app/include/driver/i2c_master.h | 90 ++++----- app/include/user_config.h | 7 + app/modules/i2c.c | 10 +- app/platform/cpu_esp8266.h | 2 +- app/platform/platform.c | 24 ++- app/platform/platform.h | 4 +- docs/modules/i2c.md | 67 +++++-- 8 files changed, 345 insertions(+), 194 deletions(-) diff --git a/app/driver/i2c_master.c b/app/driver/i2c_master.c index 7fb5d14218..22f9451f54 100644 --- a/app/driver/i2c_master.c +++ b/app/driver/i2c_master.c @@ -12,33 +12,30 @@ #include "osapi.h" #include "gpio.h" #include "user_interface.h" - +#include "cpu_esp8266.h" #include "driver/i2c_master.h" - #include "pin_map.h" -LOCAL uint8 m_nLastSDA; -LOCAL uint8 m_nLastSCL; - -LOCAL uint8 pinSDA = 2; -LOCAL uint8 pinSCL = 15; +#define CPU_CYCLES_BETWEEN_DELAYS 80 +#define MIN_SPEED 25000 +#define GPIO16_SCL_MAX_SPEED 400000 +#define GPIO16_RTC_REG_MASK 0xfffffffe -LOCAL uint32 i2c_speed = 0; -LOCAL int cycles_delay = 0; +static i2c_master_state i2c[NUM_I2C]; /****************************************************************************** * FunctionName : i2c_master_set_DC_delay - * Description : Internal used function - calculate delay for setDC - * Parameters : NONE + * Description : Internal used function - calculate delay for i2c_master_setDC + * Parameters : bus id * Returns : NONE *******************************************************************************/ -LOCAL int ICACHE_FLASH_ATTR -i2c_master_set_DC_delay(void) +LOCAL void ICACHE_FLASH_ATTR +i2c_master_set_DC_delay(uint16 id) { // [cpu cycles per half SCL clock period] - [cpu cycles that code takes to run] - cycles_delay = system_get_cpu_freq() * 500000 / i2c_speed - 130; - if(cycles_delay < 0){ - cycles_delay = 0; + i2c[id].cycles_delay = system_get_cpu_freq() * 500000 / i2c[id].speed - CPU_CYCLES_BETWEEN_DELAYS; + if(i2c[id].cycles_delay < 0){ + i2c[id].cycles_delay = 0; } } @@ -46,27 +43,19 @@ i2c_master_set_DC_delay(void) * FunctionName : i2c_master_setDC * Description : Internal used function - * set i2c SDA and SCL bit value for half clk cycle - * Parameters : uint8 SDA - * uint8 SCL + * Parameters : bus id, uint8 SDA, uint8 SCL * Returns : NONE *******************************************************************************/ LOCAL void ICACHE_FLASH_ATTR -i2c_master_setDC(uint8 SDA, uint8 SCL) +i2c_master_setDC(uint16 id, uint8 SDA, uint8 SCL) { - uint32 cycles_start; - uint32 cycles_curr; +#ifdef I2C_MASTER_OLD_VERSION + uint8 sclLevel; SDA &= 0x01; SCL &= 0x01; - m_nLastSDA = SDA; - m_nLastSCL = SCL; - - if(cycles_delay > 0){ - asm volatile("rsr %0, ccount":"=a"(cycles_start)); //Cycle count register - do{ - asm volatile("rsr %0, ccount":"=a"(cycles_curr)); - } while (cycles_curr - cycles_start < cycles_delay); - } + i2c[id].m_nLastSDA = SDA; + i2c[id].m_nLastSCL = SCL; if ((0 == SDA) && (0 == SCL)) { I2C_MASTER_SDA_LOW_SCL_LOW(); @@ -77,86 +66,170 @@ i2c_master_setDC(uint8 SDA, uint8 SCL) } else { I2C_MASTER_SDA_HIGH_SCL_HIGH(); } - if(1 == SCL) { //clock stretching + if(1 == SCL) { do { - } while(0 == GPIO_INPUT_GET(GPIO_ID_PIN(I2C_MASTER_SCL_GPIO))); + sclLevel = GPIO_INPUT_GET(GPIO_ID_PIN(I2C_MASTER_SCL_GPIO)); + } while(sclLevel == 0); } + i2c_master_wait(5); +#else + uint32 cycles_start; + uint32 cycles_curr; + uint32 this_SDA_SCL_set_mask = (SDA << i2c[id].pinSDA) | (SCL << i2c[id].pinSCL); + uint32 this_SDA_SCL_clear_mask = i2c[id].pin_SDA_SCL_mask ^ this_SDA_SCL_set_mask; + i2c[id].m_nLastSDA = SDA; + i2c[id].m_nLastSCL = SCL; + + if(i2c[id].cycles_delay > 0){// + asm volatile("rsr %0, ccount":"=a"(cycles_start)); //Cycle count register + do{ + asm volatile("rsr %0, ccount":"=a"(cycles_curr)); + } while (cycles_curr - cycles_start < i2c[id].cycles_delay); + } + if(16 == i2c[id].pinSCL){ //if GPIO16 + WRITE_PERI_REG(RTC_GPIO_OUT, + (READ_PERI_REG(RTC_GPIO_OUT) & (uint32)GPIO16_RTC_REG_MASK) | (uint32)SCL); + GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, this_SDA_SCL_clear_mask); //SCL is shifted out of mask so no worry + GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, this_SDA_SCL_set_mask); + } + else{ + GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, this_SDA_SCL_clear_mask); + GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, this_SDA_SCL_set_mask); + if(1 == SCL) { //clock stretching + //instead of: while(!((gpio_input_get() >> pinSCL) & 1)) {} + asm volatile("l_wait:" + "l16ui %0, %[gpio_in_addr], 0;" //read gpio state into register %0 + "memw;" //wait for read completion + "bnall %0, %[gpio_SCL_mask], l_wait;" // test if SCL bit not set + ::[gpio_SCL_mask] "r" (i2c[id].pin_SCL_mask), + [gpio_in_addr] "r" (PERIPHS_GPIO_BASEADDR + GPIO_IN_ADDRESS) + ); + } + } + +#endif } /****************************************************************************** * FunctionName : i2c_master_getDC * Description : Internal used function - * get i2c SDA bit value - * Parameters : NONE + * Parameters : bus id * Returns : uint8 - SDA bit value *******************************************************************************/ LOCAL uint8 ICACHE_FLASH_ATTR -i2c_master_getDC(void) +i2c_master_getDC(uint16 id) { uint8 sda_out; +#ifdef I2C_MASTER_OLD_VERSION sda_out = GPIO_INPUT_GET(GPIO_ID_PIN(I2C_MASTER_SDA_GPIO)); +#else + uint32 gpio_in_mask; + //instead of: gpio_in_mask = gpio_input_get(); + asm volatile("l16ui %[gpio_in_mask], %[gpio_in_addr], 0;" //read gpio state + "memw;" //wait for read completion + :[gpio_in_mask] "=r" (gpio_in_mask) + :[gpio_in_addr] "r" (PERIPHS_GPIO_BASEADDR + GPIO_IN_ADDRESS) + ); + sda_out = (gpio_in_mask >> i2c[id].pinSDA) & 1; +#endif return sda_out; } /****************************************************************************** * FunctionName : i2c_master_init * Description : initilize I2C bus to enable i2c operations - * Parameters : NONE + * Parameters : bus id * Returns : NONE *******************************************************************************/ void ICACHE_FLASH_ATTR -i2c_master_init(void) +i2c_master_init(uint16 id) { uint8 i; - i2c_master_setDC(1, 0); + i2c_master_setDC(id, 1, 0); // when SCL = 0, toggle SDA to clear up - i2c_master_setDC(0, 0) ; - i2c_master_setDC(1, 0) ; + i2c_master_setDC(id, 0, 0) ; + i2c_master_setDC(id, 1, 0) ; // set data_cnt to max value for (i = 0; i < 28; i++) { - i2c_master_setDC(1, 0); - i2c_master_setDC(1, 1); + i2c_master_setDC(id, 1, 0); + i2c_master_setDC(id, 1, 1); } // reset all - i2c_master_stop(); + i2c_master_stop(id); return; } -uint8 i2c_master_get_pinSDA(){ - return pinSDA; +/****************************************************************************** + * FunctionName : i2c_master_get_pinSDA + * Description : returns SDA pin number + * Parameters : bus id + * Returns : SDA pin number +*******************************************************************************/ +uint8 ICACHE_FLASH_ATTR +i2c_master_get_pinSDA(uint16 id){ + return i2c[id].pinSDA; +} + +/****************************************************************************** + * FunctionName : i2c_master_get_pinSCL + * Description : returns SCL pin number + * Parameters : bus id + * Returns : SCL pin number +*******************************************************************************/ +uint8 ICACHE_FLASH_ATTR +i2c_master_get_pinSCL(uint16 id){ + return i2c[id].pinSCL; } -uint8 i2c_master_get_pinSCL(){ - return pinSCL; +/****************************************************************************** + * FunctionName : i2c_master_configured + * Description : returns readiness of i2c bus + by checking if speed paramter is set + * Parameters : bus id + * Returns : boolean value, true if configured +*******************************************************************************/ +bool ICACHE_FLASH_ATTR +i2c_master_configured(uint16 id){ + return (i2c[id].speed > 0); } /****************************************************************************** * FunctionName : i2c_master_gpio_init * Description : config SDA and SCL gpio to open-drain output mode, * mux and gpio num defined in i2c_master.h - * Parameters : NONE - * Returns : NONE + * Parameters : bus id + * Returns : configured speed *******************************************************************************/ uint32 ICACHE_FLASH_ATTR -i2c_master_gpio_init(uint8 sda, uint8 scl, uint32 speed) +i2c_master_gpio_init(uint16 id, uint8 sda, uint8 scl, uint32 speed) { - pinSDA = pin_num[sda]; - pinSCL = pin_num[scl]; - - if(speed < 1000){ // lowest clock speed - i2c_speed = 1000; - } else{ - i2c_speed = speed; + i2c[id].pinSDA = pin_num[sda]; + i2c[id].pinSCL = pin_num[scl]; + i2c[id].pin_SDA_mask = (1 << i2c[id].pinSDA); + i2c[id].pin_SCL_mask = (1 << i2c[id].pinSCL); + i2c[id].pin_SDA_SCL_mask = (1 << i2c[id].pinSDA) | (1 << i2c[id].pinSCL); + i2c[id].speed = speed; + + if(i2c[id].speed < MIN_SPEED){ + i2c[id].speed = MIN_SPEED; + } + if(16 == i2c[id].pinSDA & i2c[id].speed > GPIO16_SCL_MAX_SPEED){ + i2c[id].speed = GPIO16_SCL_MAX_SPEED; } - i2c_master_set_DC_delay(); // recalibrate clock + + i2c_master_set_DC_delay(id); // recalibrate clock ETS_GPIO_INTR_DISABLE() ; // ETS_INTR_LOCK(); +#ifdef I2C_MASTER_OLD_VERSION + i2c[id].speed = 100000; + PIN_FUNC_SELECT(I2C_MASTER_SDA_MUX, I2C_MASTER_SDA_FUNC); PIN_FUNC_SELECT(I2C_MASTER_SCL_MUX, I2C_MASTER_SCL_FUNC); @@ -166,87 +239,116 @@ i2c_master_gpio_init(uint8 sda, uint8 scl, uint32 speed) GPIO_REG_WRITE(GPIO_ENABLE_ADDRESS, GPIO_REG_READ(GPIO_ENABLE_ADDRESS) | (1 << I2C_MASTER_SCL_GPIO)); I2C_MASTER_SDA_HIGH_SCL_HIGH(); +#else + if(16 == i2c[id].pinSCL){ //if GPIO16 + WRITE_PERI_REG(PAD_XPD_DCDC_CONF, + (READ_PERI_REG(PAD_XPD_DCDC_CONF) & 0xffffffbc) | (uint32)0x1); // mux configuration for XPD_DCDC to output rtc_gpio0 + WRITE_PERI_REG(RTC_GPIO_CONF, + (READ_PERI_REG(RTC_GPIO_CONF) & (uint32)0xfffffffe) | (uint32)0x0); //mux configuration for out enable + WRITE_PERI_REG(RTC_GPIO_ENABLE, + (READ_PERI_REG(RTC_GPIO_ENABLE) & (uint32)0xfffffffe) | (uint32)0x1); //out enable + } + else{ + PIN_FUNC_SELECT(pin_mux[scl], pin_func[scl]); + GPIO_REG_WRITE(GPIO_PIN_ADDR(GPIO_ID_PIN(i2c[id].pinSCL)), + GPIO_REG_READ(GPIO_PIN_ADDR(GPIO_ID_PIN(i2c[id].pinSCL))) | GPIO_PIN_PAD_DRIVER_SET(GPIO_PAD_DRIVER_ENABLE)); //open drain; + GPIO_REG_WRITE(GPIO_ENABLE_ADDRESS, GPIO_REG_READ(GPIO_ENABLE_ADDRESS) | i2c[id].pin_SCL_mask); + gpio_output_set(i2c[id].pin_SCL_mask, 0, i2c[id].pin_SCL_mask, 0); + } + + PIN_FUNC_SELECT(pin_mux[sda], pin_func[sda]); + GPIO_REG_WRITE(GPIO_PIN_ADDR(GPIO_ID_PIN(i2c[id].pinSDA)), + GPIO_REG_READ(GPIO_PIN_ADDR(GPIO_ID_PIN(i2c[id].pinSDA))) | GPIO_PIN_PAD_DRIVER_SET(GPIO_PAD_DRIVER_ENABLE)); //open drain; + GPIO_REG_WRITE(GPIO_ENABLE_ADDRESS, GPIO_REG_READ(GPIO_ENABLE_ADDRESS) | i2c[id].pin_SDA_mask); + gpio_output_set(i2c[id].pin_SDA_mask, 0, i2c[id].pin_SDA_mask, 0); +#endif ETS_GPIO_INTR_ENABLE() ; // ETS_INTR_UNLOCK(); - i2c_master_init(); - return i2c_speed; + i2c_master_init(id); + return i2c[id].speed; } /****************************************************************************** * FunctionName : i2c_master_start * Description : set i2c to send state - * Parameters : NONE + * Parameters : bus id * Returns : NONE *******************************************************************************/ void ICACHE_FLASH_ATTR -i2c_master_start(void) +i2c_master_start(uint16 id) { - i2c_master_set_DC_delay(); // recalibrate clock - i2c_master_setDC(1, m_nLastSCL); - i2c_master_setDC(1, 1); - i2c_master_setDC(0, 1); + i2c_master_set_DC_delay(id); // recalibrate clock + i2c_master_setDC(id, 1, i2c[id].m_nLastSCL); + i2c_master_setDC(id, 1, 1); + i2c_master_setDC(id, 0, 1); } /****************************************************************************** * FunctionName : i2c_master_stop * Description : set i2c to stop sending state - * Parameters : NONE + * Parameters : bus id * Returns : NONE *******************************************************************************/ void ICACHE_FLASH_ATTR -i2c_master_stop(void) +i2c_master_stop(uint16 id) { - i2c_master_setDC(0, m_nLastSCL); - i2c_master_setDC(0, 1); - i2c_master_setDC(1, 1); +#ifdef I2C_MASTER_OLD_VERSION + i2c_master_wait(5); +#endif + i2c_master_setDC(id, 0, i2c[id].m_nLastSCL); + i2c_master_setDC(id, 0, 1); + i2c_master_setDC(id, 1, 1); } /****************************************************************************** * FunctionName : i2c_master_setAck * Description : set ack to i2c bus as level value - * Parameters : uint8 level - 0 or 1 + * Parameters : bus id, uint8 level - 0 or 1 * Returns : NONE *******************************************************************************/ void ICACHE_FLASH_ATTR -i2c_master_setAck(uint8 level) +i2c_master_setAck(uint16 id, uint8 level) { - i2c_master_setDC(m_nLastSDA, 0); - i2c_master_setDC(level, 0); - i2c_master_setDC(level, 1); - i2c_master_setDC(level, 0); - i2c_master_setDC(1, 0); + i2c_master_setDC(id, i2c[id].m_nLastSDA, 0); + i2c_master_setDC(id, level, 0); + i2c_master_setDC(id, level, 1); +#ifdef I2C_MASTER_OLD_VERSION + i2c_master_wait(3); +#endif + i2c_master_setDC(id, level, 0); + i2c_master_setDC(id, 1, 0); } /****************************************************************************** * FunctionName : i2c_master_getAck * Description : confirm if peer send ack - * Parameters : NONE + * Parameters : bus id * Returns : uint8 - ack value, 0 or 1 *******************************************************************************/ uint8 ICACHE_FLASH_ATTR -i2c_master_getAck(void) +i2c_master_getAck(uint16 id) { uint8 retVal; - i2c_master_setDC(m_nLastSDA, 0); - i2c_master_setDC(1, 0); - i2c_master_setDC(1, 1); - retVal = i2c_master_getDC(); - i2c_master_setDC(1, 0); + i2c_master_setDC(id, i2c[id].m_nLastSDA, 0); + i2c_master_setDC(id, 1, 0); + i2c_master_setDC(id, 1, 1); + retVal = i2c_master_getDC(id); + i2c_master_setDC(id, 1, 0); return retVal; } /****************************************************************************** * FunctionName : i2c_master_checkAck * Description : get dev response -* Parameters : NONE +* Parameters : bus id * Returns : true : get ack ; false : get nack *******************************************************************************/ bool ICACHE_FLASH_ATTR -i2c_master_checkAck(void) +i2c_master_checkAck(uint16 id) { - if(i2c_master_getAck()){ + if(i2c_master_getAck(id)){ return FALSE; }else{ return TRUE; @@ -256,67 +358,80 @@ i2c_master_checkAck(void) /****************************************************************************** * FunctionName : i2c_master_send_ack * Description : response ack -* Parameters : NONE +* Parameters : bus id * Returns : NONE *******************************************************************************/ void ICACHE_FLASH_ATTR -i2c_master_send_ack(void) +i2c_master_send_ack(uint16 id) { - i2c_master_setAck(0x0); + i2c_master_setAck(id, 0x0); } /****************************************************************************** * FunctionName : i2c_master_send_nack * Description : response nack -* Parameters : NONE +* Parameters : bus id * Returns : NONE *******************************************************************************/ void ICACHE_FLASH_ATTR -i2c_master_send_nack(void) +i2c_master_send_nack(uint16 id) { - i2c_master_setAck(0x1); + i2c_master_setAck(id, 0x1); } /****************************************************************************** * FunctionName : i2c_master_readByte * Description : read Byte from i2c bus - * Parameters : NONE + * Parameters : bus id * Returns : uint8 - readed value *******************************************************************************/ uint8 ICACHE_FLASH_ATTR -i2c_master_readByte(void) +i2c_master_readByte(uint16 id) { uint8 retVal = 0; - uint8 k, i; - - i2c_master_setDC(m_nLastSDA, 0); + uint8 k; + sint8 i; - for (i = 0; i < 8; i++) { - i2c_master_setDC(1, 0); - i2c_master_setDC(1, 1); - k = i2c_master_getDC(); - k <<= (7 - i); +#ifdef I2C_MASTER_OLD_VERSION + i2c_master_wait(5); +#endif + i2c_master_setDC(id, i2c[id].m_nLastSDA, 0); + for (i = 7; i >= 0; i--) { + i2c_master_setDC(id, 1, 0); + i2c_master_setDC(id, 1, 1); + k = i2c_master_getDC(id); + k <<= i; retVal |= k; } - - i2c_master_setDC(1, 0); +#ifdef I2C_MASTER_OLD_VERSION + i2c_master_wait(3); +#endif + i2c_master_setDC(id, 1, 0); return retVal; } /****************************************************************************** * FunctionName : i2c_master_writeByte * Description : write wrdata value(one byte) into i2c - * Parameters : uint8 wrdata - write value + * Parameters : bus id, uint8 wrdata - write value * Returns : NONE *******************************************************************************/ void ICACHE_FLASH_ATTR -i2c_master_writeByte(uint8 wrdata) +i2c_master_writeByte(uint16 id, uint8 wrdata) { uint8 dat; sint8 i; +#ifdef I2C_MASTER_OLD_VERSION + i2c_master_wait(3); +#endif + i2c_master_setDC(id, i2c[id].m_nLastSDA, 0); for (i = 7; i >= 0; i--) { - dat = wrdata >> i; - i2c_master_setDC(dat, 0); - i2c_master_setDC(dat, 1); + dat = (wrdata >> i) & 1; + i2c_master_setDC(id, dat, 0); + i2c_master_setDC(id, dat, 1); } +#ifdef I2C_MASTER_OLD_VERSION + i2c_master_wait(3); +#endif + i2c_master_setDC(id, dat, 0); } diff --git a/app/include/driver/i2c_master.h b/app/include/driver/i2c_master.h index b08213e961..d15e4ad926 100644 --- a/app/include/driver/i2c_master.h +++ b/app/include/driver/i2c_master.h @@ -1,46 +1,17 @@ #ifndef __I2C_MASTER_H__ #define __I2C_MASTER_H__ +#include "user_config.h" + +#ifdef I2C_MASTER_OLD_VERSION + #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_GPIO (i2c[id].pinSDA) +#define I2C_MASTER_SCL_GPIO (i2c[id].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< Date: Thu, 11 Oct 2018 09:58:09 +0300 Subject: [PATCH 3/7] Dynamic memory allocation, error checks, simplification, timing tweaks. --- app/driver/i2c_master.c | 409 +++++++++++++++++++++----------- app/include/driver/i2c_master.h | 39 --- app/include/user_config.h | 11 +- app/modules/i2c.c | 9 +- app/platform/platform.c | 5 +- docs/modules/i2c.md | 54 ++++- 6 files changed, 327 insertions(+), 200 deletions(-) diff --git a/app/driver/i2c_master.c b/app/driver/i2c_master.c index 22f9451f54..47ce16ad45 100644 --- a/app/driver/i2c_master.c +++ b/app/driver/i2c_master.c @@ -1,27 +1,70 @@ -/****************************************************************************** - * Copyright 2013-2014 Espressif Systems (Wuxi) +/* + * ESPRESSIF MIT License * - * FileName: i2c_master.c + * Copyright (c) 2016 * - * Description: i2c master API + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: * - * Modification history: - * 2014/3/12, v1.0 create this file. -*******************************************************************************/ + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * + * Rework of original driver: Natalia Sorokina , 2018 + */ + +#include "../libc/c_stdlib.h" #include "ets_sys.h" #include "osapi.h" #include "gpio.h" #include "user_interface.h" + #include "cpu_esp8266.h" -#include "driver/i2c_master.h" #include "pin_map.h" +#include "user_config.h" + +#include "driver/i2c_master.h" + +//used only by old driver +#define i2c_master_wait os_delay_us + +// enable use GPIO16 (D0) pin as SCL line. ~450 kHz maximum frequency +#ifdef I2C_MASTER_GPIO16_ENABLED +#define IS_PIN16(n) ((n)==16) #define CPU_CYCLES_BETWEEN_DELAYS 80 -#define MIN_SPEED 25000 -#define GPIO16_SCL_MAX_SPEED 400000 -#define GPIO16_RTC_REG_MASK 0xfffffffe +#define CPU_CYCLES_GPIO16 90 +#else +#define IS_PIN16(n) (0) //removes GPIO16-related code during compile +#define CPU_CYCLES_BETWEEN_DELAYS 74 +#endif //I2C_MASTER_GPIO16_ENABLED -static i2c_master_state i2c[NUM_I2C]; +#define MIN_SPEED 25000 +#define MAX_NUMBER_OF_I2C NUM_I2C + +typedef struct { + uint8 last_SDA; + uint8 last_SCL; + uint8 pin_SDA; + uint8 pin_SCL; + uint32 pin_SDA_SCL_mask; + uint32 pin_SDA_mask; + uint32 pin_SCL_mask; + uint32 speed; + sint16 cycles_delay; +} i2c_master_state_t; +static i2c_master_state_t *i2c[MAX_NUMBER_OF_I2C]; /****************************************************************************** * FunctionName : i2c_master_set_DC_delay @@ -33,16 +76,60 @@ LOCAL void ICACHE_FLASH_ATTR i2c_master_set_DC_delay(uint16 id) { // [cpu cycles per half SCL clock period] - [cpu cycles that code takes to run] - i2c[id].cycles_delay = system_get_cpu_freq() * 500000 / i2c[id].speed - CPU_CYCLES_BETWEEN_DELAYS; - if(i2c[id].cycles_delay < 0){ - i2c[id].cycles_delay = 0; + i2c[id]->cycles_delay = system_get_cpu_freq() * 500000 / i2c[id]->speed - CPU_CYCLES_BETWEEN_DELAYS; + #ifdef I2C_MASTER_GPIO16_ENABLED + if(IS_PIN16(i2c[id]->pin_SCL)){ //if GPIO16 + i2c[id]->cycles_delay -= CPU_CYCLES_GPIO16; //decrease delay } + #endif //I2C_MASTER_GPIO16_ENABLED + if(i2c[id]->cycles_delay < 0){ + i2c[id]->cycles_delay = 0; + } +} +/****************************************************************************** + * FunctionName : i2c_master_wait_cpu_cycles + * Description : Internal used function - wait for given count of cpu cycles + * Parameters : sint16 cycles_delay + * Returns : NONE +*******************************************************************************/ +static inline void i2c_master_wait_cpu_cycles(sint16 cycles_delay) +{ + uint32 cycles_start; + uint32 cycles_curr; + // uses special 'ccount' register which is increased every CPU cycle + // to make precise delay + asm volatile("rsr %0, ccount":"=a"(cycles_start)); + do{ + asm volatile("rsr %0, ccount":"=a"(cycles_curr)); + } while (cycles_curr - cycles_start < cycles_delay); +} + +/****************************************************************************** + * FunctionName : i2c_master_wait_gpio_SCL_high + * Description : Internal used function - wait until SCL line in a high state + (slave device may hold SCL line low until it is ready to proceed) + * Parameters : bus id + * Returns : NONE +*******************************************************************************/ +static inline void i2c_master_wait_gpio_SCL_high(uint16 id) +{ + // retrieves bitmask of all GPIOs from memory-mapped gpio register and exits if SCL bit is set + // equivalent, but slow variant: + // while(!(READ_PERI_REG(PERIPHS_GPIO_BASEADDR + GPIO_IN_ADDRESS) & i2c[id]->pin_SCL_mask)) {}; + // even slower: while (!(gpio_input_get() & i2c[id]->pin_SCL_mask)) {}; + asm volatile("l_wait:" + "l16ui %0, %[gpio_in_addr], 0;" //read gpio state into register %0 + "memw;" //wait for read completion + "bnall %0, %[gpio_SCL_mask], l_wait;" // test if SCL bit not set + ::[gpio_SCL_mask] "r" (i2c[id]->pin_SCL_mask), + [gpio_in_addr] "r" (PERIPHS_GPIO_BASEADDR + GPIO_IN_ADDRESS) + ); } /****************************************************************************** * FunctionName : i2c_master_setDC * Description : Internal used function - - * set i2c SDA and SCL bit value for half clk cycle + * set i2c SDA and SCL bit value for half clock cycle * Parameters : bus id, uint8 SDA, uint8 SCL * Returns : NONE *******************************************************************************/ @@ -50,60 +137,61 @@ LOCAL void ICACHE_FLASH_ATTR i2c_master_setDC(uint16 id, uint8 SDA, uint8 SCL) { #ifdef I2C_MASTER_OLD_VERSION + // intentionally not optimized to keep timings of old version accurate uint8 sclLevel; SDA &= 0x01; SCL &= 0x01; - i2c[id].m_nLastSDA = SDA; - i2c[id].m_nLastSCL = SCL; + i2c[id]->last_SDA = SDA; + i2c[id]->last_SCL = SCL; if ((0 == SDA) && (0 == SCL)) { - I2C_MASTER_SDA_LOW_SCL_LOW(); + gpio_output_set(0, 1<pin_SDA | 1<pin_SCL, 1<pin_SDA | 1<pin_SCL, 0); } else if ((0 == SDA) && (1 == SCL)) { - I2C_MASTER_SDA_LOW_SCL_HIGH(); + gpio_output_set(1<pin_SCL, 1<pin_SDA, 1<pin_SDA | 1<pin_SCL, 0); } else if ((1 == SDA) && (0 == SCL)) { - I2C_MASTER_SDA_HIGH_SCL_LOW(); + gpio_output_set(1<pin_SDA, 1<pin_SCL, 1<pin_SDA | 1<pin_SCL, 0); } else { - I2C_MASTER_SDA_HIGH_SCL_HIGH(); + gpio_output_set(1<pin_SDA | 1<pin_SCL, 0, 1<pin_SDA | 1<pin_SCL, 0); } if(1 == SCL) { do { - sclLevel = GPIO_INPUT_GET(GPIO_ID_PIN(I2C_MASTER_SCL_GPIO)); - } while(sclLevel == 0); + sclLevel = GPIO_INPUT_GET(GPIO_ID_PIN(i2c[id]->pin_SCL)); + } while(0 == sclLevel); } i2c_master_wait(5); #else - uint32 cycles_start; - uint32 cycles_curr; - uint32 this_SDA_SCL_set_mask = (SDA << i2c[id].pinSDA) | (SCL << i2c[id].pinSCL); - uint32 this_SDA_SCL_clear_mask = i2c[id].pin_SDA_SCL_mask ^ this_SDA_SCL_set_mask; - i2c[id].m_nLastSDA = SDA; - i2c[id].m_nLastSCL = SCL; - - if(i2c[id].cycles_delay > 0){// - asm volatile("rsr %0, ccount":"=a"(cycles_start)); //Cycle count register - do{ - asm volatile("rsr %0, ccount":"=a"(cycles_curr)); - } while (cycles_curr - cycles_start < i2c[id].cycles_delay); + uint32 this_SDA_SCL_set_mask; + uint32 this_SDA_SCL_clear_mask; + i2c[id]->last_SDA = SDA; + i2c[id]->last_SCL = SCL; + + if(i2c[id]->cycles_delay > 0){ + i2c_master_wait_cpu_cycles(i2c[id]->cycles_delay); } - if(16 == i2c[id].pinSCL){ //if GPIO16 - WRITE_PERI_REG(RTC_GPIO_OUT, - (READ_PERI_REG(RTC_GPIO_OUT) & (uint32)GPIO16_RTC_REG_MASK) | (uint32)SCL); - GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, this_SDA_SCL_clear_mask); //SCL is shifted out of mask so no worry - GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, this_SDA_SCL_set_mask); + if (IS_PIN16(i2c[id]->pin_SCL)){ //GPIO16 wired differently, it has it's own register address + WRITE_PERI_REG(RTC_GPIO_OUT, SCL); // write SCL value + if(1 == SDA){ + GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, i2c[id]->pin_SDA_mask); //SDA = 1 + }else{ + GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, i2c[id]->pin_SDA_mask); // SDA = 0 + } + if(1 == SCL){ //clock stretching, GPIO16 version + while(!(READ_PERI_REG(RTC_GPIO_IN_DATA) & 1)) {}; //read SCL value until SCL goes high + }else{ + // dummy read operation and empty CPU cycles to maintain equal times for low and high state + READ_PERI_REG(RTC_GPIO_IN_DATA) & 1; asm volatile("nop;nop;nop;nop;"); + } } else{ + this_SDA_SCL_set_mask = (SDA << i2c[id]->pin_SDA) | (SCL << i2c[id]->pin_SCL); + this_SDA_SCL_clear_mask = i2c[id]->pin_SDA_SCL_mask ^ this_SDA_SCL_set_mask; GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, this_SDA_SCL_clear_mask); GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, this_SDA_SCL_set_mask); if(1 == SCL) { //clock stretching - //instead of: while(!((gpio_input_get() >> pinSCL) & 1)) {} - asm volatile("l_wait:" - "l16ui %0, %[gpio_in_addr], 0;" //read gpio state into register %0 - "memw;" //wait for read completion - "bnall %0, %[gpio_SCL_mask], l_wait;" // test if SCL bit not set - ::[gpio_SCL_mask] "r" (i2c[id].pin_SCL_mask), - [gpio_in_addr] "r" (PERIPHS_GPIO_BASEADDR + GPIO_IN_ADDRESS) - ); + i2c_master_wait_gpio_SCL_high(id); + }else{ + asm volatile("nop;nop;nop;"); // empty CPU cycles to maintain equal times for low and high state } } @@ -117,12 +205,12 @@ i2c_master_setDC(uint16 id, uint8 SDA, uint8 SCL) * Parameters : bus id * Returns : uint8 - SDA bit value *******************************************************************************/ -LOCAL uint8 ICACHE_FLASH_ATTR +static inline uint8 ICACHE_FLASH_ATTR i2c_master_getDC(uint16 id) { uint8 sda_out; #ifdef I2C_MASTER_OLD_VERSION - sda_out = GPIO_INPUT_GET(GPIO_ID_PIN(I2C_MASTER_SDA_GPIO)); + sda_out = GPIO_INPUT_GET(GPIO_ID_PIN(i2c[id]->pin_SDA)); #else uint32 gpio_in_mask; //instead of: gpio_in_mask = gpio_input_get(); @@ -131,14 +219,59 @@ i2c_master_getDC(uint16 id) :[gpio_in_mask] "=r" (gpio_in_mask) :[gpio_in_addr] "r" (PERIPHS_GPIO_BASEADDR + GPIO_IN_ADDRESS) ); - sda_out = (gpio_in_mask >> i2c[id].pinSDA) & 1; + sda_out = (gpio_in_mask >> i2c[id]->pin_SDA) & 1; #endif return sda_out; } +/****************************************************************************** + * FunctionName : i2c_master_get_pin_SDA + * Description : returns SDA pin number + * Parameters : bus id + * Returns : SDA pin number +*******************************************************************************/ +uint8 ICACHE_FLASH_ATTR +i2c_master_get_pin_SDA(uint16 id){ + return (NULL == i2c[id]) ? 0 : i2c[id]->pin_SDA; +} + +/****************************************************************************** + * FunctionName : i2c_master_get_pin_SCL + * Description : returns SCL pin number + * Parameters : bus id + * Returns : SCL pin number +*******************************************************************************/ +uint8 ICACHE_FLASH_ATTR +i2c_master_get_pin_SCL(uint16 id){ + return (NULL == i2c[id]) ? 0 : i2c[id]->pin_SCL; +} + +/****************************************************************************** + * FunctionName : i2c_master_get_speed + * Description : returns configured bus speed + * Parameters : bus id + * Returns : i2c speed +*******************************************************************************/ +uint16 ICACHE_FLASH_ATTR +i2c_master_get_speed(uint16 id){ + return (NULL == i2c[id]) ? 0 : i2c[id]->speed; +} + +/****************************************************************************** + * FunctionName : i2c_master_configured + * Description : checks if i2c bus is configured + * Parameters : bus id + * Returns : boolean value, true if configured +*******************************************************************************/ +bool ICACHE_FLASH_ATTR +i2c_master_configured(uint16 id){ + return !(NULL == i2c[id]); +} + /****************************************************************************** * FunctionName : i2c_master_init - * Description : initilize I2C bus to enable i2c operations + * Description : initialize I2C bus to enable i2c operations + (reset state of all slave devices) * Parameters : bus id * Returns : NONE *******************************************************************************/ @@ -164,110 +297,72 @@ i2c_master_init(uint16 id) return; } -/****************************************************************************** - * FunctionName : i2c_master_get_pinSDA - * Description : returns SDA pin number - * Parameters : bus id - * Returns : SDA pin number -*******************************************************************************/ -uint8 ICACHE_FLASH_ATTR -i2c_master_get_pinSDA(uint16 id){ - return i2c[id].pinSDA; -} - -/****************************************************************************** - * FunctionName : i2c_master_get_pinSCL - * Description : returns SCL pin number - * Parameters : bus id - * Returns : SCL pin number -*******************************************************************************/ -uint8 ICACHE_FLASH_ATTR -i2c_master_get_pinSCL(uint16 id){ - return i2c[id].pinSCL; -} - -/****************************************************************************** - * FunctionName : i2c_master_configured - * Description : returns readiness of i2c bus - by checking if speed paramter is set - * Parameters : bus id - * Returns : boolean value, true if configured -*******************************************************************************/ -bool ICACHE_FLASH_ATTR -i2c_master_configured(uint16 id){ - return (i2c[id].speed > 0); -} - /****************************************************************************** * FunctionName : i2c_master_gpio_init - * Description : config SDA and SCL gpio to open-drain output mode, - * mux and gpio num defined in i2c_master.h + * Description : Initializes and configures the driver on given bus ID * Parameters : bus id * Returns : configured speed *******************************************************************************/ uint32 ICACHE_FLASH_ATTR i2c_master_gpio_init(uint16 id, uint8 sda, uint8 scl, uint32 speed) { - i2c[id].pinSDA = pin_num[sda]; - i2c[id].pinSCL = pin_num[scl]; - i2c[id].pin_SDA_mask = (1 << i2c[id].pinSDA); - i2c[id].pin_SCL_mask = (1 << i2c[id].pinSCL); - i2c[id].pin_SDA_SCL_mask = (1 << i2c[id].pinSDA) | (1 << i2c[id].pinSCL); - i2c[id].speed = speed; - - if(i2c[id].speed < MIN_SPEED){ - i2c[id].speed = MIN_SPEED; + if(NULL == i2c[id]){ + i2c[id] = (i2c_master_state_t*) c_malloc(sizeof(i2c_master_state_t)); } - if(16 == i2c[id].pinSDA & i2c[id].speed > GPIO16_SCL_MAX_SPEED){ - i2c[id].speed = GPIO16_SCL_MAX_SPEED; + if(NULL == i2c[id]){ // if malloc failed + return 0; + } + i2c[id]->last_SDA = 1; //default idle state + i2c[id]->last_SCL = 1; + i2c[id]->pin_SDA = pin_num[sda]; + i2c[id]->pin_SCL = pin_num[scl]; + i2c[id]->pin_SDA_mask = 1 << i2c[id]->pin_SDA; + i2c[id]->pin_SCL_mask = 1 << i2c[id]->pin_SCL; + i2c[id]->pin_SDA_SCL_mask = i2c[id]->pin_SDA_mask | i2c[id]->pin_SCL_mask; + i2c[id]->speed = speed; + i2c[id]->cycles_delay = 0; + + if(i2c[id]->speed < MIN_SPEED){ + i2c[id]->speed = MIN_SPEED; } - - i2c_master_set_DC_delay(id); // recalibrate clock - - ETS_GPIO_INTR_DISABLE() ; -// ETS_INTR_LOCK(); #ifdef I2C_MASTER_OLD_VERSION - i2c[id].speed = 100000; + i2c[id]->speed = 100000; //dummy speed for backward compatibility +#endif - PIN_FUNC_SELECT(I2C_MASTER_SDA_MUX, I2C_MASTER_SDA_FUNC); - PIN_FUNC_SELECT(I2C_MASTER_SCL_MUX, I2C_MASTER_SCL_FUNC); + i2c_master_set_DC_delay(id); // recalibrate clock - GPIO_REG_WRITE(GPIO_PIN_ADDR(GPIO_ID_PIN(I2C_MASTER_SDA_GPIO)), GPIO_REG_READ(GPIO_PIN_ADDR(GPIO_ID_PIN(I2C_MASTER_SDA_GPIO))) | GPIO_PIN_PAD_DRIVER_SET(GPIO_PAD_DRIVER_ENABLE)); //open drain; - GPIO_REG_WRITE(GPIO_ENABLE_ADDRESS, GPIO_REG_READ(GPIO_ENABLE_ADDRESS) | (1 << I2C_MASTER_SDA_GPIO)); - GPIO_REG_WRITE(GPIO_PIN_ADDR(GPIO_ID_PIN(I2C_MASTER_SCL_GPIO)), GPIO_REG_READ(GPIO_PIN_ADDR(GPIO_ID_PIN(I2C_MASTER_SCL_GPIO))) | GPIO_PIN_PAD_DRIVER_SET(GPIO_PAD_DRIVER_ENABLE)); //open drain; - GPIO_REG_WRITE(GPIO_ENABLE_ADDRESS, GPIO_REG_READ(GPIO_ENABLE_ADDRESS) | (1 << I2C_MASTER_SCL_GPIO)); + ETS_GPIO_INTR_DISABLE(); //disable gpio interrupts - I2C_MASTER_SDA_HIGH_SCL_HIGH(); -#else - if(16 == i2c[id].pinSCL){ //if GPIO16 + if (IS_PIN16(i2c[id]->pin_SCL)){ //if GPIO16 + //SET_PERI_REG_MASK(PAD_XPD_DCDC_CONF, 0x1); // select function RTC_GPIO0 for pin XPD_DCDC WRITE_PERI_REG(PAD_XPD_DCDC_CONF, - (READ_PERI_REG(PAD_XPD_DCDC_CONF) & 0xffffffbc) | (uint32)0x1); // mux configuration for XPD_DCDC to output rtc_gpio0 + (READ_PERI_REG(PAD_XPD_DCDC_CONF) & 0xffffffbc) | (uint32)0x1); // mux configuration for XPD_DCDC to output rtc_gpio0 + //CLEAR_PERI_REG_MASK(RTC_GPIO_CONF, 0x1); //mux configuration for out enable WRITE_PERI_REG(RTC_GPIO_CONF, - (READ_PERI_REG(RTC_GPIO_CONF) & (uint32)0xfffffffe) | (uint32)0x0); //mux configuration for out enable + (READ_PERI_REG(RTC_GPIO_CONF) & (uint32)0xfffffffe) | (uint32)0x0); //mux configuration for out enable + //SET_PERI_REG_MASK(RTC_GPIO_ENABLE, 0x1); //out enable WRITE_PERI_REG(RTC_GPIO_ENABLE, - (READ_PERI_REG(RTC_GPIO_ENABLE) & (uint32)0xfffffffe) | (uint32)0x1); //out enable + (READ_PERI_REG(RTC_GPIO_ENABLE) & (uint32)0xfffffffe) | (uint32)0x1); //out enable + //SET_PERI_REG_MASK(RTC_GPIO_OUT, 0x1); // set SCL high + WRITE_PERI_REG(RTC_GPIO_OUT, + (READ_PERI_REG(RTC_GPIO_OUT) & (uint32)0xfffffffe) | (uint32)0x1); //set high } else{ PIN_FUNC_SELECT(pin_mux[scl], pin_func[scl]); - GPIO_REG_WRITE(GPIO_PIN_ADDR(GPIO_ID_PIN(i2c[id].pinSCL)), - GPIO_REG_READ(GPIO_PIN_ADDR(GPIO_ID_PIN(i2c[id].pinSCL))) | GPIO_PIN_PAD_DRIVER_SET(GPIO_PAD_DRIVER_ENABLE)); //open drain; - GPIO_REG_WRITE(GPIO_ENABLE_ADDRESS, GPIO_REG_READ(GPIO_ENABLE_ADDRESS) | i2c[id].pin_SCL_mask); - gpio_output_set(i2c[id].pin_SCL_mask, 0, i2c[id].pin_SCL_mask, 0); + SET_PERI_REG_MASK(PERIPHS_GPIO_BASEADDR + GPIO_PIN_ADDR(GPIO_ID_PIN(i2c[id]->pin_SCL)), + GPIO_PIN_PAD_DRIVER_SET(GPIO_PAD_DRIVER_ENABLE)); //open drain + gpio_output_set(i2c[id]->pin_SCL_mask, 0, i2c[id]->pin_SCL_mask, 0); //enable and set high } - PIN_FUNC_SELECT(pin_mux[sda], pin_func[sda]); - GPIO_REG_WRITE(GPIO_PIN_ADDR(GPIO_ID_PIN(i2c[id].pinSDA)), - GPIO_REG_READ(GPIO_PIN_ADDR(GPIO_ID_PIN(i2c[id].pinSDA))) | GPIO_PIN_PAD_DRIVER_SET(GPIO_PAD_DRIVER_ENABLE)); //open drain; - GPIO_REG_WRITE(GPIO_ENABLE_ADDRESS, GPIO_REG_READ(GPIO_ENABLE_ADDRESS) | i2c[id].pin_SDA_mask); - gpio_output_set(i2c[id].pin_SDA_mask, 0, i2c[id].pin_SDA_mask, 0); -#endif + SET_PERI_REG_MASK(PERIPHS_GPIO_BASEADDR + GPIO_PIN_ADDR(GPIO_ID_PIN(i2c[id]->pin_SDA)), + GPIO_PIN_PAD_DRIVER_SET(GPIO_PAD_DRIVER_ENABLE)); //open drain + gpio_output_set(i2c[id]->pin_SDA_mask, 0, i2c[id]->pin_SDA_mask, 0); //enable and set high - ETS_GPIO_INTR_ENABLE() ; -// ETS_INTR_UNLOCK(); + ETS_GPIO_INTR_ENABLE(); //enable gpio interrupts i2c_master_init(id); - return i2c[id].speed; + return i2c[id]->speed; } /****************************************************************************** @@ -280,7 +375,7 @@ void ICACHE_FLASH_ATTR i2c_master_start(uint16 id) { i2c_master_set_DC_delay(id); // recalibrate clock - i2c_master_setDC(id, 1, i2c[id].m_nLastSCL); + i2c_master_setDC(id, 1, i2c[id]->last_SCL); i2c_master_setDC(id, 1, 1); i2c_master_setDC(id, 0, 1); } @@ -297,7 +392,7 @@ i2c_master_stop(uint16 id) #ifdef I2C_MASTER_OLD_VERSION i2c_master_wait(5); #endif - i2c_master_setDC(id, 0, i2c[id].m_nLastSCL); + i2c_master_setDC(id, 0, i2c[id]->last_SCL); i2c_master_setDC(id, 0, 1); i2c_master_setDC(id, 1, 1); } @@ -311,7 +406,7 @@ i2c_master_stop(uint16 id) void ICACHE_FLASH_ATTR i2c_master_setAck(uint16 id, uint8 level) { - i2c_master_setDC(id, i2c[id].m_nLastSDA, 0); + i2c_master_setDC(id, i2c[id]->last_SDA, 0); i2c_master_setDC(id, level, 0); i2c_master_setDC(id, level, 1); #ifdef I2C_MASTER_OLD_VERSION @@ -331,7 +426,7 @@ uint8 ICACHE_FLASH_ATTR i2c_master_getAck(uint16 id) { uint8 retVal; - i2c_master_setDC(id, i2c[id].m_nLastSDA, 0); + i2c_master_setDC(id, i2c[id]->last_SDA, 0); i2c_master_setDC(id, 1, 0); i2c_master_setDC(id, 1, 1); retVal = i2c_master_getDC(id); @@ -393,8 +488,7 @@ i2c_master_readByte(uint16 id) #ifdef I2C_MASTER_OLD_VERSION i2c_master_wait(5); -#endif - i2c_master_setDC(id, i2c[id].m_nLastSDA, 0); + i2c_master_setDC(id, i2c[id]->last_SDA, 0); for (i = 7; i >= 0; i--) { i2c_master_setDC(id, 1, 0); i2c_master_setDC(id, 1, 1); @@ -402,10 +496,19 @@ i2c_master_readByte(uint16 id) k <<= i; retVal |= k; } -#ifdef I2C_MASTER_OLD_VERSION i2c_master_wait(3); -#endif i2c_master_setDC(id, 1, 0); +#else + i2c_master_setDC(id, i2c[id]->last_SDA, 0); + i2c_master_setDC(id, 1, 0); + for (i = 7; i >= 0; i--) { + i2c_master_setDC(id, 1, 1); + k = i2c_master_getDC(id); + i2c_master_setDC(id, 1, 0); + k <<= i; + retVal |= k; + } +#endif return retVal; } @@ -422,16 +525,32 @@ i2c_master_writeByte(uint16 id, uint8 wrdata) sint8 i; #ifdef I2C_MASTER_OLD_VERSION - i2c_master_wait(3); -#endif - i2c_master_setDC(id, i2c[id].m_nLastSDA, 0); + i2c_master_wait(5); + + i2c_master_setDC(id, i2c[id]->last_SDA, 0); + i2c_master_wait(5); + + for (i = 7; i >= 0; i--) { + dat = wrdata >> i; + i2c_master_setDC(id, dat, 0); + i2c_master_wait(5); + i2c_master_setDC(id, dat, 1); + i2c_master_wait(5); + + if (i == 0) { + i2c_master_wait(3); //// + } + + i2c_master_setDC(id, dat, 0); + i2c_master_wait(5); + } +#else + i2c_master_setDC(id, i2c[id]->last_SDA, 0); for (i = 7; i >= 0; i--) { dat = (wrdata >> i) & 1; i2c_master_setDC(id, dat, 0); i2c_master_setDC(id, dat, 1); } -#ifdef I2C_MASTER_OLD_VERSION - i2c_master_wait(3); -#endif i2c_master_setDC(id, dat, 0); +#endif } diff --git a/app/include/driver/i2c_master.h b/app/include/driver/i2c_master.h index d15e4ad926..88d5ba38fe 100644 --- a/app/include/driver/i2c_master.h +++ b/app/include/driver/i2c_master.h @@ -1,45 +1,6 @@ #ifndef __I2C_MASTER_H__ #define __I2C_MASTER_H__ -#include "user_config.h" - -#ifdef I2C_MASTER_OLD_VERSION - -#define I2C_MASTER_SDA_MUX (pin_mux[sda]) -#define I2C_MASTER_SCL_MUX (pin_mux[scl]) -#define I2C_MASTER_SDA_GPIO (i2c[id].pinSDA) -#define I2C_MASTER_SCL_GPIO (i2c[id].pinSCL) -#define I2C_MASTER_SDA_FUNC (pin_func[sda]) -#define I2C_MASTER_SCL_FUNC (pin_func[scl]) - -#define I2C_MASTER_SDA_HIGH_SCL_HIGH() \ - gpio_output_set(1< Date: Wed, 17 Oct 2018 19:42:58 +0300 Subject: [PATCH 4/7] Separated the code of old driver for better compatibility and simplicity --- app/driver/i2c_master.c | 436 ++++++++++++++++++++++++++------ app/include/driver/i2c_master.h | 1 + 2 files changed, 362 insertions(+), 75 deletions(-) diff --git a/app/driver/i2c_master.c b/app/driver/i2c_master.c index 47ce16ad45..cf540c0491 100644 --- a/app/driver/i2c_master.c +++ b/app/driver/i2c_master.c @@ -37,8 +37,12 @@ #include "driver/i2c_master.h" -//used only by old driver -#define i2c_master_wait os_delay_us + +#ifndef I2C_MASTER_OLD_VERSION +/****************************************************************************** +* NEW driver +* Enabled if I2C_MASTER_OLD_VERSION is not defined in user_config.h +*******************************************************************************/ // enable use GPIO16 (D0) pin as SCL line. ~450 kHz maximum frequency #ifdef I2C_MASTER_GPIO16_ENABLED @@ -136,31 +140,6 @@ static inline void i2c_master_wait_gpio_SCL_high(uint16 id) LOCAL void ICACHE_FLASH_ATTR i2c_master_setDC(uint16 id, uint8 SDA, uint8 SCL) { -#ifdef I2C_MASTER_OLD_VERSION - // intentionally not optimized to keep timings of old version accurate - uint8 sclLevel; - - SDA &= 0x01; - SCL &= 0x01; - i2c[id]->last_SDA = SDA; - i2c[id]->last_SCL = SCL; - - if ((0 == SDA) && (0 == SCL)) { - gpio_output_set(0, 1<pin_SDA | 1<pin_SCL, 1<pin_SDA | 1<pin_SCL, 0); - } else if ((0 == SDA) && (1 == SCL)) { - gpio_output_set(1<pin_SCL, 1<pin_SDA, 1<pin_SDA | 1<pin_SCL, 0); - } else if ((1 == SDA) && (0 == SCL)) { - gpio_output_set(1<pin_SDA, 1<pin_SCL, 1<pin_SDA | 1<pin_SCL, 0); - } else { - gpio_output_set(1<pin_SDA | 1<pin_SCL, 0, 1<pin_SDA | 1<pin_SCL, 0); - } - if(1 == SCL) { - do { - sclLevel = GPIO_INPUT_GET(GPIO_ID_PIN(i2c[id]->pin_SCL)); - } while(0 == sclLevel); - } - i2c_master_wait(5); -#else uint32 this_SDA_SCL_set_mask; uint32 this_SDA_SCL_clear_mask; i2c[id]->last_SDA = SDA; @@ -194,8 +173,6 @@ i2c_master_setDC(uint16 id, uint8 SDA, uint8 SCL) asm volatile("nop;nop;nop;"); // empty CPU cycles to maintain equal times for low and high state } } - -#endif } /****************************************************************************** @@ -209,9 +186,6 @@ static inline uint8 ICACHE_FLASH_ATTR i2c_master_getDC(uint16 id) { uint8 sda_out; -#ifdef I2C_MASTER_OLD_VERSION - sda_out = GPIO_INPUT_GET(GPIO_ID_PIN(i2c[id]->pin_SDA)); -#else uint32 gpio_in_mask; //instead of: gpio_in_mask = gpio_input_get(); asm volatile("l16ui %[gpio_in_mask], %[gpio_in_addr], 0;" //read gpio state @@ -220,7 +194,6 @@ i2c_master_getDC(uint16 id) :[gpio_in_addr] "r" (PERIPHS_GPIO_BASEADDR + GPIO_IN_ADDRESS) ); sda_out = (gpio_in_mask >> i2c[id]->pin_SDA) & 1; -#endif return sda_out; } @@ -252,7 +225,7 @@ i2c_master_get_pin_SCL(uint16 id){ * Parameters : bus id * Returns : i2c speed *******************************************************************************/ -uint16 ICACHE_FLASH_ATTR +uint32 ICACHE_FLASH_ATTR i2c_master_get_speed(uint16 id){ return (NULL == i2c[id]) ? 0 : i2c[id]->speed; } @@ -325,11 +298,6 @@ i2c_master_gpio_init(uint16 id, uint8 sda, uint8 scl, uint32 speed) if(i2c[id]->speed < MIN_SPEED){ i2c[id]->speed = MIN_SPEED; } - -#ifdef I2C_MASTER_OLD_VERSION - i2c[id]->speed = 100000; //dummy speed for backward compatibility -#endif - i2c_master_set_DC_delay(id); // recalibrate clock ETS_GPIO_INTR_DISABLE(); //disable gpio interrupts @@ -389,9 +357,6 @@ i2c_master_start(uint16 id) void ICACHE_FLASH_ATTR i2c_master_stop(uint16 id) { -#ifdef I2C_MASTER_OLD_VERSION - i2c_master_wait(5); -#endif i2c_master_setDC(id, 0, i2c[id]->last_SCL); i2c_master_setDC(id, 0, 1); i2c_master_setDC(id, 1, 1); @@ -409,9 +374,6 @@ i2c_master_setAck(uint16 id, uint8 level) i2c_master_setDC(id, i2c[id]->last_SDA, 0); i2c_master_setDC(id, level, 0); i2c_master_setDC(id, level, 1); -#ifdef I2C_MASTER_OLD_VERSION - i2c_master_wait(3); -#endif i2c_master_setDC(id, level, 0); i2c_master_setDC(id, 1, 0); } @@ -486,19 +448,6 @@ i2c_master_readByte(uint16 id) uint8 k; sint8 i; -#ifdef I2C_MASTER_OLD_VERSION - i2c_master_wait(5); - i2c_master_setDC(id, i2c[id]->last_SDA, 0); - for (i = 7; i >= 0; i--) { - i2c_master_setDC(id, 1, 0); - i2c_master_setDC(id, 1, 1); - k = i2c_master_getDC(id); - k <<= i; - retVal |= k; - } - i2c_master_wait(3); - i2c_master_setDC(id, 1, 0); -#else i2c_master_setDC(id, i2c[id]->last_SDA, 0); i2c_master_setDC(id, 1, 0); for (i = 7; i >= 0; i--) { @@ -508,7 +457,6 @@ i2c_master_readByte(uint16 id) k <<= i; retVal |= k; } -#endif return retVal; } @@ -524,33 +472,371 @@ i2c_master_writeByte(uint16 id, uint8 wrdata) uint8 dat; sint8 i; -#ifdef I2C_MASTER_OLD_VERSION + i2c_master_setDC(id, i2c[id]->last_SDA, 0); + for (i = 7; i >= 0; i--) { + dat = (wrdata >> i) & 1; + i2c_master_setDC(id, dat, 0); + i2c_master_setDC(id, dat, 1); + } + i2c_master_setDC(id, dat, 0); +} + + + +#else // if defined I2C_MASTER_OLD_VERSION +/****************************************************************************** +* OLD driver +* Enabled when I2C_MASTER_OLD_VERSION is defined in user_config.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_HIGH_SCL_HIGH() \ + gpio_output_set(1<last_SDA, 0); +/****************************************************************************** + * FunctionName : i2c_master_getDC + * Description : Internal used function - + * get i2c SDA bit value + * Parameters : NONE + * Returns : uint8 - SDA bit value +*******************************************************************************/ +LOCAL uint8 ICACHE_FLASH_ATTR +i2c_master_getDC() +{ + uint8 sda_out; + sda_out = GPIO_INPUT_GET(GPIO_ID_PIN(I2C_MASTER_SDA_GPIO)); + return sda_out; +} + +/****************************************************************************** + * FunctionName : i2c_master_init + * Description : initilize I2C bus to enable i2c operations + * Parameters : bus id + * Returns : NONE +*******************************************************************************/ +void ICACHE_FLASH_ATTR +i2c_master_init(uint16 id) +{ + uint8 i; + + i2c_master_setDC(1, 0); + + // when SCL = 0, toggle SDA to clear up + i2c_master_setDC(0, 0) ; + i2c_master_setDC(1, 0) ; + + // set data_cnt to max value + for (i = 0; i < 28; i++) { + i2c_master_setDC(1, 0); + i2c_master_setDC(1, 1); + } + + // reset all + i2c_master_stop(I2C_MASTER_BUS_ID); + return; +} + +/****************************************************************************** + * FunctionName : i2c_master_get_pin_SDA + * Description : returns SDA pin number + * Parameters : bus id + * Returns : SDA pin number +*******************************************************************************/ +uint8 ICACHE_FLASH_ATTR +i2c_master_get_pinSDA(uint16 id){ + return pinSDA; +} + +/****************************************************************************** + * FunctionName : i2c_master_get_pin_SCL + * Description : returns SCL pin number + * Parameters : bus id + * Returns : SCL pin number +*******************************************************************************/ +uint8 ICACHE_FLASH_ATTR +i2c_master_get_pinSCL(uint16 id){ + return pinSCL; +} + +/****************************************************************************** + * FunctionName : i2c_master_get_speed + * Description : returns configured bus speed + * Parameters : bus id + * Returns : i2c speed +*******************************************************************************/ +uint32 ICACHE_FLASH_ATTR +i2c_master_get_speed(uint16 id){ + return I2C_MASTER_SPEED; +} + +/****************************************************************************** + * FunctionName : i2c_master_configured + * Description : checks if i2c bus is configured + * Parameters : bus id + * Returns : boolean value, true if configured +*******************************************************************************/ +bool ICACHE_FLASH_ATTR +i2c_master_configured(uint16 id){ + return true; +} + +/****************************************************************************** + * FunctionName : i2c_master_gpio_init + * Description : config SDA and SCL gpio to open-drain output mode, + * mux and gpio num defined in i2c_master.h + * Parameters : bus id, uint8 sda, uint8 scl, uint32 speed + * Returns : configured speed +*******************************************************************************/ +uint32 ICACHE_FLASH_ATTR +i2c_master_gpio_init(uint16 id, uint8 sda, uint8 scl, uint32 speed) +{ + pinSDA = pin_num[sda]; + pinSCL = pin_num[scl]; + + ETS_GPIO_INTR_DISABLE() ; +// ETS_INTR_LOCK(); + + PIN_FUNC_SELECT(I2C_MASTER_SDA_MUX, I2C_MASTER_SDA_FUNC); + PIN_FUNC_SELECT(I2C_MASTER_SCL_MUX, I2C_MASTER_SCL_FUNC); + + GPIO_REG_WRITE(GPIO_PIN_ADDR(GPIO_ID_PIN(I2C_MASTER_SDA_GPIO)), GPIO_REG_READ(GPIO_PIN_ADDR(GPIO_ID_PIN(I2C_MASTER_SDA_GPIO))) | GPIO_PIN_PAD_DRIVER_SET(GPIO_PAD_DRIVER_ENABLE)); //open drain; + GPIO_REG_WRITE(GPIO_ENABLE_ADDRESS, GPIO_REG_READ(GPIO_ENABLE_ADDRESS) | (1 << I2C_MASTER_SDA_GPIO)); + GPIO_REG_WRITE(GPIO_PIN_ADDR(GPIO_ID_PIN(I2C_MASTER_SCL_GPIO)), GPIO_REG_READ(GPIO_PIN_ADDR(GPIO_ID_PIN(I2C_MASTER_SCL_GPIO))) | GPIO_PIN_PAD_DRIVER_SET(GPIO_PAD_DRIVER_ENABLE)); //open drain; + GPIO_REG_WRITE(GPIO_ENABLE_ADDRESS, GPIO_REG_READ(GPIO_ENABLE_ADDRESS) | (1 << I2C_MASTER_SCL_GPIO)); + + I2C_MASTER_SDA_HIGH_SCL_HIGH(); + + ETS_GPIO_INTR_ENABLE() ; +// ETS_INTR_UNLOCK(); + + i2c_master_init(I2C_MASTER_BUS_ID); + + return I2C_MASTER_SPEED; +} + +/****************************************************************************** + * FunctionName : i2c_master_start + * Description : set i2c to send state + * Parameters : bus id + * Returns : NONE +*******************************************************************************/ +void ICACHE_FLASH_ATTR +i2c_master_start(uint16 id) +{ + i2c_master_setDC(1, m_nLastSCL); + i2c_master_setDC(1, 1); + i2c_master_setDC(0, 1); +} + +/****************************************************************************** + * FunctionName : i2c_master_stop + * Description : set i2c to stop sending state + * Parameters : bus id + * Returns : NONE +*******************************************************************************/ +void ICACHE_FLASH_ATTR +i2c_master_stop(uint16 id) +{ i2c_master_wait(5); - for (i = 7; i >= 0; i--) { - dat = wrdata >> i; - i2c_master_setDC(id, dat, 0); + i2c_master_setDC(0, m_nLastSCL); + i2c_master_setDC(0, 1); + i2c_master_setDC(1, 1); +} + +/****************************************************************************** + * FunctionName : i2c_master_setAck + * Description : set ack to i2c bus as level value + * Parameters : bus id, uint8 level - 0 or 1 + * Returns : NONE +*******************************************************************************/ +void ICACHE_FLASH_ATTR +i2c_master_setAck(uint16 id, uint8 level) +{ + i2c_master_setDC(m_nLastSDA, 0); + i2c_master_setDC(level, 0); + i2c_master_setDC(level, 1); + i2c_master_wait(3); + i2c_master_setDC(level, 0); + i2c_master_setDC(1, 0); +} + +/****************************************************************************** + * FunctionName : i2c_master_getAck + * Description : confirm if peer send ack + * Parameters : bus id + * Returns : uint8 - ack value, 0 or 1 +*******************************************************************************/ +uint8 ICACHE_FLASH_ATTR +i2c_master_getAck(uint16 id) +{ + uint8 retVal; + i2c_master_setDC(m_nLastSDA, 0); + i2c_master_setDC(1, 0); + i2c_master_setDC(1, 1); + + retVal = i2c_master_getDC(); + i2c_master_wait(5); + i2c_master_setDC(1, 0); + + return retVal; +} + +/****************************************************************************** +* FunctionName : i2c_master_checkAck +* Description : get dev response +* Parameters : bus id +* Returns : true : get ack ; false : get nack +*******************************************************************************/ +bool ICACHE_FLASH_ATTR +i2c_master_checkAck(uint16 id) +{ + if(i2c_master_getAck(I2C_MASTER_BUS_ID)){ + return FALSE; + }else{ + return TRUE; + } +} + +/****************************************************************************** +* FunctionName : i2c_master_send_ack +* Description : response ack +* Parameters : bus id +* Returns : NONE +*******************************************************************************/ +void ICACHE_FLASH_ATTR +i2c_master_send_ack(uint16 id) +{ + i2c_master_setAck(I2C_MASTER_BUS_ID, 0x0); +} +/****************************************************************************** +* FunctionName : i2c_master_send_nack +* Description : response nack +* Parameters : bus id +* Returns : NONE +*******************************************************************************/ +void ICACHE_FLASH_ATTR +i2c_master_send_nack(uint16 id) +{ + i2c_master_setAck(I2C_MASTER_BUS_ID, 0x1); +} + +/****************************************************************************** + * FunctionName : i2c_master_readByte + * Description : read Byte from i2c bus + * Parameters : bus id + * Returns : uint8 - readed value +*******************************************************************************/ +uint8 ICACHE_FLASH_ATTR +i2c_master_readByte(uint16 id) +{ + uint8 retVal = 0; + uint8 k, i; + + i2c_master_wait(5); + i2c_master_setDC(m_nLastSDA, 0); + + for (i = 0; i < 8; i++) { i2c_master_wait(5); - i2c_master_setDC(id, dat, 1); + i2c_master_setDC(1, 0); + i2c_master_setDC(1, 1); + + k = i2c_master_getDC(); i2c_master_wait(5); - if (i == 0) { + if (i == 7) { i2c_master_wait(3); //// } - i2c_master_setDC(id, dat, 0); - i2c_master_wait(5); + k <<= (7 - i); + retVal |= k; } -#else - i2c_master_setDC(id, i2c[id]->last_SDA, 0); + + i2c_master_setDC(1, 0); + + return retVal; +} + +/****************************************************************************** + * FunctionName : i2c_master_writeByte + * Description : write wrdata value(one byte) into i2c + * Parameters : bus id, uint8 wrdata - write value + * Returns : NONE +*******************************************************************************/ +void ICACHE_FLASH_ATTR +i2c_master_writeByte(uint16 id, uint8 wrdata) +{ + uint8 dat; + sint8 i; + + i2c_master_wait(5); + + i2c_master_setDC(m_nLastSDA, 0); + for (i = 7; i >= 0; i--) { - dat = (wrdata >> i) & 1; - i2c_master_setDC(id, dat, 0); - i2c_master_setDC(id, dat, 1); + dat = wrdata >> i; + i2c_master_setDC(dat, 0); + i2c_master_setDC(dat, 1); + + if (i == 0) { + i2c_master_wait(3); //// + } + + i2c_master_setDC(dat, 0); } - i2c_master_setDC(id, dat, 0); -#endif } +#endif diff --git a/app/include/driver/i2c_master.h b/app/include/driver/i2c_master.h index 88d5ba38fe..0106b7a19d 100644 --- a/app/include/driver/i2c_master.h +++ b/app/include/driver/i2c_master.h @@ -17,5 +17,6 @@ void i2c_master_send_nack(uint16 id); uint8 i2c_master_get_pinSDA(uint16 id); uint8 i2c_master_get_pinSCL(uint16 id); +uint32 i2c_master_get_speed(uint16 id); #endif //__I2C_MASTER_H__ From 770d13df85c902433de7baa992dcf2a448cf44ae Mon Sep 17 00:00:00 2001 From: Natalia Sorokina Date: Sun, 4 Nov 2018 05:21:43 +0300 Subject: [PATCH 5/7] Change of driver interface --- app/driver/i2c_master.c | 314 +++++++------------------------- app/include/driver/i2c_master.h | 16 +- app/include/user_config.h | 4 +- app/platform/cpu_esp8266.h | 6 + app/platform/platform.c | 14 +- docs/modules/i2c.md | 28 ++- 6 files changed, 100 insertions(+), 282 deletions(-) diff --git a/app/driver/i2c_master.c b/app/driver/i2c_master.c index cf540c0491..874ca79501 100644 --- a/app/driver/i2c_master.c +++ b/app/driver/i2c_master.c @@ -45,14 +45,24 @@ *******************************************************************************/ // enable use GPIO16 (D0) pin as SCL line. ~450 kHz maximum frequency -#ifdef I2C_MASTER_GPIO16_ENABLED +#ifdef I2C_MASTER_GPIO16_ENABLE #define IS_PIN16(n) ((n)==16) +// CPU_CYCLES_BETWEEN_DELAYS describes how much cpu cycles code runs +// between i2c_master_setDC() calls if delay is zero and i2c_master_set_DC_delay() +// is not being called. This is not exact value, but proportional with length of code. +// Increasing the value results in less delay and faster i2c clock speed. #define CPU_CYCLES_BETWEEN_DELAYS 80 +// CPU_CYCLES_GPIO16 is added to CPU_CYCLES_BETWEEN_DELAYS, +// as RTC-related IO takes much more time than standard GPIOs. +// Increasing the value results in less delay and faster i2c clock speed for GPIO16. #define CPU_CYCLES_GPIO16 90 + #else -#define IS_PIN16(n) (0) //removes GPIO16-related code during compile +// If GPIO16 support is not enabled, remove GPIO16-related code during compile +// and change timing constants. +#define IS_PIN16(n) (0) #define CPU_CYCLES_BETWEEN_DELAYS 74 -#endif //I2C_MASTER_GPIO16_ENABLED +#endif //I2C_MASTER_GPIO16_ENABLE #define MIN_SPEED 25000 #define MAX_NUMBER_OF_I2C NUM_I2C @@ -81,11 +91,11 @@ i2c_master_set_DC_delay(uint16 id) { // [cpu cycles per half SCL clock period] - [cpu cycles that code takes to run] i2c[id]->cycles_delay = system_get_cpu_freq() * 500000 / i2c[id]->speed - CPU_CYCLES_BETWEEN_DELAYS; - #ifdef I2C_MASTER_GPIO16_ENABLED + #ifdef I2C_MASTER_GPIO16_ENABLE if(IS_PIN16(i2c[id]->pin_SCL)){ //if GPIO16 i2c[id]->cycles_delay -= CPU_CYCLES_GPIO16; //decrease delay } - #endif //I2C_MASTER_GPIO16_ENABLED + #endif //I2C_MASTER_GPIO16_ENABLE if(i2c[id]->cycles_delay < 0){ i2c[id]->cycles_delay = 0; } @@ -197,39 +207,6 @@ i2c_master_getDC(uint16 id) return sda_out; } -/****************************************************************************** - * FunctionName : i2c_master_get_pin_SDA - * Description : returns SDA pin number - * Parameters : bus id - * Returns : SDA pin number -*******************************************************************************/ -uint8 ICACHE_FLASH_ATTR -i2c_master_get_pin_SDA(uint16 id){ - return (NULL == i2c[id]) ? 0 : i2c[id]->pin_SDA; -} - -/****************************************************************************** - * FunctionName : i2c_master_get_pin_SCL - * Description : returns SCL pin number - * Parameters : bus id - * Returns : SCL pin number -*******************************************************************************/ -uint8 ICACHE_FLASH_ATTR -i2c_master_get_pin_SCL(uint16 id){ - return (NULL == i2c[id]) ? 0 : i2c[id]->pin_SCL; -} - -/****************************************************************************** - * FunctionName : i2c_master_get_speed - * Description : returns configured bus speed - * Parameters : bus id - * Returns : i2c speed -*******************************************************************************/ -uint32 ICACHE_FLASH_ATTR -i2c_master_get_speed(uint16 id){ - return (NULL == i2c[id]) ? 0 : i2c[id]->speed; -} - /****************************************************************************** * FunctionName : i2c_master_configured * Description : checks if i2c bus is configured @@ -271,13 +248,13 @@ i2c_master_init(uint16 id) } /****************************************************************************** - * FunctionName : i2c_master_gpio_init + * FunctionName : i2c_master_setup * Description : Initializes and configures the driver on given bus ID * Parameters : bus id * Returns : configured speed *******************************************************************************/ uint32 ICACHE_FLASH_ATTR -i2c_master_gpio_init(uint16 id, uint8 sda, uint8 scl, uint32 speed) +i2c_master_setup(uint16 id, uint8 sda, uint8 scl, uint32 speed) { if(NULL == i2c[id]){ i2c[id] = (i2c_master_state_t*) c_malloc(sizeof(i2c_master_state_t)); @@ -303,18 +280,11 @@ i2c_master_gpio_init(uint16 id, uint8 sda, uint8 scl, uint32 speed) ETS_GPIO_INTR_DISABLE(); //disable gpio interrupts if (IS_PIN16(i2c[id]->pin_SCL)){ //if GPIO16 - //SET_PERI_REG_MASK(PAD_XPD_DCDC_CONF, 0x1); // select function RTC_GPIO0 for pin XPD_DCDC - WRITE_PERI_REG(PAD_XPD_DCDC_CONF, - (READ_PERI_REG(PAD_XPD_DCDC_CONF) & 0xffffffbc) | (uint32)0x1); // mux configuration for XPD_DCDC to output rtc_gpio0 - //CLEAR_PERI_REG_MASK(RTC_GPIO_CONF, 0x1); //mux configuration for out enable - WRITE_PERI_REG(RTC_GPIO_CONF, - (READ_PERI_REG(RTC_GPIO_CONF) & (uint32)0xfffffffe) | (uint32)0x0); //mux configuration for out enable - //SET_PERI_REG_MASK(RTC_GPIO_ENABLE, 0x1); //out enable - WRITE_PERI_REG(RTC_GPIO_ENABLE, - (READ_PERI_REG(RTC_GPIO_ENABLE) & (uint32)0xfffffffe) | (uint32)0x1); //out enable - //SET_PERI_REG_MASK(RTC_GPIO_OUT, 0x1); // set SCL high - WRITE_PERI_REG(RTC_GPIO_OUT, - (READ_PERI_REG(RTC_GPIO_OUT) & (uint32)0xfffffffe) | (uint32)0x1); //set high + CLEAR_PERI_REG_MASK(PAD_XPD_DCDC_CONF, 0x43); //disable all functions for XPD_DCDC + SET_PERI_REG_MASK(PAD_XPD_DCDC_CONF, 0x1); // select function RTC_GPIO0 for pin XPD_DCDC + CLEAR_PERI_REG_MASK(RTC_GPIO_CONF, 0x1); //mux configuration for out enable + SET_PERI_REG_MASK(RTC_GPIO_ENABLE, 0x1); //out enable + SET_PERI_REG_MASK(RTC_GPIO_OUT, 0x1); // set SCL high } else{ PIN_FUNC_SELECT(pin_mux[scl], pin_func[scl]); @@ -362,79 +332,6 @@ i2c_master_stop(uint16 id) i2c_master_setDC(id, 1, 1); } -/****************************************************************************** - * FunctionName : i2c_master_setAck - * Description : set ack to i2c bus as level value - * Parameters : bus id, uint8 level - 0 or 1 - * Returns : NONE -*******************************************************************************/ -void ICACHE_FLASH_ATTR -i2c_master_setAck(uint16 id, uint8 level) -{ - i2c_master_setDC(id, i2c[id]->last_SDA, 0); - i2c_master_setDC(id, level, 0); - i2c_master_setDC(id, level, 1); - i2c_master_setDC(id, level, 0); - i2c_master_setDC(id, 1, 0); -} - -/****************************************************************************** - * FunctionName : i2c_master_getAck - * Description : confirm if peer send ack - * Parameters : bus id - * Returns : uint8 - ack value, 0 or 1 -*******************************************************************************/ -uint8 ICACHE_FLASH_ATTR -i2c_master_getAck(uint16 id) -{ - uint8 retVal; - i2c_master_setDC(id, i2c[id]->last_SDA, 0); - i2c_master_setDC(id, 1, 0); - i2c_master_setDC(id, 1, 1); - retVal = i2c_master_getDC(id); - i2c_master_setDC(id, 1, 0); - return retVal; -} - -/****************************************************************************** -* FunctionName : i2c_master_checkAck -* Description : get dev response -* Parameters : bus id -* Returns : true : get ack ; false : get nack -*******************************************************************************/ -bool ICACHE_FLASH_ATTR -i2c_master_checkAck(uint16 id) -{ - if(i2c_master_getAck(id)){ - return FALSE; - }else{ - return TRUE; - } -} - -/****************************************************************************** -* FunctionName : i2c_master_send_ack -* Description : response ack -* Parameters : bus id -* Returns : NONE -*******************************************************************************/ -void ICACHE_FLASH_ATTR -i2c_master_send_ack(uint16 id) -{ - i2c_master_setAck(id, 0x0); -} -/****************************************************************************** -* FunctionName : i2c_master_send_nack -* Description : response nack -* Parameters : bus id -* Returns : NONE -*******************************************************************************/ -void ICACHE_FLASH_ATTR -i2c_master_send_nack(uint16 id) -{ - i2c_master_setAck(id, 0x1); -} - /****************************************************************************** * FunctionName : i2c_master_readByte * Description : read Byte from i2c bus @@ -442,12 +339,13 @@ i2c_master_send_nack(uint16 id) * Returns : uint8 - readed value *******************************************************************************/ uint8 ICACHE_FLASH_ATTR -i2c_master_readByte(uint16 id) +i2c_master_readByte(uint16 id, sint16 ack) { uint8 retVal = 0; uint8 k; sint8 i; - + uint8 ackLevel = (ack ? 0 : 1); + i2c_master_setDC(id, i2c[id]->last_SDA, 0); i2c_master_setDC(id, 1, 0); for (i = 7; i >= 0; i--) { @@ -457,6 +355,12 @@ i2c_master_readByte(uint16 id) k <<= i; retVal |= k; } + // set ACK + i2c_master_setDC(id, i2c[id]->last_SDA, 0); + i2c_master_setDC(id, ackLevel, 0); + i2c_master_setDC(id, ackLevel, 1); + i2c_master_setDC(id, ackLevel, 0); + i2c_master_setDC(id, 1, 0); return retVal; } @@ -466,11 +370,12 @@ i2c_master_readByte(uint16 id) * Parameters : bus id, uint8 wrdata - write value * Returns : NONE *******************************************************************************/ -void ICACHE_FLASH_ATTR +uint8 ICACHE_FLASH_ATTR i2c_master_writeByte(uint16 id, uint8 wrdata) { uint8 dat; sint8 i; + uint8 retVal; i2c_master_setDC(id, i2c[id]->last_SDA, 0); for (i = 7; i >= 0; i--) { @@ -479,6 +384,13 @@ i2c_master_writeByte(uint16 id, uint8 wrdata) i2c_master_setDC(id, dat, 1); } i2c_master_setDC(id, dat, 0); + //get ACK + //i2c_master_setDC(id, i2c[id]->last_SDA, 0); + i2c_master_setDC(id, 1, 0); + i2c_master_setDC(id, 1, 1); + retVal = i2c_master_getDC(id); + i2c_master_setDC(id, 1, 0); + return ! retVal; } @@ -538,7 +450,8 @@ i2c_master_setDC(uint8 SDA, uint8 SCL) I2C_MASTER_SDA_HIGH_SCL_LOW(); } else { I2C_MASTER_SDA_HIGH_SCL_HIGH(); - } + } + if(1 == SCL) { do { sclLevel = GPIO_INPUT_GET(GPIO_ID_PIN(I2C_MASTER_SCL_GPIO)); @@ -590,39 +503,6 @@ i2c_master_init(uint16 id) return; } -/****************************************************************************** - * FunctionName : i2c_master_get_pin_SDA - * Description : returns SDA pin number - * Parameters : bus id - * Returns : SDA pin number -*******************************************************************************/ -uint8 ICACHE_FLASH_ATTR -i2c_master_get_pinSDA(uint16 id){ - return pinSDA; -} - -/****************************************************************************** - * FunctionName : i2c_master_get_pin_SCL - * Description : returns SCL pin number - * Parameters : bus id - * Returns : SCL pin number -*******************************************************************************/ -uint8 ICACHE_FLASH_ATTR -i2c_master_get_pinSCL(uint16 id){ - return pinSCL; -} - -/****************************************************************************** - * FunctionName : i2c_master_get_speed - * Description : returns configured bus speed - * Parameters : bus id - * Returns : i2c speed -*******************************************************************************/ -uint32 ICACHE_FLASH_ATTR -i2c_master_get_speed(uint16 id){ - return I2C_MASTER_SPEED; -} - /****************************************************************************** * FunctionName : i2c_master_configured * Description : checks if i2c bus is configured @@ -630,19 +510,20 @@ i2c_master_get_speed(uint16 id){ * Returns : boolean value, true if configured *******************************************************************************/ bool ICACHE_FLASH_ATTR -i2c_master_configured(uint16 id){ +i2c_master_configured(uint16 id) +{ return true; } /****************************************************************************** - * FunctionName : i2c_master_gpio_init + * FunctionName : i2c_master_setup * Description : config SDA and SCL gpio to open-drain output mode, * mux and gpio num defined in i2c_master.h * Parameters : bus id, uint8 sda, uint8 scl, uint32 speed * Returns : configured speed *******************************************************************************/ uint32 ICACHE_FLASH_ATTR -i2c_master_gpio_init(uint16 id, uint8 sda, uint8 scl, uint32 speed) +i2c_master_setup(uint16 id, uint8 sda, uint8 scl, uint32 speed) { pinSDA = pin_num[sda]; pinSCL = pin_num[scl]; @@ -698,83 +579,6 @@ i2c_master_stop(uint16 id) i2c_master_setDC(1, 1); } -/****************************************************************************** - * FunctionName : i2c_master_setAck - * Description : set ack to i2c bus as level value - * Parameters : bus id, uint8 level - 0 or 1 - * Returns : NONE -*******************************************************************************/ -void ICACHE_FLASH_ATTR -i2c_master_setAck(uint16 id, uint8 level) -{ - i2c_master_setDC(m_nLastSDA, 0); - i2c_master_setDC(level, 0); - i2c_master_setDC(level, 1); - i2c_master_wait(3); - i2c_master_setDC(level, 0); - i2c_master_setDC(1, 0); -} - -/****************************************************************************** - * FunctionName : i2c_master_getAck - * Description : confirm if peer send ack - * Parameters : bus id - * Returns : uint8 - ack value, 0 or 1 -*******************************************************************************/ -uint8 ICACHE_FLASH_ATTR -i2c_master_getAck(uint16 id) -{ - uint8 retVal; - i2c_master_setDC(m_nLastSDA, 0); - i2c_master_setDC(1, 0); - i2c_master_setDC(1, 1); - - retVal = i2c_master_getDC(); - i2c_master_wait(5); - i2c_master_setDC(1, 0); - - return retVal; -} - -/****************************************************************************** -* FunctionName : i2c_master_checkAck -* Description : get dev response -* Parameters : bus id -* Returns : true : get ack ; false : get nack -*******************************************************************************/ -bool ICACHE_FLASH_ATTR -i2c_master_checkAck(uint16 id) -{ - if(i2c_master_getAck(I2C_MASTER_BUS_ID)){ - return FALSE; - }else{ - return TRUE; - } -} - -/****************************************************************************** -* FunctionName : i2c_master_send_ack -* Description : response ack -* Parameters : bus id -* Returns : NONE -*******************************************************************************/ -void ICACHE_FLASH_ATTR -i2c_master_send_ack(uint16 id) -{ - i2c_master_setAck(I2C_MASTER_BUS_ID, 0x0); -} -/****************************************************************************** -* FunctionName : i2c_master_send_nack -* Description : response nack -* Parameters : bus id -* Returns : NONE -*******************************************************************************/ -void ICACHE_FLASH_ATTR -i2c_master_send_nack(uint16 id) -{ - i2c_master_setAck(I2C_MASTER_BUS_ID, 0x1); -} - /****************************************************************************** * FunctionName : i2c_master_readByte * Description : read Byte from i2c bus @@ -782,11 +586,12 @@ i2c_master_send_nack(uint16 id) * Returns : uint8 - readed value *******************************************************************************/ uint8 ICACHE_FLASH_ATTR -i2c_master_readByte(uint16 id) +i2c_master_readByte(uint16 id, sint16 ack) { uint8 retVal = 0; uint8 k, i; - + uint8 ackLevel = (ack ? 0 : 1); + i2c_master_wait(5); i2c_master_setDC(m_nLastSDA, 0); @@ -807,7 +612,13 @@ i2c_master_readByte(uint16 id) } i2c_master_setDC(1, 0); - + // set ACK + i2c_master_setDC(m_nLastSDA, 0); + i2c_master_setDC(ackLevel, 0); + i2c_master_setDC(ackLevel, 1); + i2c_master_wait(3); + i2c_master_setDC(ackLevel, 0); + i2c_master_setDC(1, 0); return retVal; } @@ -817,12 +628,13 @@ i2c_master_readByte(uint16 id) * Parameters : bus id, uint8 wrdata - write value * Returns : NONE *******************************************************************************/ -void ICACHE_FLASH_ATTR +uint8 ICACHE_FLASH_ATTR i2c_master_writeByte(uint16 id, uint8 wrdata) { uint8 dat; sint8 i; - + uint8 retVal; + i2c_master_wait(5); i2c_master_setDC(m_nLastSDA, 0); @@ -838,5 +650,13 @@ i2c_master_writeByte(uint16 id, uint8 wrdata) i2c_master_setDC(dat, 0); } + // get ACK + i2c_master_setDC(m_nLastSDA, 0); + i2c_master_setDC(1, 0); + i2c_master_setDC(1, 1); + retVal = i2c_master_getDC(); + i2c_master_wait(5); + i2c_master_setDC(1, 0); + return ! retVal; } #endif diff --git a/app/include/driver/i2c_master.h b/app/include/driver/i2c_master.h index 0106b7a19d..5a9eed193a 100644 --- a/app/include/driver/i2c_master.h +++ b/app/include/driver/i2c_master.h @@ -1,22 +1,12 @@ #ifndef __I2C_MASTER_H__ #define __I2C_MASTER_H__ -uint32 i2c_master_gpio_init(uint16 id, uint8 sda, uint8 scl, uint32 speed); +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); -void i2c_master_setAck(uint16 id, uint8 level); -uint8 i2c_master_getAck(uint16 id); -uint8 i2c_master_readByte(uint16 id); -void i2c_master_writeByte(uint16 id, uint8 wrdata); - -bool i2c_master_checkAck(uint16 id); -void i2c_master_send_ack(uint16 id); -void i2c_master_send_nack(uint16 id); - -uint8 i2c_master_get_pinSDA(uint16 id); -uint8 i2c_master_get_pinSCL(uint16 id); -uint32 i2c_master_get_speed(uint16 id); +uint8 i2c_master_readByte(uint16 id, sint16 ack); +uint8 i2c_master_writeByte(uint16 id, uint8 wrdata); #endif //__I2C_MASTER_H__ diff --git a/app/include/user_config.h b/app/include/user_config.h index b88b35ae7a..06e52a2ae7 100644 --- a/app/include/user_config.h +++ b/app/include/user_config.h @@ -157,13 +157,13 @@ // I2C software driver partially supports use of GPIO16 (D0) pin for SCL line. -// GPIO16 does not support open-drain mode, and have drive current about 40mA, +// 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_ENABLED +//#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 diff --git a/app/platform/cpu_esp8266.h b/app/platform/cpu_esp8266.h index a2a36d2f44..7ff7b6cf1e 100644 --- a/app/platform/cpu_esp8266.h +++ b/app/platform/cpu_esp8266.h @@ -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 +#else +#define NUM_I2C 1 +#endif //I2C_MASTER_OLD_VERSION + #define NUM_OW GPIO_PIN_NUM #define NUM_TMR 7 diff --git a/app/platform/platform.c b/app/platform/platform.c index 612c8f6037..7d45471d01 100644 --- a/app/platform/platform.c +++ b/app/platform/platform.c @@ -735,7 +735,7 @@ 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 - return i2c_master_gpio_init(id, sda, scl, speed); + return i2c_master_setup(id, sda, scl, speed); } bool platform_i2c_configured( unsigned id ){ @@ -757,23 +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(id, + return i2c_master_writeByte(id, (uint8_t) ((address << 1) + (direction == PLATFORM_I2C_DIRECTION_TRANSMITTER ? 0 : 1)) ); - // Low-level returns nack (0=acked); we return ack (1=acked). - return ! i2c_master_getAck(id); } int platform_i2c_send_byte(unsigned id, uint8_t data ){ - i2c_master_writeByte(id, data); - // Low-level returns nack (0=acked); we return ack (1=acked). - return ! i2c_master_getAck(id); + return i2c_master_writeByte(id, data); } int platform_i2c_recv_byte( unsigned id, int ack ){ - uint8_t r = i2c_master_readByte(id); - i2c_master_setAck(id, !ack ); - return r; + return i2c_master_readByte(id, ack); } // ***************************************************************************** diff --git a/docs/modules/i2c.md b/docs/modules/i2c.md index 6cd8cbdbba..207ec33f86 100644 --- a/docs/modules/i2c.md +++ b/docs/modules/i2c.md @@ -4,9 +4,9 @@ | 2014-12-22 | [Zeroday](https://github.com/funshine) | [Zeroday](https://github.com/funshine) | [i2c.c](../../../app/modules/i2c.c)| | 2018-08-30 | [Natalia Sorokina](https://github.com/sonaux) | | [i2c_master.c](../../../app/driver/i2c_master.c)| -I²C (I2C, IIC) is a serial 2-wire bus for communicating with various devices. +I²C (I2C, IIC) is a serial 2-wire bus for communicating with various devices. Also known as SMBus or TWI, though SMBus have some additions to the I2C protocol. ESP8266 chip does not have hardware I²C, so module uses software I²C driver. -It can be set up on any GPIO pins including GPIO16. +It can be set up on any GPIO pins including GPIO16 (see below). This module supports: - Master mode @@ -15,28 +15,36 @@ This module supports: - Clock stretching (slow slave device can tell the master to wait) - Sharing SDA line over multiple I²C buses to save available pins - GPIO16 pin can be used as SCL pin, but selected bus will be limited to not more than FAST speed. + + HIGH-speed mode (3.5MHz clock) and 10-bit addressing scheme is not supported. You have to call `i2c.setup` on a given I²C bus at least once before communicating to any device connected to that bus, otherwise you will get an error. I²C bus designed to work in open-drain mode, so it needs pull-up resistors 1k - 10k on SDA and SCL lines. Though many peripheral modules have pull-up resistors onboard and will work without additional external resistors. -Hint for using many identical devices with same address: initialize many I²C buses calling `i2c.setup` with different bus numbers and pins. SCL pins should be different, SDA can be shared on one pin. +Hint for using many identical devices with same address: +Many devices allow to choose between 2 I²C addresses via pin or soldered 0 Ohm resistor. +If address change is not an option or you need to use more than 2 similar devices, you can use different I²C buses. +Initialize them once by calling `i2c.setup` with different bus numbers and pins, then refer to each device by bus id and device address. +SCL pins should be different, SDA can be shared on one pin. -Note that historically many drivers and modules assumed that only a single I²C bus with id 0 is available, so it is always safer to start with id 0 as first bus in your code. -If your device driver functions do not have I²C bus id as an input parameter and/or not built with Lua OOP principles then most probably device will only be accessible through bus id 0 and must be connected to its pins. +Note that historically many NodeMCU drivers and modules assumed that only a single I²C bus with id 0 is available, so it is always safer to start with id 0 as first bus in your code. +If your device driver functions do not have I²C bus id as an input parameter and/or not built with Lua OOP principles then most probably device will be accessible through bus id 0 only and must be connected to its pins. To enable new driver comment line `#define I2C_MASTER_OLD_VERSION` in `user_config.h` To enable support for GPIO16 (D0) uncomment line `#define I2C_MASTER_GPIO16_ENABLED` in `user_config.h` -GPIO16 pin have very strong pullup resistor - about 100 Ohm, and that may lead to communication errors when slave device wants to stretch SCL clock but unable to hold it low. If that happens, try setting lower I²C speed. +GPIO16 does not support open-drain mode and works in push-pull mode. That may lead to communication errors when slave device tries to stretch SCL clock but unable to hold SCL line low. If that happens, try setting lower I²C speed. !!! caution If your module reboots when trying to use GPIO16 pin, then it is wired to RESET pin to support deep sleep mode and you cannot use GPIO16 for I²C bus or other purposes. + ## i2c.address() Setup I²C address and read/write mode for the next transfer. +On I²C bus every device is addressed by 7-bit number. Address for the particular device can be found in its datasheet. #### Syntax `i2c.address(id, device_addr, direction)` @@ -74,7 +82,7 @@ scl = 2 -- initialize i2c, set pin 1 as sda, set pin 2 as scl i2c.setup(id, sda, scl, i2c.FAST) --- user defined function: read from reg_addr content of dev_addr +-- user defined function: read 1 byte of data from device function read_reg(id, dev_addr, reg_addr) i2c.start(id) i2c.address(id, dev_addr, i2c.TRANSMITTER) @@ -105,11 +113,11 @@ Initialize the I²C bus with the selected bus number, pins and speed. - `id` 0~9, bus number - `pinSDA` 1~12, IO index - `pinSCL` 0~12, IO index -- `speed` `i2c.SLOW`, `i2c.FAST`, `i2c.FASTPLUS` or any clock frequency in range of 25000-1000000 Hz. -FASTPLUS mode requires setting CPU frequency to 160MHz with function node.setcpufreq(node.CPU160MHZ), otherwise speed won't be much faster than in FAST mode. +- `speed` `i2c.SLOW` (100kHz), `i2c.FAST` (400kHz), `i2c.FASTPLUS` (1MHz) or any clock frequency in range of 25000-1000000 Hz. +FASTPLUS mode results in 600kHz I2C clock speed at default 80MHz CPU frequency. To get 1MHz I2C clock speed change CPU frequency to 160MHz with function `node.setcpufreq(node.CPU160MHZ)`. #### Returns -`speed` the selected speed +`speed` the selected speed, `0` if bus initialization error. #### Example ```lua From 2371f3b5b786fb669fd369e8ce625c8da032f6a8 Mon Sep 17 00:00:00 2001 From: Natalia Sorokina Date: Mon, 5 Nov 2018 21:53:08 +0300 Subject: [PATCH 6/7] Add bus status check in setup(); simplify getDC(); remove unnesessary lines in ACK read/write --- app/driver/i2c_master.c | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/app/driver/i2c_master.c b/app/driver/i2c_master.c index 874ca79501..a1234887f6 100644 --- a/app/driver/i2c_master.c +++ b/app/driver/i2c_master.c @@ -43,8 +43,12 @@ * NEW driver * Enabled if I2C_MASTER_OLD_VERSION is not defined in user_config.h *******************************************************************************/ +// Supports multiple i2c buses +// I2C speed in range 25kHz - 550kHz (25kHz - 1MHz if CPU at 160MHz) +// If GPIO16 is used as SCL then speed is limited to 25kHz - 400kHz +// Speed is defined for every bus separately -// enable use GPIO16 (D0) pin as SCL line. ~450 kHz maximum frequency +// enable use GPIO16 (D0) pin as SCL line #ifdef I2C_MASTER_GPIO16_ENABLE #define IS_PIN16(n) ((n)==16) // CPU_CYCLES_BETWEEN_DELAYS describes how much cpu cycles code runs @@ -195,16 +199,7 @@ i2c_master_setDC(uint16 id, uint8 SDA, uint8 SCL) static inline uint8 ICACHE_FLASH_ATTR i2c_master_getDC(uint16 id) { - uint8 sda_out; - uint32 gpio_in_mask; - //instead of: gpio_in_mask = gpio_input_get(); - asm volatile("l16ui %[gpio_in_mask], %[gpio_in_addr], 0;" //read gpio state - "memw;" //wait for read completion - :[gpio_in_mask] "=r" (gpio_in_mask) - :[gpio_in_addr] "r" (PERIPHS_GPIO_BASEADDR + GPIO_IN_ADDRESS) - ); - sda_out = (gpio_in_mask >> i2c[id]->pin_SDA) & 1; - return sda_out; + return (READ_PERI_REG(PERIPHS_GPIO_BASEADDR + GPIO_IN_ADDRESS) >> i2c[id]->pin_SDA) & 1; } /****************************************************************************** @@ -299,7 +294,13 @@ i2c_master_setup(uint16 id, uint8 sda, uint8 scl, uint32 speed) ETS_GPIO_INTR_ENABLE(); //enable gpio interrupts + if (! (gpio_input_get() ^ i2c[id]->pin_SCL_mask)){ //SCL is in low state, bus failure + return 0; + } i2c_master_init(id); + if (! (gpio_input_get() ^ i2c[id]->pin_SDA_mask)){ //SDA is in low state, bus failure + return 0; + } return i2c[id]->speed; } @@ -344,6 +345,7 @@ i2c_master_readByte(uint16 id, sint16 ack) uint8 retVal = 0; uint8 k; sint8 i; + //invert and clamp ACK to 0/1, because ACK == 1 for i2c means SDA in low state uint8 ackLevel = (ack ? 0 : 1); i2c_master_setDC(id, i2c[id]->last_SDA, 0); @@ -351,15 +353,13 @@ i2c_master_readByte(uint16 id, sint16 ack) for (i = 7; i >= 0; i--) { i2c_master_setDC(id, 1, 1); k = i2c_master_getDC(id); - i2c_master_setDC(id, 1, 0); + i2c_master_setDC(id, 1, 0); // unnecessary in last iteration k <<= i; retVal |= k; } // set ACK - i2c_master_setDC(id, i2c[id]->last_SDA, 0); i2c_master_setDC(id, ackLevel, 0); i2c_master_setDC(id, ackLevel, 1); - i2c_master_setDC(id, ackLevel, 0); i2c_master_setDC(id, 1, 0); return retVal; } @@ -383,9 +383,7 @@ i2c_master_writeByte(uint16 id, uint8 wrdata) i2c_master_setDC(id, dat, 0); i2c_master_setDC(id, dat, 1); } - i2c_master_setDC(id, dat, 0); //get ACK - //i2c_master_setDC(id, i2c[id]->last_SDA, 0); i2c_master_setDC(id, 1, 0); i2c_master_setDC(id, 1, 1); retVal = i2c_master_getDC(id); From e0ad8860a9fa6fef7f274e9fc9ac5ceb8c5141ab Mon Sep 17 00:00:00 2001 From: Natalia Sorokina Date: Mon, 18 Feb 2019 13:51:22 +0300 Subject: [PATCH 7/7] Fix for moved doc file and trailing whitespaces --- app/driver/i2c_master.c | 18 +++++++++--------- docs/modules/i2c.md | 8 ++++---- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/app/driver/i2c_master.c b/app/driver/i2c_master.c index a1234887f6..b3ec4869da 100644 --- a/app/driver/i2c_master.c +++ b/app/driver/i2c_master.c @@ -51,12 +51,12 @@ // enable use GPIO16 (D0) pin as SCL line #ifdef I2C_MASTER_GPIO16_ENABLE #define IS_PIN16(n) ((n)==16) -// CPU_CYCLES_BETWEEN_DELAYS describes how much cpu cycles code runs +// CPU_CYCLES_BETWEEN_DELAYS describes how much cpu cycles code runs // between i2c_master_setDC() calls if delay is zero and i2c_master_set_DC_delay() // is not being called. This is not exact value, but proportional with length of code. // Increasing the value results in less delay and faster i2c clock speed. #define CPU_CYCLES_BETWEEN_DELAYS 80 -// CPU_CYCLES_GPIO16 is added to CPU_CYCLES_BETWEEN_DELAYS, +// CPU_CYCLES_GPIO16 is added to CPU_CYCLES_BETWEEN_DELAYS, // as RTC-related IO takes much more time than standard GPIOs. // Increasing the value results in less delay and faster i2c clock speed for GPIO16. #define CPU_CYCLES_GPIO16 90 @@ -64,7 +64,7 @@ #else // If GPIO16 support is not enabled, remove GPIO16-related code during compile // and change timing constants. -#define IS_PIN16(n) (0) +#define IS_PIN16(n) (0) #define CPU_CYCLES_BETWEEN_DELAYS 74 #endif //I2C_MASTER_GPIO16_ENABLE @@ -275,7 +275,7 @@ i2c_master_setup(uint16 id, uint8 sda, uint8 scl, uint32 speed) ETS_GPIO_INTR_DISABLE(); //disable gpio interrupts if (IS_PIN16(i2c[id]->pin_SCL)){ //if GPIO16 - CLEAR_PERI_REG_MASK(PAD_XPD_DCDC_CONF, 0x43); //disable all functions for XPD_DCDC + CLEAR_PERI_REG_MASK(PAD_XPD_DCDC_CONF, 0x43); //disable all functions for XPD_DCDC SET_PERI_REG_MASK(PAD_XPD_DCDC_CONF, 0x1); // select function RTC_GPIO0 for pin XPD_DCDC CLEAR_PERI_REG_MASK(RTC_GPIO_CONF, 0x1); //mux configuration for out enable SET_PERI_REG_MASK(RTC_GPIO_ENABLE, 0x1); //out enable @@ -347,7 +347,7 @@ i2c_master_readByte(uint16 id, sint16 ack) sint8 i; //invert and clamp ACK to 0/1, because ACK == 1 for i2c means SDA in low state uint8 ackLevel = (ack ? 0 : 1); - + i2c_master_setDC(id, i2c[id]->last_SDA, 0); i2c_master_setDC(id, 1, 0); for (i = 7; i >= 0; i--) { @@ -448,7 +448,7 @@ i2c_master_setDC(uint8 SDA, uint8 SCL) I2C_MASTER_SDA_HIGH_SCL_LOW(); } else { I2C_MASTER_SDA_HIGH_SCL_HIGH(); - } + } if(1 == SCL) { do { @@ -517,7 +517,7 @@ i2c_master_configured(uint16 id) * FunctionName : i2c_master_setup * Description : config SDA and SCL gpio to open-drain output mode, * mux and gpio num defined in i2c_master.h - * Parameters : bus id, uint8 sda, uint8 scl, uint32 speed + * Parameters : bus id, uint8 sda, uint8 scl, uint32 speed * Returns : configured speed *******************************************************************************/ uint32 ICACHE_FLASH_ATTR @@ -589,7 +589,7 @@ i2c_master_readByte(uint16 id, sint16 ack) uint8 retVal = 0; uint8 k, i; uint8 ackLevel = (ack ? 0 : 1); - + i2c_master_wait(5); i2c_master_setDC(m_nLastSDA, 0); @@ -632,7 +632,7 @@ i2c_master_writeByte(uint16 id, uint8 wrdata) uint8 dat; sint8 i; uint8 retVal; - + i2c_master_wait(5); i2c_master_setDC(m_nLastSDA, 0); diff --git a/docs/modules/i2c.md b/docs/modules/i2c.md index 207ec33f86..94ba23557a 100644 --- a/docs/modules/i2c.md +++ b/docs/modules/i2c.md @@ -1,8 +1,8 @@ # I²C Module | Since | Origin / Contributor | Maintainer | Source | | :----- | :-------------------- | :---------- | :------ | -| 2014-12-22 | [Zeroday](https://github.com/funshine) | [Zeroday](https://github.com/funshine) | [i2c.c](../../../app/modules/i2c.c)| -| 2018-08-30 | [Natalia Sorokina](https://github.com/sonaux) | | [i2c_master.c](../../../app/driver/i2c_master.c)| +| 2014-12-22 | [Zeroday](https://github.com/funshine) | [Zeroday](https://github.com/funshine) | [i2c.c](../../app/modules/i2c.c)| +| 2018-08-30 | [Natalia Sorokina](https://github.com/sonaux) | | [i2c_master.c](../../app/driver/i2c_master.c)| I²C (I2C, IIC) is a serial 2-wire bus for communicating with various devices. Also known as SMBus or TWI, though SMBus have some additions to the I2C protocol. ESP8266 chip does not have hardware I²C, so module uses software I²C driver. @@ -15,14 +15,14 @@ This module supports: - Clock stretching (slow slave device can tell the master to wait) - Sharing SDA line over multiple I²C buses to save available pins - GPIO16 pin can be used as SCL pin, but selected bus will be limited to not more than FAST speed. - + HIGH-speed mode (3.5MHz clock) and 10-bit addressing scheme is not supported. You have to call `i2c.setup` on a given I²C bus at least once before communicating to any device connected to that bus, otherwise you will get an error. I²C bus designed to work in open-drain mode, so it needs pull-up resistors 1k - 10k on SDA and SCL lines. Though many peripheral modules have pull-up resistors onboard and will work without additional external resistors. -Hint for using many identical devices with same address: +Hint for using many identical devices with same address: Many devices allow to choose between 2 I²C addresses via pin or soldered 0 Ohm resistor. If address change is not an option or you need to use more than 2 similar devices, you can use different I²C buses. Initialize them once by calling `i2c.setup` with different bus numbers and pins, then refer to each device by bus id and device address.