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.

TMS570LS1114 I2C Interface to DS1621

Other Parts Discussed in Thread: TMS570LS1114

I'm attempting to interface my TMS570LS1114 to a DS1621 via I2C.  I have included my send and recieve routines below based on the HAL CoGen drivers.  Currently the send routine appears to be working, but I am having trouble with receive since it requires a repeated start.  I appreciate any input.

void DS1621::I2CSend(uint8 Cmd, uint32 length, uint8 * data)
{
	//config
	/* Set mode as Master */
	i2cSetMode(i2cREG1, I2C_MASTER);
	i2cSetDirection(mNode, I2C_TRANSMITTER);
	i2cSetSlaveAdd(mNode, SlaveAddr);
	i2cSetCount(mNode, length+1);
	i2cSetStop(mNode);

	//send
	i2cSetStart(mNode);
	i2cSendByte(mNode, Cmd);
	i2cSend(mNode, length, data);

	/* Wait until Bus Busy is cleared */
	while(i2cIsBusBusy(mNode) == true);

	/* Wait until Stop is detected */
	while(i2cIsStopDetected(mNode) == 0);

	/* Clear the Stop condition */
	i2cClearSCD(mNode);
}

void DS1621::I2CRcv(uint8 Cmd, uint32 length, uint8 * data)
{
	//config
	i2cSetMode(i2cREG1, I2C_MASTER);
	i2cSetDirection(mNode, I2C_TRANSMITTER);
	i2cSetSlaveAdd(mNode, SlaveAddr);
	i2cSetCount(mNode, length+1);
	i2cSetStop(mNode);

	//send
	i2cSetStart(mNode);
	i2cSendByte(mNode, Cmd);

	/* Wait until Bus Busy is cleared */
//	while(i2cIsBusBusy(mNode) == true);

	//reconfig
	i2cSetDirection(mNode, I2C_RECEIVER);

	//receive
	i2cSetStart(mNode);
	i2cReceive(mNode, length, data);

	/* Wait until Bus Busy is cleared */
	while(i2cIsBusBusy(mNode) == true);

	/* Wait until Stop is detected */
	while(i2cIsStopDetected(mNode) == 0);

	/* Clear the Stop condition */
	i2cClearSCD(mNode);
}

  • Hi Matthew,

      It looks like per DS1621 datasheet you need a address byte after the command byte with a repeated start in between. I don't see that in your code. 

      

  • That is true, but does i2cReceive send the address, set using i2cSetSlaveAdd with the R/W bit set to Read, or should I be sending that address manually. All the examples I have seen never send the address word manually.

    Matt
  • Hi Matt,
    I'm not talking about the first slave address. If you look at the diagram there is a Repeated Start -> Address Bytes -> Data Bytes.
  • Charles,

    Yes I understand that, and when I try to send the address with the R/W set to R the program hangs in that i2cSendByte.  What I really need to know is when you call i2cSendByte or i2cReceiveByte are they appending the correct R/W slave address send before waiting for the read or write.  If they don't then what is the point of setting the SlaveAddress register in the i2c module.

    For reference here is the i2cSend and i2cReceive generated by HAL CoGen:

    void i2cSend(i2cBASE_t *i2c, uint32 length, uint8 * data)
    {
    
    /* USER CODE BEGIN (17) */
    /* USER CODE END */
    
        if ((g_i2cTransfer_t.mode & (uint32)I2C_TX_INT) != 0U)
        {
            /* Interrupt mode */
            /*SAFETYMCUSW 45 D MR:21.1 <APPROVED> "Valid non NULL input parameters are only allowed in this driver" */
            g_i2cTransfer_t.data   = data;
            /* start transmit by sending first byte */
            /*SAFETYMCUSW 45 D MR:21.1 <APPROVED> "Valid non NULL input parameters are only allowed in this driver" */
            i2c->DXR = (uint32)(*g_i2cTransfer_t.data);
            /*SAFETYMCUSW 45 D MR:21.1 <APPROVED> "Valid non NULL input parameters are only allowed in this driver" */
            /*SAFETYMCUSW 567 S MR:17.1,17.4 <APPROVED> "Pointer increment needed" */
            g_i2cTransfer_t.data++;
    
            /* Length -1 since one data is written already */
            g_i2cTransfer_t.length = (length - 1U);
    
            /* Enable Transmit Interrupt */
            i2c->IMR |= (uint32)I2C_TX_INT;
        }
        else
        {
            /* send the data */
            while (length > 0U)
            {
                /*SAFETYMCUSW 28 D MR:NA <APPROVED> "Potentially infinite loop found - Hardware Status check for execution sequence" */
                while ((i2c->STR & (uint32)I2C_TX_INT) == 0U)
                {
                } /* Wait */
                /*SAFETYMCUSW 45 D MR:21.1 <APPROVED> "Valid non NULL input parameters are only allowed in this driver" */
                i2c->DXR = (uint32)(*data);
                /*SAFETYMCUSW 45 D MR:21.1 <APPROVED> "Valid non NULL input parameters are only allowed in this driver" */
                /*SAFETYMCUSW 567 S MR:17.1,17.4 <APPROVED> "Pointer increment needed" */
                data++;
                length--;
            }
        }
    /* USER CODE BEGIN (18) */
    /* USER CODE END */
    }
    void i2cReceive(i2cBASE_t *i2c, uint32 length, uint8 * data)
    {
    
    /* USER CODE BEGIN (26) */
    /* USER CODE END */
        if ((i2c->IMR & (uint32)I2C_RX_INT) != 0U)
        {
            /* we are in interrupt mode */
            /* clear error flags */
            i2c->STR = (uint32)I2C_AL_INT | (uint32)I2C_NACK_INT;
    
            g_i2cTransfer_t.length = length;
            /*SAFETYMCUSW 45 D MR:21.1 <APPROVED> "Valid non NULL input parameters are only allowed in this driver" */
            g_i2cTransfer_t.data   = data;
        }
        else
        {
            while (length > 0U)
            {
                /*SAFETYMCUSW 28 D MR:NA <APPROVED> "Potentially infinite loop found - Hardware Status check for execution sequence" */
                while ((i2c->STR & (uint32)I2C_RX_INT) == 0U)
                {
                } /* Wait */
                /*SAFETYMCUSW 45 D MR:21.1 <APPROVED> "Valid non NULL input parameters are only allowed in this driver" */
                *data = ((uint8)i2c->DRR);
                /*SAFETYMCUSW 45 D MR:21.1 <APPROVED> "Valid non NULL input parameters are only allowed in this driver" */
                /*SAFETYMCUSW 567 S MR:17.1,17.4 <APPROVED> "Pointer increment needed" */
                data++;
                length--;
            }
        }
    
    /* USER CODE BEGIN (27) */
    /* USER CODE END */
    }

  • Hi Matthew,
    Is there a reason why you comment out while(i2cIsBusBusy(mNode) == true); in your orignal code? Without waiting for the bus to be not busy you have already started to change the direction and start the receive. I think you want to uncomment it.

    When you issue the i2cSetStart() it should generate the START bit and the slave address + R/W bit.

    Can you use the scope to capture the bus activities? This way it is easier to know where the problem is.
  • I have a partial solution, which allows the reading of 1 byte.  Reading 2 bytes is not handled correctly due to the use of ACK and NACK.  The i2cReceiveByte is issuing a NACK after the first 8 bytes which then hangs the program.  The revised code is below:

    void DS1621::I2CRcv(uint8 Cmd, uint32 length, uint8 * data)
    {
    	//config
    	i2cSetMode(mNode, I2C_MASTER);
    	i2cSetDirection(mNode, I2C_TRANSMITTER);
    	i2cSetSlaveAdd(mNode, SlaveAddr);
    	i2cSetCount(mNode, length+1);
    	i2cSetStop(mNode);
    
    	//send
    	i2cSetStart(mNode);
    	i2cSendByte(mNode, Cmd);
    
    	while(i2cIsTxReady(mNode) == 0);
    
    	//reconfig
    	i2cSetMode(mNode, I2C_MASTER);
    	i2cSetDirection(mNode, I2C_RECEIVER);
    	i2cSetSlaveAdd(mNode, SlaveAddr);
    
    	//receive
    	i2cSetStart(mNode);
    	if(length == 1)
    	{
    		*data = i2cReceiveByte(mNode);
    	}
    	else
    	{
    
    		i2cReceive(mNode, length, data);
    	}
    
    	/* Wait until Bus Busy is cleared */
    	while(i2cIsBusBusy(mNode) == true);
    
    	/* Wait until Stop is detected */
    	while(i2cIsStopDetected(mNode) == 0);
    
    	/* Clear the Stop condition */
    	i2cClearSCD(mNode);
    
    	for(int delay=0;delay<1000000;delay++);
    }
    The i2clsIsTxReady was the last piece of the puzzle, i2clsBusBusy cannot be used because it will always return true in the case of a repeated start.



  • Hi Matthew,

     I replied to this post from the TI FAE that you might have in contact with.

    In that post I have suggested a wiki page for some tips on the repeated START generation and another post to look at that might be helpful.

    Here is another userguide that contains the I2C operation flowcharts. Even thought it is for the TI DSP device but the Hercules I2C shares the identical module. 

     Here is an I2C code that you can also take a look.

    4375.sys_main.c