/* * 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; }
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) } }
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(); }
/*! * \brief Initialize TWI interface. * * The specified slave address is used only, if the local system * is running as a slave. Anyway, care must be taken that it doesn't * conflict with another connected device. * * \param sla Slave address, must be specified as a 7-bit address, * always lower than 128. * * \return Always 0. * */ int TwBbifInit(void) { SDA_HIGH(); SCL_HIGH(); TWI_ENABLE(); twibb_initialized = 1; return 0; }
/* * 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); }
void TwInit(void) { SDA_HIGH(); SCL_HIGH(); outr(TWI_SDA_COD_REG, _BV(TWI_SDA_BIT)); outr(TWI_SCL_COD_REG, _BV(TWI_SCL_BIT)); outr(TWI_SDA_PE_REG, _BV(TWI_SDA_BIT)); outr(TWI_SCL_PE_REG, _BV(TWI_SCL_BIT)); }
/* * 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); }
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 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) // update twi state twi_state = TWI_READY; }
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 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; }
// 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 }
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_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; }
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 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; } }