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/TMS320F28377S: I2C - No output at GPIO pins 42 and 43

Part Number: TMS320F28377S
Other Parts Discussed in Thread: C2000WARE

Tool/software: Code Composer Studio

I've been working on LaunchPad F28377S for a while now. I recently got an OLED I2C display to work with. In TMS320F28377S technical reference guide, they mentioned GPIOs 42,43 and GPIOs 91,92 both for I2C-A. But I decided to settle on the GPIOs 42 and 43. I couldn't get any output at those pins (neither clock nor data). I've tried GPIOs 91, 92 but in vain. Here's my code:

#include "F28x_Project.h"
/**
 * main.c
 */

#define OLED_I2C_ADDRESS   0x3C

// Control byte
#define OLED_CONTROL_BYTE_CMD_SINGLE    0x0080
#define OLED_CONTROL_BYTE_CMD_STREAM    0x0000
#define OLED_CONTROL_BYTE_DATA_STREAM   0x0040

// Fundamental commands (pg.28)
#define OLED_CMD_SET_CONTRAST           0x0081    // follow with 0x7F
#define OLED_CMD_DISPLAY_RAM            0x00A4
#define OLED_CMD_DISPLAY_ALLON          0x00A5
#define OLED_CMD_DISPLAY_NORMAL         0x00A6
#define OLED_CMD_DISPLAY_INVERTED       0x00A7
#define OLED_CMD_DISPLAY_OFF            0x00AE
#define OLED_CMD_DISPLAY_ON             0x00AF

// Addressing Command Table (pg.30)
#define OLED_CMD_SET_MEMORY_ADDR_MODE   0x0020    // follow with 0x00 = HORZ mode = Behave like a KS108 graphic LCD
#define OLED_CMD_SET_COLUMN_RANGE       0x0021    // can be used only in HORZ/VERT mode - follow with 0x00 and 0x7F = COL127
#define OLED_CMD_SET_PAGE_RANGE         0x0022    // can be used only in HORZ/VERT mode - follow with 0x00 and 0x07 = PAGE7

// Hardware Config (pg.31)
#define OLED_CMD_SET_DISPLAY_START_LINE 0x0040
#define OLED_CMD_SET_SEGMENT_REMAP      0x00A1
#define OLED_CMD_SET_MUX_RATIO          0x00A8    // follow with 0x3F = 64 MUX
#define OLED_CMD_SET_COM_SCAN_MODE      0x00C8
#define OLED_CMD_SET_DISPLAY_OFFSET     0x00D3    // follow with 0x00
#define OLED_CMD_SET_COM_PIN_MAP        0x00DA    // follow with 0x12
#define OLED_CMD_NOP                    0x00E3    // NOP

// Timing and Driving Scheme (pg.32)
#define OLED_CMD_SET_DISPLAY_CLK_DIV    0x00D5    // follow with 0x80
#define OLED_CMD_SET_PRECHARGE          0x00D9    // follow with 0xF1
#define OLED_CMD_SET_VCOMH_DESELCT      0x00DB    // follow with 0x30

// Charge Pump (pg.62)
#define OLED_CMD_SET_CHARGE_PUMP        0x008D    // follow with 0x14

void oled_init(Uint16 Slave_address);
void I2C_Write(Uint16 Slave_address, Uint16 No_of_databytes, Uint16 Write_Array[]);
void I2C_WriteByte(Uint16 Slave_address, Uint16 databyte);
Uint16 pattern1[17] = {0x0040,0x0000,0x007E,0x0042,0x0042,0x0042,0x0042,0x007E,0x0000,0x0000,0x007E,0x0042,0x0042,0x0042,0x0042,0x007E,0x0000};
void i2c_a_gpio_init (void);
void I2CA_Init();
int main(void)
{uint32_t i;
    InitSysCtrl();
    InitGpio();

    i2c_a_gpio_init ();

    InitPieCtrl();
    InitPieVectTable();
    I2CA_Init();
        I2caRegs.I2CMDR.bit.IRS = 0;
    I2caRegs.I2CPSC.all = 19;    // I2C clock should be between 7Mhz-12Mhz
        I2caRegs.I2CCLKL = 45;      // Prescalers set for 100kHz bit rate
        I2caRegs.I2CCLKH = 45;      // At a 10Mhz I2C clock
        I2caRegs.I2CMDR.bit.IRS = 1;

    Uint16 Slave_address = 0x003C;
    oled_init(Slave_address);
    Uint16 write_array[7] = {OLED_CONTROL_BYTE_CMD_STREAM,OLED_CMD_SET_COLUMN_RANGE,0x0000,0x007F,OLED_CMD_SET_PAGE_RANGE,0x0000,0x0007};
    I2C_Write(Slave_address, 7, write_array);
    I2C_Write(Slave_address,17, pattern1);

	return 0;
}
void I2C_Write(Uint16 Slave_address, Uint16 No_of_databytes, Uint16 Write_Array[])
{
/*Uint16 i = 0;

I2caRegs.I2CSAR.all = Slave_address;
while(I2caRegs.I2CMDR.bit.STP != 0);

I2caRegs.I2CMDR.all = 0x2620;

I2caRegs.I2CCNT = No_of_databytes;
// Data Bytes to be transmitted
while(i < No_of_databytes)
{
while(I2caRegs.I2CSTR.bit.XRDY != 1);
 DSP28x_usDelay(5000);
if (I2caRegs.I2CSTR.bit.XRDY == 1)
{
I2caRegs.I2CDXR.all = Write_Array[i++]; // Lower 16 address bits
}
}


while(I2caRegs.I2CSTR.bit.SCD != 1);
I2caRegs.I2CSTR.bit.SCD = 1; // Clear stop condition */

    I2caRegs.I2CMDR.bit.IRS = 1;                // reset I2C

        // Make sure I2C is not busy and has stopped
        while (I2caRegs.I2CSTR.bit.BB == 1);        // busy loop
        I2caRegs.I2CSTR.bit.SCD = 1;                // Clear the SCD bit (stop condition bit)
        while(I2caRegs.I2CMDR.bit.STP == 1);        // stop bit loop

        I2caRegs.I2CSAR.all = Slave_address;                     // I2C slave address
        while (I2caRegs.I2CSTR.bit.BB == 1);        // still busy?

        I2caRegs.I2CCNT = No_of_databytes;                        // assume register address = 1 byte, and data is 1 byte

        //I2caRegs.I2CMDR.all = 0x6E20;                 // start, stop, no rm, reset i2c  01101110 00100000
        I2caRegs.I2CMDR.bit.NACKMOD = 0;            // NACK mode bit
        I2caRegs.I2CMDR.bit.FREE = 1;               // Run free I2C when suspended
        I2caRegs.I2CMDR.bit.STT = 1;                // START condition bit
        I2caRegs.I2CMDR.bit.STP = 1;                // STOP condition bit
        I2caRegs.I2CMDR.bit.MST = 1;                // Master mode
        I2caRegs.I2CMDR.bit.TRX = 1;                // Transmitter mode
        I2caRegs.I2CMDR.bit.XA = 0;                 // 7-bit addressing mode
        I2caRegs.I2CMDR.bit.RM = 0;                 // Nonrepeat mode
        I2caRegs.I2CMDR.bit.DLB = 0;                // Digital loopback mode is disabled
        I2caRegs.I2CMDR.bit.IRS = 1;                // The I2C module is enabled
        I2caRegs.I2CMDR.bit.STB = 0;                // The I2C module is not in the START byte mode
        I2caRegs.I2CMDR.bit.FDF = 0;                // Free data format mode is disabled
        I2caRegs.I2CMDR.bit.BC = 0;                 // 8 bits per data byte


        Uint16 i;
        for(i=0;i<No_of_databytes;i++)
        {
        while(I2caRegs.I2CSTR.bit.XRDY == 0);       // Do nothing till bus is free
        I2caRegs.I2CDXR.all = Write_Array[i];                     // data to be sent (1 byte)
        }
        I2caRegs.I2CMDR.bit.STP = 1;                // stop bit when CNT=0

        while(!I2caRegs.I2CSTR.bit.SCD);        // wait for STOP condition


}
void I2C_WriteByte(Uint16 Slave_address, Uint16 databyte)
{
    Uint16 arr[1] = {databyte};
    I2C_Write(Slave_address, 1, arr);
}
void oled_init(Uint16 Slave_address)
{
    I2C_WriteByte(Slave_address,OLED_CONTROL_BYTE_CMD_STREAM);

      // Follow instructions on pg.64 of the dataSheet for software configuration of the SSD1306
      // Turn the Display OFF
      I2C_WriteByte(Slave_address,OLED_CMD_DISPLAY_OFF);
      // Set mux ration tp select max number of rows - 64
      I2C_WriteByte(Slave_address,OLED_CMD_SET_MUX_RATIO);
      I2C_WriteByte(Slave_address,0x3F);
      // Set the display offset to 0
      I2C_WriteByte(Slave_address,OLED_CMD_SET_DISPLAY_OFFSET);
      I2C_WriteByte(Slave_address,0x00);
      // Display start line to 0
      I2C_WriteByte(Slave_address,OLED_CMD_SET_DISPLAY_START_LINE);

      // Mirror the x-axis. In case you set it up such that the pins are north.
      // I2C_WriteByte(Slave_address,0xA0); - in case pins are south - default
      I2C_WriteByte(Slave_address,OLED_CMD_SET_SEGMENT_REMAP);

      // Mirror the y-axis. In case you set it up such that the pins are north.
      // I2C_WriteByte(Slave_address,0xC0); - in case pins are south - default
      I2C_WriteByte(Slave_address,OLED_CMD_SET_COM_SCAN_MODE);

      // Default - alternate COM pin map
      I2C_WriteByte(Slave_address,OLED_CMD_SET_COM_PIN_MAP);
      I2C_WriteByte(Slave_address,0x12);
      // set contrast
      I2C_WriteByte(Slave_address,OLED_CMD_SET_CONTRAST);
      I2C_WriteByte(Slave_address,0x7F);
      // Set display to enable rendering from GDDRAM (Graphic Display Data RAM)
      I2C_WriteByte(Slave_address,OLED_CMD_DISPLAY_RAM);
      // Normal mode!
      I2C_WriteByte(Slave_address,OLED_CMD_DISPLAY_NORMAL);
      // Default oscillator clock
      I2C_WriteByte(Slave_address,OLED_CMD_SET_DISPLAY_CLK_DIV);
      I2C_WriteByte(Slave_address,0x80);
      // Enable the charge pump
      I2C_WriteByte(Slave_address,OLED_CMD_SET_CHARGE_PUMP);
      I2C_WriteByte(Slave_address,0x14);
      // Set precharge cycles to high cap type
      I2C_WriteByte(Slave_address,OLED_CMD_SET_PRECHARGE);
      I2C_WriteByte(Slave_address,0x22);
      // Set the V_COMH deselect volatage to max
      I2C_WriteByte(Slave_address,OLED_CMD_SET_VCOMH_DESELCT);
      I2C_WriteByte(Slave_address,0x30);
      // Horizonatal addressing mode - same as the KS108 GLCD
      I2C_WriteByte(Slave_address,OLED_CMD_SET_MEMORY_ADDR_MODE);
      I2C_WriteByte(Slave_address,0x00);
      // Turn the Display ON
      I2C_WriteByte(Slave_address,OLED_CMD_DISPLAY_ON);

}

void I2CA_Init()
{
    I2caRegs.I2CMDR.all = 0x0000;


    I2caRegs.I2CPSC.all = 8;                 // 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 = 0x24;            // Enable SCD & ARDY interrupts  0010 0100
    I2caRegs.I2CIER.bit.AAS = 0;             // Addressed as slave interrupt enable bit
    I2caRegs.I2CIER.bit.SCD = 1;             // Stop condition detected interrupt enable bit
    I2caRegs.I2CIER.bit.XRDY = 1;            // Transmit-data-ready interrupt enable bit
    I2caRegs.I2CIER.bit.XRDY = 1;            // Receive-data-ready interrupt enable bit
    I2caRegs.I2CIER.bit.ARDY = 1;            // Register-access-ready interrupt enable bit
    I2caRegs.I2CIER.bit.NACK = 0;            // No-acknowledgment interrupt enable bit
    I2caRegs.I2CIER.bit.ARBL = 0;            // Arbitration-lost interrupt enable bit

    //I2caRegs.I2CMDR.all = 0x0020;          // Take I2C out of reset,Stop I2C when suspended
    I2caRegs.I2CMDR.bit.NACKMOD = 0;         // NACK mode bit
    I2caRegs.I2CMDR.bit.FREE = 0;            // Stop I2C when suspended
    I2caRegs.I2CMDR.bit.STT = 0;             // START condition bit
    I2caRegs.I2CMDR.bit.STP = 0;             // STOP condition bit
    I2caRegs.I2CMDR.bit.MST = 1;             // Slave mode
    I2caRegs.I2CMDR.bit.TRX = 1;             // Receiver mode
    I2caRegs.I2CMDR.bit.XA = 0;              // 7-bit addressing mode
    I2caRegs.I2CMDR.bit.RM = 0;              // Nonrepeat mode
    I2caRegs.I2CMDR.bit.DLB = 0;             // Digital loopback mode is disabled
    I2caRegs.I2CMDR.bit.IRS = 1;             // The I2C module is enabled
    I2caRegs.I2CMDR.bit.STB = 0;             // The I2C module is not in the START byte mode
    I2caRegs.I2CMDR.bit.FDF = 0;             // Free data format mode is disabled
    I2caRegs.I2CMDR.bit.BC = 0;              // 8 bits per data byte

    // FIFO not used

    return;
 }


void i2c_a_gpio_init (void)
{
    EALLOW;

    // Set qualification for the selected I2C pins
    GpioCtrlRegs.GPBQSEL1.bit.GPIO42 = 3;
    GpioCtrlRegs.GPBQSEL1.bit.GPIO43 = 3;
    GpioCtrlRegs.GPBDIR.bit.GPIO43 = 1;
    // Configure which of the possible GPIO pins will be I2C_A pins
    // using GPIO registers
    GpioCtrlRegs.GPBMUX1.bit.GPIO42 = 6;
    GpioCtrlRegs.GPBMUX1.bit.GPIO43= 6;

    GpioCtrlRegs.GPBPUD.bit.GPIO43=0;
    GpioCtrlRegs.GPBPUD.bit.GPIO42=0;

    //GPIO_SetupPinMux(42, GPIO_MUX_CPU1,6);
    //GPIO_SetupPinMux(43, GPIO_MUX_CPU1,6);
    EDIS;
}

  • Hi,

    I am not an expert in I2C, but I do see one issue. 

    6 is not a value that can be put into the GPBMUX1 register bit (it only has a range from 0-3). 

    Instead, you'll need to use a combination of GPBGMUX1 and GPBMUX1 (the global and local mux, respectively).  The "Pin Multiplexing" section of the datasheet should help you configure these bits correctly.


    Thank you,
    Brett

  • Hey,
    I also tried
    GpioCtrlRegs.GPBGMUX1.bit.GPIO42 = 1;
    GpioCtrlRegs.GPBMUX1.bit.GPIO42 = 3;
    GpioCtrlRegs.GPBGMUX1.bit.GPIO43 = 1;
    GpioCtrlRegs.GPBMUX1.bit.GPIO43= 3;

    Before reading some other threads on this forum and switching to
    GpioCtrlRegs.GPBMUX1.bit.GPIO43= 6;

    Both of those codes didn't work.
    Thanks for your reply, Brett.
  • Hi,

    Based on the datasheet, GPBMUX1.bit.GPIO42/43 should be 2 (vs 3) - correct?  I think this will solve your issue.

    ===

    As mentioned, GPBMUX1's range is 0-3. If you take a look at the GPBMUX1 register definition within the F2837xS TRM, you'll see why I say what I am. 
    http://www.ti.com/lit/spruhx5

    To prove this using CCS, if you put GPBMUX1 into the variable/expressions watch window, and set a breakpoint after the your register writes are made, you are likely to see that your write of 6 actually gets put in as 2 into the register bit [6 modulo 4 = 2].


    Thank you,
    Brett

  • Hi, Brett. Thanks for your reply.

    I tried your suggestion, but I still didn't get any output. I'm getting a constant positive voltage on clock pin(GPIO 42) but neither any voltage nor ground on GPIO43 (while measuring from GPIO pins directly).

    I also tried connecting my OLED display with and without external pullups for SCA and SDA, but that didn't work either. (I used 4.7k resistors for pullups).

    One more thing I noticed was that, when I debug my code and use Step Into(F5) , the code halts at the stop condition in the end of first I2C_Write() call.

    void I2C_Write(Uint16 Slave_address, Uint16 No_of_databytes, Uint16 Write_Array[])
    {
        I2caRegs.I2CMDR.bit.IRS = 1;                
    
            // Make sure I2C is not busy and has stopped
            while (I2caRegs.I2CSTR.bit.BB == 1);        
            I2caRegs.I2CSTR.bit.SCD = 1;                
            while(I2caRegs.I2CMDR.bit.STP == 1);     
    
            I2caRegs.I2CSAR.all = Slave_address;     
            while (I2caRegs.I2CSTR.bit.BB == 1);     
    
            I2caRegs.I2CCNT = No_of_databytes;       
    
            //I2caRegs.I2CMDR.all = 0x6E20;          
            I2caRegs.I2CMDR.bit.NACKMOD = 0;         
            I2caRegs.I2CMDR.bit.FREE = 1;            
            I2caRegs.I2CMDR.bit.STT = 1;             
            I2caRegs.I2CMDR.bit.STP = 1;             
            I2caRegs.I2CMDR.bit.MST = 1;             
            I2caRegs.I2CMDR.bit.TRX = 1;             
            I2caRegs.I2CMDR.bit.XA = 0;              
            I2caRegs.I2CMDR.bit.RM = 0;              
            I2caRegs.I2CMDR.bit.DLB = 0;             
            I2caRegs.I2CMDR.bit.IRS = 1;             
            I2caRegs.I2CMDR.bit.STB = 0;             
            I2caRegs.I2CMDR.bit.FDF = 0;             
            I2caRegs.I2CMDR.bit.BC = 0;              
    
    
            Uint16 i;
            for(i=0;i<No_of_databytes;i++)
            {
            while(I2caRegs.I2CSTR.bit.XRDY == 0);    
            I2caRegs.I2CDXR.all = Write_Array[i];    
            }
            I2caRegs.I2CMDR.bit.STP = 1;             
    
            while(!I2caRegs.I2CSTR.bit.SCD);        // CODE STOPS HERE. IT DOESN'T MOVE ON.
    
    
    }
    

    I'd also tried GPIOs 91 and 92, but of no use. I honestly don't know whats the problem here, but I'm pretty sure that my Analog Discovery from DIGILINK and my OLED display are working properly.

    From my launchpad manual that came with the box, I think that I'd be needing a BoosterPack for my code to work, since I2CA SCA and I2CA SDA are connected to BoosterPack's I2C Chip(or circuitry?).

    P42 and P43 refer to GPIOs 42 and 43 respectively.

    Again thanks for your reply!.

  • Can you explain what your hardware setup is?

    Are you using wires to connect to your OLED display or is the OLED board a BoosterPack that is plugged into the LaunchPad?

    As Brett prviously mentioned, the GPIO configuration for GPIO42/GPIO43 will be as follows:
    EALLOW;
    GpioCtrlRegs.GPBGMUX1.bit.GPIO42 = 1; // group 1
    GpioCtrlRegs.GPBGMUX1.bit.GPIO42 = 2; // mux position 2
    GpioCtrlRegs.GPBGMUX1.bit.GPIO43 = 1; // group 1
    GpioCtrlRegs.GPBGMUX1.bit.GPIO43 = 2; // mux position 2
    EDIS;

    Check out the GPIO muxed pins section of the datasheet: www.ti.com/.../terminal-configuration-and-functions Scroll to find GPIO42 and GPIO43. then scroll up in the same column to the header of the table and you can see the exact settings for the GPxGMUXy and GPxMUXy registers.

    GPIO42 and GPIO43 are available on header J1.10 and J1.9 respectively. GPIO91 is at J6.59 and GPIO92 is at J6.52.

    Please adjust your GPIO mux settings and then explain how your hardware is set up and I think that we can get to a resolution quickly.

    Thanks,
    Mark
  • Hello, Mark.

    I already mentioned I changed my code according to Brett's suggestion.

    Here's my i2c_a_gpio_init() code changes:

    EALLOW;

    GpioCtrlRegs.GPBGMUX1.bit.GPIO42 = 1;

    GpioCtrlRegs.GPBMUX1.bit.GPIO42 = 2;

    GpioCtrlRegs.GPBGMUX1.bit.GPIO43 = 1;

    GpioCtrlRegs.GPBMUX1.bit.GPIO43 = 2;

    EDIS;

    And No. I'm not using an OLED BoosterPack. I'm connecting my OLED display to LaunchPad via wires. I also know where the GPIO pins are, as in my manual and in the launchpad PCB too.I asked whether I'd be needing a BoosterPack board to get the I2C to work.

    I know the display works because I ensured its working with Arduino.

    My hardware setup is simple.

    GPIOs 42 and 43 are connected to 5V pullups separately via two 4.7k resistors. And then they're connected to SCA and SDA of OLED display appropriately.

    Thanks for your reply, Mark.

    Hoping to get it resolved soon!.

  • Thanks. I was just trying to re-baseline where we were at.

    One major issue is that the F28377S cannot tolerate 5V signals on the IOs. If you have statically connected to the GPIOs to 5V rails for some time, there is a good chance that the IOs (and the MCU itself) are damaged and that is why you are not seeing any signals on the GPIOs.

    You do not necessarily need a BoosterPack for evaluation. Wiring boards together is a perfectly valid use of the LaunchPad. When connecting other boards, you will need to ensure that the Grounds to the two boards as well as the desired signals are connected. You will also need to ensure that the voltages of the two boards are compatible. The F28377S is not capable of handling 5 V signals, so unless the OLED board can operate at 3.3 V or you have a level translator for I2C signals, I am not sure if you will be able to use this configuration.

    Thanks,
    Mark
  • Thanks for the immediate response, Mark.

    The MCU and the PCB are working just fine. I've ensured it working, with some of my other projects. I also tried the classic Blink program on the GPIO pins 42, 43, 91 and 92 and they work properly. Anyways, I'll remember not to connect them to 5V rails again!

    I used Analog Discovery module from DIGILINK to measure the output of the pins directly from the board(while they are and aren't connected to the OLED display.)

    The OLED display is not comfortable with 3.3V SDA and SCA, but I'll be using a level translator once I get clock on SCA-A on the LaunchPad. (Thanks for this!.)

    It might be a problem with my code, because I can't see any issues with the MCU or the board.

    As I already mentioned, the program execution stays indefinitely at the I2C stop condition check loop. I don't know why is this happening either.

    Thanks again, Mark.

  • When there is nothing connected to the I2C and you initiate a transfer, do you see the I2C clock and data toggle on a scope?

    Also, comparing your I2CWrite function with our I2C example, you are writing to the I2CMDR register before setting up the data to transmit.

    please check out the example:
    C:\ti\c2000\C2000Ware_1_00_03_00\device_support\f2837xs\examples\cpu1\i2c_eeprom\cpu01\Example_2837xSI2C_eeprom.c

    -Mark
  • Hello there,

    I haven’t heard from you for some time, so I’m assuming you were able to resolve your issue. If this isn’t the case, please reject this resolution or reply to this thread. If this thread locks, please make a new thread describing the current status of your issue.

    Thanks,
    Mark
  • Hi there,

    I noticed that you have not resolved your issue. Can you please provide a little more information so that we can reach a resolution?
    Have you looked into the eeprom example code? I2C is unfortunately a bit of a tricky module. There isn't a ton of error detection built in. Do you have and scope captures of the I2C bus when it gets stuck?

    Thanks,
    Mark