[GD32] I2C Arbitration Error - Page 1
Forum section: electronics / general

author: Saimoun
author_rank: Frequent Contributor
timestamp: January 13, 2023, 03:13:02 pm
content: HiI've got a tough one, hard to be sure but it looks like a silicon bug. I am using GD32F350 - manual is here:https://www.gd32mcu.com/data/documents/userManual/GD32F3x0_User_Manual_Rev2.6.pdfI've got the following code to read an EEPROM over I2C:Code:uint8_t readByte;I2C1->CTL0 |= I2C_CTL0_START; // generate start conditionwhile (!(I2C1->STAT0 & I2C_STAT0_SBSEND)); // wait for Start condition to be generatedI2C1->DATA = (I2CEEPROM_ADDRESS << 1) | 1; // send address in READ modewhile (!(I2C1->STAT0 & I2C_STAT0_ADDSEND)); // wait for address to be sentI2C1->STAT1; // reads I2C_STAT1 to clear ADDRI2C1->CTL0 |= I2C_CTL0_STOP; // we do not set ACKEN bit but set STOP => NACK and then STOP will be sent after the byte is receivedwhile (!(I2C1->STAT0 & I2C_STAT0_RBNE)); // wait till the byte is receivedreadByte = I2C1->DATA;The byte is actually read fine, I get the value previously put in the EEPROM (I have no issues when writing to the EEPROM, only when reading).But the Arbitration error (LOSTARB bit) is set as soon as the peripheral receives something without the ACKEN bit enabled.If I set the ACKEN bit instead of STOP everything works (but the EEPROM keeps sending more data), I can then read all the data fine. Until I clear the ACKEN bit, then I get Arbitration Error again right away.I know this is super specific, I do not really expect a solution (unless something notices something obviously wrong?) but I am thinking it might useful for anyone who has the same issue at some pointEDIT: Solved - nothing to do with the peripheral or the MCU, but with a faulty chip (a display driver) connected to the I2C lines and pulling SDA low when it should not...It was very unlucky because1) I have been using this chip for years, never got a faulty one before2) of course the faulty chip was on a brand new design with a new MCU (which made me believe this was the MCU's fault)and 3) the error was very very strange, the chip was working 100% fine (driving the display and responding correctly to I2C messages) but decided to ACK every single messageThis created the Arbitration Error when the MCU (I2C master) wanted to send NACK and the faulty chip was sending ACK - the MCU detected something else was pulling SDA low when it shoud not.Anyways - I desoldered the chip, soldered a new one and everything works like it should now.

author: Saimoun
author_rank: Frequent Contributor
timestamp: January 15, 2023, 04:35:08 pm
content: Just FYI - adding the code I wrote to handle the faulty chip in firmware, thinking it could be useful if someone experiences Arbitration Error. I am not sure how STM32 micros handle this, but on this GD32 I could not get the peripheral back to a decent state without resetting the I2C peripheral.On top of that, the faulty chip was keeping SDA pulled low until it got a clock cycle on SCL (first 8 lines after the if)Code:/* In case a faulty display chip pulls SDA low (i.e. sends ACK while the MCU tries to sends NACK), this creates a double issue:*-> the faulty chip waits for a SCL cycle to release SDA*-> the I2C peripheral triggers a "Arbitration Lost" error* we need to release SDA by pulling SCL low then high, then clear the LOSTARB*/if (I2C1->STAT0 & I2C_STAT0_LOSTARB) {// change SCL pin from AFIO to Output (10=AFIO, 01=output)I2C_SCL_Port->CTL = (I2C_SCL_Port->CTL & ~(0b11 << (2U*I2C_SCL_PinNumber))) | (0b01 << (2U*I2C_SCL_PinNumber));DELAY_US(5); // I2C running on 100k, i.e. clock half periods of 5usI2C_SCL_Port->BC = I2C_SCL_Pin;DELAY_US(5);I2C_SCL_Port->BOP = I2C_SCL_Pin;// change SCL pin back from Output to AFIOI2C_SCL_Port->CTL = (I2C_SCL_Port->CTL & ~(0b11 << (2U*I2C_SCL_PinNumber))) | (0b10 << (2U*I2C_SCL_PinNumber));I2C1->CTL0 |= I2C_CTL0_SRESET; // reset I2C peripheral (yes that's the only way to clear the I2CBSY flag... >_< )I2C1->CTL0 = 0; // clear resetsetup_i2c1(); // setup again clock speed, rise time, and enable I2C}