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.

TM4C1230E6PM: Having issues with I2c behavior

Part Number: TM4C1230E6PM
Other Parts Discussed in Thread: PCF8574

Hello all, I'm having issues with the tivaware commands for I2c.  I need to send two bytes of info to the I2C slave (MCP23017 16 bit IO expander) mounted on a small PCA.  I have verified the PCA works properly with an Arduino and example code.

According to SPMA073, I2C_MASTER_CMD_BURST_SEND_START  is supposed to send the start bit, slave address, cleared write bit, and the additional byte command in I2CMDR entered with I2CDataPut.  The second byte of data can then be sent with I2C_MASTER_CMD_BURST_SEND_FINISH.  This would suggest that basically the start bit, slave address, write bit, and two bytes are sent in this way.

My problem is that I2C_MASTER_CMD_BURST_SEND_START does not appear to be sending the byte entered in I2CMDR.  Please see my code below, and the attached scope shot of the I2C send on the bus.  If I have incorrect code, or have a misunderstanding of how the process should work, please let me know.  Thanks for all responses.

#include <__cross_studio_io.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include "inc/hw_i2c.h"
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "inc/hw_ints.h"
#include "driverlib/i2c.h"
#include "driverlib/interrupt.h"
#include "driverlib/sysctl.h"
#include "driverlib/timer.h"
#include "driverlib/gpio.h"
#include "driverlib/uart.h"
#include "driverlib/pin_map.h"
#include "driverlib/debug.h"
#include "driverlib/rom.h"

#ifdef DEBUG
void
__error__(char *pcFilename, uint32_t ui32Line)
{
}
#endif

uint8_t opcode = 0x27; //MCP23017 with A0 through A2 set as High

//initialize I2C module 5
void InitI2C5(void)
{

    //enable I2C module 0
    SysCtlPeripheralDisable(SYSCTL_PERIPH_I2C5);
    SysCtlPeripheralReset(SYSCTL_PERIPH_I2C5);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_I2C5);

    while(!SysCtlPeripheralReady(SYSCTL_PERIPH_I2C5));

    // Enable and initialize the I2C5 master module.  Use the system clock for
    // the I2C5 module.  The last parameter sets the I2C data transfer rate.
    // If false the data rate is set to 100kbps and if true the data rate will
    // be set to 400kbps.
    I2CMasterInitExpClk(I2C5_BASE, SysCtlClockGet(), false);

    //enable GPIO peripheral that contains I2C 5
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
 
    // Configure the pin muxing for I2C5 functions on port B6 and B7.
    GPIOPinConfigure(GPIO_PB6_I2C5SCL);
    GPIOPinConfigure(GPIO_PB7_I2C5SDA);
     
    // Select the I2C function for these pins.
    GPIOPinTypeI2CSCL(GPIO_PORTB_BASE, GPIO_PIN_6);
    GPIOPinTypeI2C(GPIO_PORTB_BASE, GPIO_PIN_7);

    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOC);
    SysCtlDelay(1);
    //
    // Configure LED pins as outputs.
    //
    GPIOPinTypeGPIOOutput(GPIO_PORTC_BASE, GPIO_PIN_5 | GPIO_PIN_6);

}

void main(void)
{
    // Set the clocking to run directly from the external crystal/oscillator.
     SysCtlClockSet(SYSCTL_SYSDIV_4 | SYSCTL_USE_PLL | SYSCTL_XTAL_16MHZ | SYSCTL_OSC_MAIN);

    //initialize I2C module 5
    InitI2C5();

     //Turn I2C power on.
     GPIOPinWrite(GPIO_PORTC_BASE, GPIO_PIN_5, GPIO_PIN_5);

    while(1)
    {
     //Turn Red LED on.
     //GPIOPinWrite(GPIO_PORTC_BASE, GPIO_PIN_6, GPIO_PIN_6);

     SysCtlDelay(5000000); 

        // Wait until MCU is done transferring.
        while(I2CMasterBusBusy(I2C5_BASE)) {}

         // Tell the master module what address it will place on the bus when
         // communicating with the slave.
        I2CMasterSlaveAddrSet(I2C5_BASE, opcode, false);

//-------------------------------------------------------------------   
         //Configure MCP23017 IODIRB output pins     
         //put data to be sent into FIFO
         I2CMasterDataPut(I2C5_BASE, 0x13);
       
         //Initiate send of data from the MCU
        I2CMasterControl(I2C5_BASE, I2C_MASTER_CMD_BURST_SEND_START);
       
        // Wait until MCU is done transferring.
        while(I2CMasterBusBusy(I2C5_BASE)) {}

        //Check for errors
        if (I2CMasterErr(I2C5_BASE) != I2C_MASTER_ERR_NONE)
          {
            //Turn Red LED on.
	    GPIOPinWrite(GPIO_PORTC_BASE, GPIO_PIN_5, GPIO_PIN_5);
          }

         //put data to be sent into FIFO
         I2CMasterDataPut(I2C5_BASE, 0x55);
       
         //Initiate send of data from the MCU
        I2CMasterControl(I2C5_BASE, I2C_MASTER_CMD_BURST_SEND_FINISH);
       
        // Wait until MCU is done transferring.
        while(I2CMasterBusBusy(I2C5_BASE)) {}

        //Check for errors
        if (I2CMasterErr(I2C5_BASE) != I2C_MASTER_ERR_NONE)
          {
            //Turn Red LED on.
	    GPIOPinWrite(GPIO_PORTC_BASE, GPIO_PIN_5, GPIO_PIN_5);
          }
//-------------------------------------------------------------------

     //Turn Red LED off.
     //GPIOPinWrite(GPIO_PORTC_BASE, GPIO_PIN_6, 0);

     SysCtlDelay(5000000); 

    }
}

  • Sorry, I don't see the issue just looking at the code. It looks very similar to the examples I have. I am not in the office and may have to dig further on Monday.

    //*****************************************************************************
    //
    // Copyright (c) 2012-2020 Texas Instruments Incorporated.  All rights reserved.
    // Software License Agreement
    // 
    // Texas Instruments (TI) is supplying this software for use solely and
    // exclusively on TI's microcontroller products. The software is owned by
    // TI and/or its suppliers, and is protected under applicable copyright
    // laws. You may not combine this software with "viral" open-source
    // software in order to form a larger program.
    // 
    // THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
    // NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
    // NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    // A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
    // CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
    // DAMAGES, FOR ANY REASON WHATSOEVER.
    // 
    //*****************************************************************************
    
    #include <stdint.h>
    #include <stdbool.h>
    #include "inc/hw_types.h"
    #include "inc/hw_memmap.h"
    #include "driverlib/sysctl.h"
    #include "driverlib/gpio.h"
    #include "driverlib/i2c.h"
    #include "driverlib/pin_map.h"
    
    void I2CWriteRegister(uint8_t reg, uint8_t value);
    
    int main()
    {
    
        SysCtlClockSet(SYSCTL_SYSDIV_4|SYSCTL_USE_PLL|SYSCTL_OSC_MAIN|SYSCTL_XTAL_16MHZ);
    
        //Enable I2C Module 0
        SysCtlPeripheralEnable(SYSCTL_PERIPH_I2C0);
    
        //enable GPIO peripheral that contains I2C 0
        SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
    
        // Configure the pin muxing for I2C0 functions on port B2 and B3.
        GPIOPinConfigure(GPIO_PB2_I2C0SCL);
        GPIOPinConfigure(GPIO_PB3_I2C0SDA);
    
        // Select the I2C function for these pins.
        GPIOPinTypeI2CSCL(GPIO_PORTB_BASE, GPIO_PIN_2);
        GPIOPinTypeI2C(GPIO_PORTB_BASE, GPIO_PIN_3);
    
        //Initialize the Master and Slave
        I2CMasterInitExpClk(I2C0_BASE, SysCtlClockGet(), false);
    
        //Identify Slave Address
        I2CMasterSlaveAddrSet(I2C0_BASE, 0x55, false);
    
        ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    
        //Send Data Bytes to Slave Sub Addresses as described above???? ///
        I2CWriteRegister(0x25u, 0x05u);
        I2CWriteRegister(0x27u, 0x03u);
        I2CWriteRegister(0x29u, 0x08u);
    
        ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    
        
        return 0;
    }
    
    void I2CWriteRegister(uint8_t reg, uint8_t value)
    {
        I2CMasterDataPut(I2C0_BASE, reg);
        I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_SEND_START);
        while(I2CMasterBusy(I2C0_BASE));
        I2CMasterDataPut(I2C0_BASE, value);
        I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_SEND_FINISH);
        while(I2CMasterBusy(I2C0_BASE));
    }
    

  • Hi -- the code looks OK to me. What is the value of opcode? (For some reason Microchip calls the slave address an "opcode." Weird.) Knowing that would at least let us check to see whether the address phase of the transfer is correct. Although it's acknowledged so the expander is happy. 

    The byte sent out in the 'scope trace is the 0x55 you load in line 110, not the 0x13 indicated in line 94.  It's as if the call in line 94 is not being executed. Maybe step through it in the debugger?

  • Hi Bob and Andy, thanks for the replies.  The opcode of the MCP23017 is 0100111, all address bits are pulled high, so that first byte on the scope looks right to me.  As another check, I tweaked the code to run on I2C2 on a Launchpad with a TMC1230 (the original code is running on a prototype PCB), and got an identical result.  Indeed it is debugger time; unfortunately I only code about once a year and have to relearn the details.  Disappointed  But indeed thanks for confirming that the code looks right.  I'll post back here if I find anything weird.

  • I tried to reproduce the issue you have seen. I have different hardware so the slave address and the I2C port are different. I am unable to reproduce the issue you have.

        // Initialize the MPU9150
        MPU9150WriteRegister(0x6B, 0x80);
    

    void MPU9150WriteRegister(uint8_t reg, uint8_t value)
    {
        I2CMasterSlaveAddrSet(MPU9150_I2C_BASE, MPU9150_I2C_ADDRESS, false);
        I2CMasterDataPut(MPU9150_I2C_BASE, reg);
        I2CMasterControl(MPU9150_I2C_BASE, I2C_MASTER_CMD_BURST_SEND_START);
        while(I2CMasterBusy(MPU9150_I2C_BASE));
        if (I2CMasterErr(MPU9150_I2C_BASE) != I2C_MASTER_ERR_NONE)
        {
            //Turn Red LED on.
            GPIOPinWrite(GPIO_PORTG_BASE, GPIO_PIN_2, GPIO_PIN_2);
        }
        I2CMasterDataPut(MPU9150_I2C_BASE, value);
        I2CMasterControl(MPU9150_I2C_BASE, I2C_MASTER_CMD_BURST_SEND_FINISH);
        while(I2CMasterBusy(MPU9150_I2C_BASE));
        if (I2CMasterErr(MPU9150_I2C_BASE) != I2C_MASTER_ERR_NONE)
        {
            //Turn Red LED on.
            GPIOPinWrite(GPIO_PORTG_BASE, GPIO_PIN_2, GPIO_PIN_2);
        }
    
    }
    

    Let us know if you find out anything else.

  • Thanks again for all the help.  I had more success in my application changing to a different I2C part with simpler instruction requirements (I was able to confirm with the new part, a PCF8574, that I was getting bidirectional communication).  The problem is still there, but all your help has convinced me it is most likely in the compiler (Rowley Crossworks) and I just need to track it down.  My main immediate issue was to ensure the hardware path was working, which it seems to be, and I can get the next run of PCAs made.  The I2C problem is still there, but I can put that off to another day now that the hardware is verified.  As I get into the I2C integration (probably in a few months), I'll repost as soon as I find the culprit.

  • Thanks for the update. If you don't mind, I will mark your post as "TI Thinks Resolved" for now. Let us know if we can be of any additional assistance.