// ...existing code... /*! \brief write data to I2C device with configurable length \param[in] slave_addr: slave device address (7-bit) \param[in] reg_addr: register address \param[in] data: pointer to data buffer \param[in] length: number of bytes to write (1-255) \param[out] none \retval i2c_result_t: operation result */ i2c_result_t i2c_write(uint8_t slave_addr, uint8_t reg_addr, uint8_t *data, uint8_t length) { i2c_state_t state = I2C_STATE_START; uint16_t timeout = 0; uint8_t retry_count = 0; uint8_t data_index = 0; /* parameter validation */ if (data == NULL || slave_addr > 0x7F || length == 0) { return I2C_RESULT_INVALID_PARAM; } while (retry_count < I2C_MAX_RETRY) { switch (state) { case I2C_STATE_START: timeout = 0; data_index = 0; /* wait for bus to be idle */ while (i2c_flag_get(I2C0, I2C_FLAG_I2CBSY) && (timeout < I2C_TIME_OUT)) { timeout++; } if (timeout >= I2C_TIME_OUT) { state = I2C_STATE_ERROR; break; } i2c_start_on_bus(I2C0); timeout = 0; state = I2C_STATE_SEND_ADDRESS; break; case I2C_STATE_SEND_ADDRESS: /* wait for start condition to be sent. SBSEND flag */ while((!i2c_flag_get(I2C0, I2C_FLAG_SBSEND)) && (timeout < I2C_TIME_OUT)) { timeout++; } if (timeout >= I2C_TIME_OUT) { state = I2C_STATE_ERROR; break; } /* send slave address */ i2c_master_addressing(I2C0, slave_addr << 1, I2C_TRANSMITTER); timeout = 0; state = I2C_STATE_CLEAR_ADDRESS; break; case I2C_STATE_CLEAR_ADDRESS: /* wait for address to be acknowledged.ADDSEND set means i2c slave sends ACK */ while ((!i2c_flag_get(I2C0, I2C_FLAG_ADDSEND)) && (!i2c_flag_get(I2C0, I2C_FLAG_AERR)) && (timeout < I2C_TIME_OUT)) { timeout++; } if (timeout >= I2C_TIME_OUT) { state = I2C_STATE_ERROR; break; } else if (i2c_flag_get(I2C0, I2C_FLAG_ADDSEND)) { i2c_flag_clear(I2C0, I2C_FLAG_ADDSEND); timeout = 0; state = I2C_STATE_TRANSMIT_REG; break; } else { i2c_flag_clear(I2C0, I2C_FLAG_AERR); timeout = 0; #ifdef DEBUG_VERBOSE printf("IIC write failed for Error Slave Address. \n"); #endif return I2C_RESULT_NACK; } case I2C_STATE_TRANSMIT_REG: /* wait until the transmit data buffer is empty */ while ((!i2c_flag_get(I2C0, I2C_FLAG_TBE)) && (timeout < I2C_TIME_OUT)) { timeout++; } if (timeout >= I2C_TIME_OUT) { state = I2C_STATE_ERROR; break; } /* send register address */ i2c_data_transmit(I2C0, reg_addr); timeout = 0; state = I2C_STATE_TRANSMIT_DATA; break; case I2C_STATE_TRANSMIT_DATA: /* wait until the transmit data buffer is empty */ while ((!i2c_flag_get(I2C0, I2C_FLAG_TBE)) && (timeout < I2C_TIME_OUT)) { timeout++; } if (timeout >= I2C_TIME_OUT) { state = I2C_STATE_ERROR; break; } /* send data byte */ i2c_data_transmit(I2C0, data[data_index]); data_index++; /* check for errors */ if (i2c_flag_get(I2C0, I2C_FLAG_AERR)) { i2c_stop_on_bus(I2C0); return I2C_RESULT_NACK; } else if (i2c_flag_get(I2C0, I2C_FLAG_BERR) || i2c_flag_get(I2C0, I2C_FLAG_LOSTARB)) { i2c_stop_on_bus(I2C0); return I2C_RESULT_ERROR; } /* check if all data has been sent */ if (data_index >= length) { /* wait until BTC bit is set for last byte */ timeout = 0; while (!i2c_flag_get(I2C0, I2C_FLAG_BTC) && (timeout < I2C_TIME_OUT)) { timeout++; } if (timeout >= I2C_TIME_OUT) { state = I2C_STATE_ERROR; break; } state = I2C_STATE_STOP; } timeout = 0; break; case I2C_STATE_STOP: /* send a stop condition to I2C bus */ i2c_stop_on_bus(I2C0); timeout = 0; while ((I2C_CTL0(I2C0) & I2C_CTL0_STOP) && (timeout < I2C_TIME_OUT)) { timeout++; } if (timeout >= I2C_TIME_OUT) { state = I2C_STATE_ERROR; break; } /* success */ return I2C_RESULT_SUCCESS; case I2C_STATE_ERROR: /* send a stop condition to I2C bus */ i2c_stop_on_bus(I2C0); timeout = 0; while ((I2C_CTL0(I2C0) & I2C_CTL0_STOP) && (timeout < I2C_TIME_OUT)) { timeout++; } i2c_flag_clear(I2C0, I2C_FLAG_AERR); i2c_flag_clear(I2C0, I2C_FLAG_BERR); i2c_flag_clear(I2C0, I2C_FLAG_LOSTARB); retry_count++; if (retry_count >= I2C_MAX_RETRY) { #ifdef DEBUG_VERBOSE printf("IIC write failed after %d retries\n", I2C_MAX_RETRY); #endif return I2C_RESULT_ERROR; } /* reset state machine for retry */ state = I2C_STATE_START; timeout = 0; /* small delay before retry */ delay_10us(10); break; default: state = I2C_STATE_START; break; } } return I2C_RESULT_TIMEOUT; } /*! \brief read data from I2C device with configurable length \param[in] slave_addr: slave device address (7-bit) \param[in] reg_addr: register address \param[out] data: pointer to data buffer \param[in] length: number of bytes to read (1-255) \retval i2c_result_t: operation result */ i2c_result_t i2c_read(uint8_t slave_addr, uint8_t reg_addr, uint8_t *data, uint8_t length) { i2c_state_t state = I2C_STATE_START; uint16_t timeout = 0; uint8_t retry_count = 0; bool write_phase = true; uint8_t data_index = 0; /* parameter validation */ if (data == NULL || slave_addr > 0x7F || length == 0) { return I2C_RESULT_INVALID_PARAM; } /* enable acknowledge */ i2c_ack_config(I2C0, I2C_ACK_ENABLE); while (retry_count < (uint8_t)I2C_MAX_RETRY) { switch (state) { case I2C_STATE_START: timeout = 0; data_index = 0; /* wait for bus to be idle */ while (i2c_flag_get(I2C0, I2C_FLAG_I2CBSY) && (timeout < I2C_TIME_OUT)) { timeout++; } if (timeout >= I2C_TIME_OUT) { state = I2C_STATE_ERROR; break; } /* send start condition */ i2c_start_on_bus(I2C0); state = I2C_STATE_SEND_ADDRESS; timeout = 0; break; case I2C_STATE_SEND_ADDRESS: /* wait for start condition to be sent */ while ((!i2c_flag_get(I2C0, I2C_FLAG_SBSEND)) && (timeout < I2C_TIME_OUT)) { timeout++; } if (timeout >= I2C_TIME_OUT) { state = I2C_STATE_ERROR; break; } /* send slave address */ if (write_phase) { /* write phase: send address with write bit */ i2c_master_addressing(I2C0, (slave_addr << 1), I2C_TRANSMITTER); } else { /* read phase: send address with read bit */ i2c_master_addressing(I2C0, (slave_addr << 1) | 0x01, I2C_RECEIVER); } state = I2C_STATE_CLEAR_ADDRESS; timeout = 0; break; case I2C_STATE_CLEAR_ADDRESS: /* wait for address to be acknowledged */ while ((!i2c_flag_get(I2C0, I2C_FLAG_ADDSEND)) && (timeout < I2C_TIME_OUT)) { timeout++; } if (timeout >= I2C_TIME_OUT) { state = I2C_STATE_ERROR; break; } if (write_phase) { /* clear address flag (write phase) */ i2c_flag_clear(I2C0, I2C_FLAG_ADDSEND); state = I2C_STATE_TRANSMIT_DATA; } else { /* read phase setup based on length */ if (length == 1) { /* single byte read: disable ACK before clearing ADDR */ i2c_ack_config(I2C0, I2C_ACK_DISABLE); i2c_flag_clear(I2C0, I2C_FLAG_ADDSEND); /* send STOP immediately after clearing ADDR for single byte */ i2c_stop_on_bus(I2C0); } else if (length == 2) { /* two bytes read: set POS=NEXT and disable ACK before clearing ADDR */ i2c_ackpos_config(I2C0, I2C_ACKPOS_NEXT); i2c_ack_config(I2C0, I2C_ACK_DISABLE); i2c_flag_clear(I2C0, I2C_FLAG_ADDSEND); } else { /* multi-byte read: clear ADDR with ACK enabled */ i2c_flag_clear(I2C0, I2C_FLAG_ADDSEND); } state = I2C_STATE_RECEIVE_DATA; } timeout = 0; break; case I2C_STATE_TRANSMIT_DATA: /* wait for transmit buffer to be empty */ while ((!i2c_flag_get(I2C0, I2C_FLAG_TBE)) && (timeout < I2C_TIME_OUT)) { timeout++; } if (timeout >= I2C_TIME_OUT) { state = I2C_STATE_ERROR; break; } /* send register address */ i2c_data_transmit(I2C0, reg_addr); state = I2C_STATE_RESTART; timeout = 0; break; case I2C_STATE_RESTART: /* wait for byte transfer complete */ while ((!i2c_flag_get(I2C0, I2C_FLAG_BTC)) && (timeout < I2C_TIME_OUT)) { timeout++; } if (timeout >= I2C_TIME_OUT) { state = I2C_STATE_ERROR; break; } /* generate repeated start condition */ i2c_start_on_bus(I2C0); /* wait for repeated start condition to be sent */ timeout = 0; while ((!i2c_flag_get(I2C0, I2C_FLAG_SBSEND)) && (timeout < I2C_TIME_OUT)) { timeout++; } if (timeout >= I2C_TIME_OUT) { state = I2C_STATE_ERROR; break; } /* send slave address with read bit */ i2c_master_addressing(I2C0, (slave_addr << 1), I2C_RECEIVER); /* switch to read phase */ write_phase = false; state = I2C_STATE_CLEAR_ADDRESS; timeout = 0; break; case I2C_STATE_RECEIVE_DATA: if (length == 1) { /* single byte read */ while ((!i2c_flag_get(I2C0, I2C_FLAG_RBNE)) && (timeout < I2C_TIME_OUT)) { timeout++; } if (timeout >= I2C_TIME_OUT) { state = I2C_STATE_ERROR; break; } data[0] = i2c_data_receive(I2C0); state = I2C_STATE_STOP; } else if (length == 2) { /* two bytes read */ while ((!i2c_flag_get(I2C0, I2C_FLAG_BTC)) && (timeout < I2C_TIME_OUT)) { timeout++; } if (timeout >= I2C_TIME_OUT) { state = I2C_STATE_ERROR; break; } /* send STOP before reading the last two bytes */ i2c_stop_on_bus(I2C0); /* read the two bytes back-to-back */ data[0] = i2c_data_receive(I2C0); data[1] = i2c_data_receive(I2C0); state = I2C_STATE_STOP; } else { /* multi-byte read (length > 2) */ while (data_index < length) { /* wait for RBNE (receive buffer not empty) */ while ((!i2c_flag_get(I2C0, I2C_FLAG_RBNE)) && (timeout < I2C_TIME_OUT)) { timeout++; } if (timeout >= I2C_TIME_OUT) { state = I2C_STATE_ERROR; break; } /* special handling for last 3 bytes */ if (data_index == length - 3) { /* wait for BTF (byte transfer finished) before reading N-2 */ while ((!i2c_flag_get(I2C0, I2C_FLAG_BTC)) && (timeout < I2C_TIME_OUT)) { timeout++; } if (timeout >= I2C_TIME_OUT) { state = I2C_STATE_ERROR; break; } /* disable ACK for last 2 bytes */ i2c_ack_config(I2C0, I2C_ACK_DISABLE); } /* read data byte */ data[data_index] = i2c_data_receive(I2C0); data_index++; /* send STOP after reading N-1 byte */ if (data_index == length - 1) { i2c_stop_on_bus(I2C0); } timeout = 0; } state = I2C_STATE_STOP; } break; case I2C_STATE_STOP: /* wait for stop condition to complete (only if not already sent) */ if (length > 2) { /* for multi-byte reads, STOP was already sent */ /* just wait for the STOP bit to clear */ while ((I2C_CTL0(I2C0) & I2C_CTL0_STOP) && (timeout < I2C_TIME_OUT)) { timeout++; } if (timeout >= I2C_TIME_OUT) { state = I2C_STATE_ERROR; break; } } /* reset ACK configuration for next operation */ i2c_ack_config(I2C0, I2C_ACK_ENABLE); i2c_ackpos_config(I2C0, I2C_ACKPOS_CURRENT); /* success */ return I2C_RESULT_SUCCESS; case I2C_STATE_ERROR: /* send stop condition to release bus */ i2c_stop_on_bus(I2C0); /* reset ACK configuration */ i2c_ack_config(I2C0, I2C_ACK_ENABLE); i2c_ackpos_config(I2C0, I2C_ACKPOS_CURRENT); retry_count++; if (retry_count >= I2C_MAX_RETRY) { #ifdef DEBUG_VERBOSE printf("I2C read failed after %d retries\n", I2C_MAX_RETRY); #endif return I2C_RESULT_ERROR; } /* reset state machine for retry */ state = I2C_STATE_START; write_phase = true; timeout = 0; /* small delay before retry */ delay_10us(10); break; default: state = I2C_STATE_START; break; } } return I2C_RESULT_TIMEOUT; } /* compatibility functions for legacy code */ i2c_result_t i2c_write_16bits(uint8_t slave_addr, uint8_t reg_addr, uint8_t data[2]) { return i2c_write(slave_addr, reg_addr, data, 2); } i2c_result_t i2c_read_16bits(uint8_t slave_addr, uint8_t reg_addr, uint8_t *data) { return i2c_read(slave_addr, reg_addr, data, 2); } /* convenience functions for common operations */ i2c_result_t i2c_write_8bits(uint8_t slave_addr, uint8_t reg_addr, uint8_t data) { return i2c_write(slave_addr, reg_addr, &data, 1); } i2c_result_t i2c_read_8bits(uint8_t slave_addr, uint8_t reg_addr, uint8_t *data) { return i2c_read(slave_addr, reg_addr, data, 1); } i2c_result_t i2c_write_32bits(uint8_t slave_addr, uint8_t reg_addr, uint8_t data[4]) { return i2c_write(slave_addr, reg_addr, data, 4); } i2c_result_t i2c_read_32bits(uint8_t slave_addr, uint8_t reg_addr, uint8_t *data) { return i2c_read(slave_addr, reg_addr, data, 4); } // ...existing code... // ...existing code... /*! \brief write data to I2C device with configurable length \param[in] slave_addr: slave device address (7-bit) \param[in] reg_addr: register address \param[in] data: pointer to data buffer \param[in] length: number of bytes to write (1-255) \param[out] none \retval i2c_result_t: operation result */ i2c_result_t i2c_write(uint8_t slave_addr, uint8_t reg_addr, uint8_t *data, uint8_t length) { i2c_state_t state = I2C_STATE_START; uint16_t timeout = 0; uint8_t retry_count = 0; uint8_t data_index = 0; /* parameter validation */ if (data == NULL || slave_addr > 0x7F || length == 0) { return I2C_RESULT_INVALID_PARAM; } while (retry_count < I2C_MAX_RETRY) { switch (state) { case I2C_STATE_START: timeout = 0; data_index = 0; /* wait for bus to be idle */ while (i2c_flag_get(I2C0, I2C_FLAG_I2CBSY) && (timeout < I2C_TIME_OUT)) { timeout++; } if (timeout >= I2C_TIME_OUT) { state = I2C_STATE_ERROR; break; } i2c_start_on_bus(I2C0); timeout = 0; state = I2C_STATE_SEND_ADDRESS; break; case I2C_STATE_SEND_ADDRESS: /* wait for start condition to be sent. SBSEND flag */ while((!i2c_flag_get(I2C0, I2C_FLAG_SBSEND)) && (timeout < I2C_TIME_OUT)) { timeout++; } if (timeout >= I2C_TIME_OUT) { state = I2C_STATE_ERROR; break; } /* send slave address */ i2c_master_addressing(I2C0, slave_addr << 1, I2C_TRANSMITTER); timeout = 0; state = I2C_STATE_CLEAR_ADDRESS; break; case I2C_STATE_CLEAR_ADDRESS: /* wait for address to be acknowledged.ADDSEND set means i2c slave sends ACK */ while ((!i2c_flag_get(I2C0, I2C_FLAG_ADDSEND)) && (!i2c_flag_get(I2C0, I2C_FLAG_AERR)) && (timeout < I2C_TIME_OUT)) { timeout++; } if (timeout >= I2C_TIME_OUT) { state = I2C_STATE_ERROR; break; } else if (i2c_flag_get(I2C0, I2C_FLAG_ADDSEND)) { i2c_flag_clear(I2C0, I2C_FLAG_ADDSEND); timeout = 0; state = I2C_STATE_TRANSMIT_REG; break; } else { i2c_flag_clear(I2C0, I2C_FLAG_AERR); timeout = 0; #ifdef DEBUG_VERBOSE printf("IIC write failed for Error Slave Address. \n"); #endif return I2C_RESULT_NACK; } case I2C_STATE_TRANSMIT_REG: /* wait until the transmit data buffer is empty */ while ((!i2c_flag_get(I2C0, I2C_FLAG_TBE)) && (timeout < I2C_TIME_OUT)) { timeout++; } if (timeout >= I2C_TIME_OUT) { state = I2C_STATE_ERROR; break; } /* send register address */ i2c_data_transmit(I2C0, reg_addr); timeout = 0; state = I2C_STATE_TRANSMIT_DATA; break; case I2C_STATE_TRANSMIT_DATA: /* wait until the transmit data buffer is empty */ while ((!i2c_flag_get(I2C0, I2C_FLAG_TBE)) && (timeout < I2C_TIME_OUT)) { timeout++; } if (timeout >= I2C_TIME_OUT) { state = I2C_STATE_ERROR; break; } /* send data byte */ i2c_data_transmit(I2C0, data[data_index]); data_index++; /* check for errors */ if (i2c_flag_get(I2C0, I2C_FLAG_AERR)) { i2c_stop_on_bus(I2C0); return I2C_RESULT_NACK; } else if (i2c_flag_get(I2C0, I2C_FLAG_BERR) || i2c_flag_get(I2C0, I2C_FLAG_LOSTARB)) { i2c_stop_on_bus(I2C0); return I2C_RESULT_ERROR; } /* check if all data has been sent */ if (data_index >= length) { /* wait until BTC bit is set for last byte */ timeout = 0; while (!i2c_flag_get(I2C0, I2C_FLAG_BTC) && (timeout < I2C_TIME_OUT)) { timeout++; } if (timeout >= I2C_TIME_OUT) { state = I2C_STATE_ERROR; break; } state = I2C_STATE_STOP; } timeout = 0; break; case I2C_STATE_STOP: /* send a stop condition to I2C bus */ i2c_stop_on_bus(I2C0); timeout = 0; while ((I2C_CTL0(I2C0) & I2C_CTL0_STOP) && (timeout < I2C_TIME_OUT)) { timeout++; } if (timeout >= I2C_TIME_OUT) { state = I2C_STATE_ERROR; break; } /* success */ return I2C_RESULT_SUCCESS; case I2C_STATE_ERROR: /* send a stop condition to I2C bus */ i2c_stop_on_bus(I2C0); timeout = 0; while ((I2C_CTL0(I2C0) & I2C_CTL0_STOP) && (timeout < I2C_TIME_OUT)) { timeout++; } i2c_flag_clear(I2C0, I2C_FLAG_AERR); i2c_flag_clear(I2C0, I2C_FLAG_BERR); i2c_flag_clear(I2C0, I2C_FLAG_LOSTARB); retry_count++; if (retry_count >= I2C_MAX_RETRY) { #ifdef DEBUG_VERBOSE printf("IIC write failed after %d retries\n", I2C_MAX_RETRY); #endif return I2C_RESULT_ERROR; } /* reset state machine for retry */ state = I2C_STATE_START; timeout = 0; /* small delay before retry */ delay_10us(10); break; default: state = I2C_STATE_START; break; } } return I2C_RESULT_TIMEOUT; } /*! \brief read data from I2C device with configurable length \param[in] slave_addr: slave device address (7-bit) \param[in] reg_addr: register address \param[out] data: pointer to data buffer \param[in] length: number of bytes to read (1-255) \retval i2c_result_t: operation result */ i2c_result_t i2c_read(uint8_t slave_addr, uint8_t reg_addr, uint8_t *data, uint8_t length) { i2c_state_t state = I2C_STATE_START; uint16_t timeout = 0; uint8_t retry_count = 0; bool write_phase = true; uint8_t data_index = 0; /* parameter validation */ if (data == NULL || slave_addr > 0x7F || length == 0) { return I2C_RESULT_INVALID_PARAM; } /* enable acknowledge */ i2c_ack_config(I2C0, I2C_ACK_ENABLE); while (retry_count < (uint8_t)I2C_MAX_RETRY) { switch (state) { case I2C_STATE_START: timeout = 0; data_index = 0; /* wait for bus to be idle */ while (i2c_flag_get(I2C0, I2C_FLAG_I2CBSY) && (timeout < I2C_TIME_OUT)) { timeout++; } if (timeout >= I2C_TIME_OUT) { state = I2C_STATE_ERROR; break; } /* send start condition */ i2c_start_on_bus(I2C0); state = I2C_STATE_SEND_ADDRESS; timeout = 0; break; case I2C_STATE_SEND_ADDRESS: /* wait for start condition to be sent */ while ((!i2c_flag_get(I2C0, I2C_FLAG_SBSEND)) && (timeout < I2C_TIME_OUT)) { timeout++; } if (timeout >= I2C_TIME_OUT) { state = I2C_STATE_ERROR; break; } /* send slave address */ if (write_phase) { /* write phase: send address with write bit */ i2c_master_addressing(I2C0, (slave_addr << 1), I2C_TRANSMITTER); } else { /* read phase: send address with read bit */ i2c_master_addressing(I2C0, (slave_addr << 1) | 0x01, I2C_RECEIVER); } state = I2C_STATE_CLEAR_ADDRESS; timeout = 0; break; case I2C_STATE_CLEAR_ADDRESS: /* wait for address to be acknowledged */ while ((!i2c_flag_get(I2C0, I2C_FLAG_ADDSEND)) && (timeout < I2C_TIME_OUT)) { timeout++; } if (timeout >= I2C_TIME_OUT) { state = I2C_STATE_ERROR; break; } if (write_phase) { /* clear address flag (write phase) */ i2c_flag_clear(I2C0, I2C_FLAG_ADDSEND); state = I2C_STATE_TRANSMIT_DATA; } else { /* read phase setup based on length */ if (length == 1) { /* single byte read: disable ACK before clearing ADDR */ i2c_ack_config(I2C0, I2C_ACK_DISABLE); i2c_flag_clear(I2C0, I2C_FLAG_ADDSEND); /* send STOP immediately after clearing ADDR for single byte */ i2c_stop_on_bus(I2C0); } else if (length == 2) { /* two bytes read: set POS=NEXT and disable ACK before clearing ADDR */ i2c_ackpos_config(I2C0, I2C_ACKPOS_NEXT); i2c_ack_config(I2C0, I2C_ACK_DISABLE); i2c_flag_clear(I2C0, I2C_FLAG_ADDSEND); } else { /* multi-byte read: clear ADDR with ACK enabled */ i2c_flag_clear(I2C0, I2C_FLAG_ADDSEND); } state = I2C_STATE_RECEIVE_DATA; } timeout = 0; break; case I2C_STATE_TRANSMIT_DATA: /* wait for transmit buffer to be empty */ while ((!i2c_flag_get(I2C0, I2C_FLAG_TBE)) && (timeout < I2C_TIME_OUT)) { timeout++; } if (timeout >= I2C_TIME_OUT) { state = I2C_STATE_ERROR; break; } /* send register address */ i2c_data_transmit(I2C0, reg_addr); state = I2C_STATE_RESTART; timeout = 0; break; case I2C_STATE_RESTART: /* wait for byte transfer complete */ while ((!i2c_flag_get(I2C0, I2C_FLAG_BTC)) && (timeout < I2C_TIME_OUT)) { timeout++; } if (timeout >= I2C_TIME_OUT) { state = I2C_STATE_ERROR; break; } /* generate repeated start condition */ i2c_start_on_bus(I2C0); /* wait for repeated start condition to be sent */ timeout = 0; while ((!i2c_flag_get(I2C0, I2C_FLAG_SBSEND)) && (timeout < I2C_TIME_OUT)) { timeout++; } if (timeout >= I2C_TIME_OUT) { state = I2C_STATE_ERROR; break; } /* send slave address with read bit */ i2c_master_addressing(I2C0, (slave_addr << 1), I2C_RECEIVER); /* switch to read phase */ write_phase = false; state = I2C_STATE_CLEAR_ADDRESS; timeout = 0; break; case I2C_STATE_RECEIVE_DATA: if (length == 1) { /* single byte read */ while ((!i2c_flag_get(I2C0, I2C_FLAG_RBNE)) && (timeout < I2C_TIME_OUT)) { timeout++; } if (timeout >= I2C_TIME_OUT) { state = I2C_STATE_ERROR; break; } data[0] = i2c_data_receive(I2C0); state = I2C_STATE_STOP; } else if (length == 2) { /* two bytes read */ while ((!i2c_flag_get(I2C0, I2C_FLAG_BTC)) && (timeout < I2C_TIME_OUT)) { timeout++; } if (timeout >= I2C_TIME_OUT) { state = I2C_STATE_ERROR; break; } /* send STOP before reading the last two bytes */ i2c_stop_on_bus(I2C0); /* read the two bytes back-to-back */ data[0] = i2c_data_receive(I2C0); data[1] = i2c_data_receive(I2C0); state = I2C_STATE_STOP; } else { /* multi-byte read (length > 2) */ while (data_index < length) { /* wait for RBNE (receive buffer not empty) */ while ((!i2c_flag_get(I2C0, I2C_FLAG_RBNE)) && (timeout < I2C_TIME_OUT)) { timeout++; } if (timeout >= I2C_TIME_OUT) { state = I2C_STATE_ERROR; break; } /* special handling for last 3 bytes */ if (data_index == length - 3) { /* wait for BTF (byte transfer finished) before reading N-2 */ while ((!i2c_flag_get(I2C0, I2C_FLAG_BTC)) && (timeout < I2C_TIME_OUT)) { timeout++; } if (timeout >= I2C_TIME_OUT) { state = I2C_STATE_ERROR; break; } /* disable ACK for last 2 bytes */ i2c_ack_config(I2C0, I2C_ACK_DISABLE); } /* read data byte */ data[data_index] = i2c_data_receive(I2C0); data_index++; /* send STOP after reading N-1 byte */ if (data_index == length - 1) { i2c_stop_on_bus(I2C0); } timeout = 0; } state = I2C_STATE_STOP; } break; case I2C_STATE_STOP: /* wait for stop condition to complete */ while ((I2C_CTL0(I2C0) & I2C_CTL0_STOP) && (timeout < I2C_TIME_OUT)) { timeout++; } if (timeout >= I2C_TIME_OUT) { state = I2C_STATE_ERROR; break; } /* reset ACK configuration for next operation */ i2c_ack_config(I2C0, I2C_ACK_ENABLE); i2c_ackpos_config(I2C0, I2C_ACKPOS_CURRENT); /* success */ return I2C_RESULT_SUCCESS; case I2C_STATE_ERROR: /* send stop condition to release bus */ i2c_stop_on_bus(I2C0); /* reset ACK configuration */ i2c_ack_config(I2C0, I2C_ACK_ENABLE); i2c_ackpos_config(I2C0, I2C_ACKPOS_CURRENT); retry_count++; if (retry_count >= I2C_MAX_RETRY) { #ifdef DEBUG_VERBOSE printf("I2C read failed after %d retries\n", I2C_MAX_RETRY); #endif return I2C_RESULT_ERROR; } /* reset state machine for retry */ state = I2C_STATE_START; write_phase = true; timeout = 0; /* small delay before retry */ delay_10us(10); break; default: state = I2C_STATE_START; break; } } return I2C_RESULT_TIMEOUT; } /* convenience functions for common operations */ i2c_result_t i2c_write_8bits(uint8_t slave_addr, uint8_t reg_addr, uint8_t data) { return i2c_write(slave_addr, reg_addr, &data, 1); } i2c_result_t i2c_read_8bits(uint8_t slave_addr, uint8_t reg_addr, uint8_t *data) { return i2c_read(slave_addr, reg_addr, data, 1); } i2c_result_t i2c_write_32bits(uint8_t slave_addr, uint8_t reg_addr, uint8_t data[4]) { return i2c_write(slave_addr, reg_addr, data, 4); } i2c_result_t i2c_read_32bits(uint8_t slave_addr, uint8_t reg_addr, uint8_t *data) { return i2c_read(slave_addr, reg_addr, data, 4); } /* 显示面板专用函数 - 支持读取显示界面参数 */ i2c_result_t i2c_read_display_params(uint8_t slave_addr, uint8_t reg_addr, uint8_t *data, uint8_t length) { /* 针对显示面板的多字节读取,支持13字节的完整参数读取 */ if (length > 13) { return I2C_RESULT_INVALID_PARAM; } return i2c_read(slave_addr, reg_addr, data, length); } // ...existing code...