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; 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 (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? return I2C_OK; }
static bool twi_read_bit(void) { uint32_t i = 0; SCL_LOW(); SDA_HIGH(); twi_delay(twi_dcount+2); SCL_HIGH(); while (SCL_READ() == 0 && (i++) < twi_clockStretchLimit);// Clock stretching bool bit = SDA_READ(); twi_delay(twi_dcount); return bit; }
static bool twi_write_bit(bool bit) { uint32_t i = 0; SCL_LOW(); if (bit) SDA_HIGH(); else SDA_LOW(); twi_delay(twi_dcount+1); SCL_HIGH(); while (SCL_READ() == 0 && (i++) < twi_clockStretchLimit);// Clock stretching twi_delay(twi_dcount); return true; }
static bool ICACHE_FLASH_ATTR twi_read_bit() { unsigned int i = 0; SCL_LOW(); SDA_HIGH(); twi_delay(twi_dcount + 2); SCL_HIGH(); while (SCL_READ() == 0 && (i++) < twi_clockStretchLimit); // Clock stretching bool bit = SDA_READ(); twi_delay(twi_dcount); return bit; }
static bool twi_write_stop(void){ uint32_t i = 0; SCL_LOW(); SDA_LOW(); twi_delay(twi_dcount); SCL_HIGH(); while (SCL_READ() == 0 && (i++) < twi_clockStretchLimit); // Clock stretching twi_delay(twi_dcount); SDA_HIGH(); twi_delay(twi_dcount); return true; }
static bool ICACHE_FLASH_ATTR twi_write_stop(void) { unsigned int i = 0; SCL_LOW(); SDA_LOW(); twi_delay(twi_dcount); SCL_HIGH(); while (SCL_READ() == 0 && (i++) < twi_clockStretchLimit); // Clock stretching twi_delay(twi_dcount); SDA_HIGH(); twi_delay(twi_dcount); return true; }
unsigned char twi_readFrom(unsigned char address, unsigned char* buf, unsigned int len, unsigned char sendStop){ unsigned int i; if(!twi_write_start()) return 4;//line busy if(!twi_write_byte(((address << 1) | 1) & 0xFF)) { if (sendStop) twi_write_stop(); return 2;//received NACK on transmit of address } for(i=0; i<(len-1); i++) buf[i] = twi_read_byte(false); buf[len-1] = twi_read_byte(true); if(sendStop) twi_write_stop(); i = 0; while(SDA_READ() == 0 && (i++) < 10){ SCL_LOW(); twi_delay(twi_dcount); SCL_HIGH(); unsigned int t=0; while(SCL_READ()==0 && (t++)<twi_clockStretchLimit); // twi_clockStretchLimit twi_delay(twi_dcount); } return 0; }
unsigned char twi_writeTo(unsigned char address, unsigned char * buf, unsigned int len, unsigned char sendStop){ unsigned int i; if(!twi_write_start()) return 4;//line busy if(!twi_write_byte(((address << 1) | 0) & 0xFF)) { if (sendStop) twi_write_stop(); return 2; //received NACK on transmit of address } for(i=0; i<len; i++) { if(!twi_write_byte(buf[i])) { if (sendStop) twi_write_stop(); return 3;//received NACK on transmit of data } } if(sendStop) twi_write_stop(); i = 0; while(SDA_READ() == 0 && (i++) < 10){ SCL_LOW(); twi_delay(twi_dcount); SCL_HIGH(); unsigned int t=0; while(SCL_READ()==0 && (t++)<twi_clockStretchLimit); // twi_clockStretchLimit twi_delay(twi_dcount); } return 0; }
void ICACHE_RAM_ATTR onSdaChange(void) { static uint8_t sda; static uint8_t scl; sda = SDA_READ(); scl = SCL_READ(); switch (twip_state) { case TWIP_IDLE: if (!scl) { // DATA - ignore } else if (sda) { // STOP - ignore } else { // START bitCount = 8; twip_state = TWIP_START; ets_timer_arm_new(&timer, twi_timeout_ms, false, true); // Once, ms } 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; } }
void ICACHE_RAM_ATTR onSclChange(void) { static uint8_t sda; static uint8_t scl; sda = SDA_READ(); scl = SCL_READ(); 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; } }