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.

TMS320F280049C: I2C polling (non-interrupt) robust functions

Part Number: TMS320F280049C
Other Parts Discussed in Thread: C2000WARE

I have written the following code to write a byte to an EEPROM (AT24C128C). I can't use interrupts:

uint16_t I2C_EEPROM_WriteByte(uint16_t address, uint16_t byte)
{
    uint32_t WaitCount = 0;

    // Wait until the STP bit is cleared from any previous master
    // communication. Clearing of this bit by the module is delayed until after
    // the SCD bit is set. If this bit is not checked prior to initiating a new
    // message, the I2C could get confused.
    //
    if(I2C_getStopConditionStatus(I2CA_BASE))
    {
        return(ERROR_STOP_NOT_READY);
    }

    //disable write protect
    GPIO_writePin(39, 0);

    // To read a word from the EEPROM, an address must be given first in
    // master transmitter mode. Then a restart is performed and data can
    // be read back in master receiver mode.
    I2C_setDataCount(I2CA_BASE, 0x03);
    
    I2C_putData(I2CA_BASE, address>>8);
    I2C_putData(I2CA_BASE, address);
    //
    // Setup data to send
    //
    I2C_putData(I2CA_BASE,byte);//data word

    // Send start as master transmitter
    I2C_setConfig(I2CA_BASE, I2C_MASTER_SEND_MODE);
    
    I2C_sendStartCondition(I2CA_BASE);
    I2C_sendStopCondition(I2CA_BASE);

    // Wait until communication done
    while(I2C_getStopConditionStatus(I2CA_BASE))
    {
        if(I2C_getStatus(I2CA_BASE) & I2C_STR_NACK)
        {
            //clear the NACK bit and stop the transfer
            I2C_sendStopCondition(I2CA_BASE);

            HWREGH(I2CA_BASE + I2C_O_STR) |= I2C_STR_NACK;
            
            //disable and enable FIFOs to flush them out
            I2C_disableFIFO(I2CA_BASE);
            I2C_enableFIFO(I2CA_BASE);

            //enable write protect
            GPIO_writePin(39, 1);

            return I2C_NACK_ERROR;
        }
    }

   // Wait until EEPROM is writing and is unresponsive to I2C (max 5ms)
   do
   {
       I2C_setDataCount(I2CA_BASE, 0x02);
       I2C_putData(I2CA_BASE, address>>8);
       I2C_putData(I2CA_BASE, address);
       I2C_setConfig(I2CA_BASE, I2C_MASTER_SEND_MODE);
       I2C_sendStartCondition(I2CA_BASE);
       I2C_sendStopCondition(I2CA_BASE);
       while(I2C_getStopConditionStatus(I2CA_BASE))
       {
           if(I2C_getStatus(I2CA_BASE) & I2C_STR_NACK)
               break;
       }
       
       if(I2C_getStatus(I2CA_BASE) & I2C_STR_NACK)
       {
           I2C_sendStopCondition(I2CA_BASE);
           HWREGH(I2CA_BASE + I2C_O_STR) |= I2C_STR_NACK;
           I2C_disableFIFO(I2CA_BASE);
           I2C_enableFIFO(I2CA_BASE);
           SysCtl_delay(20000);
           WaitCount++;
       }
       else
           break;
   }
   while(WaitCount < 15);

   GPIO_writePin(39, 1);//enable write protect

   return NO_ERROR;
}

The code is sometimes getting stuck in the while loop at line 66, waiting for the STP bit to go low. Please suggest a way to write proper read and write functions for I2C without using interrupts. All example codes I saw were with interrupt or were with loophole (BootROM example code). Where did i go wrong? And once the STP bit stays high, how do I recover from ths state if I put a timeout inside the loop?

Also, this link is broken: https://processors.wiki.ti.com/index.php/I2C_Tips

  • Arpan,

    We already have an example using polling option in C2000Ware. Did you already check that?

    <C2000Ware>\driverlib\f28004x\examples\i2c\i2c_ex4_eeprom_polling

    Regards,

    Manoj

  • Hi Manoj,

    Interesting! This example didn't exists while I wrote the code (December 2020). Thanks for pointing out. I'll go through the example.

    Regards,
    Arpan

  • Arpan,

    This example was posted in 1Q 2021 (Feb). You should have received this example if you had updated your C2000Ware during that time frame

    Regards,

    Manoj

  • Hi Manoj,

    I have gone through the example and I have one doubt:

    I don't see any Stop bit related code in the example. How is the code working without sending Stop bits?

    Regards,
    Arpan

  • Arpan,

    Please check i2cLib_FIFO_polling.c file. STOP condition is generated using I2C_sendStopCondition(base) function.

    Regards,

    Manoj

  • Oops!! Missed it! Embarrassing!

  • Hi Manoj,

    I got 2 more doubts. And I hope it's not silly like the previous one:

    1. i2c_ex4_eeprom_polling code has a lot of interrupts enabled. But there is no ISR involved. Are those all lines of code useless?

    2. For example, at the end of I2C_MasterTransmitter(),

     

    while(I2C_getStopConditionStatus(base) && attemptCount <= 3U)
    {
        DEVICE_DELAY_US(I2C_Params->Delay_us);
        attemptCount++;
    }
    
    return SUCCESS;

    If Stop condition stays high, but attempt times out, it will still return success. I should add a condition to check for timeout and return an error. Am I correct?

    Regards,
    Arpan

  • Arpan,

    Yes, you can add a condition to check STOP condition status. If STOP condition not generated, you can report an error.

    Regards,

    Manoj

  • Hi Manoj,

    In the example code, inside function I2C_TransmitSlaveAddress_ControlBytes(), what is the logic behind the following lines of code?

        if(status)
        {
          if(attemptCount <= (I2C_Params->NumOfAttempts))
          {
              attemptCount++;
              I2C_setConfig(base, (I2C_MASTER_SEND_MODE));
              I2C_sendStartCondition(base);
              DEVICE_DELAY_US(I2C_Params->Delay_us);
          }
          else
          {
              return status;
          }
    	}

    Also, I2C_setConfig sets sometimes in I2C_REPEAT_MODE and sometimes not. Why is it like that?

    Regards,
    Arpan

  • Hi Manoj,

    1. What is the use of the following line in code?
    while(I2C_getStatus(EEPROM.base) & I2C_STS_BUS_BUSY);

    2. In I2C_MasterTransmitter() and I2C_MasterReceiver(), 

    status = handleNACK(base);
    if(status)
    {
      return status;
    }

    these lines cause code to exit function even before sending STOP after START has been sent. Won't it keep the I2C bus in busy state, leading to failure of subsequent communications?

    3. Can I eliminate all the interrupt related lines as ISR is not there?

    Regards,
    Arpan

  • Hi Manoj,

    I have rewritten the functions, pending the querries I have already posted. Tghose clarifications are still required.  What do you think of the code below? Is it proper and fully robust?

    	//#################################################
    	void UV_I2C_EEPROM_Init(void)
    	{
    		//----------------------------------------------
            //GPIO configuration for I2CA
            //----------------------------------------------
            //Unlock the GPIO configuration registers
            EALLOW;
            GPIO_unlockPortConfig(GPIO_PORT_A,0x00000000);
            GPIO_unlockPortConfig(GPIO_PORT_B,0x00000000);
            //Enable pull up on GPIOs 26, 27 pins
            GPIO_setPadConfig(26,GPIO_PIN_TYPE_PULLUP);
            GPIO_setPadConfig(27,GPIO_PIN_TYPE_PULLUP);
    
            //GPIO26 = SDAA
            //GPIO27 = SCLA
            GPIO_setPinConfig(GPIO_26_SDAA);
            GPIO_setPinConfig(GPIO_27_SCLA);
    
            //Configure GPIOs 26, 27 pins as async pins
            GPIO_setQualificationMode(26,GPIO_QUAL_ASYNC);
            GPIO_setQualificationMode(27,GPIO_QUAL_ASYNC);
    
            //EEPROM WP pin setup as GPIO
            GPIO_setPinConfig(GPIO_39_GPIO39);
            //EEPROM WP pin pullup enabled for write protection
            GPIO_setPadConfig(39,GPIO_PIN_TYPE_PULLUP);
            //enable write protect
            GPIO_writePin(39, 1);
            EDIS;
    
            //----------------------------------------------
            // Initialize the I2C-A port for communications
            //----------------------------------------------
            // Configure I2C pins and turn on I2C clock
            EALLOW;
            // Turn I2C module clock on
            SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_I2CA);
    
            EDIS;
    		
    		//Disable operation of the I2C module (I2C_MDR_IRS bit)
    		I2C_disableModule(I2CA_BASE);
    		
    		// Initialize I2C in master transmitter mode
            // I2C clock should be between 7Mhz-12Mhz
            //I2C bit rate (in freq) (Output clock)   = 100 KHz
            //Duty Cycle  =  50%
            I2C_initMaster(I2CA_BASE,DEVICE_SYSCLK_FREQ,100000U,I2C_DUTYCYCLE_50);
    		
    		// Master transmitter
    		I2C_setConfig(I2CA_BASE, I2C_MASTER_SEND_MODE);
    		
            // Slave address - EEPROM control code, A0,A1,A2 are all pulled to GND
            I2C_setSlaveAddress(I2CA_BASE, 0x0050);
    		
    		//I2CA address
    		I2C_setOwnSlaveAddress(I2CA_BASE, 96);
    		
    		I2C_disableLoopback(I2CA_BASE);
    		
    		I2C_setBitCount(I2CA_BASE, I2C_BITCOUNT_8);
    		
    		I2C_setAddressMode(I2CA_BASE, I2C_ADDR_MODE_7BITS);
    		
    		//Enable RXFIFO and TXFIFO
            I2C_enableFIFO(I2CA_BASE);
    		
    		I2C_clearInterruptStatus(I2CA_BASE, I2C_INT_ARB_LOST | I2C_INT_NO_ACK);
    		I2C_clearInterruptStatus(I2CA_BASE, I2C_INT_RXFF | I2C_INT_TXFF);
    		
    		//I2C_setFIFOInterruptLevel(I2CA_BASE, I2C_FIFO_TXEMPTY, I2C_FIFO_RX2);
    		
    		//I2C_enableInterrupt(I2CA_BASE, I2C_INT_ADDR_SLAVE | I2C_INT_ARB_LOST | I2C_INT_NO_ACK | I2C_INT_STOP_CONDITION);
    
            //Disable back compatibility and forward compatibility modes
            HWREGH(I2CA_BASE + I2C_O_EMDR) &= ~I2C_EMDR_BC;
            HWREGH(I2CA_BASE + I2C_O_EMDR) &= ~I2C_EMDR_FCM;
    
            //Free run in debug mode
            I2C_setEmulationMode(I2CA_BASE, I2C_EMULATION_FREE_RUN);
    
            I2C_enableModule(I2CA_BASE);
    		
    		//After taking the I2C peripheral out of reset by setting the IRS bit to 1, wait a period larger than the total time
    		//taken for the longest data transfer in the application. By waiting for a period of time after I2C comes out of
    		//reset, users can ensure that at least one START or STOP condition will have occurred on the I2C bus and
    		//been captured by the BB bit. After this period, the BB bit will correctly reflect the state of the I2C bus.
    		DEVICE_DELAY_US(150U);
    	}
    	
    	//#################################################
        uint16_t UV_I2C_EEPROM_CurrentAddrSet(uint16_t address)
        {
    		uint16_t status = NO_ERROR;
    		uint16_t attemptCount = 0;
    		
    		while(attemptCount < 3)
    		{
    			status = checkBusStatus(I2CA_BASE);
    			
    			if (status == SUCCESS)
    				break;
    			
    			attemptCount++;
    			DEVICE_DELAY_US(10);
    		}
    		
    		if (status != SUCCESS)
    			return status;
    		
    		//Set as master transmitter in Repeat mode
    		I2C_setConfig(I2CA_BASE, (I2C_MASTER_SEND_MODE|I2C_REPEAT_MODE));
    		
    		//Setup slave address, also mask address to restrict it to 7-bit
    		I2C_setSlaveAddress(I2CA_BASE, address & 0x7F);
    		
    		//Setup how many bytes to send
            I2C_setDataCount(I2CA_BASE, 0x02);
    		
    		//Configure fifo data for EEPROM address 
    		I2C_putData(I2CA_BASE, (address>>8)) & 0xFF);
            I2C_putData(I2CA_BASE, address ) & 0xFF);
    		
    		//Send start
    		I2C_sendStartCondition(I2CA_BASE);
    		
    		DEVICE_DELAY_US(150U);
    		
    		status = handleNACK(I2CA_BASE);
    		
    		if (status != SUCCESS)
    		{
    			if(attemptCount <= 3)
    			{
    				attemptCount++;
    				I2C_setConfig(I2CA_BASE, (I2C_MASTER_SEND_MODE));
    				I2C_sendStartCondition(I2CA_BASE);
    				DEVICE_DELAY_US(10);
    			}
    			else
    			{
    				return status;
    			}
    		}
    		
    		attemptCount = 1;
    		
    		//wait till all data in FIFO has been transmited
    		while(I2C_getTxFIFOStatus(I2CA_BASE) && attemptCount <= (9 * 4U))
    		{
    			status = handleNACK(I2CA_BASE);
    			if(status != SUCCESS)
    			{
    				//stop the transfer
    				I2C_sendStopCondition(I2CA_BASE);
    				//Clear NACK bit by writing 1 to it
    				HWREGH(I2CA_BASE + I2C_O_STR) |= I2C_STR_NACK;
    				//disable and enable FIFOs to flush them out
    				I2C_disableFIFO(I2CA_BASE);
    				I2C_enableFIFO(I2CA_BASE);
    				return status;
    			}
    			attemptCount++;
    			DEVICE_DELAY_US(10U);
    		}
    		
    		//check if TX FIFO still has data or not. If it has, that means timeout occurred
    		if (I2C_getTxFIFOStatus(I2CA_BASE) > 0)
    		{
    			return RET_ERROR;
    		}
    
    		return SUCCESS;
    	}
    	
    	//#################################################
        uint16_t UV_I2C_EEPROM_ReadByte(uint16_t *byte)
        {
    		uint16_t status;
    		uint16_t attemptCount;
    
    		//Flush FIFOs
    		I2C_disableFIFO(I2CA_BASE);
    		I2C_enableFIFO(I2CA_BASE);
    		
    		I2C_setConfig(I2CA_BASE, (I2C_MASTER_RECEIVE_MODE|I2C_REPEAT_MODE));
    		
    		I2C_sendStartCondition(I2CA_BASE);
    		
    		status = handleNACK(I2CA_BASE);
            if(status != SUCCESS)
            {
    			//stop the transfer
    			I2C_sendStopCondition(I2CA_BASE);
    			//Clear NACK bit by writing 1 to it
    			HWREGH(I2CA_BASE + I2C_O_STR) |= I2C_STR_NACK;
    			//disable and enable FIFOs to flush them out
    			I2C_disableFIFO(I2CA_BASE);
    			I2C_enableFIFO(I2CA_BASE);
    			return status;
            }
    		
    		attemptCount = 1;
    		while(!(I2C_getRxFIFOStatus(I2CA_BASE) >= 1) && attemptCount <= (9 * 3U))
    		{
    		   DEVICE_DELAY_US(10U);
    		   attemptCount++;
    		}
    		
    		//In repeat mode, sending stop also generates NACK bit to slave
    		I2C_sendStopCondition(base);
    		
    		//check if data has been received in FIFO, if not that means timeout has occurred
    		if ((I2C_getRxFIFOStatus(I2CA_BASE) >= 1))
    			*byte = I2C_getData(I2CA_BASE);
    		
    		status = handleNACK(I2CA_BASE);
    		if(status != SUCCESS)
    		{
    			//stop the transfer
    			I2C_sendStopCondition(I2CA_BASE);
    			//Clear NACK bit by writing 1 to it
    			HWREGH(I2CA_BASE + I2C_O_STR) |= I2C_STR_NACK;
    			//disable and enable FIFOs to flush them out
    			I2C_disableFIFO(I2CA_BASE);
    			I2C_enableFIFO(I2CA_BASE);
    			return status;
    		}
    		
    		I2C_disableFIFO(I2CA_BASE);
    		
    		attemptCount = 1;
    		
    		while(I2C_getStopConditionStatus(I2CA_BASE) && attemptCount <= 3U)
    		{
    			DEVICE_DELAY_US(10U);
    			attemptCount++;
    		}
    		
    		//If Stop bit is still high, that means timeout has occurred
    		if (I2C_getStopConditionStatus(I2CA_BASE))
    		{
    			//TODO: Add Stop condition recovery sequence
    			return ERROR_STOP_NOT_READY;
    		}
    		
    		return SUCCESS;
    	}
    	
    	//#################################################
        uint16_t UV_I2C_EEPROM_WriteByte(uint16_t address, uint16_t byte)
        {
    		uint16_t status, attemptCount;
    		
    		//Flush FIFOs
    		I2C_disableFIFO(I2CA_BASE);
    		I2C_enableFIFO(I2CA_BASE);
    		
    		status = UV_I2C_EEPROM_CurrentAddrSet(address);
    
    		if(status != SUCCESS)
    		{
    			return status;
    		}
    		
    		//disable write protect
            GPIO_writePin(39, 0);
    		
    		I2C_setDataCount(I2CA_BASE, 0x01);
    		
    		//I2C_setFIFOInterruptLevel(I2CA_BASE, I2C_FIFO_TXEMPTY, I2C_FIFO_RXFULL);
    		//I2C_enableInterrupt(I2CA_BASE, I2C_INT_TXFF);
    		
    		I2C_putData(I2CA_BASE, byte);
    		
    		attemptCount = 1;
    		//Keep checking FIFO till all bytes in it has been transferred
    		while(I2C_getTxFIFOStatus(I2CA_BASE) && attemptCount <= (9 * 3U))
    		{
    			status = handleNACK(I2CA_BASE);
    			if(status)
    			{
    				//stop the transfer
    				I2C_sendStopCondition(I2CA_BASE);
    				//Clear NACK bit by writing 1 to it
    				HWREGH(I2CA_BASE + I2C_O_STR) |= I2C_STR_NACK;
    				//disable and enable FIFOs to flush them out
    				I2C_disableFIFO(I2CA_BASE);
    				I2C_enableFIFO(I2CA_BASE);
    				return status;
    			}
    			attemptCount++;
    			DEVICE_DELAY_US(10U);
    		}
    		
    		I2C_sendStopCondition(I2CA_BASE);
    		
    		//if TX FIFO still has data, that means timeout occurred
    		if(I2C_getTxFIFOStatus(I2CA_BASE))
    		{
    			return RET_ERROR;
    		}
    		
    		attemptCount = 1;
    		while(I2C_getStopConditionStatus(I2CA_BASE) && attemptCount <= 3U)
    		{
    			DEVICE_DELAY_US(10U);
    			attemptCount++;
    		}
    		
    		//If Stop bit is still high, that means timeout has occurred
    		if (I2C_getStopConditionStatus(I2CA_BASE))
    		{
    			//TODO: Add Stop condition recovery sequence
    			return ERROR_STOP_NOT_READY;
    		}
    		
    		// Wait until EEPROM is writing and is unresponsive to I2C (max 5ms)
           do
           {
               I2C_setDataCount(I2CA_BASE, 0x02);
               I2C_putData(I2CA_BASE, (address>>8) & 0xFF);
               I2C_putData(I2CA_BASE, address  & 0xFF);
               I2C_setConfig(I2CA_BASE, I2C_MASTER_SEND_MODE);
               I2C_sendStartCondition(I2CA_BASE);
               I2C_sendStopCondition(I2CA_BASE);
    		   
    		   attemptCount = 1;
               while(I2C_getStopConditionStatus(I2CA_BASE) && attemptCount <= 3U)
               {
    				if(I2C_getStatus(I2CA_BASE) & I2C_STR_NACK)
    					break;
    			   
    				DEVICE_DELAY_US(10U);
    				attemptCount++;
               }
    		   
    		   //If Stop bit is still high, that means timeout has occurred
    			if (I2C_getStopConditionStatus(I2CA_BASE))
    			{
    				//TODO: Add Stop condition recovery sequence
    				return ERROR_STOP_NOT_READY;
    			}
    		   
               if(I2C_getStatus(I2CA_BASE) & I2C_STR_NACK)
               {
                   I2C_sendStopCondition(I2CA_BASE);
                   HWREGH(I2CA_BASE + I2C_O_STR) |= I2C_STR_NACK;
                   I2C_disableFIFO(I2CA_BASE);
                   I2C_enableFIFO(I2CA_BASE);
                   SysCtl_delay(20000);
                   WaitCount++;
               }
               else
                   break;
           }
           while(WaitCount < 15);
    
           GPIO_writePin(39, 1);//enable write protect
    		
    		return SUCCESS;
    	}
    	
    	//#################################################
    	uint16_t checkBusStatus()
    	{
    		if(I2C_isBusBusy(I2CA_BASE))
    		{
    			return ERROR_BUS_BUSY;
    		}
    
    		if(I2C_getStopConditionStatus(I2CA_BASE))
    		{
    			return ERROR_STOP_NOT_READY;
    		}
    
    		return SUCCESS;
    	}
    
    	//#################################################
    	uint16_t handleNACK()
    	{
    		if(I2C_getStatus(I2CA_BASE) & I2C_STS_NO_ACK)
    		{
    			I2C_clearStatus(I2CA_BASE, I2C_STS_NO_ACK);
    			I2C_sendStopCondition(I2CA_BASE);
    
    			return I2C_NACK_ERROR;
    		}
    
    		return SUCCESS;
    	}

    Regards,
    Arpan

  • Arpan,

    I'm puzzled why you have re-written the code? Where you not able to use master transmitter / master receiver functions as it is in your application?

    Regards,

    Manoj

  • Hi Manoj,

    We are already using these functions. I am having to change the old functions' code because it is running into some error. That's why I used the logic of the example code in our functions and rewrote. the example functions and the new ones are more or less same, just a few enhancements. You can ignore the names of my functions.

    Regards,
    Arpan

  • Arpan,

    i2c_ex4_eeprom_polling example code is validated and should work without any issues. What is the error you are seeing?

    In the example code, inside function I2C_TransmitSlaveAddress_ControlBytes(), what is the logic behind the following lines of code?

    If the I2C bus is busy in earlier attempt, it allows user to wait for sometime and re-trigger I2C transaction.

    Also, I2C_setConfig sets sometimes in I2C_REPEAT_MODE and sometimes not. Why is it like that?

    Regards,

    It is just the method used for implementation. You can implement it in REPEAT mode (or) non-REPEAT MODE.

    1. What is the use of the following line in code?
    while(I2C_getStatus(EEPROM.base) & I2C_STS_BUS_BUSY);

    This waits for the I2C bus to go to idle state. (meaning STOP condition was successfully generated in previous transaction)

    handleNACK function is used to handle when I2C master receive NACK signal from slave.

    these lines cause code to exit function even before sending STOP after START has been sent. Won't it keep the I2C bus in busy state, leading to failure of subsequent communications?

    STOP condition is set before check calling handleNACK function. Once the previous I2C transaction is complete, I2C will automatically generate STOP condition.

    3. Can I eliminate all the interrupt related lines as ISR is not there?

    Yes, it should be okay to disable interrupts related to I2C

    Regards,

    Manoj

  • Thanks a lot Manoj! The original code I posted inside the question has some issues. I have not yet tested the example code. As my original functions are used throughout my code, I had to keep the function names same. So, I copied from example code, added some enhancements (example: as we discussed above, example code returns SUCCESS even if there was timeout error inside. I have tried to rectify issues like these) and hardcoded for data size of 1 byte and 7-bit address.

    Regards,
    Arpan

  • If the I2C bus is busy in earlier attempt, it allows user to wait for sometime and re-trigger I2C transaction.

    I think the code should have "while" condition instead of "if" condition here, like below:

    while(status)
    {
      if(attemptCount <= (I2C_Params->NumOfAttempts))
      {
          attemptCount++;
          I2C_setConfig(base, (I2C_MASTER_SEND_MODE));
          I2C_sendStartCondition(base);
          DEVICE_DELAY_US(I2C_Params->Delay_us);
          status = handleNACK(base);
      }
      else
      {
          return status;
      }
    }

    Regards,
    Arpan

  • Hi Manoj,

    While testing this code, both SDA and SCL got low and I got the following register values:

    C2000 should always be the master. How did it get addressed as a slave? What could be the issue?

    Regards,
    Arpan

  • Arpan,

    I2CSAR should hold slave address you are trying to talk to

    I2COAR should hold address of the C2000 I2C.

    From your screenhot, I2CSAR and I2COAR hold 0x60. I2COAR shouldn't be same value as slave address.

    Regards,

    MAnoj

  • Arpan,

    It is still not clear to me what error you encountered in the example code? Can you please elaborate?

    Regards,

    Manoj

  • Hi Manoj,

    Thanks for spotting the issue. I had made a mistake in my code. Rectified it. That caused this addressed as slave issue.

    Regards,
    Arpan

  • Hi Manoj,

    I tried with modfied code that I had written based on example code. There too I faced some issues. Now I am trying to use example code as it is. Once I test that, I will get back to you.

    Regards,
    Arpan

  • Please test and let me know you run into any issues.

  • Hi Manoj,

    Quoting you: "In my setup, I'm not able to generate repeated start condition when there is a pending underflow condition in non-repeat mode." from https://e2e.ti.com/support/microcontrollers/c2000-microcontrollers-group/c2000/f/c2000-microcontrollers-forum/956519/tms320f280049-i2c-repeated-start-behavior-rm-bit-accurate-rx-count/3536597?tisearch=e2e-sitesearch&keymatch=BB%2525252525252520I2C#3536597


    I couldn't find this documented in TRM. Could you please clarify on this? Is there similar behaviour in FIFO mode? How do we work around such idiosyncracies of the peripheral?

  • I'm working on documenting this behavior on TRM.

    The content provided in the post pointed earlier is correct. 

  • Hi Manoj,

    Do you have a list of undocumented behaviours of the I2C module that you could share with me? Actually the example code wasn't working by default because it has so many delays and I had to change delay timings to get the code working. Also, I would prefer the code to work on the basis of register polls instead of blind delays. That's why I am reluctant to use the example code directly. But I am concerned that the documentation of I2C in TRM is inadequate.

    Regards,
    Arpan

  • Arpan,

    I2C chapter pretty much captures everything required for firmware engineers. I probably should have made my earlier statement clearly. In I2CCNT description we do specify that in non-repeat mode, STOP condition gets generated after I2CCNT number of bytes are transmitted (or) received.

    Below statement is missing and it is not obvious from I2CCNT bit-field description.

    In non-repeat mode, I2C state machine wouldn't allow you to generate STOP condition unless you reset the I2C module (or) when I2C transaction is complete. Once communication has started with given I2CCNT, it cannot be modified in middle of transaction.

    Actually the example code wasn't working by default because it has so many delays and I had to change delay timings to get the code working.

    Are you talking about below delay timing in the example code? Can you please clarify? What did you have to make the code working.

    DEVICE_DELAY_US(150U): After the START command, the code needs to wait for START condition + slave address to be transmitted before handleNACK(base) function gets executed. Without this delay handleNACK(base) will get executed early and we might not catch NACK condition.

    If you looking for alternate implementation then checkout PMBus implementation over I2C. This example got recently updated into C2000Ware. So, please download latest C2000Ware.

    <C2000Ware>\libraries\communications\PMBus\c28\examples\28004x_pmbus_over_i2c_master

    <C2000Ware>\libraries\communications\PMBus\c28\examples\common\pmbus_over_i2c_master\pmbus_over_i2c_lib.c

    <C2000Ware>\libraries\communications\PMBus\c28\examples\common\pmbus_over_i2c_master\pmbus_over_i2c_lib.h

    Regards,

    Manoj

  • Are you talking about below delay timing in the example code? Can you please clarify? What did you have to make the code working.

    I had to increase all the delays to get the code working. Also, I would like to use ARDY or some registers to wait till TX is done instead of blind delays.

    I2C chapter pretty much captures everything required for firmware engineers.

    Not very confidence inducing. For example, I had to read SPI chapter FIFO in TRM to understand I2C FIFOs.

    "In my setup, I'm not able to generate repeated start condition when there is a pending underflow condition in non-repeat mode."

    If this is not mentioned, my code may get stuck in non-repeat mode. I am not sure how are you saying that TRM has enough information for firmware engineers. Is there any other hidden behaviours related to I2C modules that is known to you?

    Is there similar behaviour in FIFO mode?

    Is the underflow issue present in FIFO mode too?

  • I had to increase all the delays to get the code working. Also, I would like to use ARDY or some registers to wait till TX is done instead of blind delays.

    In non-repeat mode, ARDY bit behavior is tied to I2CCNT register.

    Below is snippet from ARDY bit-field. In my example, I wanted to transmit / receive more than 16 bytes (FIFO) because when you set I2CCNT greater than 16, ARDY bit will never get set when I check whether RX FIFO is full (or) TX buffer is empty. That is the reason why I used delay function in my program. If you are okay with I2C frame less than (or) equal to 16 bytes you can use ARDY bit and remove delay functions.

    Information provided in "SPI FIFO Description" section is pretty much covered in I2CFFTX / I2CFFRX bit-field description.

    "In my setup, I'm not able to generate repeated start condition when there is a pending underflow condition in non-repeat mode."

    In repeat mode, you should be able to generate repeated START condition even in underflow condition

    In non-repeat mode, underflow condition is generated when I2CCNT bytes are not transmitted. In this condition, since I2C state machine is still expecting more bytes to be transmitted based on I2CCNT, so it doesn't allow you to generate repeated START because previous transaction is still pending

    Is the underflow issue present in FIFO mode too?

    Yes

    Regards,

    Manoj

  • Hi Manoj,

    If you are okay with I2C frame less than (or) equal to 16 bytes you can use ARDY bit and remove delay functions.

    Ok understood

    In non-repeat mode, underflow condition is generated when I2CCNT bytes are not transmitted. In this condition, since I2C state machine is still expecting more bytes to be transmitted based on I2CCNT, so it doesn't allow you to generate repeated START because previous transaction is still pending

    Understood.

    I'll try out the new logic. Thanks.

    Regards,
    Arpan

  • Hi Manoj,

    The example code runs fine without issues. I had to only change the timeout timings to get the code working. Also, it's error checks don't catch timeout errors.

    Yes, you can add a condition to check STOP condition status. If STOP condition not generated, you can report an error.


    Regards,
    Arpan

  • Hi Manoj,


    I wanted to transmit / receive more than 16 bytes (FIFO) because when you set I2CCNT greater than 16, ARDY bit will never get set when I check whether RX FIFO is full (or) TX buffer is empty.

    What if  ARDY is combined with TXFFST and RXFFST to fill up data when there is space in FIFO?

    Regards,
    Arpan

  • Arpan,

    In non-repeat mode:

    ARDY bit will get set only only after I2CCNT bytes are transmitted / received.

    When I2CCNT > 16 (Max. FIFO level), ARDY bit will not get SET even if transmitted / received number of bytes reaches max. FIFO level and only get set only when I2CCNT number of bytes is transmitted /received.

    When I2CCNT <=16, ARDY bit can be polled along with TXFFST if required as ARDY bit does get set.

    Regards,

    Manoj

  • Hi Manoj,

    I meant while in a loop waiting for ARDY to get high, it can keep tracking the bytes transmitted though TXFFST. Whenever the number crosses some threshold, it can add more bytes to the FIFO till I2CCNT is reached. At this point, ARDY will be set and code will go out of the loop.

    Regards,
    Arpan

  • Arpan,

    In non-repeat mode, you can use ARDY bit as demonstrated below for EEPROM write 'N' number of bytes because I precisely know that ARDY bit will get set only when I2CCNT bytes are transmitted.

    #define WAIT_TILL_REGISTERS_ARE_READY !(I2C_getStatus(I2CA_BASE) & I2C_STS_REG_ACCESS_RDY)

        uint16_t NumOfDataBytes    = 25;
        uint16_t numofSixteenByte  = NumOfDataBytes / I2C_FIFO_LEVEL;
        uint16_t remainingBytes    = NumOfDataBytes % I2C_FIFO_LEVEL;

        uint16_t count = 0, buff_pos = 0;

        I2C_setConfig(I2CA_BASE, I2C_MASTER_SEND_MODE);

        I2C_setEmulationMode(I2CA_BASE, I2C_EMULATION_FREE_RUN);

        I2C_setDataCount(I2CA_BASE, NumOfDataBytes + 2U); //Add 2 additional bytes for EEPROM address bytes

        I2C_enableFIFO(I2CA_BASE);

        I2C_putData(I2CA_BASE, 0);
        I2C_putData(I2CA_BASE, 0);

        I2C_sendStartCondition(I2CA_BASE);

        while(I2C_getTxFIFOStatus(I2CA_BASE));

        while(count < numofSixteenByte)
        {
                if(I2C_getTxFIFOStatus(I2CA_BASE) == I2C_FIFO_TXEMPTY)
                {
                    for(i=0;i<I2C_FIFO_TX16;i++)
                    {
                        I2C_putData(I2CA_BASE, TX_MsgBuffer[buff_pos++]);
                    }

                    status = handleNACK(I2CA_BASE);
                    if(status)
                    {
                      return status;
                    }

                    while(I2C_getTxFIFOStatus(I2CA_BASE));
                }

                count++;
        }

        for (i=0; i < remainingBytes; i++)
        {
           I2C_putData(I2CA_BASE, TX_MsgBuffer[buff_pos++]);
        }

        status = handleNACK(I2CA_BASE);
        if(status)
        {
           return status;
        }

        while(WAIT_TILL_REGISTERS_ARE_READY);

        I2C_sendStopCondition(I2CA_BASE);

    Regards,

    Manoj

  • Thanks Manoj. Please close tis thread too.