Jul 06, 2020
05:35 AM
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Jul 06, 2020
05:35 AM
It happens that some I2C slave permanently pulls down SDA, after the I2C bus was interrupted during some transmission.
A solution to this is toggling the clock 8 times and sending a stop condition. A similar solution is to perform a Nack Read without Start Condition.
The reference manual describes such a procedure in 18.5.4.2 Valid Master Transmit Data Formats in case of a wrong TDF code.
I would like to perform such a Bus Reset on each boot of my XMC4800. I tried with
after initialization. Unfortunately, in case of a stuck SDA all what happens is a single clock toggle.
I do not even get an i2c event interrupt. So I need to boot the XMC4800 up to eight times to reset the bus.
Is there a clean way to achieve this bus reset on initialization? Or do I need to configure the Pins as GPIO
first and toggle the clock myself before initializing the I2C module?
A solution to this is toggling the clock 8 times and sending a stop condition. A similar solution is to perform a Nack Read without Start Condition.
The reference manual describes such a procedure in 18.5.4.2 Valid Master Transmit Data Formats in case of a wrong TDF code.
I would like to perform such a Bus Reset on each boot of my XMC4800. I tried with
XMC_I2C_CH_MasterReceiveNack(channel);
XMC_I2C_CH_MasterStop(channel);
after initialization. Unfortunately, in case of a stuck SDA all what happens is a single clock toggle.
I do not even get an i2c event interrupt. So I need to boot the XMC4800 up to eight times to reset the bus.
Is there a clean way to achieve this bus reset on initialization? Or do I need to configure the Pins as GPIO
first and toggle the clock myself before initializing the I2C module?
6 Replies
Jul 06, 2020
01:18 PM
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Jul 06, 2020
01:18 PM
Hi,
Can you try with the following sequence?
Regards,
Jesus
Can you try with the following sequence?
XMC_I2C_CH_ClearStatusFlag(i2c->i2c, XMC_I2C_CH_STATUS_FLAG_TRANSMIT_SHIFT_INDICATION);
// Clear the bus by sending nine clock pulses
XMC_I2C_CH_MasterStart(i2c->i2c, 0xff, XMC_I2C_CH_CMD_READ);
while ((XMC_I2C_CH_GetStatusFlag(i2c->i2c) & XMC_I2C_CH_STATUS_FLAG_TRANSMIT_SHIFT_INDICATION) == 0U)
;
XMC_I2C_CH_ClearStatusFlag(i2c->i2c, XMC_I2C_CH_STATUS_FLAG_TRANSMIT_SHIFT_INDICATION);
XMC_I2C_CH_MasterStop(i2c->i2c);
while ((XMC_I2C_CH_GetStatusFlag(i2c->i2c) & XMC_I2C_CH_STATUS_FLAG_TRANSMIT_SHIFT_INDICATION) == 0U)
;
Regards,
Jesus
Jul 08, 2020
05:05 AM
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Jul 08, 2020
05:05 AM
Thanks for the reply. Unfortunately the suggested solution does not work for me. In case no slave holds down SDA I can see the clock toggles. But if a slave holds SDA, the clock is not toggled even once and the code remains in the first loop waiting for XMC_I2C_CH_STATUS_FLAG_TRANSMIT_SHIFT_INDICATION for ever.
Jul 10, 2020
06:02 AM
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Jul 10, 2020
06:02 AM
Hi,
I cannot check right now, but maybe you could try:
Regards,
Jesus
I cannot check right now, but maybe you could try:
XMC_I2C_CH_SetInputSource(i2c->i2c, XMC_I2C_CH_INPUT_SDA, USIC_INPUT_ALWAYS_1);
XMC_I2C_CH_ClearStatusFlag(i2c->i2c, XMC_I2C_CH_STATUS_FLAG_TRANSMIT_SHIFT_INDICATION);
// Clear the bus by sending nine clock pulses
XMC_I2C_CH_MasterStart(i2c->i2c, 0xff, XMC_I2C_CH_CMD_READ);
while ((XMC_I2C_CH_GetStatusFlag(i2c->i2c) & XMC_I2C_CH_STATUS_FLAG_TRANSMIT_SHIFT_INDICATION) == 0U)
;
XMC_I2C_CH_ClearStatusFlag(i2c->i2c, XMC_I2C_CH_STATUS_FLAG_TRANSMIT_SHIFT_INDICATION);
XMC_I2C_CH_MasterStop(i2c->i2c);
while ((XMC_I2C_CH_GetStatusFlag(i2c->i2c) & XMC_I2C_CH_STATUS_FLAG_TRANSMIT_SHIFT_INDICATION) == 0U)
;
XMC_I2C_CH_SetInputSource(i2c->i2c, XMC_I2C_CH_INPUT_SDA, i2c->sda_pin_input);
Regards,
Jesus
Jul 14, 2020
08:59 AM
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Jul 14, 2020
08:59 AM
Hi,
I have being trying it out and finally you need to do something like
I have being trying it out and finally you need to do something like
XMC_GPIO_SetMode(SDA_PIN, XMC_GPIO_MODE_INPUT_TRISTATE);
XMC_I2C_CH_SetInputSource(I2C_CHANNEL, XMC_I2C_CH_INPUT_SDA1, USIC0_C0_DX3_DOUT0);
do
{
XMC_I2C_CH_SetInputSource(I2C_CHANNEL, XMC_I2C_CH_INPUT_SDA, USIC0_C0_DX0_DX3INS);
XMC_I2C_CH_ClearStatusFlag(I2C_CHANNEL, XMC_I2C_CH_STATUS_FLAG_TRANSMIT_SHIFT_INDICATION);
// Clear the bus by sending nine clock pulses
XMC_I2C_CH_MasterStart(I2C_CHANNEL, 0xff, XMC_I2C_CH_CMD_READ);
while ((XMC_I2C_CH_GetStatusFlag(I2C_CHANNEL) & XMC_I2C_CH_STATUS_FLAG_TRANSMIT_SHIFT_INDICATION) == 0U);
// Not Acknowledge software recovery since operating in Loop Back Mode
XMC_USIC_CH_TXFIFO_Flush(I2C_CHANNEL);
XMC_USIC_CH_TXFIFO_Flush(I2C_CHANNEL);
XMC_USIC_CH_SetTransmitBufferStatus(I2C_CHANNEL, XMC_USIC_CH_TBUF_STATUS_SET_IDLE);
XMC_I2C_CH_ClearStatusFlag(I2C_CHANNEL, 0x1ffff);
XMC_I2C_CH_SetInputSource(I2C_CHANNEL, XMC_I2C_CH_INPUT_SDA, USIC0_C0_DX0_P2_1);
}
while (XMC_GPIO_GetInput(SDA_PIN) == 0);
Jul 15, 2020
04:43 AM
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Jul 15, 2020
04:43 AM
I just implemented a solution using the GPIO interface before configuring the I2C interface. Thanks anyway for the pure-I2C-interface-solution you just provided.
Dec 20, 2021
12:44 AM
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Dec 20, 2021
12:44 AM
Hi Jesus,
I just tried your code to implement a well done I2C bus clear.
Unfortunately I still don't understand the connections between peripherals and GPIOs. For this reason I was unable to adapt your code to my application which uses the I2C3 serial with P3.15 as SDA and P0.13 as SCL. Could you help me?
Best regards Antonio