generated from hulk/gd32e23x_template_cmake_vscode
fix i2c reset bus function
This commit is contained in:
12
Inc/i2c.h
12
Inc/i2c.h
@@ -39,7 +39,10 @@ typedef enum {
|
||||
I2C_RESULT_NACK, /* No acknowledge received */
|
||||
I2C_RESULT_BUS_BUSY, /* Bus is busy */
|
||||
I2C_RESULT_ERROR, /* General error */
|
||||
I2C_RESULT_INVALID_PARAM /* Invalid parameter */
|
||||
I2C_RESULT_INVALID_PARAM, /* Invalid parameter */
|
||||
I2C_RECOVERY_OK,
|
||||
I2C_RECOVERY_SDA_STUCK_LOW,
|
||||
I2C_RECOVERY_SCL_STUCK_LOW
|
||||
} i2c_result_t;
|
||||
|
||||
/* I2C state machine enumeration */
|
||||
@@ -69,24 +72,21 @@ typedef enum {
|
||||
|
||||
|
||||
/* Function declarations */
|
||||
|
||||
// TODO I2C Result
|
||||
/*!
|
||||
\brief configure the I2C interface
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval i2c_result_t
|
||||
*/
|
||||
void i2c_config(void);
|
||||
i2c_result_t i2c_config(void);
|
||||
|
||||
// TODO I2C Result
|
||||
/*!
|
||||
\brief reset I2C bus with proper recovery
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval i2c_result_t
|
||||
*/
|
||||
void i2c_bus_reset(void);
|
||||
i2c_result_t i2c_bus_reset(void);
|
||||
|
||||
/*!
|
||||
\brief scan I2C bus for devices
|
||||
|
120
Src/i2c.c
120
Src/i2c.c
@@ -31,7 +31,7 @@ void i2c_gpio_config(void) {
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void i2c_config(void) {
|
||||
i2c_result_t i2c_config(void) {
|
||||
/* configure I2C GPIO */
|
||||
i2c_gpio_config();
|
||||
/* enable I2C clock */
|
||||
@@ -44,6 +44,26 @@ void i2c_config(void) {
|
||||
i2c_enable(I2C0);
|
||||
/* enable acknowledge */
|
||||
i2c_ack_config(I2C0, I2C_ACK_ENABLE);
|
||||
|
||||
return I2C_RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
static bool i2c_wait_scl_high(uint16_t max_wait_time) {
|
||||
while (max_wait_time--) {
|
||||
if (gpio_input_bit_get(I2C_SCL_PORT, I2C_SCL_PIN)) {
|
||||
return true;
|
||||
}
|
||||
delay_10us(1);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* generate one manual SCL pulse; return true if SCL observed high (no stuck/overstretch) */
|
||||
static bool i2c_generate_scl_pulse(void) {
|
||||
GPIO_BC(I2C_SCL_PORT) = I2C_SCL_PIN; /* drive SCL low */
|
||||
delay_10us(1);
|
||||
GPIO_BOP(I2C_SCL_PORT) = I2C_SCL_PIN; /* release SCL (open-drain -> high via pull-up) */
|
||||
return i2c_wait_scl_high(200); /* wait up to ~2ms for clock stretching release */
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -52,31 +72,87 @@ void i2c_config(void) {
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void i2c_bus_reset(void) {
|
||||
i2c_result_t i2c_bus_reset(void) {
|
||||
/* 1. Disable & deinit peripheral so pins can be fully controlled */
|
||||
i2c_disable(I2C0);
|
||||
i2c_deinit(I2C0);
|
||||
/* configure SDA/SCL for GPIO */
|
||||
GPIO_BC(I2C_SCL_PORT) |= I2C_SCL_PIN;
|
||||
GPIO_BC(I2C_SDA_PORT) |= I2C_SDA_PIN;
|
||||
gpio_output_options_set(I2C_SCL_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, I2C_SCL_PIN);
|
||||
gpio_output_options_set(I2C_SDA_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, I2C_SDA_PIN);
|
||||
__NOP();
|
||||
__NOP();
|
||||
__NOP();
|
||||
__NOP();
|
||||
__NOP();
|
||||
GPIO_BOP(I2C_SCL_PORT) |= I2C_SCL_PIN;
|
||||
__NOP();
|
||||
__NOP();
|
||||
__NOP();
|
||||
__NOP();
|
||||
__NOP();
|
||||
GPIO_BOP(I2C_SDA_PORT) |= I2C_SDA_PIN;
|
||||
/* connect I2C_SCL_PIN to I2C_SCL */
|
||||
/* connect I2C_SDA_PIN to I2C_SDA */
|
||||
|
||||
#ifdef DEBUG_VERBOSE
|
||||
printf("I2C bus reset\r\n");
|
||||
#endif
|
||||
|
||||
/* 2. Configure SCL/SDA as GPIO open-drain outputs with pull-up and release them */
|
||||
gpio_mode_set(I2C_SCL_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLUP, I2C_SCL_PIN);
|
||||
gpio_mode_set(I2C_SDA_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLUP, I2C_SDA_PIN);
|
||||
gpio_output_options_set(I2C_SCL_PORT, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ, I2C_SCL_PIN);
|
||||
gpio_output_options_set(I2C_SDA_PORT, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ, I2C_SDA_PIN);
|
||||
/* configure the I2CX interface */
|
||||
gpio_bit_set(I2C_SCL_PORT, I2C_SCL_PIN); /* release SCL */
|
||||
gpio_bit_set(I2C_SDA_PORT, I2C_SDA_PIN); /* release SDA */
|
||||
|
||||
#ifdef DEBUG_VERBOSE
|
||||
printf("I2C bus reset: SCL = %d, SDA = %d\r\n", gpio_input_bit_get(I2C_SCL_PORT, I2C_SCL_PIN), gpio_input_bit_get(I2C_SDA_PORT, I2C_SDA_PIN));
|
||||
#endif
|
||||
|
||||
/* 3. Double sample to confirm bus state */
|
||||
delay_10us(1);
|
||||
bool scl_value1 = gpio_input_bit_get(I2C_SCL_PORT, I2C_SCL_PIN);
|
||||
bool sda_value1 = gpio_input_bit_get(I2C_SDA_PORT, I2C_SDA_PIN);
|
||||
delay_10us(1);
|
||||
bool scl_value2 = gpio_input_bit_get(I2C_SCL_PORT, I2C_SCL_PIN);
|
||||
bool sda_value2 = gpio_input_bit_get(I2C_SDA_PORT, I2C_SDA_PIN);
|
||||
|
||||
/* 4. If SCL low -> stuck (cannot proceed) */
|
||||
if (!scl_value2) {
|
||||
#ifdef DEBUG_VERBOSE
|
||||
printf("I2C bus reset: SCL stuck low\r\n");
|
||||
#endif
|
||||
return I2C_RECOVERY_SCL_STUCK_LOW;
|
||||
}
|
||||
|
||||
/* 5. Fast path: bus idle */
|
||||
if (scl_value1 && sda_value1 && scl_value2 && sda_value2) {
|
||||
i2c_config();
|
||||
#ifdef DEBUG_VERBOSE
|
||||
printf("I2C bus reset: bus idle\r\n");
|
||||
#endif
|
||||
return I2C_RECOVERY_OK;
|
||||
}
|
||||
|
||||
/* 6. SDA low: attempt to free by generating up to I2C_RECOVERY_CLOCKS pulses */
|
||||
if (scl_value2 && !sda_value2) {
|
||||
bool sda_released = false;
|
||||
#ifdef DEBUG_VERBOSE
|
||||
printf("I2C bus reset: SCL will try to free SDA\r\n");
|
||||
#endif
|
||||
for (uint8_t i = 0; i < I2C_RECOVERY_CLOCKS && !sda_released; i++) {
|
||||
if (!i2c_generate_scl_pulse()) {
|
||||
return I2C_RECOVERY_SCL_STUCK_LOW; /* SCL failed to go high */
|
||||
}
|
||||
if (gpio_input_bit_get(I2C_SDA_PORT, I2C_SDA_PIN)) {
|
||||
sda_released = true;
|
||||
}
|
||||
}
|
||||
if (!sda_released) {
|
||||
return I2C_RECOVERY_SDA_STUCK_LOW;
|
||||
}
|
||||
/* 7. Generate a STOP condition to leave bus in idle state */
|
||||
#ifdef DEBUG_VERBOSE
|
||||
printf("I2C bus reset: generating STOP condition\r\n");
|
||||
#endif
|
||||
gpio_bit_reset(I2C_SDA_PORT, I2C_SDA_PIN); /* SDA low */
|
||||
delay_10us(1);
|
||||
gpio_bit_set(I2C_SCL_PORT, I2C_SCL_PIN); /* ensure SCL high */
|
||||
delay_10us(1);
|
||||
gpio_bit_set(I2C_SDA_PORT, I2C_SDA_PIN); /* SDA rising while SCL high -> STOP */
|
||||
delay_10us(1);
|
||||
}
|
||||
|
||||
#ifdef DEBUG_VERBOSE
|
||||
printf("I2C bus reset: bus recovered\r\n");
|
||||
#endif
|
||||
/* 8. Reconfigure & enable peripheral */
|
||||
i2c_config();
|
||||
return I2C_RECOVERY_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
|
22
Src/main.c
22
Src/main.c
@@ -60,7 +60,7 @@ int main(void)
|
||||
led_init();
|
||||
|
||||
#ifdef DEBUG_VERBOSE
|
||||
char hello_world[] = {"Hello World!"};
|
||||
char hello_world[] = {"Hello World!\r\n"};
|
||||
|
||||
for (uint8_t i = 0; i < sizeof(hello_world); i++)
|
||||
{
|
||||
@@ -69,29 +69,23 @@ int main(void)
|
||||
}
|
||||
|
||||
while (usart_flag_get(RS485_PHY, USART_FLAG_TC) == RESET) {}
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG_VERBOSE
|
||||
i2c_config();
|
||||
|
||||
i2c_scan();
|
||||
|
||||
// i2c_bus_reset();
|
||||
|
||||
// uint8_t sensor_data[2] = {0};
|
||||
|
||||
// i2c_read_16bits(0x2B, 0x7E, sensor_data);
|
||||
|
||||
// printf("Sensor Data: 0x%02X 0x%02X\r\n", sensor_data[0], sensor_data[1]);
|
||||
|
||||
// i2c_bus_reset();
|
||||
i2c_bus_reset();
|
||||
|
||||
i2c_scan();
|
||||
#endif
|
||||
|
||||
ldc1612_iic_get_sensor_infomation();
|
||||
|
||||
#ifdef DEBUG_VERBOSE
|
||||
i2c_scan();
|
||||
#endif
|
||||
|
||||
|
||||
while(1){
|
||||
command_process();
|
||||
|
Reference in New Issue
Block a user