From 3cd9a4a0e07225d28c3fbd277dba128d7fca94eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mate=CC=8Cj=20Sychra?= Date: Mon, 24 Sep 2018 15:20:36 +0200 Subject: [PATCH 1/3] I2C slave support; resolving conflicts against current master --- cores/esp8266/core_esp8266_si2c.c | 737 ++++++++++++++++++++++++++++-- cores/esp8266/twi.h | 15 + cores/esp8266/twi_util.h | 243 ++++++++++ libraries/Wire/Wire.cpp | 76 +-- 4 files changed, 989 insertions(+), 82 deletions(-) create mode 100644 cores/esp8266/twi_util.h diff --git a/cores/esp8266/core_esp8266_si2c.c b/cores/esp8266/core_esp8266_si2c.c index 784a546be2..b7f0b78da4 100644 --- a/cores/esp8266/core_esp8266_si2c.c +++ b/cores/esp8266/core_esp8266_si2c.c @@ -17,15 +17,89 @@ You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + Modified January 2017 by Bjorn Hammarberg (bjoham@esp8266.com) - i2c slave support */ #include "twi.h" #include "pins_arduino.h" #include "wiring_private.h" unsigned int preferred_si2c_clock = 100000; +#include "twi_util.h" + +#include "ets_sys.h" + unsigned char twi_dcount = 18; static unsigned char twi_sda, twi_scl; static uint32_t twi_clockStretchLimit; +static unsigned char twi_addr = 0; + +// modes (private) +#define TWIPM_UNKNOWN 0 +#define TWIPM_IDLE 1 +#define TWIPM_ADDRESSED 2 +#define TWIPM_WAIT 3 + +// states (private) +#define TWIP_UNKNOWN 0 +#define TWIP_IDLE 1 +#define TWIP_START 2 +#define TWIP_SEND_ACK 3 +#define TWIP_WAIT_ACK 4 +#define TWIP_WAIT_STOP 5 +#define TWIP_SLA_W 6 +#define TWIP_SLA_R 7 +#define TWIP_REP_START 8 +#define TWIP_READ 9 +#define TWIP_STOP 10 +#define TWIP_REC_ACK 11 +#define TWIP_READ_ACK 12 +#define TWIP_RWAIT_ACK 13 +#define TWIP_WRITE 14 +#define TWIP_BUS_ERR 15 + +static volatile uint8_t twip_mode = TWIPM_IDLE; +static volatile uint8_t twip_state = TWIP_IDLE; +static volatile uint8_t twip_status = TW_NO_INFO; +static volatile uint8_t bitCount = 0; + +#define TWDR twi_data +static volatile uint8_t twi_data = 0x00; +static volatile uint8_t twi_ack = 0; +static volatile uint8_t twi_ack_rec = 0; +static volatile int twi_timeout_ms = 10; + +#define TWI_READY 0 +#define TWI_MRX 1 +#define TWI_MTX 2 +#define TWI_SRX 3 +#define TWI_STX 4 +static volatile uint8_t twi_state = TWI_READY; +static volatile uint8_t twi_error = 0xFF; + +static uint8_t twi_txBuffer[TWI_BUFFER_LENGTH]; +static volatile uint8_t twi_txBufferIndex; +static volatile uint8_t twi_txBufferLength; + +static uint8_t twi_rxBuffer[TWI_BUFFER_LENGTH]; +static volatile uint8_t twi_rxBufferIndex; + +static void (*twi_onSlaveTransmit)(void); +static void (*twi_onSlaveReceive)(uint8_t*, int); + +static void onSclChange(void); +static void onSdaChange(void); + +#define EVENTTASK_QUEUE_SIZE 1 +#define EVENTTASK_QUEUE_PRIO 2 + +#define TWI_SIG_RANGE 0x00000100 +#define TWI_SIG_RX (TWI_SIG_RANGE + 0x01) +#define TWI_SIG_TX (TWI_SIG_RANGE + 0x02) + +static ETSEvent eventTaskQueue[EVENTTASK_QUEUE_SIZE]; +static void eventTask(ETSEvent *e); +static ETSTimer timer; +static void onTimer(void *timer_arg); #define SDA_LOW() (GPES = (1 << twi_sda)) //Enable SDA (becomes output and since GPO is 0 for the pin, it will pull the line low) #define SDA_HIGH() (GPEC = (1 << twi_sda)) //Disable SDA (becomes input and since it has pullup it will go high) @@ -45,17 +119,14 @@ static uint32_t twi_clockStretchLimit; #endif void twi_setClock(unsigned int freq){ - preferred_si2c_clock = freq; #if F_CPU == FCPU80 - if(freq <= 50000) twi_dcount = 38;//about 50KHz - else if(freq <= 100000) twi_dcount = 19;//about 100KHz + if(freq <= 100000) twi_dcount = 19;//about 100KHz else if(freq <= 200000) twi_dcount = 8;//about 200KHz else if(freq <= 300000) twi_dcount = 3;//about 300KHz else if(freq <= 400000) twi_dcount = 1;//about 400KHz else twi_dcount = 1;//about 400KHz #else - if(freq <= 50000) twi_dcount = 64;//about 50KHz - else if(freq <= 100000) twi_dcount = 32;//about 100KHz + if(freq <= 100000) twi_dcount = 32;//about 100KHz else if(freq <= 200000) twi_dcount = 14;//about 200KHz else if(freq <= 300000) twi_dcount = 8;//about 300KHz else if(freq <= 400000) twi_dcount = 5;//about 400KHz @@ -69,36 +140,59 @@ void twi_setClockStretchLimit(uint32_t limit){ twi_clockStretchLimit = limit * TWI_CLOCK_STRETCH_MULTIPLIER; } -void twi_init(unsigned char sda, unsigned char scl){ +void twi_init(unsigned char sda, unsigned char scl) +{ + // set timer function + ets_timer_setfn(&timer, onTimer, NULL); + + // create event task + ets_task(eventTask, EVENTTASK_QUEUE_PRIO, eventTaskQueue, EVENTTASK_QUEUE_SIZE); + twi_sda = sda; twi_scl = scl; pinMode(twi_sda, INPUT_PULLUP); pinMode(twi_scl, INPUT_PULLUP); twi_setClock(preferred_si2c_clock); + //pinMode(2, OUTPUT); + //pinMode(12, OUTPUT); + //pinMode(14, OUTPUT); + //pinMode(13, OUTPUT); + //digitalWrite(2, HIGH); twi_setClockStretchLimit(230); // default value is 230 uS + + if (twi_addr != 0) + { + attachInterrupt(scl, onSclChange, CHANGE); + attachInterrupt(sda, onSdaChange, CHANGE); + } } +void twi_setAddress(uint8_t address) +{ + // set twi slave address (skip over R/W bit) + twi_addr = address << 1; +} +#if 0 void twi_stop(void){ pinMode(twi_sda, INPUT); pinMode(twi_scl, INPUT); } +#endif -static void twi_delay(unsigned char v){ +static void ICACHE_RAM_ATTR twi_delay(unsigned char v){ unsigned int i; #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-but-set-variable" unsigned int reg; - for(i=0;i0) { //if SDA low, read the bits slaves have to sent to a max - --clockCount; + while (SDA_READ()==0 && clockCount>0){ //if SDA low, read the bits slaves have to sent to a max twi_read_bit(); - if (SCL_READ()==0) - return I2C_SCL_HELD_LOW_AFTER_READ; //I2C bus error. SCL held low beyond slave clock stretch time + if (SCL_READ()==0) return I2C_SCL_HELD_LOW_AFTER_READ; //I2C bus error. SCL held low beyond slave clock stretch time } - if (SDA_READ()==0) - return I2C_SDA_HELD_LOW; //I2C bus error. SDA line held low by slave/another_master after n bits. + if (SDA_READ()==0) return I2C_SDA_HELD_LOW; //I2C bus error. SDA line held low by slave/another_master after n bits. + + if(!twi_write_start()) return I2C_SDA_HELD_LOW_AFTER_INIT; //line busy. SDA again held low by another device. 2nd master? + else return I2C_OK; //all ok +} + +uint8_t twi_transmit(const uint8_t* data, uint8_t length) +{ + uint8_t i; + + // ensure data will fit into buffer + if (length > TWI_BUFFER_LENGTH) { + return 1; + } + + // ensure we are currently a slave transmitter + if (twi_state != TWI_STX) { + return 2; + } + + // set length and copy data into tx buffer + twi_txBufferLength = length; + for (i = 0; i < length; ++i) { + twi_txBuffer[i] = data[i]; + } + + return 0; +} + +void twi_attachSlaveRxEvent( void (*function)(uint8_t*, int) ) +{ + twi_onSlaveReceive = function; +} + +void twi_attachSlaveTxEvent( void (*function)(void) ) +{ + twi_onSlaveTransmit = function; +} + +void ICACHE_RAM_ATTR twi_reply(uint8_t ack) +{ + // transmit master read ready signal, with or without ack + if (ack) { + //TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWINT) | _BV(TWEA); + SCL_HIGH(); // _BV(TWINT) + twi_ack = 1; // _BV(TWEA) + } else { + //TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWINT); + SCL_HIGH(); // _BV(TWINT) + twi_ack = 0; // ~_BV(TWEA) + } +} + +#if 1 +void ICACHE_RAM_ATTR twi_stop(void) +{ + // send stop condition + //TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWINT) | _BV(TWSTO); + SCL_HIGH(); // _BV(TWINT) + twi_ack = 1; // _BV(TWEA) + twi_delay(5); // Maybe this should be here + SDA_HIGH(); // _BV(TWSTO) + + // wait for stop condition to be exectued on bus + // TWINT is not set after a stop condition! + while (false) { //TWCR & _BV(TWSTO)){ + continue; + } + + // update twi state + twi_state = TWI_READY; +} +#endif + +void ICACHE_RAM_ATTR twi_releaseBus(void) +{ + // release bus + //TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWINT); + SCL_HIGH(); // _BV(TWINT) + twi_ack = 1; // _BV(TWEA) + SDA_HIGH(); + + // update twi state + twi_state = TWI_READY; +} + +void ICACHE_RAM_ATTR onTimer(void *timer_arg) +{ + //digitalWrite(13, HIGH); + twi_releaseBus(); + //ets_timer_disarm(&timer); + + twip_status = TW_BUS_ERROR; + twi_onTwipEvent(twip_status); + twip_mode = TWIPM_WAIT; + twip_state = TWIP_BUS_ERR; + //digitalWrite(13, LOW); +} + +static void eventTask(ETSEvent *e) +{ + //digitalWrite(14, HIGH); + + if (e == NULL) { + return; + } + + switch (e->sig) + { + case TWI_SIG_TX: + twi_onSlaveTransmit(); + + // if they didn't change buffer & length, initialize it + if (twi_txBufferLength == 0) { + twi_txBufferLength = 1; + twi_txBuffer[0] = 0x00; + } + + // Initiate transmission + twi_onTwipEvent(TW_ST_DATA_ACK); + + break; + + case TWI_SIG_RX: + // ack future responses and leave slave receiver state + twi_releaseBus(); + twi_onSlaveReceive(twi_rxBuffer, e->par); + break; + } - if(!twi_write_start()) - return I2C_SDA_HELD_LOW_AFTER_INIT; //line busy. SDA again held low by another device. 2nd master? + //digitalWrite(14, LOW); +} + +void ICACHE_RAM_ATTR twi_onTwipEvent(uint8_t status) +{ + //digitalWrite(13, HIGH); + //switch(TW_STATUS){ + switch(status) { +#if 0 + // All Master + case TW_START: // sent start condition + case TW_REP_START: // sent repeated start condition + // copy device address and r/w bit to output register and ack + TWDR = twi_slarw; + twi_reply(1); + break; + + // Master Transmitter + case TW_MT_SLA_ACK: // slave receiver acked address + case TW_MT_DATA_ACK: // slave receiver acked data + // if there is data to send, send it, otherwise stop + if(twi_masterBufferIndex < twi_masterBufferLength){ + // copy data to output register and ack + TWDR = twi_masterBuffer[twi_masterBufferIndex++]; + twi_reply(1); + }else{ + if (twi_sendStop) + twi_stop(); + else { + twi_inRepStart = true; // we're gonna send the START + // don't enable the interrupt. We'll generate the start, but we + // avoid handling the interrupt until we're in the next transaction, + // at the point where we would normally issue the start. + TWCR = _BV(TWINT) | _BV(TWSTA)| _BV(TWEN) ; + twi_state = TWI_READY; + } + } + break; + case TW_MT_SLA_NACK: // address sent, nack received + twi_error = TW_MT_SLA_NACK; + twi_stop(); + break; + case TW_MT_DATA_NACK: // data sent, nack received + twi_error = TW_MT_DATA_NACK; + twi_stop(); + break; + case TW_MT_ARB_LOST: // lost bus arbitration + twi_error = TW_MT_ARB_LOST; + twi_releaseBus(); + break; + + // Master Receiver + case TW_MR_DATA_ACK: // data received, ack sent + // put byte into buffer + twi_masterBuffer[twi_masterBufferIndex++] = TWDR; + case TW_MR_SLA_ACK: // address sent, ack received + // ack if more bytes are expected, otherwise nack + if(twi_masterBufferIndex < twi_masterBufferLength){ + twi_reply(1); + }else{ + twi_reply(0); + } + break; + case TW_MR_DATA_NACK: // data received, nack sent + // put final byte into buffer + twi_masterBuffer[twi_masterBufferIndex++] = TWDR; + if (twi_sendStop) + twi_stop(); + else { + twi_inRepStart = true; // we're gonna send the START + // don't enable the interrupt. We'll generate the start, but we + // avoid handling the interrupt until we're in the next transaction, + // at the point where we would normally issue the start. + TWCR = _BV(TWINT) | _BV(TWSTA)| _BV(TWEN) ; + twi_state = TWI_READY; + } + break; + case TW_MR_SLA_NACK: // address sent, nack received + twi_stop(); + break; + // TW_MR_ARB_LOST handled by TW_MT_ARB_LOST case +#endif + + // Slave Receiver + case TW_SR_SLA_ACK: // addressed, returned ack + case TW_SR_GCALL_ACK: // addressed generally, returned ack + case TW_SR_ARB_LOST_SLA_ACK: // lost arbitration, returned ack + case TW_SR_ARB_LOST_GCALL_ACK: // lost arbitration, returned ack + // enter slave receiver mode + twi_state = TWI_SRX; + // indicate that rx buffer can be overwritten and ack + twi_rxBufferIndex = 0; + twi_reply(1); + break; + case TW_SR_DATA_ACK: // data received, returned ack + case TW_SR_GCALL_DATA_ACK: // data received generally, returned ack + // if there is still room in the rx buffer + if(twi_rxBufferIndex < TWI_BUFFER_LENGTH){ + // put byte in buffer and ack + twi_rxBuffer[twi_rxBufferIndex++] = TWDR; + twi_reply(1); + }else{ + // otherwise nack + twi_reply(0); + } + break; + case TW_SR_STOP: // stop or repeated start condition received + // put a null char after data if there's room + if(twi_rxBufferIndex < TWI_BUFFER_LENGTH){ + twi_rxBuffer[twi_rxBufferIndex] = '\0'; + } + // callback to user-defined callback over event task to allow for non-RAM-residing code + //twi_rxBufferLock = true; // This may be necessary + ets_post(EVENTTASK_QUEUE_PRIO, TWI_SIG_RX, twi_rxBufferIndex); + + // since we submit rx buffer to "wire" library, we can reset it + twi_rxBufferIndex = 0; + break; + + case TW_SR_DATA_NACK: // data received, returned nack + case TW_SR_GCALL_DATA_NACK: // data received generally, returned nack + // nack back at master + twi_reply(0); + break; + + // Slave Transmitter + case TW_ST_SLA_ACK: // addressed, returned ack + case TW_ST_ARB_LOST_SLA_ACK: // arbitration lost, returned ack + // enter slave transmitter mode + twi_state = TWI_STX; + // ready the tx buffer index for iteration + twi_txBufferIndex = 0; + // set tx buffer length to be zero, to verify if user changes it + twi_txBufferLength = 0; + // callback to user-defined callback over event task to allow for non-RAM-residing code + // request for txBuffer to be filled and length to be set + // note: user must call twi_transmit(bytes, length) to do this + ets_post(EVENTTASK_QUEUE_PRIO, TWI_SIG_TX, 0); + break; + + case TW_ST_DATA_ACK: // byte sent, ack returned + // copy data to output register + TWDR = twi_txBuffer[twi_txBufferIndex++]; + + bitCount = 8; + bitCount--; + (twi_data & 0x80) ? SDA_HIGH() : SDA_LOW(); + twi_data <<= 1; + + // if there is more to send, ack, otherwise nack + if(twi_txBufferIndex < twi_txBufferLength){ + twi_reply(1); + }else{ + twi_reply(0); + } + break; + case TW_ST_DATA_NACK: // received nack, we are done + case TW_ST_LAST_DATA: // received ack, but we are done already! + // leave slave receiver state + twi_releaseBus(); + break; + + // All + case TW_NO_INFO: // no state information + break; + case TW_BUS_ERROR: // bus error, illegal stop/start + twi_error = TW_BUS_ERROR; + twi_stop(); + break; + } + //digitalWrite(13, LOW); +} + +void ICACHE_RAM_ATTR onSclChange(void) +{ + static uint8_t sda; + static uint8_t scl; + + //digitalWrite(2, LOW); + //digitalWrite(2, HIGH); + + sda = SDA_READ(); + scl = SCL_READ(); + + //digitalWrite(12, scl); + //digitalWrite(14, LOW); + + twip_status = 0xF8; // reset TWI status + + switch (twip_state) + { + case TWIP_IDLE: + case TWIP_WAIT_STOP: + case TWIP_BUS_ERR: + // ignore + break; + + case TWIP_START: + case TWIP_REP_START: + case TWIP_SLA_W: + case TWIP_READ: + if (!scl) { + // ignore + } else { + bitCount--; + twi_data <<= 1; + twi_data |= sda; + + if (bitCount != 0) { + // continue + } else { + twip_state = TWIP_SEND_ACK; + } + } + break; + + case TWIP_SEND_ACK: + if (scl) { + // ignore + } else { + if (twip_mode == TWIPM_IDLE) { + if ((twi_data & 0xFE) != twi_addr) { + // ignore + } else { + SDA_LOW(); + } + } else { + if (!twi_ack) { + // ignore + } else { + SDA_LOW(); + } + } + twip_state = TWIP_WAIT_ACK; + } + break; + + case TWIP_WAIT_ACK: + if (scl) { + // ignore + } else { + if (twip_mode == TWIPM_IDLE) { + if ((twi_data & 0xFE) != twi_addr) { + SDA_HIGH(); + twip_state = TWIP_WAIT_STOP; + } else { + SCL_LOW(); // clock stretching + SDA_HIGH(); + twip_mode = TWIPM_ADDRESSED; + if (!(twi_data & 0x01)) { + twip_status = TW_SR_SLA_ACK; + twi_onTwipEvent(twip_status); + bitCount = 8; + twip_state = TWIP_SLA_W; + } else { + twip_status = TW_ST_SLA_ACK; + twi_onTwipEvent(twip_status); + twip_state = TWIP_SLA_R; + } + } + } else { + SCL_LOW(); // clock stretching + SDA_HIGH(); + if (!twi_ack) { + twip_status = TW_SR_DATA_NACK; + twi_onTwipEvent(twip_status); + twip_mode = TWIPM_WAIT; + twip_state = TWIP_WAIT_STOP; + } else { + twip_status = TW_SR_DATA_ACK; + twi_onTwipEvent(twip_status); + bitCount = 8; + twip_state = TWIP_READ; + } + } + } + break; + + case TWIP_SLA_R: + case TWIP_WRITE: + if (scl) { + // ignore + } else { + bitCount--; + (twi_data & 0x80) ? SDA_HIGH() : SDA_LOW(); + twi_data <<= 1; + + if (bitCount != 0) { + // continue + } else { + twip_state = TWIP_REC_ACK; + } + } + break; + + case TWIP_REC_ACK: + if (scl) { + // ignore + } else { + SDA_HIGH(); + twip_state = TWIP_READ_ACK; + } + break; + + case TWIP_READ_ACK: + if (!scl) { + // ignore + } else { + twi_ack_rec = !sda; + twip_state = TWIP_RWAIT_ACK; + } + break; + + case TWIP_RWAIT_ACK: + if (scl) { + // ignore + } else { + SCL_LOW(); // clock stretching + if (twi_ack && twi_ack_rec) { + twip_status = TW_ST_DATA_ACK; + twi_onTwipEvent(twip_status); + twip_state = TWIP_WRITE; + } else { + // we have no more data to send and/or the master doesn't want anymore + twip_status = twi_ack_rec ? TW_ST_LAST_DATA : TW_ST_DATA_NACK; + twi_onTwipEvent(twip_status); + twip_mode = TWIPM_WAIT; + twip_state = TWIP_WAIT_STOP; + } + } + break; + + default: + break; + } +} - return I2C_OK; //all ok +void ICACHE_RAM_ATTR onSdaChange(void) +{ + static uint8_t sda; + static uint8_t scl; + sda = SDA_READ(); + scl = SCL_READ(); + + //digitalWrite(2, sda); + + switch (twip_state) + { + case TWIP_IDLE: + if (!scl) { + // DATA - ignore + } else if (sda) { + // STOP - ignore + } else { + // START + bitCount = 8; + twip_state = TWIP_START; + //digitalWrite(14, HIGH); + ets_timer_arm_new(&timer, twi_timeout_ms, false, true); // Once, ms + //digitalWrite(14, LOW); + } + break; + + case TWIP_START: + case TWIP_REP_START: + case TWIP_SEND_ACK: + case TWIP_WAIT_ACK: + case TWIP_SLA_R: + case TWIP_REC_ACK: + case TWIP_READ_ACK: + case TWIP_RWAIT_ACK: + case TWIP_WRITE: + if (!scl) { + // DATA - ignore + } else { + // START or STOP + SDA_HIGH(); // Should not be necessary + twip_status = TW_BUS_ERROR; + twi_onTwipEvent(twip_status); + twip_mode = TWIPM_WAIT; + twip_state = TWIP_BUS_ERR; + } + break; + + case TWIP_WAIT_STOP: + case TWIP_BUS_ERR: + if (!scl) { + // DATA - ignore + } else { + if (sda) { + // STOP + SCL_LOW(); // clock stretching + ets_timer_disarm(&timer); + twip_state = TWIP_IDLE; + twip_mode = TWIPM_IDLE; + SCL_HIGH(); + } else { + // START + if (twip_state == TWIP_BUS_ERR) { + // ignore + } else { + bitCount = 8; + twip_state = TWIP_REP_START; + ets_timer_arm_new(&timer, twi_timeout_ms, false, true); // Once, ms + } + } + } + break; + + case TWIP_SLA_W: + case TWIP_READ: + if (!scl) { + // DATA - ignore + } else { + // START or STOP + if (bitCount != 7) { + // inside byte transfer - error + twip_status = TW_BUS_ERROR; + twi_onTwipEvent(twip_status); + twip_mode = TWIPM_WAIT; + twip_state = TWIP_BUS_ERR; + } else { + // during first bit in byte transfer - ok + SCL_LOW(); // clock stretching + twip_status = TW_SR_STOP; + twi_onTwipEvent(twip_status); + if (sda) { + // STOP + ets_timer_disarm(&timer); + twip_state = TWIP_IDLE; + twip_mode = TWIPM_IDLE; + } else { + // START + bitCount = 8; + ets_timer_arm_new(&timer, twi_timeout_ms, false, true); // Once, ms + twip_state = TWIP_REP_START; + twip_mode = TWIPM_IDLE; + } + } + } + break; + default: + break; + } } diff --git a/cores/esp8266/twi.h b/cores/esp8266/twi.h index 75ac52d563..050264e39b 100644 --- a/cores/esp8266/twi.h +++ b/cores/esp8266/twi.h @@ -17,6 +17,7 @@ You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + Modified January 2017 by Bjorn Hammarberg (bjoham@esp8266.com) - i2c slave support */ #ifndef SI2C_h #define SI2C_h @@ -32,7 +33,12 @@ extern "C" { #define I2C_SDA_HELD_LOW 3 #define I2C_SDA_HELD_LOW_AFTER_INIT 4 +#ifndef TWI_BUFFER_LENGTH +#define TWI_BUFFER_LENGTH 32 +#endif + void twi_init(unsigned char sda, unsigned char scl); +void twi_setAddress(uint8_t); void twi_stop(void); void twi_setClock(unsigned int freq); void twi_setClockStretchLimit(uint32_t limit); @@ -40,6 +46,15 @@ uint8_t twi_writeTo(unsigned char address, unsigned char * buf, unsigned int len uint8_t twi_readFrom(unsigned char address, unsigned char * buf, unsigned int len, unsigned char sendStop); uint8_t twi_status(); +uint8_t twi_transmit(const uint8_t*, uint8_t); + +void twi_attachSlaveRxEvent( void (*)(uint8_t*, int) ); +void twi_attachSlaveTxEvent( void (*)(void) ); +void twi_reply(uint8_t); +//void twi_stop(void); +void twi_releaseBus(void); + + #ifdef __cplusplus } #endif diff --git a/cores/esp8266/twi_util.h b/cores/esp8266/twi_util.h new file mode 100644 index 0000000000..60a92fc965 --- /dev/null +++ b/cores/esp8266/twi_util.h @@ -0,0 +1,243 @@ +/* Copyright (c) 2002, Marek Michalkiewicz + Copyright (c) 2005, 2007 Joerg Wunsch + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + * Neither the name of the copyright holders nor the names of + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Modified January 2017 by Bjorn Hammarberg (bjoham@esp8266.com) - i2c slave support +*/ + +/* $Id$ */ +/* copied from: Id: avr/twi.h,v 1.4 2004/11/01 21:19:54 arcanum Exp */ + +#ifndef _UTIL_TWI_H_ +#define _UTIL_TWI_H_ 1 + +//#include + +/** \file */ +/** \defgroup util_twi : TWI bit mask definitions + \code #include \endcode + + This header file contains bit mask definitions for use with + the AVR TWI interface. +*/ +/** \name TWSR values + + Mnemonics: +
TW_MT_xxx - master transmitter +
TW_MR_xxx - master receiver +
TW_ST_xxx - slave transmitter +
TW_SR_xxx - slave receiver + */ + +/*@{*/ +/* Master */ +/** \ingroup util_twi + \def TW_START + start condition transmitted */ +#define TW_START 0x08 + +/** \ingroup util_twi + \def TW_REP_START + repeated start condition transmitted */ +#define TW_REP_START 0x10 + +/* Master Transmitter */ +/** \ingroup util_twi + \def TW_MT_SLA_ACK + SLA+W transmitted, ACK received */ +#define TW_MT_SLA_ACK 0x18 + +/** \ingroup util_twi + \def TW_MT_SLA_NACK + SLA+W transmitted, NACK received */ +#define TW_MT_SLA_NACK 0x20 + +/** \ingroup util_twi + \def TW_MT_DATA_ACK + data transmitted, ACK received */ +#define TW_MT_DATA_ACK 0x28 + +/** \ingroup util_twi + \def TW_MT_DATA_NACK + data transmitted, NACK received */ +#define TW_MT_DATA_NACK 0x30 + +/** \ingroup util_twi + \def TW_MT_ARB_LOST + arbitration lost in SLA+W or data */ +#define TW_MT_ARB_LOST 0x38 + +/* Master Receiver */ +/** \ingroup util_twi + \def TW_MR_ARB_LOST + arbitration lost in SLA+R or NACK */ +#define TW_MR_ARB_LOST 0x38 + +/** \ingroup util_twi + \def TW_MR_SLA_ACK + SLA+R transmitted, ACK received */ +#define TW_MR_SLA_ACK 0x40 + +/** \ingroup util_twi + \def TW_MR_SLA_NACK + SLA+R transmitted, NACK received */ +#define TW_MR_SLA_NACK 0x48 + +/** \ingroup util_twi + \def TW_MR_DATA_ACK + data received, ACK returned */ +#define TW_MR_DATA_ACK 0x50 + +/** \ingroup util_twi + \def TW_MR_DATA_NACK + data received, NACK returned */ +#define TW_MR_DATA_NACK 0x58 + +/* Slave Transmitter */ +/** \ingroup util_twi + \def TW_ST_SLA_ACK + SLA+R received, ACK returned */ +#define TW_ST_SLA_ACK 0xA8 + +/** \ingroup util_twi + \def TW_ST_ARB_LOST_SLA_ACK + arbitration lost in SLA+RW, SLA+R received, ACK returned */ +#define TW_ST_ARB_LOST_SLA_ACK 0xB0 + +/** \ingroup util_twi + \def TW_ST_DATA_ACK + data transmitted, ACK received */ +#define TW_ST_DATA_ACK 0xB8 + +/** \ingroup util_twi + \def TW_ST_DATA_NACK + data transmitted, NACK received */ +#define TW_ST_DATA_NACK 0xC0 + +/** \ingroup util_twi + \def TW_ST_LAST_DATA + last data byte transmitted, ACK received */ +#define TW_ST_LAST_DATA 0xC8 + +/* Slave Receiver */ +/** \ingroup util_twi + \def TW_SR_SLA_ACK + SLA+W received, ACK returned */ +#define TW_SR_SLA_ACK 0x60 + +/** \ingroup util_twi + \def TW_SR_ARB_LOST_SLA_ACK + arbitration lost in SLA+RW, SLA+W received, ACK returned */ +#define TW_SR_ARB_LOST_SLA_ACK 0x68 + +/** \ingroup util_twi + \def TW_SR_GCALL_ACK + general call received, ACK returned */ +#define TW_SR_GCALL_ACK 0x70 + +/** \ingroup util_twi + \def TW_SR_ARB_LOST_GCALL_ACK + arbitration lost in SLA+RW, general call received, ACK returned */ +#define TW_SR_ARB_LOST_GCALL_ACK 0x78 + +/** \ingroup util_twi + \def TW_SR_DATA_ACK + data received, ACK returned */ +#define TW_SR_DATA_ACK 0x80 + +/** \ingroup util_twi + \def TW_SR_DATA_NACK + data received, NACK returned */ +#define TW_SR_DATA_NACK 0x88 + +/** \ingroup util_twi + \def TW_SR_GCALL_DATA_ACK + general call data received, ACK returned */ +#define TW_SR_GCALL_DATA_ACK 0x90 + +/** \ingroup util_twi + \def TW_SR_GCALL_DATA_NACK + general call data received, NACK returned */ +#define TW_SR_GCALL_DATA_NACK 0x98 + +/** \ingroup util_twi + \def TW_SR_STOP + stop or repeated start condition received while selected */ +#define TW_SR_STOP 0xA0 + +/* Misc */ +/** \ingroup util_twi + \def TW_NO_INFO + no state information available */ +#define TW_NO_INFO 0xF8 + +/** \ingroup util_twi + \def TW_BUS_ERROR + illegal start or stop condition */ +#define TW_BUS_ERROR 0x00 + +#if 0 + +/** + * \ingroup util_twi + * \def TW_STATUS_MASK + * The lower 3 bits of TWSR are reserved on the ATmega163. + * The 2 LSB carry the prescaler bits on the newer ATmegas. + */ +#define TW_STATUS_MASK (_BV(TWS7)|_BV(TWS6)|_BV(TWS5)|_BV(TWS4)|\ + _BV(TWS3)) +/** + * \ingroup util_twi + * \def TW_STATUS + * + * TWSR, masked by TW_STATUS_MASK + */ +#define TW_STATUS (TWSR & TW_STATUS_MASK) +/*@}*/ +#endif + + +/** + * \name R/~W bit in SLA+R/W address field. + */ + +/*@{*/ +/** \ingroup util_twi + \def TW_READ + SLA+R address */ +#define TW_READ 1 + +/** \ingroup util_twi + \def TW_WRITE + SLA+W address */ +#define TW_WRITE 0 +/*@}*/ + +#endif /* _UTIL_TWI_H_ */ diff --git a/libraries/Wire/Wire.cpp b/libraries/Wire/Wire.cpp index b83072914a..906b22eedf 100644 --- a/libraries/Wire/Wire.cpp +++ b/libraries/Wire/Wire.cpp @@ -19,6 +19,7 @@ Modified 2012 by Todd Krein (todd@krein.org) to implement repeated starts Modified December 2014 by Ivan Grokhotkov (ivan@esp8266.com) - esp8266 support Modified April 2015 by Hrsto Gochkov (ficeto@ficeto.com) - alternative esp8266 support + Modified January 2017 by Bjorn Hammarberg (bjoham@esp8266.com) - i2c slave support */ extern "C" { @@ -78,10 +79,9 @@ void TwoWire::begin(void){ } void TwoWire::begin(uint8_t address){ - (void)address; - // twi_setAddress(address); - // twi_attachSlaveTxEvent(onRequestService); - // twi_attachSlaveRxEvent(onReceiveService); + twi_setAddress(address); + twi_attachSlaveTxEvent(onRequestService); + twi_attachSlaveRxEvent(onReceiveService); begin(); } @@ -160,7 +160,7 @@ size_t TwoWire::write(uint8_t data){ ++txBufferIndex; txBufferLength = txBufferIndex; } else { - // i2c_slave_transmit(&data, 1); + twi_transmit(&data, 1); } return 1; } @@ -171,7 +171,7 @@ size_t TwoWire::write(const uint8_t *data, size_t quantity){ if(!write(data[i])) return i; } }else{ - // i2c_slave_transmit(data, quantity); + twi_transmit(data, quantity); } return quantity; } @@ -214,51 +214,53 @@ void TwoWire::flush(void){ void TwoWire::onReceiveService(uint8_t* inBytes, int numBytes) { - (void)inBytes; - (void)numBytes; // don't bother if user hasn't registered a callback - // if(!user_onReceive){ - // return; - // } + if (!user_onReceive) { + return; + } // // don't bother if rx buffer is in use by a master requestFrom() op // // i know this drops data, but it allows for slight stupidity // // meaning, they may not have read all the master requestFrom() data yet // if(rxBufferIndex < rxBufferLength){ // return; // } - // // copy twi rx buffer into local read buffer - // // this enables new reads to happen in parallel - // for(uint8_t i = 0; i < numBytes; ++i){ - // rxBuffer[i] = inBytes[i]; - // } - // // set rx iterator vars - // rxBufferIndex = 0; - // rxBufferLength = numBytes; - // // alert user program - // user_onReceive(numBytes); + + // copy twi rx buffer into local read buffer + // this enables new reads to happen in parallel + for (uint8_t i = 0; i < numBytes; ++i) { + rxBuffer[i] = inBytes[i]; + } + + // set rx iterator vars + rxBufferIndex = 0; + rxBufferLength = numBytes; + + // alert user program + user_onReceive(numBytes); } -void TwoWire::onRequestService(void){ - // // don't bother if user hasn't registered a callback - // if(!user_onRequest){ - // return; - // } - // // reset tx buffer iterator vars - // // !!! this will kill any pending pre-master sendTo() activity - // txBufferIndex = 0; - // txBufferLength = 0; - // // alert user program - // user_onRequest(); +void TwoWire::onRequestService(void) +{ + // don't bother if user hasn't registered a callback + if (!user_onRequest) { + return; + } + + // reset tx buffer iterator vars + // !!! this will kill any pending pre-master sendTo() activity + txBufferIndex = 0; + txBufferLength = 0; + + // alert user program + user_onRequest(); } -void TwoWire::onReceive( void (*function)(int) ){ - (void)function; - //user_onReceive = function; +void TwoWire::onReceive( void (*function)(int) ) { + user_onReceive = function; } void TwoWire::onRequest( void (*function)(void) ){ - (void)function; - //user_onRequest = function; + user_onRequest = function; } // Preinstantiate Objects ////////////////////////////////////////////////////// From 66dc03eae907028f3a16a690e9a17a1a6d124aa3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mate=CC=8Cj=20Sychra?= Date: Mon, 24 Sep 2018 16:54:37 +0200 Subject: [PATCH 2/3] removed unused argument, updateded to hopefully pass Travis --- cores/esp8266/core_esp8266_si2c.c | 180 +++++++++++++++--------------- 1 file changed, 91 insertions(+), 89 deletions(-) diff --git a/cores/esp8266/core_esp8266_si2c.c b/cores/esp8266/core_esp8266_si2c.c index b7f0b78da4..236fae38fd 100644 --- a/cores/esp8266/core_esp8266_si2c.c +++ b/cores/esp8266/core_esp8266_si2c.c @@ -99,7 +99,7 @@ static void onSdaChange(void); static ETSEvent eventTaskQueue[EVENTTASK_QUEUE_SIZE]; static void eventTask(ETSEvent *e); static ETSTimer timer; -static void onTimer(void *timer_arg); +static void onTimer(); #define SDA_LOW() (GPES = (1 << twi_sda)) //Enable SDA (becomes output and since GPO is 0 for the pin, it will pull the line low) #define SDA_HIGH() (GPEC = (1 << twi_sda)) //Disable SDA (becomes input and since it has pullup it will go high) @@ -119,14 +119,17 @@ static void onTimer(void *timer_arg); #endif void twi_setClock(unsigned int freq){ + preferred_si2c_clock = freq; #if F_CPU == FCPU80 - if(freq <= 100000) twi_dcount = 19;//about 100KHz + if(freq <= 50000) twi_dcount = 38;//about 50KHz + else if(freq <= 100000) twi_dcount = 19;//about 100KHz else if(freq <= 200000) twi_dcount = 8;//about 200KHz else if(freq <= 300000) twi_dcount = 3;//about 300KHz else if(freq <= 400000) twi_dcount = 1;//about 400KHz else twi_dcount = 1;//about 400KHz #else - if(freq <= 100000) twi_dcount = 32;//about 100KHz + if(freq <= 50000) twi_dcount = 64;//about 50KHz + else if(freq <= 100000) twi_dcount = 32;//about 100KHz else if(freq <= 200000) twi_dcount = 14;//about 200KHz else if(freq <= 300000) twi_dcount = 8;//about 300KHz else if(freq <= 400000) twi_dcount = 5;//about 400KHz @@ -142,12 +145,12 @@ void twi_setClockStretchLimit(uint32_t limit){ void twi_init(unsigned char sda, unsigned char scl) { - // set timer function + // set timer function ets_timer_setfn(&timer, onTimer, NULL); - + // create event task ets_task(eventTask, EVENTTASK_QUEUE_PRIO, eventTaskQueue, EVENTTASK_QUEUE_SIZE); - + twi_sda = sda; twi_scl = scl; pinMode(twi_sda, INPUT_PULLUP); @@ -159,7 +162,7 @@ void twi_init(unsigned char sda, unsigned char scl) //pinMode(13, OUTPUT); //digitalWrite(2, HIGH); twi_setClockStretchLimit(230); // default value is 230 uS - + if (twi_addr != 0) { attachInterrupt(scl, onSclChange, CHANGE); @@ -298,19 +301,19 @@ unsigned char twi_readFrom(unsigned char address, unsigned char* buf, unsigned i return 0; } -uint8_t twi_status(){ +uint8_t twi_status(){ if (SCL_READ()==0) return I2C_SCL_HELD_LOW; //SCL held low by another device, no procedure available to recover - int clockCount = 20; + int clockCount = 20; while (SDA_READ()==0 && clockCount>0){ //if SDA low, read the bits slaves have to sent to a max - twi_read_bit(); + twi_read_bit(); if (SCL_READ()==0) return I2C_SCL_HELD_LOW_AFTER_READ; //I2C bus error. SCL held low beyond slave clock stretch time } if (SDA_READ()==0) return I2C_SDA_HELD_LOW; //I2C bus error. SDA line held low by slave/another_master after n bits. if(!twi_write_start()) return I2C_SDA_HELD_LOW_AFTER_INIT; //line busy. SDA again held low by another device. 2nd master? - else return I2C_OK; //all ok + else return I2C_OK; //all ok } uint8_t twi_transmit(const uint8_t* data, uint8_t length) @@ -321,18 +324,18 @@ uint8_t twi_transmit(const uint8_t* data, uint8_t length) if (length > TWI_BUFFER_LENGTH) { return 1; } - + // ensure we are currently a slave transmitter if (twi_state != TWI_STX) { return 2; } - + // set length and copy data into tx buffer twi_txBufferLength = length; for (i = 0; i < length; ++i) { twi_txBuffer[i] = data[i]; } - + return 0; } @@ -393,52 +396,6 @@ void ICACHE_RAM_ATTR twi_releaseBus(void) twi_state = TWI_READY; } -void ICACHE_RAM_ATTR onTimer(void *timer_arg) -{ - //digitalWrite(13, HIGH); - twi_releaseBus(); - //ets_timer_disarm(&timer); - - twip_status = TW_BUS_ERROR; - twi_onTwipEvent(twip_status); - twip_mode = TWIPM_WAIT; - twip_state = TWIP_BUS_ERR; - //digitalWrite(13, LOW); -} - -static void eventTask(ETSEvent *e) -{ - //digitalWrite(14, HIGH); - - if (e == NULL) { - return; - } - - switch (e->sig) - { - case TWI_SIG_TX: - twi_onSlaveTransmit(); - - // if they didn't change buffer & length, initialize it - if (twi_txBufferLength == 0) { - twi_txBufferLength = 1; - twi_txBuffer[0] = 0x00; - } - - // Initiate transmission - twi_onTwipEvent(TW_ST_DATA_ACK); - - break; - - case TWI_SIG_RX: - // ack future responses and leave slave receiver state - twi_releaseBus(); - twi_onSlaveReceive(twi_rxBuffer, e->par); - break; - } - - //digitalWrite(14, LOW); -} void ICACHE_RAM_ATTR twi_onTwipEvent(uint8_t status) { @@ -457,7 +414,7 @@ void ICACHE_RAM_ATTR twi_onTwipEvent(uint8_t status) // Master Transmitter case TW_MT_SLA_ACK: // slave receiver acked address case TW_MT_DATA_ACK: // slave receiver acked data - // if there is data to send, send it, otherwise stop + // if there is data to send, send it, otherwise stop if(twi_masterBufferIndex < twi_masterBufferLength){ // copy data to output register and ack TWDR = twi_masterBuffer[twi_masterBufferIndex++]; @@ -467,7 +424,7 @@ void ICACHE_RAM_ATTR twi_onTwipEvent(uint8_t status) twi_stop(); else { twi_inRepStart = true; // we're gonna send the START - // don't enable the interrupt. We'll generate the start, but we + // don't enable the interrupt. We'll generate the start, but we // avoid handling the interrupt until we're in the next transaction, // at the point where we would normally issue the start. TWCR = _BV(TWINT) | _BV(TWSTA)| _BV(TWEN) ; @@ -507,12 +464,12 @@ void ICACHE_RAM_ATTR twi_onTwipEvent(uint8_t status) twi_stop(); else { twi_inRepStart = true; // we're gonna send the START - // don't enable the interrupt. We'll generate the start, but we + // don't enable the interrupt. We'll generate the start, but we // avoid handling the interrupt until we're in the next transaction, // at the point where we would normally issue the start. TWCR = _BV(TWINT) | _BV(TWSTA)| _BV(TWEN) ; twi_state = TWI_READY; - } + } break; case TW_MR_SLA_NACK: // address sent, nack received twi_stop(); @@ -555,13 +512,13 @@ void ICACHE_RAM_ATTR twi_onTwipEvent(uint8_t status) // since we submit rx buffer to "wire" library, we can reset it twi_rxBufferIndex = 0; break; - + case TW_SR_DATA_NACK: // data received, returned nack case TW_SR_GCALL_DATA_NACK: // data received generally, returned nack // nack back at master twi_reply(0); break; - + // Slave Transmitter case TW_ST_SLA_ACK: // addressed, returned ack case TW_ST_ARB_LOST_SLA_ACK: // arbitration lost, returned ack @@ -576,7 +533,7 @@ void ICACHE_RAM_ATTR twi_onTwipEvent(uint8_t status) // note: user must call twi_transmit(bytes, length) to do this ets_post(EVENTTASK_QUEUE_PRIO, TWI_SIG_TX, 0); break; - + case TW_ST_DATA_ACK: // byte sent, ack returned // copy data to output register TWDR = twi_txBuffer[twi_txBufferIndex++]; @@ -584,7 +541,7 @@ void ICACHE_RAM_ATTR twi_onTwipEvent(uint8_t status) bitCount = 8; bitCount--; (twi_data & 0x80) ? SDA_HIGH() : SDA_LOW(); - twi_data <<= 1; + twi_data <<= 1; // if there is more to send, ack, otherwise nack if(twi_txBufferIndex < twi_txBufferLength){ @@ -593,7 +550,7 @@ void ICACHE_RAM_ATTR twi_onTwipEvent(uint8_t status) twi_reply(0); } break; - case TW_ST_DATA_NACK: // received nack, we are done + case TW_ST_DATA_NACK: // received nack, we are done case TW_ST_LAST_DATA: // received ack, but we are done already! // leave slave receiver state twi_releaseBus(); @@ -610,20 +567,65 @@ void ICACHE_RAM_ATTR twi_onTwipEvent(uint8_t status) //digitalWrite(13, LOW); } +void ICACHE_RAM_ATTR onTimer() +{ + //digitalWrite(13, HIGH); + twi_releaseBus(); + twip_status = TW_BUS_ERROR; + twi_onTwipEvent(twip_status); + twip_mode = TWIPM_WAIT; + twip_state = TWIP_BUS_ERR; + //digitalWrite(13, LOW); +} + +static void eventTask(ETSEvent *e) +{ + //digitalWrite(14, HIGH); + + if (e == NULL) { + return; + } + + switch (e->sig) + { + case TWI_SIG_TX: + twi_onSlaveTransmit(); + + // if they didn't change buffer & length, initialize it + if (twi_txBufferLength == 0) { + twi_txBufferLength = 1; + twi_txBuffer[0] = 0x00; + } + + // Initiate transmission + twi_onTwipEvent(TW_ST_DATA_ACK); + + break; + + case TWI_SIG_RX: + // ack future responses and leave slave receiver state + twi_releaseBus(); + twi_onSlaveReceive(twi_rxBuffer, e->par); + break; + } + + //digitalWrite(14, LOW); +} + void ICACHE_RAM_ATTR onSclChange(void) { static uint8_t sda; static uint8_t scl; - + //digitalWrite(2, LOW); //digitalWrite(2, HIGH); - + sda = SDA_READ(); scl = SCL_READ(); - + //digitalWrite(12, scl); //digitalWrite(14, LOW); - + twip_status = 0xF8; // reset TWI status switch (twip_state) @@ -633,7 +635,7 @@ void ICACHE_RAM_ATTR onSclChange(void) case TWIP_BUS_ERR: // ignore break; - + case TWIP_START: case TWIP_REP_START: case TWIP_SLA_W: @@ -652,7 +654,7 @@ void ICACHE_RAM_ATTR onSclChange(void) } } break; - + case TWIP_SEND_ACK: if (scl) { // ignore @@ -673,7 +675,7 @@ void ICACHE_RAM_ATTR onSclChange(void) twip_state = TWIP_WAIT_ACK; } break; - + case TWIP_WAIT_ACK: if (scl) { // ignore @@ -714,7 +716,7 @@ void ICACHE_RAM_ATTR onSclChange(void) } } break; - + case TWIP_SLA_R: case TWIP_WRITE: if (scl) { @@ -722,8 +724,8 @@ void ICACHE_RAM_ATTR onSclChange(void) } else { bitCount--; (twi_data & 0x80) ? SDA_HIGH() : SDA_LOW(); - twi_data <<= 1; - + twi_data <<= 1; + if (bitCount != 0) { // continue } else { @@ -731,7 +733,7 @@ void ICACHE_RAM_ATTR onSclChange(void) } } break; - + case TWIP_REC_ACK: if (scl) { // ignore @@ -740,7 +742,7 @@ void ICACHE_RAM_ATTR onSclChange(void) twip_state = TWIP_READ_ACK; } break; - + case TWIP_READ_ACK: if (!scl) { // ignore @@ -749,7 +751,7 @@ void ICACHE_RAM_ATTR onSclChange(void) twip_state = TWIP_RWAIT_ACK; } break; - + case TWIP_RWAIT_ACK: if (scl) { // ignore @@ -765,10 +767,10 @@ void ICACHE_RAM_ATTR onSclChange(void) twi_onTwipEvent(twip_status); twip_mode = TWIPM_WAIT; twip_state = TWIP_WAIT_STOP; - } + } } break; - + default: break; } @@ -780,9 +782,9 @@ void ICACHE_RAM_ATTR onSdaChange(void) static uint8_t scl; sda = SDA_READ(); scl = SCL_READ(); - + //digitalWrite(2, sda); - + switch (twip_state) { case TWIP_IDLE: @@ -799,7 +801,7 @@ void ICACHE_RAM_ATTR onSdaChange(void) //digitalWrite(14, LOW); } break; - + case TWIP_START: case TWIP_REP_START: case TWIP_SEND_ACK: @@ -820,7 +822,7 @@ void ICACHE_RAM_ATTR onSdaChange(void) twip_state = TWIP_BUS_ERR; } break; - + case TWIP_WAIT_STOP: case TWIP_BUS_ERR: if (!scl) { @@ -845,7 +847,7 @@ void ICACHE_RAM_ATTR onSdaChange(void) } } break; - + case TWIP_SLA_W: case TWIP_READ: if (!scl) { From 8323afa9e9e4b74455c83184eaf16079e6a23580 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mate=CC=8Cj=20Sychra?= Date: Thu, 11 Oct 2018 13:13:01 +0200 Subject: [PATCH 3/3] cleaning up commit as requested by https://github.com/esp8266/Arduino/pull/5162#pullrequestreview-162242359 --- cores/esp8266/core_esp8266_si2c.c | 151 +++++------------------------- 1 file changed, 23 insertions(+), 128 deletions(-) diff --git a/cores/esp8266/core_esp8266_si2c.c b/cores/esp8266/core_esp8266_si2c.c index 236fae38fd..71c48f28b1 100644 --- a/cores/esp8266/core_esp8266_si2c.c +++ b/cores/esp8266/core_esp8266_si2c.c @@ -84,7 +84,7 @@ static uint8_t twi_rxBuffer[TWI_BUFFER_LENGTH]; static volatile uint8_t twi_rxBufferIndex; static void (*twi_onSlaveTransmit)(void); -static void (*twi_onSlaveReceive)(uint8_t*, int); +static void (*twi_onSlaveReceive)(uint8_t*, size_t); static void onSclChange(void); static void onSdaChange(void); @@ -156,11 +156,6 @@ void twi_init(unsigned char sda, unsigned char scl) pinMode(twi_sda, INPUT_PULLUP); pinMode(twi_scl, INPUT_PULLUP); twi_setClock(preferred_si2c_clock); - //pinMode(2, OUTPUT); - //pinMode(12, OUTPUT); - //pinMode(14, OUTPUT); - //pinMode(13, OUTPUT); - //digitalWrite(2, HIGH); twi_setClockStretchLimit(230); // default value is 230 uS if (twi_addr != 0) @@ -176,26 +171,23 @@ void twi_setAddress(uint8_t address) twi_addr = address << 1; } -#if 0 -void twi_stop(void){ - pinMode(twi_sda, INPUT); - pinMode(twi_scl, INPUT); -} -#endif - static void ICACHE_RAM_ATTR twi_delay(unsigned char v){ unsigned int i; #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-but-set-variable" unsigned int reg; - for(i=0;i0){ //if SDA low, read the bits slaves have to sent to a max + while (SDA_READ()==0 && clockCount>0) { // if SDA low, read the bits slaves have to sent to a max twi_read_bit(); - if (SCL_READ()==0) return I2C_SCL_HELD_LOW_AFTER_READ; //I2C bus error. SCL held low beyond slave clock stretch time + if (SCL_READ()==0) { + return I2C_SCL_HELD_LOW_AFTER_READ; // I2C bus error. SCL held low beyond slave clock stretch time + } + } + if (SDA_READ()==0) { + return I2C_SDA_HELD_LOW; // I2C bus error. SDA line held low by slave/another_master after n bits. + } + if (!twi_write_start()) { + return I2C_SDA_HELD_LOW_AFTER_INIT; // line busy. SDA again held low by another device. 2nd master? + } else { + return I2C_OK; } - - if (SDA_READ()==0) return I2C_SDA_HELD_LOW; //I2C bus error. SDA line held low by slave/another_master after n bits. - - if(!twi_write_start()) return I2C_SDA_HELD_LOW_AFTER_INIT; //line busy. SDA again held low by another device. 2nd master? - else return I2C_OK; //all ok } uint8_t twi_transmit(const uint8_t* data, uint8_t length) @@ -363,7 +360,6 @@ void ICACHE_RAM_ATTR twi_reply(uint8_t ack) } } -#if 1 void ICACHE_RAM_ATTR twi_stop(void) { // send stop condition @@ -372,17 +368,9 @@ void ICACHE_RAM_ATTR twi_stop(void) twi_ack = 1; // _BV(TWEA) twi_delay(5); // Maybe this should be here SDA_HIGH(); // _BV(TWSTO) - - // wait for stop condition to be exectued on bus - // TWINT is not set after a stop condition! - while (false) { //TWCR & _BV(TWSTO)){ - continue; - } - // update twi state twi_state = TWI_READY; } -#endif void ICACHE_RAM_ATTR twi_releaseBus(void) { @@ -399,84 +387,7 @@ void ICACHE_RAM_ATTR twi_releaseBus(void) void ICACHE_RAM_ATTR twi_onTwipEvent(uint8_t status) { - //digitalWrite(13, HIGH); - //switch(TW_STATUS){ switch(status) { -#if 0 - // All Master - case TW_START: // sent start condition - case TW_REP_START: // sent repeated start condition - // copy device address and r/w bit to output register and ack - TWDR = twi_slarw; - twi_reply(1); - break; - - // Master Transmitter - case TW_MT_SLA_ACK: // slave receiver acked address - case TW_MT_DATA_ACK: // slave receiver acked data - // if there is data to send, send it, otherwise stop - if(twi_masterBufferIndex < twi_masterBufferLength){ - // copy data to output register and ack - TWDR = twi_masterBuffer[twi_masterBufferIndex++]; - twi_reply(1); - }else{ - if (twi_sendStop) - twi_stop(); - else { - twi_inRepStart = true; // we're gonna send the START - // don't enable the interrupt. We'll generate the start, but we - // avoid handling the interrupt until we're in the next transaction, - // at the point where we would normally issue the start. - TWCR = _BV(TWINT) | _BV(TWSTA)| _BV(TWEN) ; - twi_state = TWI_READY; - } - } - break; - case TW_MT_SLA_NACK: // address sent, nack received - twi_error = TW_MT_SLA_NACK; - twi_stop(); - break; - case TW_MT_DATA_NACK: // data sent, nack received - twi_error = TW_MT_DATA_NACK; - twi_stop(); - break; - case TW_MT_ARB_LOST: // lost bus arbitration - twi_error = TW_MT_ARB_LOST; - twi_releaseBus(); - break; - - // Master Receiver - case TW_MR_DATA_ACK: // data received, ack sent - // put byte into buffer - twi_masterBuffer[twi_masterBufferIndex++] = TWDR; - case TW_MR_SLA_ACK: // address sent, ack received - // ack if more bytes are expected, otherwise nack - if(twi_masterBufferIndex < twi_masterBufferLength){ - twi_reply(1); - }else{ - twi_reply(0); - } - break; - case TW_MR_DATA_NACK: // data received, nack sent - // put final byte into buffer - twi_masterBuffer[twi_masterBufferIndex++] = TWDR; - if (twi_sendStop) - twi_stop(); - else { - twi_inRepStart = true; // we're gonna send the START - // don't enable the interrupt. We'll generate the start, but we - // avoid handling the interrupt until we're in the next transaction, - // at the point where we would normally issue the start. - TWCR = _BV(TWINT) | _BV(TWSTA)| _BV(TWEN) ; - twi_state = TWI_READY; - } - break; - case TW_MR_SLA_NACK: // address sent, nack received - twi_stop(); - break; - // TW_MR_ARB_LOST handled by TW_MT_ARB_LOST case -#endif - // Slave Receiver case TW_SR_SLA_ACK: // addressed, returned ack case TW_SR_GCALL_ACK: // addressed generally, returned ack @@ -564,23 +475,19 @@ void ICACHE_RAM_ATTR twi_onTwipEvent(uint8_t status) twi_stop(); break; } - //digitalWrite(13, LOW); } void ICACHE_RAM_ATTR onTimer() { - //digitalWrite(13, HIGH); twi_releaseBus(); twip_status = TW_BUS_ERROR; twi_onTwipEvent(twip_status); twip_mode = TWIPM_WAIT; twip_state = TWIP_BUS_ERR; - //digitalWrite(13, LOW); } static void eventTask(ETSEvent *e) { - //digitalWrite(14, HIGH); if (e == NULL) { return; @@ -608,8 +515,6 @@ static void eventTask(ETSEvent *e) twi_onSlaveReceive(twi_rxBuffer, e->par); break; } - - //digitalWrite(14, LOW); } void ICACHE_RAM_ATTR onSclChange(void) @@ -617,15 +522,9 @@ void ICACHE_RAM_ATTR onSclChange(void) static uint8_t sda; static uint8_t scl; - //digitalWrite(2, LOW); - //digitalWrite(2, HIGH); - sda = SDA_READ(); scl = SCL_READ(); - //digitalWrite(12, scl); - //digitalWrite(14, LOW); - twip_status = 0xF8; // reset TWI status switch (twip_state) @@ -783,8 +682,6 @@ void ICACHE_RAM_ATTR onSdaChange(void) sda = SDA_READ(); scl = SCL_READ(); - //digitalWrite(2, sda); - switch (twip_state) { case TWIP_IDLE: @@ -796,9 +693,7 @@ void ICACHE_RAM_ATTR onSdaChange(void) // START bitCount = 8; twip_state = TWIP_START; - //digitalWrite(14, HIGH); ets_timer_arm_new(&timer, twi_timeout_ms, false, true); // Once, ms - //digitalWrite(14, LOW); } break;