i2c_error SendAndRcvI2C2Data(wordUnion_t *value, unsigned char i2cAddress, unsigned char command, unsigned char address) { i2c_error errorCode = I2C_ERROR_NONE; wordUnion_t wil; wil.l = 0; SKIP_IF_NO_ADDRESS; // Startup if (errorCode == I2C_ERROR_NONE) { i2cChecksumIn = 0; i2cChecksumOut = command ^ address; // Clear the FIFO SET_I2C_REG_FIELD_NAME(CONTROL, CLEAR, CLEAR); // Reset any latched status SET_I2C_REG_FIELD_NAME(STATUS, CLK_TIMEOUT, TIMEOUT); SET_I2C_REG_FIELD_NAME(STATUS, ERR_ACK, SLAVE_NACK); SET_I2C_REG_FIELD_NAME(STATUS, DONE, FINISHED); // Setup message parameters SET_I2C_REG_FIELD(SLAVE_ADDR, ADDR, i2cAddress); SET_I2C_REG_FIELD_NAME(CONTROL, RW, WRITE); SET_I2C_REG_FIELD(DATA_LEN, BYTES, 3); // Start the device running and check the acknowledge status SET_I2C_REG_FIELD_NAME(CONTROL, START, START); errorCode = WaitForI2CTxFifo(I2C_ERROR_ADDR_NACK); } if (errorCode == I2C_ERROR_NONE) DO_INTER_CHARACTER_DELAY; // Command code if (errorCode == I2C_ERROR_NONE) errorCode = WaitForI2CTxFifo(I2C_ERROR_DATA_NACK); if (errorCode == I2C_ERROR_NONE) SET_I2C_REG_FIELD(DATA_FIFO, DATA, command); if (errorCode == I2C_ERROR_NONE) DO_INTER_CHARACTER_DELAY; // Address if (errorCode == I2C_ERROR_NONE) errorCode = WaitForI2CTxFifo(I2C_ERROR_DATA_NACK); if (errorCode == I2C_ERROR_NONE) SET_I2C_REG_FIELD(DATA_FIFO, DATA, address); if (errorCode == I2C_ERROR_NONE) DO_INTER_CHARACTER_DELAY; // Checksum outbound if (errorCode == I2C_ERROR_NONE) errorCode = WaitForI2CTxFifo(I2C_ERROR_DATA_NACK); if (errorCode == I2C_ERROR_NONE) SET_I2C_REG_FIELD(DATA_FIFO, DATA, i2cChecksumOut); if (errorCode == I2C_ERROR_NONE) DO_INTER_CHARACTER_DELAY; // Restart if (errorCode == I2C_ERROR_NONE) errorCode = WaitForI2CFinished(I2C_ERROR_DATA_NACK); if (errorCode == I2C_ERROR_NONE) { // Clear the FIFO SET_I2C_REG_FIELD_NAME(CONTROL, CLEAR, CLEAR); // Reset any latched status SET_I2C_REG_FIELD_NAME(STATUS, CLK_TIMEOUT, TIMEOUT); SET_I2C_REG_FIELD_NAME(STATUS, ERR_ACK, SLAVE_NACK); SET_I2C_REG_FIELD_NAME(STATUS, DONE, FINISHED); // Setup message parameters SET_I2C_REG_FIELD(SLAVE_ADDR, ADDR, i2cAddress); SET_I2C_REG_FIELD_NAME(CONTROL, RW, READ); SET_I2C_REG_FIELD(DATA_LEN, BYTES, 5); // Start the device running and check the acknowledge status SET_I2C_REG_FIELD_NAME(CONTROL, START, START); errorCode = WaitForI2CTxFifo(I2C_ERROR_ADDR_NACK); } if (errorCode == I2C_ERROR_NONE) DO_INTER_CHARACTER_DELAY; // Read byte 0 and ACK if (errorCode == I2C_ERROR_NONE) errorCode = WaitForI2CRxFifo(); if (errorCode == I2C_ERROR_NONE) wil.c[0] = (unsigned char)(GET_I2C_REG_FIELD(DATA_FIFO, DATA) & 0xFF); if (errorCode == I2C_ERROR_NONE) DO_INTER_CHARACTER_DELAY; // Read byte 1 and ACK if (errorCode == I2C_ERROR_NONE) errorCode = WaitForI2CRxFifo(); if (errorCode == I2C_ERROR_NONE) wil.c[1] = (unsigned char)(GET_I2C_REG_FIELD(DATA_FIFO, DATA) & 0xFF); if (errorCode == I2C_ERROR_NONE) DO_INTER_CHARACTER_DELAY; // Read byte 2 and ACK if (errorCode == I2C_ERROR_NONE) errorCode = WaitForI2CRxFifo(); if (errorCode == I2C_ERROR_NONE) wil.c[2] = (unsigned char)(GET_I2C_REG_FIELD(DATA_FIFO, DATA) & 0xFF); if (errorCode == I2C_ERROR_NONE) DO_INTER_CHARACTER_DELAY; // Read byte 3 and ACK if (errorCode == I2C_ERROR_NONE) errorCode = WaitForI2CRxFifo(); if (errorCode == I2C_ERROR_NONE) wil.c[3] = (unsigned char)(GET_I2C_REG_FIELD(DATA_FIFO, DATA) & 0xFF); if (errorCode == I2C_ERROR_NONE) DO_INTER_CHARACTER_DELAY; // Checksum inbound and NACK (final byte) if (errorCode == I2C_ERROR_NONE) errorCode = WaitForI2CRxFifo(); if (errorCode == I2C_ERROR_NONE) { i2cChecksumIn = (unsigned char)(GET_I2C_REG_FIELD(DATA_FIFO, DATA) & 0xFF); if (i2cChecksumIn ^ wil.c[0] ^ wil.c[1] ^ wil.c[2] ^ wil.c[3]) { // XOR != 0, therefore the checksum does not match (note the slave may have sent a bad checksum on purpose) errorCode = I2C_ERROR_CRC_FAILURE; } } // Shutdown if (errorCode == I2C_ERROR_NONE) WaitForI2CFinished(I2C_ERROR_CRC_FAILURE); // Do not set an error condition, we already received valid data if (errorCode != I2C_ERROR_NONE) { ++(i2cErrors[errorCode - 1]); } else { if (value) value->l = wil.l; SetSuccessI2C(i2cAddress); } return errorCode; }