This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

MSPM0G1106: I2C pulling down SDA issue

Part Number: MSPM0G1106

Hi !

I've seen the behavior recently.

My device is jamming the line like this.

The message that we are observing is being sent by another device. After finishing its message, my device attempts to send something and then pulls down the line forever. I already detected that it's my device who is pulling down the line.

How can I detect that my own device is jamming the line? I saw that there is no collision interruption.

Before sending, I polled the line with 

                if ( !DL_I2C_getSDAStatus( I2C_INST )
                    && !DL_I2C_getSCLStatus ( I2C_INST )
and then check the BUSBUSY status with
                    while(( DL_I2C_getControllerStatus( I2C_INST ) &
                            DL_I2C_CONTROLLER_STATUS_BUSY_BUS ))
After then:
- Fill FIFO
-  while ((!( DL_I2C_getControllerStatus( I2C_INST ) &
                                DL_I2C_CONTROLLER_STATUS_IDLE ))
-  DL_I2C_startControllerTransferAdvanced( I2C_INST,
                            ( i2c_msg_g.buf[ 0 ] >> 1 ), DL_I2C_CONTROLLER_DIRECTION_TX,
                            i2c_msg_g.length - 1, DL_I2C_CONTROLLER_START_ENABLE, DL_I2C_CONTROLLER_STOP_ENABLE,
                            I2C_MCTR_ACK_DISABLE );
NOTE: This is not happening always. I'm currently running a test every 350 ms where 3 devices send a message at the same time. Sometimes it fails after the 30th message. Sometimes it takes longer to fail.
I would like to know how to detect and handle collisions, and make bulletproof the "before sending" process. The other devices are different than mine, and are not TI based. 
  • UPDATE: This is what I do to send it down. I implemented a timeout to transfer, and everytime it times out, I do this

    DL_I2C_disablePower( I2C_INST );
    DL_GPIO_initDigitalOutput(GPIO_I2C_IOMUX_SCL);
    DL_GPIO_initDigitalOutput(GPIO_I2C_IOMUX_SDA);

    DL_GPIO_writePins( GPIO_I2C_SCL_PORT,
    GPIO_I2C_SCL_PIN | GPIO_I2C_SDA_PIN );
    DL_GPIO_initPeripheralInputFunctionFeatures(GPIO_I2C_IOMUX_SDA,
    GPIO_I2C_IOMUX_SDA_FUNC, DL_GPIO_INVERSION_DISABLE,
    DL_GPIO_RESISTOR_NONE, DL_GPIO_HYSTERESIS_DISABLE,
    DL_GPIO_WAKEUP_DISABLE);
    DL_GPIO_initPeripheralInputFunctionFeatures(GPIO_I2C_IOMUX_SCL,
    GPIO_I2C_IOMUX_SCL_FUNC, DL_GPIO_INVERSION_DISABLE,
    DL_GPIO_RESISTOR_NONE, DL_GPIO_HYSTERESIS_DISABLE,
    DL_GPIO_WAKEUP_DISABLE);
    DL_GPIO_enableHiZ(GPIO_I2C_IOMUX_SDA);
    DL_GPIO_enableHiZ(GPIO_I2C_IOMUX_SCL);
    DL_I2C_enablePower( I2C_INST );
    It eventually fails and puts the line like this:
    I tried resetting it with DL_i2c_Reset() function, but it doesn't work. The thing is that when it fails, the controller is usually busy.
    I don't really know what else to do. I'll appreciate your help
  • Hello Asiel;

    There are a few issues you need to check and ensure:

    1). From the figure 1 you sent, it can be seen that M0 is the target device. After the host device writes 0x59 to M0, seven clocks still appear and seven bits transmission occur. But the format for I2C transmission should be 8 bits data + ACK, so the I2C transmission here was not completed for some. reason. You can try to find the reason. Maybe it is caused by host device.

    2). If you only want to send data to the host device using M0, M0 can also send data in I2C target mode, only can not control the SCL. But if you want to let M0 control SCL and send data to other device, you should switch I2C's to GPIO first before re-configure target to host through IOMUX, you can refer to the "chapter 8.2.1 Peripheral Function Assignment" of MSPM0G series user guide. And I that my colleague Helic has replied to you in the post "MSPM0G1106: I2C jamming". After that, you can continue to configure the I2C host configuration(such as DL_I2C_startControllerTransferAdvanced, etc.). 

    3). When you configure the I2C, I think that you don't need to configure Hi-Z, maybe you can try to delete the Hi-Z configuration. When the output logic is 1, the output is high impedance. The Hi-Z is not high level or low level. You can see Hi-Z as ”open circuit", it impedance is very high. Hi-Z will make I2C host device have no impact on the I2C target device.

    4). You can check the pull up register of SDA and SCL line.

    5). I2C supports one host <-> multiply target, but it doesn't support multiply host <-> one target. So you should check the meaning of "where 3 devices send a message at the same time".

    6). Our SDK have many example code which may help you to correct your code and configuration.

    Best Regards,

    Janz Bai

  • Thank you! 

    1.- This is a multimaster channel that has requirements to be met, so sending while being target is not much of an option, that's why I'm doing the dynamic switching from master to target. But yes, I saw that my device is the one that tries to send and then holds the line down.

    2.- I didn't know I had to change pins first before switching from master to target. I wasn't changing the GPIO from target to Controller. The GPIO change is because, in order to solve the first problem, I forced SCL and SDA to go UP, and then go back to I2C mode. I don't know if am following the right sequence to do that.

    3.- I'll remove the HI-Z. It's just that I'm not sure how to switch between I2C and GPIO mode. I just based that sequence on the initalization that's autogenerated.

    4.- How and why could I check that?

    5.- All of the devices in the communication are multi master

    6.- I've checked them and my code is based on that.

    7.- Is it there a way to abort a transfer? Even if it hasn't started or is on an ongoing transaction?

    Thanks for your support.

  • Now, I think that you need to do following things:

    1). Clarify the logic of the entire operation process, which can help you find the errors.

    2). Check if there is only one host device executing the send task at the same time. Multiple host devices can not send messages at the same time.

    3). Check whether M0 in the first figure you send is a host device or a target device. If M0 is a target or even a host after changing, it's also impossible that the M0 sending process was interrupted because there were not second read/write instructions. Please check why another device's sending process was interrupted (I already mentioned in previous response). If M0 was originally the host, please check the M0 code to ensure that why the sending process is not complete.

    3). However, before switching between host and target mode, it's best to ensure that you first do deinitialization and then reinitialize it. This is the reason why Helic let you change pin function.

    4).  I2C supports one host <-> multiply target, but it doesn't support multiply host <-> one target. So you should check the meaning of "where 3 devices send a message at the same time".

    5). You can try to build your project based on our SDK sample code.

    6). If you still have problems, you can send an email to the AE/FAE who is responsible for you or your area.

    Hope you can solve this problem and Best Regards,

    Janz Bai

  • Maybe contacting with the FAE who is responsible for you is a good choice, he can come to the scene to help you.

    Best Regards,

    Janz Bai