From b24c0853c94416d320a081f847b92cba8edbb620 Mon Sep 17 00:00:00 2001 From: yelvlab Date: Sat, 16 Aug 2025 15:53:47 +0800 Subject: [PATCH] rewrite write 16bits --- Src/i2c.c | 276 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 145 insertions(+), 131 deletions(-) diff --git a/Src/i2c.c b/Src/i2c.c index 15bbbff..e241b58 100644 --- a/Src/i2c.c +++ b/Src/i2c.c @@ -264,166 +264,193 @@ void i2c_scan(void) { } i2c_result_t i2c_write_16bits(uint8_t slave_addr, uint8_t reg_addr, uint8_t data[2]) { - uint8_t state = I2C_STATE_START; + i2c_state_t state = I2C_STATE_START; uint16_t timeout = 0; - uint8_t i2c_timeout_flag = 0; + uint8_t retry_count = 0; /* parameter validation */ if (data == NULL || slave_addr > 0x7F) { return I2C_RESULT_INVALID_PARAM; } - /* enable acknowledge */ - i2c_ack_config(I2C0, I2C_ACK_ENABLE); - - while (!(i2c_timeout_flag)) { + while (retry_count < I2C_MAX_RETRY) { switch (state) { case I2C_STATE_START: - /* i2c master sends start signal only when the bus is idle */ + timeout = 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) { - i2c_start_on_bus(I2C0); - timeout = 0; - state = I2C_STATE_SEND_ADDRESS; - } else { - timeout = 0; - state = I2C_STATE_START; -#ifdef DEBUG_VERBOES - printf("i2c bus is busy in WRITE BYTE!\n"); -#endif + 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: - /* i2c master sends START signal successfully */ - while ((!i2c_flag_get(I2C0, I2C_FLAG_SBSEND)) && (timeout < I2C_TIME_OUT)) { + /* 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) { - i2c_master_addressing(I2C0, slave_addr << 1, I2C_TRANSMITTER); - timeout = 0; - state = I2C_STATE_CLEAR_ADDRESS; - } else { - timeout = 0; - state = I2C_STATE_START; -#ifdef DEBUG_VERBOES - printf("i2c master sends start signal timeout in WRITE BYTE!\n"); -#endif + 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: - /* address flag set means i2c slave sends ACK */ - while ((!i2c_flag_get(I2C0, I2C_FLAG_ADDSEND)) && (timeout < I2C_TIME_OUT)) { + /* 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) { + 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_DATA; + timeout =0; + state = I2C_STATE_TRANSMIT_REG; + break; } else { - timeout = 0; - state = I2C_STATE_START; + i2c_flag_clear(I2C0, I2C_FLAG_AERR); + timeout =0; #ifdef DEBUG_VERBOES - printf("i2c master clears address flag timeout in WRITE BYTE!\n"); + 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) { - /* send IIC register address */ - i2c_data_transmit(I2C0, reg_addr); - timeout = 0; - } else { - timeout = 0; - state = I2C_STATE_START; -#ifdef DEBUG_VERBOES - printf("i2c master sends data timeout in WRITE BYTE!\n"); -#endif + if (timeout >= I2C_TIME_OUT) { + state = I2C_STATE_ERROR; + break; } - /* wait until BTC bit is set */ - while ((!i2c_flag_get(I2C0, I2C_FLAG_BTC)) && (timeout < I2C_TIME_OUT)) { + /* send register MSB value */ + i2c_data_transmit(I2C0, data[0]); + timeout = 0; + + /* 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) { - /* send register MSB value */ - i2c_data_transmit(I2C0, data[0]); - timeout = 0; - } else { - timeout = 0; - state = I2C_STATE_START; -#ifdef DEBUG_VERBOES - printf("i2c master sends MSB data timeout in WRITE BYTE!\n"); -#endif + if (timeout >= I2C_TIME_OUT) { + state = I2C_STATE_ERROR; + break; } - /* wait until BTC bit is set */ - while ((!i2c_flag_get(I2C0, I2C_FLAG_BTC)) && (timeout < I2C_TIME_OUT)) { - timeout++; - } - if (timeout < I2C_TIME_OUT) { - /* send register LSB value */ - i2c_data_transmit(I2C0, data[1]); - timeout = 0; - state = I2C_STATE_STOP; - } else { - timeout = 0; - state = I2C_STATE_START; -#ifdef DEBUG_VERBOES - printf("i2c master sends LSB data timeout in WRITE BYTE!\n"); -#endif + 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; } - /* wait until BTC bit is set */ - while ((!i2c_flag_get(I2C0, I2C_FLAG_BTC)) && (timeout < I2C_TIME_OUT)) { + /* send register LSB value */ + i2c_data_transmit(I2C0, data[1]); + timeout = 0; + + /* wait until BTC bit is set */ + while (!i2c_flag_get(I2C0, I2C_FLAG_BTC) && (timeout < I2C_TIME_OUT)) { timeout++; } - if (timeout < I2C_TIME_OUT) { - state = I2C_STATE_STOP; - timeout = 0; - } else { - timeout = 0; - state = I2C_STATE_START; -#ifdef DEBUG_VERBOES - printf("i2c master sends data timeout in WRITE BYTE!\n"); -#endif + if (timeout >= I2C_TIME_OUT) { + state = I2C_STATE_ERROR; + break; } + + state = I2C_STATE_STOP; break; + case I2C_STATE_STOP: /* send a stop condition to I2C bus */ i2c_stop_on_bus(I2C0); - /* i2c master sends STOP signal successfully */ + + timeout = 0; while ((I2C_CTL0(I2C0) & I2C_CTL0_STOP) && (timeout < I2C_TIME_OUT)) { timeout++; } - if (timeout < I2C_TIME_OUT) { - timeout = 0; - state = I2C_STATE_END; - i2c_timeout_flag = I2C_OK; - } else { - timeout = 0; - state = I2C_STATE_START; -#ifdef DEBUG_VERBOES - printf("i2c master sends stop signal timeout in WRITE BYTE!\n"); -#endif + if (timeout >= I2C_TIME_OUT) { + state = I2C_STATE_ERROR; + break; } + + /* i2c master sends STOP signal successfully */ + /* 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++; + } + if (timeout >= I2C_TIME_OUT) { + return I2C_RESULT_ERROR; + } + + 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_VERBOES + 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; - i2c_timeout_flag = I2C_OK; - timeout = 0; -#ifdef DEBUG_VERBOES - printf("i2c master sends start signal in WRITE BYTE.\n"); -#endif break; } } - return I2C_RESULT_SUCCESS; + return I2C_RESULT_TIMEOUT; } i2c_result_t i2c_read_16bits(uint8_t slave_addr, uint8_t reg_addr, uint8_t *data) { @@ -431,7 +458,6 @@ i2c_result_t i2c_read_16bits(uint8_t slave_addr, uint8_t reg_addr, uint8_t *data uint16_t timeout = 0; uint8_t retry_count = 0; bool write_phase = true; - uint8_t data_index = 0; // 参数检查:防止空指针和非法地址 if (data == NULL || slave_addr > 0x7F) { @@ -494,18 +520,19 @@ i2c_result_t i2c_read_16bits(uint8_t slave_addr, uint8_t reg_addr, uint8_t *data break; } - /* clear address flag, address flag set means i2c slave sends ACK */ - i2c_flag_clear(I2C0, I2C_FLAG_ADDSEND); - if (write_phase) { + /* clear address flag (write phase) */ + i2c_flag_clear(I2C0, I2C_FLAG_ADDSEND); state = I2C_STATE_TRANSMIT_DATA; } else { - /* 读阶段:配置ACK位置和禁用ACK(针对2字节读取) */ + /* READ phase for 2 bytes: set POS=NEXT and disable ACK BEFORE clearing ADDR */ i2c_ackpos_config(I2C0, I2C_ACKPOS_NEXT); i2c_ack_config(I2C0, I2C_ACK_DISABLE); - + + /* now clear address flag to release SCL and enter data phase */ + i2c_flag_clear(I2C0, I2C_FLAG_ADDSEND); + state = I2C_STATE_RECEIVE_DATA; - data_index = 0; } timeout = 0; @@ -550,9 +577,9 @@ i2c_result_t i2c_read_16bits(uint8_t slave_addr, uint8_t reg_addr, uint8_t *data break; } - /* send slave address with read bit */ - i2c_master_addressing(I2C0, (slave_addr << 1) | 0x01, I2C_RECEIVER); - + /* send slave address with read bit (R/W bit is set by library) */ + i2c_master_addressing(I2C0, (slave_addr << 1), I2C_RECEIVER); + /* switch to read phase */ write_phase = false; state = I2C_STATE_CLEAR_ADDRESS; @@ -560,7 +587,7 @@ i2c_result_t i2c_read_16bits(uint8_t slave_addr, uint8_t reg_addr, uint8_t *data break; case I2C_STATE_RECEIVE_DATA: - /* 等待BTC标志表示第一个字节接收完成 */ + /* Wait for BTC (both bytes received) */ while ((!i2c_flag_get(I2C0, I2C_FLAG_BTC)) && (timeout < I2C_TIME_OUT)) { timeout++; } @@ -568,26 +595,14 @@ i2c_result_t i2c_read_16bits(uint8_t slave_addr, uint8_t reg_addr, uint8_t *data state = I2C_STATE_ERROR; break; } - - /* 发送STOP条件 */ + + /* 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); - - /* 等待第二个字节接收完成 */ - timeout = 0; - while ((!i2c_flag_get(I2C0, I2C_FLAG_RBNE)) && (timeout < I2C_TIME_OUT)) { - timeout++; - } - if (timeout >= I2C_TIME_OUT) { - state = I2C_STATE_ERROR; - break; - } - - /* 读取第二个字节 */ data[1] = i2c_data_receive(I2C0); - + state = I2C_STATE_STOP; break; @@ -620,7 +635,6 @@ i2c_result_t i2c_read_16bits(uint8_t slave_addr, uint8_t reg_addr, uint8_t *data /* reset state machine for retry */ state = I2C_STATE_START; write_phase = true; - data_index = 0; timeout = 0; /* small delay before retry */