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.

CCS/TMS320F28035: TMS320F28035 Piccolo I2C communication Slave

Part Number: TMS320F28035

Tool/software: Code Composer Studio

Hi , So I am trying to have a I2C communication between two Piccolo TMS320F28035 I2C communication. I am stuck with Slave side, and the document doesn't explain much. I would appreciate some help.I am pretty sure I am doing some thing wrong but don't know what.

P.S. : I am not using interrupts like polling the BB, XRDY, RRDY or NACK bits for now, just to keep it simple.

Following is my code:

########## MASTER CODE (Only Write)#####################################

#define I2C_SLAVE_ADDR        0x0055

void main(void)
{

    InitSysCtrl();
    InitI2CGpio();\

bool flag = true;

  I2CA_Init_master();

for(;;)
    {

      while(GpioDataRegs.GPBDAT.bit.GPIO44 == 0 && flag )
      {

        GREENLED_ON ;
        I2CA_WriteData();
        GREENLED_OFF ;
        flag = false;
        //DELAY_US(1000000);
      }
    }

void I2CA_Init_master(void)
{
    I2caRegs.I2CSAR = I2C_SLAVE_ADDR;       // Slave address -
    I2caRegs.I2CPSC.all = 6;        // Prescaler - need 7-12 Mhz on module clk
    I2caRegs.I2CCLKL = 10;          // NOTE: must be non zero
    I2caRegs.I2CCLKH = 5;           // NOTE: must be non zero
    I2caRegs.I2CIER.all = 0;

    I2caRegs.I2CMDR.all = 0x0020;   // Take I2C out of reset

    I2caRegs.I2CFFTX.all = 0x6000;  // Enable FIFO mode and TXFIFO
    I2caRegs.I2CFFRX.all = 0x2040;  // Enable RXFIFO, clear RXFFINT,
    DELAY_US(10);
    return;
}


void  I2CA_WriteData(void){
     Uint16 i;
  //   while (I2caRegs.I2CMDR.bit.STP == 1)
   //    {
   //    };
     I2caRegs.I2CSAR = I2C_SLAVE_ADDR;           //slave address register
     I2caRegs.I2CCNT = I2C_NUMBYTES ;     //data count is 4 bytes
     I2caRegs.I2CFFTX.all = 0x6000; //enable FIFO mode and reset TX FIFO
     I2caRegs.I2CDXR = 0xf0;
     I2caRegs.I2CMDR.bit.TRX = 1;
     I2caRegs.I2CMDR.bit.MST = 1;
     I2caRegs.I2CMDR.bit.FREE = 1;
     I2caRegs.I2CMDR.bit.STP = 1; //creating a stop condition will free the BUS thus turning the BB == 0.
     I2caRegs.I2CMDR.bit.STT = 1; // As soon as you start the Start Bit the BB == 1 becomes busy again.
     return ;
}

###################################### SLAVE CODE(Only read) #################################

void main(void){

    InitSysCtrl();
    InitI2CGpio();

   I2CASlave_init();
    DELAY_US(1000000);
 for(;;)
 {
    I2CA_ReceiveData();
 }
 }

void I2CASlave_init(void)
{

    I2caRegs.I2COAR = I2C_SLAVE_ADDR;       // Slave address

    I2caRegs.I2CPSC.all = 6;        // Prescaler - need 7-12 Mhz on module clk
    I2caRegs.I2CCLKL = 10;          // NOTE: must be non zero
    I2caRegs.I2CCLKH = 5;           // NOTE: must be non zero

    I2caRegs.I2CIER.all = 0x00;     // Enable SCD, XRDY, RRDY, ARDY, NACK interrupts...sorry don't enable anything
    I2caRegs.I2CMDR.bit.MST = 0; // Enter the slave mode
    I2caRegs.I2CMDR.bit.TRX = 0;  //receive mode
    I2caRegs.I2CMDR.bit.FREE = 1                  ; // Runs in free mode setting it to zero will stop when data is received.l
    I2caRegs.I2CMDR.all = 0x0020 ;   // enable the IRS

 //           I2caRegs.I2CFFTX.all = 0x6000;  // Enable FIFO mode and TXFIFO
 //           I2caRegs.I2CFFRX.all = 0x2040;  // Enable RXFIFO, clear RXFFINT,
    return;
}

void I2CA_ReceiveData(void)
{
    I2caRegs.I2COAR = I2C_SLAVE_ADDR;       // Slave address - EEPROM control code

    I2caRegs.I2CSAR = I2C_SLAVE_ADDR;           //slave address register
    I2caRegs.I2CCNT = 1 ; //Receive count to 4 bytes

    //while(I2caRegs.I2CSTR.bit.RRDY == 0){} ;
    Receive_Data[0] = I2caRegs.I2CDRR ;
    return;
}

  • Hello,

    On the master side you're writing data without checking to see if the FIFO is full or trying to start a transmission without checking the previous one as finished. I'm not sure what I2C_NUMBYTES is but you appear to only be writing one byte of data to the transmit register. It its more than one, the stop condition won't be generated until I2C_NUMBYTES have actually been transmitted.

    The slave side has similar issues. You aren't checking to see if data has been received before reading the I2CDRR register (or at least it looks like you've commented out the code that does so.)

    Whitney
  • I apologize for that, actually I am just trying to send 1 byte .So the way master works is :

    1. Check if the button is pressed(GPIO44)    {the flag is used so that the program should run only once}

    2. Run the loop/Send data 1 byte

    3. stop

    So I won't be needing to check if FIFO is full or not, and yea I was not supposed to initialize the FIFO if I wasn't gonna use it, so I took it out.

    I referred to the code from the following TI community thread :

    ******Master******

    As far as the master is concerned I am able to see the 9 clock pulses i.e a Start condition followed by 7 bits of address followed by R/W . but after that my clock is hung low as it waits for an ACK(which it never gets from slave) on my Oscilloscope.

    2703.Master.txt
    #define I2C_SLAVE_ADDR        0x0055
    #define I2C_NUMBYTES          1
    
    void main(void)
    {
    
       InitSysCtrl();
       InitI2CGpio();
    
       bool flag = true;
    
      I2CA_Init_master();
    
    for(;;)
        {
    
          while(GpioDataRegs.GPBDAT.bit.GPIO44 == 0 && flag )
          {
    
            GREENLED_ON ;
            I2CA_WriteData();
            GREENLED_OFF ;
            flag = false;
          }
        }
    
    void I2CA_Init_master(void)
    {
        I2caRegs.I2CSAR = I2C_SLAVE_ADDR;// Slave address -
        I2caRegs.I2CPSC.all = 6;        // Prescaler - need 7-12 Mhz on module clk
        I2caRegs.I2CCLKL = 10;          // NOTE: must be non zero
        I2caRegs.I2CCLKH = 5;           // NOTE: must be non zero
        I2caRegs.I2CIER.all = 0;
    
        I2caRegs.I2CMDR.all = 0x0020;   // Take I2C out of reset
    
        DELAY_US(10);
        return;
    }
    
    
    void  I2CA_WriteData(void){
         Uint16 i;
         //   while (I2caRegs.I2CMDR.bit.STP == 1)
         //    {
         //    };
         I2caRegs.I2CSAR = I2C_SLAVE_ADDR;           //slave address register
         I2caRegs.I2CCNT = I2C_NUMBYTES ;     	 //data count is 1 byte
        
         I2caRegs.I2CDXR = 0xf0;         		 //The only data byte I am trying to send
         
         I2caRegs.I2CMDR.bit.TRX = 1;
         I2caRegs.I2CMDR.bit.MST = 1;
         I2caRegs.I2CMDR.bit.FREE = 1;
         I2caRegs.I2CMDR.bit.STP = 1; 		//creating a stop condition will free the BUS thus turning the BB == 0.
         I2caRegs.I2CMDR.bit.STT = 1; 		// As soon as you start the Start Bit the BB == 1 becomes busy again.
         return ;
    }

    *****Slave*******

    And for the slave side please find the code attached.

    5873.Slave RX.txt
    #define I2C_SLAVE_OWN_ADDR        0x0055
    #define I2C_NUMBYTES          1
    
    void main(void){
    
        InitSysCtrl();
    
        InitI2CGpio();
    
        I2CASlave_init();
        DELAY_US(1000000);
    
     for(;;)
     {
        I2CA_ReceiveData();
     }
     }
    
    void I2CASlave_init(void)
    {
        I2caRegs.I2COAR = I2C_SLAVE_OWN_ADDR;       // Slave address 
    
        I2caRegs.I2CPSC.all = 6;        // Prescaler - need 7-12 Mhz on module clk
        I2caRegs.I2CCLKL = 10;          // NOTE: must be non zero
        I2caRegs.I2CCLKH = 5;           // NOTE: must be non zero
    
        I2caRegs.I2CIER.all = 0x00;     // sorry don't enable anything
        I2caRegs.I2CMDR.bit.MST = 0; // Enter the slave mode // if MST = 0 and FDF = 0 TRX is a don't care.Dependging upon command from the master module responds as a Rx or Tx.
        //I2caRegs.I2CMDR.bit.TRX = 0;  //receive mode --> commented because its in a don't care condition refer Table 7 from I2C document for TMS320F28035
        I2caRegs.I2CMDR.bit.FREE = 0 ;       // Runs in free mode setting it to zero will stop when data is received.l
        I2caRegs.I2CMDR.bit.IRS = 1;   // enable the IRS
    
    }
    
    void I2CA_ReceiveData(void)
    {
        Uint16 i = 0;
        //while(!I2caRegs.I2CSTR.bit.RRDY ) ;
    
        I2caRegs.I2COAR = I2C_SLAVE_OWN_ADDR;       // Slave address 
    
        while(I2caRegs.I2CSTR.bit.AAS != 1){};  //***** This is where I am trying to check if my slave could actually Recognize itself.
    
    
           // i++;
    
            Receive_Data[0] = I2caRegs.I2CDRR ;
            GREENLED_ON;
            I2caRegs.I2CMDR.bit.MST = 0;
            I2caRegs.I2CMDR.bit.FREE = 0 ;
    
        	REDLED_OFF;
    
        return;
    }

    As far as the slave is concerned I am just trying to receive as of now .So I am polling the Address as a slave bit interrupt flag. i.e. the AAS to check if its 1 which is desired , which tells me that Slave has established contact with the Master and is able to verify itself as slave. And an increment in the variable would help me verify the same.

    I know my code has lot of errors , but I would really appreciate if you could give me a heads up on the slave side code. I don't know if I am on the right track, because there is very little documentation or examples for the Slave side.

  • Thank you for the additional information. I don't think your code is too far off.

    Where is your code on the slave side if you halt the execution? Is it stuck at the while loop that's checking the AAS bit? What is the state of the I2CSTR register if you look at it in the Registers window (open under View -> Registers while debugging and halt the application).

    Whitney
  • Yes, you are right ! so I have my Master side program in the flash (F2035) and whenever I try to send a byte my master would just hang up after sending a slave address i.e. the clock is left low(observed on the oscillioscope), because it waits for an acknowledgement.(Which is totally fine !)

    Then on the slave side an ACK would be generated if the slave address it receives from master matches with the I2COAR (I assume).
    If both addresses match an Addressed As Slave(AAS) flag would be set . *****This is where my code gets stuck , the AAS bit never gets set*****
    I think setting of the AAS flag is what could be considered the first step of I2C communication.

    As far as the status of the I2CSTR is only 2 bits are set(1) --> XRDY and XSMT. Rest are cleared to 0. And I observed that these 2 bits are always set, even before the I2CASlave_init and stay the same after I2CSlave_init . And when I tried to clear them it won't accept the values and would go back to being 1. But I am not sure how it affects my code execution.

    I am pretty sure I am wrong on the slave side, could you recommend me any changes? But any help is appreciated.
  • If you put a breakpoint on the line where you write to Receive_Data[0], does it ever get hit? It is possible that AAS could be getting set and then cleared again by a stop condition, so just halting to see if it's stuck at the loop at any point in time isn't necessarily meaningful.

    If it's waiting for an ACK from the slave with the bus held low, I'm a little surprised you don't see the BB bit being set. Can you double check your GPIO configuration and hardware connections? What are you using for pull ups? Just the internal ones on the device or external ones?

    Whitney
  • * Below is my updated Code for the slave. This only contains I2C_Slave_init()   and the I2C_ReceiveData().I didn't include the main  part because it's the same.
     * I am pretty sure my program doesn't set the AAS flag because if it did The variable "i" would have incremented and the GREEN LED would have glowed at least for a second ( which it is not).

    * And YES my BB is set after a START bit and the address sent. As the master waits for an ACK the clock is pulled low and I2CSTR.bit.BB == 1 which indicates the bus is busy.

    * The STR flags bits XSMT and XRDY are set after and I2C enable. (BEFORE SENDING)
    *But, the STR bits that are set after sending a byte are NACK, ARDY,  XSMT, BB i.e. all are 1, rest are 0.(AFTER SENDING)


    *For the external Pull-ups I have 4.7K resistors both on SDA and SCL lines.
    ##########################################Master_transmit()######################################################
    void  I2CA_WriteData(void){

         I2caRegs.I2CSAR = I2C_SLAVE_ADDR;           //slave address register

         //Check if busy
         while(I2caRegs.I2CSTR.bit.BB == 1)  {};

         I2caRegs.I2CCNT = 1 ;                                       //data count is 1 byte
     
         I2caRegs.I2CDXR = DataTransmit[1] ;       //Data transmit is an array containing some data
     
         I2caRegs.I2CMDR.bit.TRX = 1;
         I2caRegs.I2CMDR.bit.MST = 1;
         I2caRegs.I2CMDR.bit.FREE = 1;

         I2caRegs.I2CMDR.bit.STP = 1;                   //creating a stop condition will free the BUS thus turning the BB == 0.
         I2caRegs.I2CMDR.bit.STT = 1;                   // As soon as you start the Start Bit the BB == 1 becomes busy again.

         return ;
    }

    *****************************Slave Side Init && Receive code **************************************************************************
    void I2C_Slave_init(void)
    {
        I2caRegs.I2COAR = I2C_SLAVE_OWN_ADDR;       // Slave address -

        I2caRegs.I2CPSC.all = 6;        // Prescaler - need 7-12 Mhz on module clk
        I2caRegs.I2CCLKL = 10;          // NOTE: must be non zero
        I2caRegs.I2CCLKH = 5;           // NOTE: must be non zero

        I2caRegs.I2CIER.bit.XRDY =1;
        I2caRegs.I2CIER.bit.RRDY = 1;
        I2caRegs.I2CIER.bit.ARDY = 1;
        I2caRegs.I2CIER.bit.AAS = 1;     //Just enabling the Addressed as a slave interrupt.

        I2caRegs.I2CMDR.bit.MST = 0; // Enter the slave mode // if MST = 0 and FDF = 0 TRX is a don't care.Dependging upon command from the  master module responds as a Rx or Tx.
     
       //I2caRegs.I2CMDR.bit.TRX = 0;  //receive mode --> commented because its in a don't care condition refer Table 7 from I2C
        //I2caRegs.I2CMDR.bit.FREE = 1 ;       // Runs in free mode setting it to zero will stop when data is received.l
        
       I2caRegs.I2CMDR.bit.IRS = 1;   // enable the IRS
        I2caRegs.I2CSTR.all = 0 ;

        return;
    }

    void I2CA_ReceiveData(void)
    {
        Uint16 i = 0;
        //while(!I2caRegs.I2CSTR.bit.RRDY ) ;

        I2caRegs.I2COAR = I2C_SLAVE_OWN_ADDR;       // Slave address
        I2caRegs.I2CCNT = 1 ; //Receive count to 1 bytes It shouldn't matter because it is in Slave receiver mode

        I2caRegs.I2CMDR.bit.MST = 0;
        I2caRegs.I2CMDR.bit.NACKMOD = 0;

        while(I2caRegs.I2CSTR.bit.AAS == 1){

            i++;
            Receive_Data[0] = I2caRegs.I2CDRR ;
            GREENLED_ON;
            REDLED_OFF;
            delay_cycles(FSYSCLK);       // wait 1 second

        }

    **************************************************************************************************************************************

  • Sorry for the delayed response. Like I said in an earlier message AAS is cleared by a stop condition, so unless you're calling I2CA_ReceiveData() with perfect timing, you're probably going to miss AAS being set. I think you're better off polling RRDY instead.

    Do you have an oscilloscope or logic analyzer capture of what is happening on SDA and SCL?

    Thanks,
    Whitney
  • Any progress on this issue?

    Edit: Since I haven't heard back from you, I'm going to assume that you've resolved the issue. If that's not the case though, please feel free to reject the answer and add a new reply to the thread!

    Whitney