From fcf10601b90dbc659dd697a8cda400ac4154bd36 Mon Sep 17 00:00:00 2001 From: yelvlab Date: Fri, 26 Sep 2025 09:02:37 +0800 Subject: [PATCH] debug version --- Inc/board_config.h | 8 + Inc/i2c.h | 72 ++++++- Src/command.c | 15 ++ Src/i2c.c | 481 +++++++++++++++++++++++++++++++++++++++++++++ Src/main.c | 2 +- Src/tmp112.c | 3 +- 6 files changed, 574 insertions(+), 7 deletions(-) diff --git a/Inc/board_config.h b/Inc/board_config.h index 13fc6c9..73f6d8a 100644 --- a/Inc/board_config.h +++ b/Inc/board_config.h @@ -27,6 +27,14 @@ /******************************************************************************/ +#define MCU_CODE 23u + +#define FW_VERSION_MAJOR 0 +#define FW_VERSION_MINOR 0 +#define FW_VERSION_PATCH 3 + +/******************************************************************************/ + /* Dynamic USART Configuration Structure */ typedef struct { uint32_t rcu_usart; diff --git a/Inc/i2c.h b/Inc/i2c.h index e810478..eaa7097 100644 --- a/Inc/i2c.h +++ b/Inc/i2c.h @@ -107,15 +107,76 @@ i2c_result_t i2c_write_16bits(uint8_t slave_addr, uint8_t reg_addr, uint8_t data */ i2c_result_t i2c_read_16bits(uint8_t slave_addr, uint8_t reg_addr, uint8_t *data); +/* Generic read/write functions with configurable length */ /*! - \brief read 16-bit data from I2C device - \param[in] slave_addr: 7-bit slave address + \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[out] data: pointer to 2-byte data buffer - \retval i2c_result_t + \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_read_16bits(uint8_t slave_addr, uint8_t reg_addr, uint8_t *data); +i2c_result_t i2c_write(uint8_t slave_addr, uint8_t reg_addr, uint8_t *data, uint8_t length); +/*! + \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); + +/* Convenience functions for common operations */ +/*! + \brief write single byte to I2C device + \param[in] slave_addr: slave device address (7-bit) + \param[in] reg_addr: register address + \param[in] data: data byte to write + \retval i2c_result_t: operation result +*/ +i2c_result_t i2c_write_8bits(uint8_t slave_addr, uint8_t reg_addr, uint8_t data); + +/*! + \brief read single byte from I2C device + \param[in] slave_addr: slave device address (7-bit) + \param[in] reg_addr: register address + \param[out] data: pointer to data byte + \retval i2c_result_t: operation result +*/ +i2c_result_t i2c_read_8bits(uint8_t slave_addr, uint8_t reg_addr, uint8_t *data); + +/*! + \brief write 32-bit data to I2C device + \param[in] slave_addr: slave device address (7-bit) + \param[in] reg_addr: register address + \param[in] data: pointer to 4-byte data array + \retval i2c_result_t: operation result +*/ +i2c_result_t i2c_write_32bits(uint8_t slave_addr, uint8_t reg_addr, uint8_t data[4]); + +/*! + \brief read 32-bit data from I2C device + \param[in] slave_addr: slave device address (7-bit) + \param[in] reg_addr: register address + \param[out] data: pointer to 4-byte data buffer + \retval i2c_result_t: operation result +*/ +i2c_result_t i2c_read_32bits(uint8_t slave_addr, uint8_t reg_addr, uint8_t *data); + +/*! + \brief read display panel parameters (multi-byte) + \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-13) + \retval i2c_result_t: operation result +*/ +i2c_result_t i2c_read_display_params(uint8_t slave_addr, uint8_t reg_addr, uint8_t *data, uint8_t length); + +#ifdef DEBUG_VERBOSE /*! \brief get status string for debugging \param[in] status: i2c_result_t value @@ -123,5 +184,6 @@ i2c_result_t i2c_read_16bits(uint8_t slave_addr, uint8_t reg_addr, uint8_t *data \retval const char* status string */ const char* i2c_get_status_string(i2c_result_t status); +#endif #endif //I2C_H diff --git a/Src/command.c b/Src/command.c index d0e34c1..8836074 100644 --- a/Src/command.c +++ b/Src/command.c @@ -306,6 +306,7 @@ void handle_command(const uint8_t *frame, uint8_t len) { case 2u: // M2: disable sensor report set_eddy_sensor_report_status(false); + send_response(RESP_TYPE_OK, s_report_status_ok, sizeof(s_report_status_ok)); return; case 3u: @@ -314,12 +315,26 @@ void handle_command(const uint8_t *frame, uint8_t len) { case 4u: set_temp_sensor_report_status(false); + send_response(RESP_TYPE_OK, s_report_status_ok, sizeof(s_report_status_ok)); return; // case 201u: // M201命令 // send_response(RESP_TYPE_OK, s_report_status_ok, sizeof(s_report_status_ok)); // return; + case 999u: //M999: 输出固件版本号(vMCU_CODE.FW_VERSION_MAJOR.FW_VERSION_MINOR.FW_VERSION_PATCH) + char version_str[16]; + int n = snprintf(version_str, sizeof(version_str), "v%u.%u.%u.%u", MCU_CODE, FW_VERSION_MAJOR, FW_VERSION_MINOR, FW_VERSION_PATCH); + send_response(RESP_TYPE_OK, (uint8_t *)version_str, (uint8_t)n); + // send_response(RESP_TYPE_OK, (uint8_t *)"v23.0.0.3", 9); + return; + + case 9999u: + // M9999: 重启系统 + __disable_irq(); // 关闭全局中断(GD32E230 CMSIS标准函数) + nvic_system_reset(); // 系统复位(GD32E230标准库函数) + break; + default: // 其它无参数命令在此扩展(示例:M100)处理逻辑该如何待定 // send_response(RESP_TYPE_OK, s_report_status_ok, sizeof(s_report_status_ok)); diff --git a/Src/i2c.c b/Src/i2c.c index e241b58..44ba655 100644 --- a/Src/i2c.c +++ b/Src/i2c.c @@ -649,6 +649,487 @@ i2c_result_t i2c_read_16bits(uint8_t slave_addr, uint8_t reg_addr, uint8_t *data return I2C_RESULT_TIMEOUT; } +/*! + \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); +} + #ifdef DEBUG_VERBOSE /*! \brief get status string for debugging diff --git a/Src/main.c b/Src/main.c index 9b9def8..2e1d23c 100644 --- a/Src/main.c +++ b/Src/main.c @@ -60,7 +60,7 @@ int main(void) // led_init(); - printf("Flash size: %d Kbytes\n", get_flash_size()); + // printf("Flash size: %d Kbytes\n", get_flash_size()); #ifdef DEBUG_VERBOSE char hello_world[] = {"Hello World!\r\n"}; diff --git a/Src/tmp112.c b/Src/tmp112.c index 63e2f01..7f5c71f 100644 --- a/Src/tmp112.c +++ b/Src/tmp112.c @@ -86,7 +86,8 @@ tmp112a_status_t tmp112a_read_temperature(tmp112a_result_t *result) { } void tmp112a_get_raw_temperature_value(uint8_t *value) { - i2c_read_16bits(TMP112A_ADDR, TMP112A_TEMP_REG, value); + // i2c_read_16bits(TMP112A_ADDR, TMP112A_TEMP_REG, value); + i2c_read(TMP112A_ADDR, TMP112A_TEMP_REG, value, 2); return; }