/* * 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; }
static void TwAck(void) { SDA_LOW(); SCL_HIGH(); TwDelay(2 * TWI_DELAY); SCL_LOW(); SDA_HIGH(); }
/* * Rising edge on the data line while the clock line is high indicates * a stop condition. * * Entry: SCL low, SDA any * Exit: SCL high, SDA high */ static void TwStop(void) { SDA_LOW(); TwDelay(TWI_DELAY); SCL_HIGH(); TwDelay(2 * TWI_DELAY); SDA_HIGH(); TwDelay(8 * TWI_DELAY); }
// SDA 0->1 while SCL=1 void i2c_stop(alt_u32 clk_base, alt_u32 data_base){ // assume SCL = 0 SDA_DIR_OUT(data_base); // data output enabled SDA_LOW(data_base); // Data Low //SCL_DELAY; SCL_HIGH(clk_base); // clock high SCL_DELAY; // clock high long delay SDA_HIGH(data_base); // data high SCL_DELAY; // data high delay }
/* * 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_write_start(void) { SCL_HIGH(); SDA_HIGH(); if (SDA_READ() == 0) { return false; } twi_delay(twi_dcount); SDA_LOW(); twi_delay(twi_dcount); return true; }
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_start(void) { SCL_HIGH(); SDA_HIGH(); if (SDA_READ() == 0) { serial_printf("twi write start sda read false\r\n"); return false; } twi_delay(twi_dcount); SDA_LOW(); 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; }
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; }
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; }
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 twi_onTwipEvent(uint8_t status) { switch(status) { // 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; } }