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.

Why I cannot use I2C to communicate in no-FDF mode normally

Other Parts Discussed in Thread: TMDSRM48HDK, RM48L952, HALCOGEN

Hello

Recently I am debugging the communication of I2C, and the CPU is TMS570LS3137PGE. I set the transmission as master, and I set the receive as slave. The puopose What I want to do is tranfering the master data to the slave .

If the master is in FDF(free data format) mode,and the slave is also in FDF mode, they can communicate normally. The code is following

master:

Initialize register of MDR

slave:

And also I set the master in FDF mode, and the slave is in no-FDF mode, they also can communicate normally.

But I set the master in no-FDF mode, and the slave are also in no-FDF mode, they cannot communicate. Why? How did I amend the code to communicate normallyin this mode, thank you in advance.

  • Hello,

    I'm not sure what happens here, but I would recommend you to read the following doc SPRU175 .  You will find some very helpful flowcharts on how to implement a working I2C driver with this module in Section 7.3.

    Please also have a look at the two functions below I wrote to communicate with an I2C slave module. Please note that these are only code examples and might not work under all circumstances.

    Best Regards,
    Christian

    EDIT: Please see the following forum post fro the newest version: 

  • Christian,

    I am using the TMDSRM48HDK to evaluate the RM48L952.  I'm testing the I2C interface with the TotalPhase Aardvark (I2C Master/Slave) and TotalPhase Beagle (I2C Sniffer).  I was able to get I2C wrting working with your example above along with notes from another of your other posts. (http://e2e.ti.com/support/microcontrollers/hercules/f/312/p/394139/1410064#1410064)

    However, I can't seem to get your read function to work correctly.  The write address and register value are sent OK.  The repeat start and read address are sent but I can only receive 1 byte.  The I2CSTR register and my I2C sniffer indicate that a NACK was sent after the first received byte, but that shouldn't happen since I do not set the NACKMOD bit and the count register is set to 5 in my test case.

    My modified version of your receive function is below.  I've highlighted where the code hangs in red.

    Thanks,

    - Andrew

    uint32_t i2cMasterReadSync(i2cBASE_t *i2c,  uint16_t u16SlaveAddress, uint8_t u8RegAddress,  uint16_t u16DataCount, uint8_t pu8DataOut[])
    {
        uint32_t u32RetVal = 0xFFFFFFFFul;
    
        if ((i2c->STR & I2C_BUSBUSY) == I2C_BUSBUSY) /* Check if the bus is free */
        {
            u32RetVal = 1ul;
        }
        else if ((i2c->MDR & I2C_MASTER) == I2C_MASTER) /* Check if the Module is already in Master Mode, this indicates that some transfer is ongoing. */
        {
            u32RetVal = 2ul;
        }
        else
        {
            uint16_t u16SendIndex = 0u;
    
            i2cDisableNotification(i2c, 0x7Ful);
    
            /* Setup to Transmit */
            i2cSetCount(i2c, 1u);
            i2cSetSlaveAdd(i2c, (uint32_t)u16SlaveAddress);
    
            /* Transmit Start Condition */
            i2cSetMode(i2c, I2C_MASTER | I2C_TRANSMITTER | I2C_START_COND | I2C_FREE_RUN);
    
            /* Wait till TX register is ready to receive next byte or ARDY if we get NACKe */
            while((i2c->STR & (I2C_TX | I2C_ARDY)) == 0ul);
    
            /* Send register address to write to */
            i2c->DXR = (uint32_t)u8RegAddress;
    
            /* wait for ARDY before beginning the read phase of the transaction */
            while ( (i2c->STR & I2C_ARDY) == 0ul );
    
            if ((i2c->STR & I2C_NACK) == I2C_NACK)
            {
                /* NACK detected during transmision
                 *
                 * According to I2C Spec the reason could be:
                 * 1. No receiver is present on the bus with the transmitted address so there is no device to respond with an acknowledge.
                 * 2. The receiver is unable to receive or transmit because it is performing some real-time function and is not ready to start communication with the master.
                 * 3. During the transfer, the receiver gets data or commands that it does not understand.
                 * 4. During the transfer, the receiver cannot receive any more data bytes.
                 */
    
                i2c->MDR |= I2C_STOP_COND; /* Send stop condition so SCL isn't held low */
    
                /* Wait for Busy Bit to go Low --> The bus is free and stop was send */
                while((i2c->STR & I2C_BUSBUSY) == I2C_BUSBUSY);
    
                i2c->STR = I2C_SCD | I2C_TX | I2C_NACK | I2C_NACKSNT; /* Clear SCD, NACK and set TXRDY flag to indicate that a new transfer is possible. */
    
                return 4ul;
            }
    
            /* Setup to Read */
            i2cSetCount(i2c, 0); /* It seems that count has to be modified... */
            i2cSetCount(i2c, u16DataCount);
    
            /* Set Receiver mode */
            i2c->MDR &= ~I2C_TRANSMITTER;
            /* Transmit Repeated Start condition */
            i2cSetMode(i2c, I2C_MASTER | I2C_RECEIVER | I2C_START_COND | I2C_STOP_COND | I2C_FREE_RUN);
    
            while(u16SendIndex < u16DataCount)
            {
                /* Wait for I2C to read data or ARDY if we get NACKe */
                while((i2c->STR & (I2C_TX | I2C_ARDY)) == 0ul);
    
                if ((i2c->STR & I2C_NACK) == I2C_NACK)
                {
                    /* NACK detected during reception
                     *
                     * According to I2C Spec the reason could be:
                     * 1. No receiver is present on the bus with the transmitted address so there is no device to respond with an acknowledge.
                     * 2. The receiver is unable to receive or transmit because it is performing some real-time function and is not ready to start communication with the master.
                     * 3. During the transfer, the receiver gets data or commands that it does not understand.
                     * 4. During the transfer, the receiver cannot receive any more data bytes.
                     */
    
                    i2c->MDR |= I2C_STOP_COND; /* Send stop condition so SCL isn't held low */
    
                    /* Wait for Busy Bit to go Low --> The bus is free and stop was send */
                    while((i2c->STR & I2C_BUSBUSY) == I2C_BUSBUSY);
    
                    i2c->STR = I2C_SCD | I2C_TX | I2C_NACK | I2C_NACKSNT; /* Clear SCD, NACK and set TXRDY flag to indicate that a new transfer is possible. */
    
                    return 6ul;
                }
                else
                {
                    /* Make sure that we got the RRDY signal */
                    while ( (i2c->STR & I2C_RX) == 0ul );   // Processor always gets stuck here after receiving 1 byte from slave
    
                    /* Read out a byte */
                    pu8DataOut[u16SendIndex] = (uint8_t)i2c->DRR;
    
                    u16SendIndex++;
                }
            }
    
            /* Stop Condition sould be send automatically */
    
            /* Wait for Busy Bit to go Low --> The bus is free. */
            while((i2c->STR & I2C_BUSBUSY) == I2C_BUSBUSY);
            /* Wait for Master Mode Bit to go Low --> This bit is cleared after generating a STOP condition. */
            /*                                        The BB bit is cleared first, and MST bit is cleared second. */
            while((i2c->MDR & I2C_MASTER)  == I2C_MASTER);
    
            /* Check that NACK was send and that STOP was detected.
             *
             * NACK was send according to I2C spec:
             * 5. A master-receiver must signal the end of the transfer to the slave transmitter.
             */
            if ( (i2c->STR & (I2C_NACKSNT | I2C_SCD)) == 0ul )
            {
                u32RetVal = 5ul;
            }
            else
            {
                /* Clear NACK Send Flag and Stop Condition Detected flag */
                i2c->STR = I2C_NACKSNT | I2C_SCD;
    
                u32RetVal = 0ul;
            }
        }
    
        return u32RetVal;
    }
    

  • Hi Andrew,

    I'm not sure what happens on your side, for me this code works fine, but there might be slaves which behaves different and causes my code not to work.

    The following screenshot from my logic analyzer shows a transmission of my working use case:

    You can see there is a setup to write to address 0x20, with data 0x40 followed by a repeated start condition.

    Followed by a setup to read from address 0x20 (0x21), with three data bytes, the first two are acknowledged by my master and the last one is terminated by a NACK and STOP as expected. The last write in the screenshot (to 0x2A) is to an unconnected slave, that why it is terminated by a NACK.

    Here is the source of the read function I used, but it should be the same as the one I posted before:

    EDIT: Please see the following forum post for the newest version: 

    Best Regards,

    Christian

  • Hello Andrew,

    One thing I think I forgo to mention is that I modified the HALCoGen function i2cSetMode in the file i2c.c, to be able to clear the TRX bit.

    Her is the modified code:

    EDIT: Please go to  for a version which doesn't need to modify the HALCoGen source.

    However, this modification should have found it's way to the newest release of HALCoGen.

    Ok, I just realized that this function was changed in HALCoGen as of version 4.02.00, but unfortunately not as intended.

    So please change this function as above, give it another try and keep me posted.

    Thanks,
    Christian

  • Christian,

    Thanks for the quick response.  I copied your code verbatim but the transaction still does not work as expected.  The execution always gets stuck at line 101 in your function.  When I pause in the debugger, the I2C_NACKSNT bit in the STA register is set.  The I2C module is acting as if it's ignoring the count register.  Via my external I2C sniffer I can see that the repeat start was sent and the read address ACKed by the I2C slave, and the first byte is transmitted, however that byte is NACKed by the RM48 and the stop condition is generated.

    I did make the suggested modifications to the i2c.c function i2cSetMode().  I am using HalCoGen 4.02.00, however I noticed my original function did not look like your original function.  Also, I had to remove or comment out your references to g_Struct as that does not exist in my code anywhere.  I'm also using CCS 6.0.1 in case it matters.

    Thoughts?

    Thanks,

    Andrew

  • Hi Andrew,

    The HALCoGen team changed the i2cSetMode function, that's why it's definetly not working with unmodified function.

    However, I just realized changing the HALCoGen function and rely on these to not change makes no sense.

    So here are my two I2C Transmit and Receive functions is a version which don't use the HALCoGen functions, but the header files with their defines and enum's:

    /*
     * i2c_app.h
     *
     *  Created on: Oct 16, 2014
     *      Author: Christian Herget
     */
    
    #ifndef I2C_APP_H_
    #define I2C_APP_H_
    
    #include "i2c.h"
    
    uint32_t i2cMasterWriteSync(i2cBASE_t *i2c, uint16_t u16SlaveAddress,                       uint16_t u16DataCount, uint8_t u8DataIn[]);
    uint32_t i2cMasterReadSync(i2cBASE_t *i2c,  uint16_t u16SlaveAddress, uint8_t u8RegAddress, uint16_t u16DataCount, uint8_t u8DataOut[]);
    
    #endif /* I2C_APP_H_ */

    /*
     * i2c_app.c
     *
     *  Created on: Oct 16, 2014
     *      Author: Christian Herget
     */
    
    #include "i2c_app.h"
    
    uint32_t i2cMasterWriteSync(i2cBASE_t *i2c, uint16_t u16SlaveAddress, uint16_t u16DataCount, uint8_t pu8DataIn[])
    {
    	uint32_t u32RetVal = 0xFFFFFFFFul;
    
    	if ((i2c->STR & I2C_BUSBUSY) == I2C_BUSBUSY) /* Check if the bus is free */
    	{
    		u32RetVal = 1ul;
    	}
    	else if ((i2c->MDR & I2C_MASTER) == I2C_MASTER) /* Check if the Module is already in Master Mode, this indicates that some transfer is ongoing. */
    	{
    		u32RetVal = 2ul;
    	}
    	else
    	{
    		uint16_t u16SendIndex = 0u;
    
    		/* Setup to Transmit */
    		/* Setup Data Length */
    		i2c->CNT = (uint32_t)u16DataCount;
    		/* Setup Slave Address */
    		i2c->SAR = (uint32_t)u16SlaveAddress;
    
    		/* Setup for Master Transmitter Mode, transmit Start Condition and use Free Run Mode (Do not stop I2C on debugger hold) */
    		i2c->MDR = (uint32_t)(I2C_RESET_OUT | I2C_MASTER | I2C_TRANSMITTER | I2C_START_COND | I2C_STOP_COND);
    
    		while(u16SendIndex < u16DataCount)
    		{
    			/* Wait till TX register is ready to receive next byte or ARDY if we get NACKe */
    			while((i2c->STR & (I2C_TX | I2C_ARDY)) == 0ul);
    
    			if ((i2c->STR & I2C_NACK) == I2C_NACK)
    			{
    				/* NACK detected during transmision
    				 *
    				 * According to I2C Spec the reason could be:
    				 * 1. No receiver is present on the bus with the transmitted address so there is no device to respond with an acknowledge.
    				 * 2. The receiver is unable to receive or transmit because it is performing some real-time function and is not ready to start communication with the master.
    				 * 3. During the transfer, the receiver gets data or commands that it does not understand.
    				 * 4. During the transfer, the receiver cannot receive any more data bytes.
    				 */
    
    				i2c->MDR |= I2C_STOP_COND; /* Send stop condition so SCL isn't held low */
    
    				/* Wait for Busy Bit to go Low --> The bus is free and stop was send */
    				while((i2c->STR & I2C_BUSBUSY) == I2C_BUSBUSY);
    
    				i2c->STR = I2C_SCD | I2C_TX | I2C_NACK; /* Clear SCD, NACK and set TXRDY flag to indicate that a new transfer is possible. */
    
    				return 4ul;
    			}
    			else
    			{
    				/* Make sure that we see the TXRDY signal */
    				while((i2c->STR & I2C_TX) == 0ul);
    
    				/* Send a byte */
    				i2c->DXR = (uint32_t)pu8DataIn[u16SendIndex];
    
    				u16SendIndex++;
    			}
    		}
    
    		/* Stop Condition sould be send automatically */
    
    		/* Wait for Busy Bit to go Low --> The bus is free. */
    		while((i2c->STR & I2C_BUSBUSY) == I2C_BUSBUSY);
    		/* Wait for Master Mode Bit to go Low --> This bit is cleared after generating a STOP condition. */
    		/*                                        The BB bit is cleared first, and MST bit is cleared second. */
    		while((i2c->MDR & I2C_MASTER)  == I2C_MASTER);
    
    		/* Check that STOP was detected. */
    		if ( (i2c->STR & I2C_SCD) == 0ul )
    		{
    			u32RetVal = 5ul;
    		}
    		else
    		{
    			/* Clear Stop Condition Detected flag */
    			i2c->STR = I2C_SCD;
    
    			u32RetVal = 0ul;
    		}
    	}
    
    	return u32RetVal;
    }
    
    uint32_t i2cMasterReadSync(i2cBASE_t *i2c,  uint16_t u16SlaveAddress, uint8_t u8RegAddress,  uint16_t u16DataCount, uint8_t pu8DataOut[])
    {
    	uint32_t u32RetVal = 0xFFFFFFFFul;
    
    	if ((i2c->STR & I2C_BUSBUSY) == I2C_BUSBUSY) /* Check if the bus is free */
    	{
    		u32RetVal = 1ul;
    	}
    	else if ((i2c->MDR & I2C_MASTER) == I2C_MASTER) /* Check if the Module is already in Master Mode, this indicates that some transfer is ongoing. */
    	{
    		u32RetVal = 2ul;
    	}
    	else
    	{
    		uint16_t u16SendIndex = 0u;
    
    		/* Setup to Transmit */
    		/* Setup Data Length (one byte) */
    		i2c->CNT = 1ul;
    		/* Setup Slave Address */
    		i2c->SAR = (uint32_t)u16SlaveAddress;
    
    		/* Setup for Master Transmitter Mode, transmit Start Condition and use Free Run Mode (Do not stop I2C on debugger hold) */
    		i2c->MDR = (uint32_t)(I2C_RESET_OUT | I2C_MASTER | I2C_TRANSMITTER | I2C_START_COND | I2C_FREE_RUN);
    
    		/* Wait till TX register is ready to receive next byte or ARDY if we get NACKe */
    		while((i2c->STR & (I2C_TX | I2C_ARDY)) == 0ul);
    
    		if ((i2c->STR & I2C_NACK) == I2C_NACK)
    		{
    			/* NACK detected during transmision
    			 *
    			 * According to I2C Spec the reason could be:
    			 * 1. No receiver is present on the bus with the transmitted address so there is no device to respond with an acknowledge.
    			 * 2. The receiver is unable to receive or transmit because it is performing some real-time function and is not ready to start communication with the master.
    			 * 3. During the transfer, the receiver gets data or commands that it does not understand.
    			 * 4. During the transfer, the receiver cannot receive any more data bytes.
    			 */
    
    			i2c->MDR |= I2C_STOP_COND; /* Send stop condition so SCL isn't held low */
    
    			/* Wait for Busy Bit to go Low --> The bus is free and stop was send */
    			while((i2c->STR & I2C_BUSBUSY) == I2C_BUSBUSY);
    
    			i2c->STR = I2C_SCD | I2C_TX | I2C_NACK; /* Clear SCD, NACK and set TXRDY flag to indicate that a new transfer is possible. */
    
    			return 4ul;
    		}
    
    		/* Send register address to write to */
    		i2c->DXR = (uint32_t)u8RegAddress;
    
    		/* wait for ARDY before beginning the read phase of the transaction */
    		while ( (i2c->STR & I2C_ARDY) == 0ul );
    
    		/* Setup to Read */
    		i2c->CNT = 0ul; /* It seems that count has to be modified... */
    		/* Setup Data Length */
    		i2c->CNT = (uint32_t)u16DataCount;
    
    		/* Transmit Repeated Start condition */
    		/* Setup for Master Receiver Mode, transmit Start Condition, prepare to send Stop Condition (after CNT = 0) and use Free Run Mode (Do not stop I2C on debugger hold) */
    		i2c->MDR = (uint32_t)(I2C_RESET_OUT | I2C_MASTER | I2C_RECEIVER | I2C_START_COND | I2C_STOP_COND | I2C_FREE_RUN);
    
    		while(u16SendIndex < u16DataCount)
    		{
    			/* Wait for I2C to read data or ARDY if we get NACKe */
    			while((i2c->STR & (I2C_TX | I2C_ARDY)) == 0ul);
    
    			if ((i2c->STR & I2C_NACK) == I2C_NACK)
    			{
    				/* NACK detected during reception
    				 *
    				 * According to I2C Spec the reason could be:
    				 * 1. No receiver is present on the bus with the transmitted address so there is no device to respond with an acknowledge.
    				 * 2. The receiver is unable to receive or transmit because it is performing some real-time function and is not ready to start communication with the master.
    				 * 3. During the transfer, the receiver gets data or commands that it does not understand.
    				 * 4. During the transfer, the receiver cannot receive any more data bytes.
    				 */
    
    				i2c->MDR |= I2C_STOP_COND; /* Send stop condition so SCL isn't held low */
    
    				/* Wait for Busy Bit to go Low --> The bus is free and stop was send */
    				while((i2c->STR & I2C_BUSBUSY) == I2C_BUSBUSY);
    
    				i2c->STR = I2C_SCD | I2C_TX | I2C_NACK; /* Clear SCD, NACK and set TXRDY flag to indicate that a new transfer is possible. */
    
    				return 6ul;
    			}
    			else
    			{
    				/* Make sure that we got the RRDY signal */
    				while ( (i2c->STR & I2C_RX) == 0ul );
    
    				/* Read out a byte */
    				pu8DataOut[u16SendIndex] = (uint8_t)i2c->DRR;
    
    				u16SendIndex++;
    			}
    		}
    
    		/* Stop Condition should be send automatically */
    
    		/* Wait for Busy Bit to go Low --> The bus is free. */
    		while((i2c->STR & I2C_BUSBUSY) == I2C_BUSBUSY);
    		/* Wait for Master Mode Bit to go Low --> This bit is cleared after generating a STOP condition. */
    		/*                                        The BB bit is cleared first, and MST bit is cleared second. */
    		while((i2c->MDR & I2C_MASTER)  == I2C_MASTER);
    
    		/* Check that NACK was send and that STOP was detected.
    		 *
    		 * NACK was send according to I2C spec:
    		 * 5. A master-receiver must signal the end of the transfer to the slave transmitter.
    		 */
    		if ( (i2c->STR & (I2C_NACKSNT | I2C_SCD)) == 0ul )
    		{
    			u32RetVal = 5ul;
    		}
    		else
    		{
    			/* Clear NACK Send Flag and Stop Condition Detected flag */
    			i2c->STR = I2C_NACKSNT | I2C_SCD;
    
    			u32RetVal = 0ul;
    		}
    
    
    	}
    
    	return u32RetVal;
    }

    The g_Struct was in there, because I experimented with an asynchronous API and I needed some basic semaphores and a needed to implement a state machine.

    So above code should work now, here is how I use it in my little test program:

    /* Init the I2C module */
    i2cInit();
    
    //...
    
    /* Set Magnetometer into Sleep Mode to be able to read Chip ID */
    if (RetVal = i2cMasterWriteSync(i2cREG1, 0x10u, 2u, (uint8_t*)Data))
    {
    	printf("RetVal = %u\n", RetVal);
    	while(1);
    }
    
    //...
    
    if(RetVal = i2cMasterReadSync(i2cREG1, 0x10u, 0x40u, 3u, &rsv[2]))
    {
    	printf("RetVal = %u\n", RetVal);
    	while(1);
    }

    Best Regards,
    Christian

  • Christian,

    Thanks for the assistance. With the source provided I was able to communicate as expected.

    Cheers,

    Andrew