diff --git a/Inc/iic_new.h b/Inc/iic_new.h new file mode 100644 index 0000000..7359d6a --- /dev/null +++ b/Inc/iic_new.h @@ -0,0 +1,46 @@ +// ...existing code... + +/* function declarations */ +i2c_result_t i2c_config(void); +i2c_result_t i2c_bus_reset(void); +void i2c_scan(void); + +/* generic read/write functions with configurable length */ +i2c_result_t i2c_write(uint8_t slave_addr, uint8_t reg_addr, uint8_t *data, uint8_t length); +i2c_result_t i2c_read(uint8_t slave_addr, uint8_t reg_addr, uint8_t *data, uint8_t length); + +/* compatibility functions for legacy code */ +i2c_result_t i2c_write_16bits(uint8_t slave_addr, uint8_t reg_addr, uint8_t data[2]); +i2c_result_t i2c_read_16bits(uint8_t slave_addr, uint8_t reg_addr, uint8_t *data); + +/* convenience functions for common operations */ +i2c_result_t i2c_write_8bits(uint8_t slave_addr, uint8_t reg_addr, uint8_t data); +i2c_result_t i2c_read_8bits(uint8_t slave_addr, uint8_t reg_addr, uint8_t *data); +i2c_result_t i2c_write_32bits(uint8_t slave_addr, uint8_t reg_addr, uint8_t data[4]); +i2c_result_t i2c_read_32bits(uint8_t slave_addr, uint8_t reg_addr, uint8_t *data); + +#ifdef DEBUG_VERBOSE +const char* i2c_get_status_string(i2c_result_t status); +#endif + +// ...existing code... + + +// 读取显示面板参数 (13字节) +uint8_t display_params[13]; +i2c_result_t result = i2c_read_display_params(0x3C, 0x0F, display_params, 13); + +// 或者使用通用函数 +result = i2c_read(0x3C, 0x0F, display_params, 13); + +// 读取单个参数 +uint8_t startup_mode; +result = i2c_read_8bits(0x3C, 0x0F, &startup_mode); + +// 读取2字节参数(如显示界面宽度) +uint8_t width_data[2]; +result = i2c_read(0x3C, 0x10, width_data, 2); + +// 写入多字节配置 +uint8_t config_data[5] = {0x01, 0x02, 0x03, 0x04, 0x05}; +result = i2c_write(0x3C, 0x20, config_data, 5); \ No newline at end of file diff --git a/Src/iic_new.c b/Src/iic_new.c new file mode 100644 index 0000000..6eedf28 --- /dev/null +++ b/Src/iic_new.c @@ -0,0 +1,975 @@ +// ...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... \ No newline at end of file diff --git a/iic_new.md b/iic_new.md new file mode 100644 index 0000000..a0b7ce3 --- /dev/null +++ b/iic_new.md @@ -0,0 +1,43 @@ +主要改进特性: +通用读写函数: + +i2c_write():支持任意长度的写操作 +i2c_read():支持任意长度的读操作 +兼容性函数:保留原有的16位读写函数以保持向后兼容 + +便利函数:提供常用的8位、16位、32位读写函数 + +智能长度处理: + +单字节读取:正确处理NACK和STOP时序 +双字节读取:使用POS=NEXT模式 +多字节读取:正确处理最后几个字节的ACK/NACK时序 +错误处理:保持原有的重试机制和错误处理逻辑 + +使用示例: + +``` +uint8_t data[4]; +i2c_result_t result; + +// 读取1字节 +result = i2c_read_8bits(0x48, 0x00, &data[0]); + +// 读取2字节 +result = i2c_read(0x48, 0x01, data, 2); + +// 读取4字节 +result = i2c_read_32bits(0x48, 0x02, data); + +// 写入3字节 +uint8_t write_data[3] = {0x11, 0x22, 0x33}; +result = i2c_write(0x48, +``` + +主要功能特性 +支持任意长度读写:从1字节到255字节 +正确的ACK/NACK处理:根据读取长度智能处理 +保持兼容性:原有的16位读写函数仍然可用 +专用显示函数:为显示面板参数读取提供专门的函数 +完整的错误处理:保持原有的重试和错误恢复机制 +这样就可以支持您文档中提到的多字节显示面板参数读写操作了 \ No newline at end of file