void ICACHE_FLASH_ATTR i2c_init(void) { //Disable interrupts ETS_GPIO_INTR_DISABLE(); //Set pin functions PIN_FUNC_SELECT(I2C_SDA_MUX, I2C_SDA_FUNC); PIN_FUNC_SELECT(I2C_SCK_MUX, I2C_SCK_FUNC); //Set SDA as open drain GPIO_REG_WRITE( GPIO_PIN_ADDR(GPIO_ID_PIN(I2C_SDA_PIN)), GPIO_REG_READ(GPIO_PIN_ADDR(GPIO_ID_PIN(I2C_SDA_PIN))) | GPIO_PIN_PAD_DRIVER_SET(GPIO_PAD_DRIVER_ENABLE) ); GPIO_REG_WRITE(GPIO_ENABLE_ADDRESS, GPIO_REG_READ(GPIO_ENABLE_ADDRESS) | (1 << I2C_SDA_PIN)); //Set SCK as open drain GPIO_REG_WRITE( GPIO_PIN_ADDR(GPIO_ID_PIN(I2C_SCK_PIN)), GPIO_REG_READ(GPIO_PIN_ADDR(GPIO_ID_PIN(I2C_SCK_PIN))) | GPIO_PIN_PAD_DRIVER_SET(GPIO_PAD_DRIVER_ENABLE) ); GPIO_REG_WRITE(GPIO_ENABLE_ADDRESS, GPIO_REG_READ(GPIO_ENABLE_ADDRESS) | (1 << I2C_SCK_PIN)); //Turn interrupt back on ETS_GPIO_INTR_ENABLE(); i2c_sda(1); i2c_sck(1); return; }
/** * Receive byte from the I2C bus * returns the byte */ uint8 ICACHE_FLASH_ATTR i2c_readByte(void) { uint8 data = 0; uint8 data_bit; uint8 i; i2c_sda(1); for (i = 0; i < 8; i++) { os_delay_us(I2C_SLEEP_TIME); i2c_sck(0); os_delay_us(I2C_SLEEP_TIME); i2c_sck(1); os_delay_us(I2C_SLEEP_TIME); data_bit = i2c_read(); os_delay_us(I2C_SLEEP_TIME); data_bit <<= (7 - i); data |= data_bit; } i2c_sck(0); os_delay_us(I2C_SLEEP_TIME); return data; }
/** * I2C Stop signal */ void ICACHE_FLASH_ATTR i2c_stop(void) { os_delay_us(I2C_SLEEP_TIME); i2c_sck(1); os_delay_us(I2C_SLEEP_TIME); i2c_sda(1); os_delay_us(I2C_SLEEP_TIME); }
/** * Send I2C ACK to the bus * uint8 state 1 or 0 * 1 for ACK * 0 for NACK */ void ICACHE_FLASH_ATTR i2c_send_ack(uint8 state) { i2c_sck(0); os_delay_us(I2C_SLEEP_TIME); //Set SDA // HIGH for NACK // LOW for ACK i2c_sda((state?0:1)); //Pulse the SCK i2c_sck(0); os_delay_us(I2C_SLEEP_TIME); i2c_sck(1); os_delay_us(I2C_SLEEP_TIME); i2c_sck(0); os_delay_us(I2C_SLEEP_TIME); i2c_sda(1); os_delay_us(I2C_SLEEP_TIME); }
/** * Receive I2C ACK from the bus * returns 1 or 0 * 1 for ACK * 0 for NACK */ uint8 ICACHE_FLASH_ATTR i2c_check_ack(void) { uint8 ack; i2c_sda(1); os_delay_us(I2C_SLEEP_TIME); i2c_sck(0); os_delay_us(I2C_SLEEP_TIME); i2c_sck(1); os_delay_us(I2C_SLEEP_TIME); //Get SDA pin status ack = i2c_read(); os_delay_us(I2C_SLEEP_TIME); i2c_sck(0); os_delay_us(I2C_SLEEP_TIME); i2c_sda(0); os_delay_us(I2C_SLEEP_TIME); return (ack?0:1); }
// ************************************************************************************************* // @fn as_write_register // @brief Write a byte to the pressure sensor // @param u8 device Device address // u8 address Register address // u8 data Data to write // @return u8 // ************************************************************************************************* u8 i2c_write_register(u8 device, u8 data) { volatile u8 success; i2c_sda(I2C_SEND_START); // Generate start condition i2c_write(device | I2C_WRITE); // Send 7bit device address + r/w bit '0' -> write success = i2c_sda(I2C_CHECK_ACK); // Check ACK from device if (!success) { I2C_SCL_HI; i2c_sda(I2C_SEND_STOP); return (0); } i2c_write(data); // Send 8bit data to register success = i2c_sda(I2C_CHECK_ACK); // Check ACK from device // Slave does not send this ACK //if (!success) return (0); i2c_sda(I2C_SEND_STOP); // Generate stop condition return (1); }
/** * Write byte to I2C bus * uint8 data: to byte to be writen */ void ICACHE_FLASH_ATTR i2c_writeByte(uint8 data) { uint8 data_bit; sint8 i; os_delay_us(I2C_SLEEP_TIME); for (i = 7; i >= 0; i--) { data_bit = data >> i; i2c_sda(data_bit); os_delay_us(I2C_SLEEP_TIME); i2c_sck(1); os_delay_us(I2C_SLEEP_TIME); i2c_sck(0); os_delay_us(I2C_SLEEP_TIME); } }
// Initialise the I2C communications static void i2c_init(void) { // Declare variables GPIO_InitTypeDef init; // SDA pin configuration init.GPIO_Pin = PIN_COMPASS_SDA; init.GPIO_Mode = GPIO_Mode_Out_OD; init.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(PORT_COMPASS_SDA, &init); // SCL pin configuration init.GPIO_Pin = PIN_COMPASS_SCL; init.GPIO_Mode = GPIO_Mode_Out_OD; init.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(PORT_COMPASS_SCL, &init); // Initialise the states of the SDA and SCL pins i2c_sda(1); i2c_scl(1); }
// Perform one step of the I2C FSM static void i2c_step(void) { switch(g_i2c_state) { // Idle states case I2C_IDLE: // Idle bus with SCL and SDA high break; case I2C_READY: // Bus ready for activity with SCL and SDA low break; // Start states case I2C_START: i2c_init(); // Sets SDA and SCL to 1 g_i2c_state = I2C_START_2; break; case I2C_START_2: i2c_sda(0); // SDA falling while SCL 1 => Start bit g_i2c_state = I2C_START_3; break; case I2C_START_3: i2c_scl(0); // Now SDA and SCL are both 0, ready for bus activity g_i2c_state = I2C_READY; break; // Write states case I2C_WRITE: i2c_sda(g_i2c_to_write & (1 << g_i2c_bit)); // SDA reflects data bit g_i2c_state = I2C_WRITE_2; break; case I2C_WRITE_2: i2c_scl(1); // Toggle SCL high g_i2c_state = I2C_WRITE_3; break; case I2C_WRITE_3: i2c_scl(0); // Toggle SCL low if(g_i2c_bit == 0) g_i2c_state = I2C_WRITE_ACK_1; else { g_i2c_bit--; g_i2c_state = I2C_WRITE; } break; case I2C_WRITE_ACK_1: i2c_sda(1); // Release SDA to allow the slave to ACK or NACK g_i2c_state = I2C_WRITE_ACK_2; break; case I2C_WRITE_ACK_2: i2c_scl(1); // Toggle SCL high g_i2c_state = I2C_WRITE_ACK_3; break; case I2C_WRITE_ACK_3: if(i2c_sda_read()) // Read the acknowledgement bit g_i2c_state = I2C_WRITE_GOT_NACK; else g_i2c_state = I2C_WRITE_GOT_ACK; i2c_scl(0); // Toggle SCL low break; case I2C_WRITE_GOT_ACK: break; case I2C_WRITE_GOT_NACK: break; // Read states case I2C_READ: i2c_sda(1); // Release SDA to allow the slave to transmit data g_i2c_state = I2C_READ_2; break; case I2C_READ_2: i2c_scl(1); // Toggle SCL high g_i2c_state = I2C_READ_3; break; case I2C_READ_3: if(i2c_sda_read()) g_i2c_read |= (1 << g_i2c_bit); i2c_scl(0); // Toggle SCL low if(g_i2c_bit == 0) g_i2c_state = I2C_READ_4; else { g_i2c_bit--; g_i2c_state = I2C_READ_2; } break; case I2C_READ_4: i2c_sda(0); // Reassert control over SDA again and pull it low for an ACK g_i2c_state = I2C_READ_ACK_1; break; case I2C_READ_ACK_1: i2c_scl(1); // Toggle SCL high g_i2c_state = I2C_READ_ACK_2; break; case I2C_READ_ACK_2: i2c_scl(0); // Toggle SCL low g_i2c_state = I2C_READ_ENDED; break; case I2C_READ_ENDED: break; // Stop states case I2C_STOP: i2c_sda(0); g_i2c_state = I2C_STOP_2; break; case I2C_STOP_2: i2c_scl(1); g_i2c_state = I2C_STOP_3; break; case I2C_STOP_3: i2c_sda(1); g_i2c_state = I2C_IDLE; break; // Default state default: break; } }