Files
ldc1612_cmake_vscode/Src/iic_new.c

975 lines
35 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// ...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...