/* * Toggles out a single byte in master mode. * * Entry: SCL low, SDA any * Exit: SCL low, SDA high */ static int TwPut(uint8_t octet) { int i; for (i = 0x80; i; i >>= 1) { /* Set the data bit. */ if (octet & i) { SDA_HIGH(); } else { SDA_LOW(); } /* Wait for data to stabelize. */ TwDelay(TWI_DELAY); /* Toggle the clock. */ SCL_HIGH(); TwDelay(2 * TWI_DELAY); SCL_LOW(); TwDelay(TWI_DELAY); } /* Set data line high to receive the ACK bit. */ SDA_HIGH(); /* ACK should appear shortly after the clock's rising edge. */ SCL_HIGH(); TwDelay(2 * TWI_DELAY); if (SDA_STAT()) { i = -1; } else { i = 0; } SCL_LOW(); return i; }
uint8_t ICACHE_FLASH_ATTR twi_writeTo(uint8_t address, uint8_t *buf, unsigned int len, uint8_t sendStop) { unsigned int i; if (!twi_write_start()) { serial_print("I2C: bus busy\r\n"); return 4; } if (!twi_write_byte(((address << 1) | 0) & 0xFF)) { if (sendStop) twi_write_stop(); serial_print("I2C: received NACK on transmit of address\r\n"); return 2; } for (i = 0; i < len; i++) { if (!twi_write_byte(buf[i])) { if (sendStop) twi_write_stop(); serial_print("I2C: received NACK on transmit of data\r\n"); return 3; } } if (sendStop) twi_write_stop(); i = 0; while (SDA_READ() == 0 && (i++) < 10) { SCL_LOW(); twi_delay(twi_dcount); SCL_HIGH(); twi_delay(twi_dcount); } return 0; }
uint8_t ICACHE_FLASH_ATTR twi_readFrom(uint8_t address, uint8_t *buf, unsigned int len, uint8_t sendStop) { unsigned int i; if (!twi_write_start()) { serial_print("I2C: bus busy\r\n"); return 4; } if (!twi_write_byte(((address << 1) | 1) & 0xFF)) { if (sendStop) twi_write_stop(); serial_print("I2C: received NACK on transmit of address\r\n"); return 2; } 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(); twi_delay(twi_dcount); } return 0; }
static void TwAck(void) { SDA_LOW(); SCL_HIGH(); TwDelay(2 * TWI_DELAY); SCL_LOW(); SDA_HIGH(); }
/* * Falling edge on the data line while the clock line is high indicates * a start condition. * * Entry: SCL any, SDA any * Exit: SCL low, SDA low */ static void TwStart(void) { SDA_HIGH(); TwDelay(TWI_DELAY); SCL_HIGH(); TwDelay(TWI_DELAY); SDA_LOW(); TwDelay(TWI_DELAY); SCL_LOW(); TwDelay(TWI_DELAY); }
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 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_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_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; }
bool i2c_write(alt_u32 clk_base, alt_u32 data_base, alt_u8 Data){ // return true if device response ack alt_u8 Mask = 0x80; bool bAck; int i; // assume, SCL = 0 SDA_DIR_OUT(data_base); // data write mode for(i=0;i<8;i++){ SCL_LOW(clk_base); // new, make sure data change at clk low // output data on bus if (Data & Mask){ // there is a delay in this command SDA_HIGH(data_base); }else{ SDA_LOW(data_base); } Mask >>= 1; // there is a delay in this command // clock high SCL_HIGH(clk_base); SCL_DELAY; SCL_LOW(clk_base); SCL_DELAY; } //===== get ack SDA_DIR_IN(data_base); // data read mode //SCL_DELAY; // clock high SCL_HIGH(clk_base); // clock high SCL_DELAY; // clock high delay bAck = SDA_READ(data_base)?FALSE:TRUE; // get ack //SCL_DELAY; //SDA_DIR_OUT; SCL_LOW(clk_base); // clock low SCL_DELAY; // clock low delay return bAck; }
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; }
void i2c_read(alt_u32 clk_base, alt_u32 data_base, alt_u8 *pData, bool bAck){ // return true if device response ack alt_u8 Data=0; int i; // assume SCL = low SDA_DIR_IN(data_base); // set data read mode SCL_LOW(clk_base); // clock low SCL_DELAY; // clock low delay for(i=0;i<8;i++){ Data <<= 1; SCL_HIGH(clk_base); // clock high SCL_DELAY; if (SDA_READ(data_base)) // read data Data |= 0x01; SCL_LOW(clk_base); // clock log SCL_DELAY; } // send ACK SCL_LOW(clk_base); // new, make sure data change at clk low SDA_DIR_OUT(data_base); // set data write mode if (bAck) SDA_LOW(data_base); else SDA_HIGH(data_base); SCL_HIGH(clk_base); // clock high SCL_DELAY; // clock high delay SCL_LOW(clk_base); // clock low SCL_DELAY; // clock low delay SDA_LOW(data_base); // data low SCL_DELAY; // data low delay // SDA_DIR_IN; // set data read mode *pData = Data; }
//SDA 1->0 while SCL=1 void i2c_start(alt_u32 clk_base, alt_u32 data_base){ // make sure it is in normal state SDA_DIR_OUT(data_base); // data output enabled // start condition SDA_HIGH(data_base); // data high SCL_HIGH(clk_base); SCL_DELAY; SDA_LOW(data_base); // data low SCL_DELAY; SCL_LOW(clk_base); // clock low SCL_DELAY; }
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; }
/* * Toggles in a single byte in master mode. * * Entry: SCL low, SDA any * Exit: SCL low, SDA high */ static uint8_t TwGet(void) { uint8_t rc = 0; int i; /* SDA is input. */ SDA_HIGH(); TwDelay(TWI_DELAY); for (i = 0x80; i; i >>= 1) { TwDelay(TWI_DELAY); /* Data should appear shortly after the clock's rising edge. */ SCL_HIGH(); TwDelay(2 * TWI_DELAY); /* SDA read. */ if (SDA_STAT()) { rc |= i; } SCL_LOW(); } return rc; }
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 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; } }
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; } }