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.

Problem with i2c i/o expander PCA9539 with TM4C123H6PZI

Other Parts Discussed in Thread: PCA9539, TCA9539, TM4C123GH6PZ

Hi,

            I am a  beginner to TI controller, I have interface 24 inputs to controller via i/o expanders PCA9539, but sometime i face problem of i/o expander looses its configuration and displays all the input, In my application these inputs are nothing but faults of the system like Water overflow fault, low level fault etc.... which I should display on the screen whenever it will occur, but now it is showing all the faults simultaneously...so i think the i/o expander hang in this case shows all faults or i am wrong in i2c configuration.  Please go through the code and help me if you can.  

/*********************************************************************************************

* Function: I2C_Configure

* Description: Configures three IO Expander chips to input and output as per functionality

*

********************************************************************************************/

void I2C_Configure(void)

{

       //Configure U48 TCA9539 with Both Ports as Output

       I2C_Slave_Configure_Write(EXP_0_Addr, 0x00, 0x00);

 

       //Configure U49 TCA9539 with Port0 as Output and Port1 as Input

       I2C_Slave_Configure_Write(EXP_1_Addr, 0x00, 0xFF);

 

       //Configure U50 TCA9539 with Both Ports as Input

       I2C_Slave_Configure_Write(EXP_2_Addr, 0xFF, 0xFF);

}

Here is an Initialization calls

//======================================================================

       //I2C init (PB2 -> SCL) (PB3 -> SDA)

       //======================================================================

       GPIOPinTypeI2CSCL(I2C_PORT, EXP_SCL_PIN); // I2CSCL

       GPIOPinTypeI2C(I2C_PORT, EXP_SDA_PIN);

 

       GPIOPinConfigure(GPIO_PB2_I2C0SCL);

       GPIOPinConfigure(GPIO_PB3_I2C0SDA);

       GPIOPadConfigSet(I2C_PORT,EXP_SDA_PIN,GPIO_STRENGTH_2MA,GPIO_PIN_TYPE_OD);

       HWREG(I2C0_BASE + I2C_O_MCR2) |= I2C_MCR2_GFPW_M; // Set to 31 clock glitch filter

       HWREG(I2C0_BASE + I2C_O_MCR) |= I2C_MCR_GFE;

       I2CMasterInitExpClk(I2C0_BASE, SysCtlClockGet(), false);// "False", 3rd argument, specifies slow transfer mode of 100Kbps i.e.STANDARD Mode

 

  • Hello Girish,

    After the IO configuration, the following lines are not required

    GPIOPadConfigSet(I2C_PORT,EXP_SDA_PIN,GPIO_STRENGTH_2MA,GPIO_PIN_TYPE_OD);

    How is the function I2C_Slave_Configure_Write prototyped?

    Regards
    Amit
  • Thanks for your reply Amit, As you said there is no need to add these lines    "GPIOPadConfigSet(I2C_PORT,EXP_SDA_PIN,GPIO_STRENGTH_2MA,GPIO_PIN_TYPE_OD);"

    But in the datasheet of TM4c123GH6PZ it is mentioned that 

    " Each I2C module is comprised of both master and slave functions and is identified by a unique
    address. A master-initiated communication generates the clock signal, SCL. For proper operation,
    the SDA pin must be configured as an open-drain signal. Due to the internal circuitry that supports
    high-speed operation, the SCL pin must not be configured as an open-drain signal, although the
    internal circuitry causes it to act as if it were an open drain signal. Both SDA and SCL signals must
    be connected to a positive supply voltage using a pull-up resistor."

    so to set the SDA pin as an open drain GPIOPadConfigSet is used, in which GPIO_PIN_TYPE_OD parameter means OD - stands for ---Open Drain. So please rethink about this point. And second thing you asked about "How is the function I2C_Slave_Configure_Write prototyped?" for that please go through the following code

     

    /*********************************************************************************************

    * Function: I2C_Slave_Configure_Write

    * Arguments:        unsigned char ucSlaveAddr, contains the address of slave IO expander chip

    *                         unsigned char Port0_cnfg, contains port 0 pin configuration value;

    *                         0 sets the port pin as output and 1 sets the port pin as input

    *                         unsigned char Port1_cnfg, contains port 1 pin configuration value;

    * Description: Configures ucSlaveAddr IO Expander ports to the configuration defined by

    *                         Port0_cnfg and Port1_cnfg

    *

    ********************************************************************************************/

    void I2C_Slave_Configure_Write(unsigned char ucSlaveAddr,

                  unsigned char Port0_cnfg, unsigned char Port1_cnfg)

    {

           I2CMasterSlaveAddrSet(I2C0_BASE, ucSlaveAddr, false); // The address of the Slave----- False means write to the slave

     

           //

           // Place the data to be sent in the data register

           //

           I2CMasterDataPut(I2C0_BASE, 0x06); // Addr of config

     

           //

           // Initiate send of data from the master. Since the loopback

           // mode is enabled, the master and slave units are connected

           // allowing us to receive the same data that we sent out.

           //

           I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_SEND_START);

     

           //

           while(I2CMasterBusy(I2C0_BASE));

     

     

           I2CMasterDataPut(I2C0_BASE, Port0_cnfg); // Port0 output

     

           //

           // Initiate send of data from the master. Since the loopback

           // mode is enabled, the master and slave units are connected

           // allowing us to receive the same data that we sent out.

           //

           I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_SEND_CONT);

     

           //

           while(I2CMasterBusy(I2C0_BASE));

     

           I2CMasterDataPut(I2C0_BASE, Port1_cnfg); // Port1 output

     

           //

           // Initiate send of data from the master. Since the loopback

           // mode is enabled, the master and slave units are connected

           // allowing us to receive the same data that we sent out.

           //

           I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_SEND_FINISH);

     

           //

           while(I2CMasterBusy(I2C0_BASE));

    }

  • Hello Girish,

    The GPIOPinTypeI2C and GPIOPinTypeI2CSCL handle the same, so that the user does not need to..

    The Write code seems fine to me. Since you mentioned that you are reading from the IO Expander, what does the read API look like and when it fails did you check the I2C Bus to see what the bus transaction is? A scope or LA snapshot will be useful.

    Regards
    Amit
  • Hello Amit Sir,
                     Yes I am reading from the I/O expander (for different fault occurs in my application) and if any fault occur i will take necessary action using TM4C123GH6PZ. I used 3 I/O expanders to accept 24 faults as an input to TM4C controller and depending on that i will take necessary action so for that i used 24 pins of these 3 expanders as an output. I am just reading for fault occur on I2C using interrupt if any then take action but as you asked   
     " what does the read API look like and when it fails did you check the I2C Bus to see what the bus transaction is?"
                       I am not doing anything if I2C read fail and I consider that no fault occur and everything going ok, Here is my read API please go through it

    /*********************************************************************************************

    * Function:  Periodic_Pos_WT5A_intr

    * Description: Wide Timer 5A periodic interrupt. It interrupts after every

    *                         10ms.It reads the position Z value each time for correct

    *                         functioning of machine. And alternatively processes communication

    *                         function, reads position X and I2C interrupts, or reads position Y.

    *

    ********************************************************************************************/

    void Periodic_Pos_WT5A_intr(void)

    {

           static int PositionCount=0;

           static bool HMIRefreshtrue=true;

           unsigned int read;

           bool I2CinputProcess=false;

           unsigned long I2C_dataIn;

           unsigned long I2C_dataIn1, I2C_dataIn2;

     

           TimerIntClear(WTIMER5_BASE, TIMER_TIMA_TIMEOUT);

           TimerDisable(WTIMER5_BASE, TIMER_A);

           switch(PositionCount)

           {

           case 0:

                  if(boolStartCommunication) //false when No data pending so enter into EDIT mode

                  {

                         if(boolHMIRequest) //Indicates data pending at HMI end

                               HMIRequest();   // Sends character to ask for pending data from HMI

                         else               //No data pending so Display won't send so send DRO values to Display from main uC

                         {

                               if(HMIRefreshtrue)

                                      HMIRefresh();

                               HMIRefreshtrue = (HMIRefreshtrue? false:true);

                         }

                  }

                  PositionCount++;

                  break;

           case 1:

                  GET_X_Pos();

     

                  read = GPIOPinRead(I2C_EXP_INT_PORT, EXP_0_INT | EXP_1_INT );

     

                  if((read & 0x01)==0x00)

                  {

                         I2C_dataIn2= I2C_INPUTS&0x0000FFFF;

     

                         //EXP_0_INT

                         //Read data from U49 Port1

                         I2C_dataIn = I2C_Input_Read(EXP_1_Addr, I2C_Input_Port1_Read);

     

                         if(I2C_dataIn == 0xFF)

                               I2C_dataIn = I2C_Input_Read(EXP_1_Addr, I2C_Input_Port1_Read);

     

                         I2C_dataIn1 = ((I2C_dataIn & 0x000000FF)<<16);

                         I2C_INPUTS = (I2C_dataIn1 | I2C_dataIn2);

     

                         I2CinputProcess=true;

                  }

     

                  if((read & 0x02)==0x00)

                  {

                         I2C_dataIn1= I2C_INPUTS&0x00FF0000;

     

                         //EXP_1_INT interrupt occurred

                         //Read data from U50 Port1

                         I2C_dataIn = I2C_Input_Read(EXP_2_Addr, I2C_Input_Port1_Read);

                         I2C_dataIn2 = ((I2C_dataIn & 0x000000FF)<<8);

     

                         //Read data from U50 Port0

                         I2C_dataIn = I2C_Input_Read(EXP_2_Addr, I2C_Input_Port0_Read);

                         I2C_dataIn2 |= (I2C_dataIn & 0x000000FF);

                         I2C_INPUTS = (I2C_dataIn1 | I2C_dataIn2);

     

                         I2CinputProcess=true;

                  }

                  if(I2CinputProcess)

                  {

                         //Call function to take action

                         I2C_Input_Response();

                  }

                  PositionCount++;

                  break;

           default:

                  GET_Y_Pos();

                  PositionCount=0;

                  break;

           }

           GET_Z_Pos();

            TimerEnable(WTIMER5_BASE, TIMER_A);

    }

     

  • Sorry I forgot to attach I2C Read function, please go through the following code

    /*********************************************************************************************
     * Function:     I2C_Input_Read
     * Arguments:     unsigned char ucSlaveAddr, contains address of IO Expander
     *                 unsigned char I2C_In_Port_Reg_Addr, contains address of Input register
     *                 of IO Expander. 0x00 for port0 input register and 0x01 for port1 input register.
     * Description: Reads value from the given port of IO Expander.
     *
     ********************************************************************************************/
    unsigned long I2C_Input_Read(unsigned char ucSlaveAddr,
            unsigned char I2C_In_Port_Reg_Addr)
    {
        unsigned long data;

        I2CMasterSlaveAddrSet(I2C0_BASE, ucSlaveAddr, false);

        I2CMasterDataPut(I2C0_BASE, I2C_In_Port_Reg_Addr); // Addr of input port register

        //
        // Initiate send of data from the master. Since the loopback
        // mode is enabled, the master and slave units are connected
        // allowing us to receive the same data that we sent out.
        //
        I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_SINGLE_SEND);

        //
        while(I2CMasterBusy(I2C0_BASE));

        //
        // Receive data from slave
        //
        I2CMasterSlaveAddrSet(I2C0_BASE, ucSlaveAddr, true);
        //
        I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_SINGLE_RECEIVE);

        //
        while(I2CMasterBusy(I2C0_BASE));

        data = I2CMasterDataGet(I2C0_BASE); //Receive

        return(data);
    }

  • Hello Girish,

    Since there is a Repeated Start during a read operation, I would suggest using I2C_MASTER_CMD_BURST_SEND_START instead of I2C_MASTER_CMD_SINGLE_SEND during the read operation.

    Regards
    Amit