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.

I2C not working on TMS320F28035

Other Parts Discussed in Thread: TLV320AIC23B

So I've been trying so hard to get I2C working. The I2C will only transmit data to write configuration data to TLV320AIC23B codec.

This is my code:

 

void i2cCodecInit() {

// init

I2caRegs.I2CMDR.bit.IRS = 0;

I2caRegs.I2CPSC.all = 5; // clock pre-scaler

I2caRegs.I2CCLKL = 10;

I2caRegs.I2CCLKH = 5;

I2caRegs.I2CIER.all = 0;

//I2caRegs.I2CMDR.all = 0x0020;

//I2caRegs.I2CFFTX.all = 0x6000;

 

I2caRegs.I2CMDR.bit.IRS = 1;

I2caRegs.I2CSAR = 0x34; // codec address

 

I2caRegs.I2CCNT = 3;

I2caRegs.I2CMDR.bit.TRX = 1;

I2caRegs.I2CMDR.bit.MST = 1;

I2caRegs.I2CMDR.bit.FREE = 1;

I2caRegs.I2CMDR.bit.RM = 1;   // These RM - STT - STP combination   

I2caRegs.I2CMDR.bit.STT = 1;  // yields S - A - D - D - D - D

I2caRegs.I2CMDR.bit.STP = 0;  // (repeat mode transfer)

 

I2caRegs.I2CDXR = 0x34;

while(I2caRegs.I2CSTR.bit.XRDY == 0) {};

I2caRegs.I2CDXR = 0x01;

while(I2caRegs.I2CSTR.bit.XRDY == 0) {};

I2caRegs.I2CDXR = 0x17;

//FunctionPointer = &i2cCodecInit;

}

 

I've looked at oscilloscope, logic analyzer, I couldn't find any activity on both clock signal data signal. When I halted the CPU, the program seems to be stuck on waiting for XRDY for the first time.

Port initialization is as follows:

//  GPIO-32 - PIN FUNCTION = --Spare--

GpioCtrlRegs.GPBMUX1.bit.GPIO32 = 1; // 0=GPIO,  1=I2CSDA-A,  2=SYNCI,  3=ADCSOCA

GpioCtrlRegs.GPBDIR.bit.GPIO32 = 0; // 1=OUTput,  0=INput 

GpioCtrlRegs.GPBPUD.bit.GPIO32 = 0; // Enable pull-up

GpioCtrlRegs.GPBQSEL1.bit.GPIO32 = 3; // Async input

// GpioDataRegs.GPBCLEAR.bit.GPIO32 = 1; // uncomment if --> Set Low initially

GpioDataRegs.GPBSET.bit.GPIO32 = 1; // uncomment if --> Set High initially

//--------------------------------------------------------------------------------------

//  GPIO-33 - PIN FUNCTION = --Spare--

GpioCtrlRegs.GPBMUX1.bit.GPIO33 = 1; // 0=GPIO,  1=I2CSCL-A,  2=SYNCO,  3=ADCSOCB

GpioCtrlRegs.GPBDIR.bit.GPIO33 = 0; // 1=OUTput,  0=INput 

GpioCtrlRegs.GPBPUD.bit.GPIO33 = 0; // Enable pull-up

GpioCtrlRegs.GPBQSEL1.bit.GPIO33 = 3; // Async input

// GpioDataRegs.GPBCLEAR.bit.GPIO33 = 1; // uncomment if --> Set Low initially

GpioDataRegs.GPBSET.bit.GPIO33 = 1; // uncomment if --> Set High initially

 

Any help would be appreciated.

Thanks

  • Two things I noticed that are different from the (working) code I wrote are that:

    (1) I write to the I2CDXR register before writing to I2CMDR

    (2) I write to I2CMDR all at once, without using the "bit" field

    The code I have is for the F2833x, but I imagine there is not a huge difference.

    I'm certainly no expert, but I've copy/pasted an I2C Write function below that I know works.  It is probably not the best-written code out there, but it does get the job done.:

    void I2CA_WriteData(char *write_data, unsigned int slave_addr, unsigned int num_bytes, char stop_bit)

    {

       unsigned int i; // counter

       

       while(I2caRegs.I2CMDR.bit.STP == 1) {} // wait until the STP bit is cleared from any previous master communication

       while(I2caRegs.I2CSTR.bit.BB == 1) {} // wait until bus not busy


       I2caRegs.I2CSAR = slave_addr; // slave address register set

       I2caRegs.I2CCNT = num_bytes; // setup number of bytes to send


       for(i = 0; i < num_bytes; i++) // setup data to send, # of bytes equals num_bytes

       {

        I2caRegs.I2CDXR = (unsigned int)(write_data[i]); // write data into Data Transmit FIFO

       }


       if(stop_bit == 'y') // if there should be a stop bit at the end of transmission, then

       {

        I2caRegs.I2CMDR.all = 0x2E20; // send start as master transmitter, w/ stop condition once all bytes have been sent

        while(I2caRegs.I2CSTR.bit.SCD != 1) {} // wait until stop condition is detected

        I2caRegs.I2CSTR.bit.SCD = 1; // clear stop condition detected bit in I2C status register

       }

       else // if there should not be a stop condition at end of transmission (master retains control of bus), then

       {

        I2caRegs.I2CMDR.all = 0x2620; // start condition, master mode, TX mode

        while(I2caRegs.I2CSTR.bit.ARDY != 1) {} // wait for I2C registers to finish working

        I2caRegs.I2CSTR.bit.ARDY = 1; // clear ARDY bit in I2C status register

       }


       return; // end of function, return value is void

    }

  • I tried as you suggested, and it works... for the first data only. I don't see the activity on SCL line however. As the pin was initially high, as soon as the code is run, the SCL goes low and stays low. It's not pulsing at all. I'm not seeing SDATA doing any activity either. It stays as it is, high. So this code is what I come with

     

    I2caRegs.I2CMDR.bit.IRS = 0;

    I2caRegs.I2CSAR = 0x34; // codec address

    I2caRegs.I2CPSC.all = 4; // clock pre-scaler

    I2caRegs.I2CCLKL = 10;

    I2caRegs.I2CCLKH = 5;

    I2caRegs.I2CIER.all = 0x3E;

    //I2caRegs.I2CMDR.all = 0x0020;

    //I2caRegs.I2CFFTX.all = 0x6000;

    I2caRegs.I2CCNT = 5;

    I2caRegs.I2CDXR = 0x01;

    I2caRegs.I2CMDR.bit.TRX = 1;

    I2caRegs.I2CMDR.bit.MST = 1;

    I2caRegs.I2CMDR.bit.FREE = 1;

    I2caRegs.I2CMDR.bit.STT = 1; 

    I2caRegs.I2CMDR.bit.STP = 1; 

    I2caRegs.I2CMDR.bit.IRS = 1;

    while (I2caRegs.I2CSTR.bit.BB == 1) {};

    while(I2caRegs.I2CSTR.bit.XRDY == 0) {};

    I2caRegs.I2CDXR = 0x17;

    while(I2caRegs.I2CSTR.bit.XRDY == 0) {}; <-- stuck here

    I2caRegs.I2CDXR = 0x08;

    while(I2caRegs.I2CSTR.bit.XRDY == 0) {};

    I2caRegs.I2CDXR = 0x14;

    while(I2caRegs.I2CSTR.bit.XRDY == 0) {};

    I2caRegs.I2CDXR = 0x47;

    while(I2caRegs.I2CSTR.bit.XRDY == 0) {};

    I2caRegs.I2CDXR = 0x87;

     

    Can anyone help? I'm frustrated already... 2 days working but cannot get I2C to work :(

  • If XRDY is anything like the other bits in I2CSTR, then you need to write a "1" to it in order to clear it before you can watch it again.  Notice how in the code I wrote above that after I check for STP or ARDY, I then write a one to the bit to clear it.  Try adding I2caRegs.I2CSTR.bit.XRDY = 1 after each time you wait for the bit to go high.

    If that doesn't work, maybe just try modifying the code I wrote?  I know that works for sure, and it uses the FIFO mode, too, which can make things a lot easier.

  • Just curious on how you initialize the MCU.

    I changed the GPIO settings to mux-out SPI and enable I2C Clock Enable. Is there anything else I need to do prior to running the code? Like PIE, interrupt vector, etc?

    Thanks

  • I've copy/pasted my I2C initialization routine below.  Note that this does not contain the GPIO mux settings and module clock enable because those are taken care of in a general initialization routine.  It would probably be more efficient to use the interrupts instead of sitting around waiting for I2CSTR to update, but since the later is what I've been doing there is no need to tinker with the PIE, etc.

     

    void I2CA_Init(void) // set register values to properly configure I2C module

    {

       I2caRegs.I2CMDR.all = 0x0000; // put I2C module in reset mode

       

       I2caRegs.I2CPSC.all = 9;   // prescaler

       I2caRegs.I2CCLKL = 10; // clock-low period, MUST BE NON-ZERO

       I2caRegs.I2CCLKH = 5; // clock-high period, MUST BE NON-ZERO


       I2caRegs.I2CMDR.all = 0x0020; // take I2C out of reset, stop I2C when emulation is suspended


       I2caRegs.I2CFFTX.all = 0x6000; // enable FIFO mode and TX_FIFO

       I2caRegs.I2CFFRX.all = 0x2040; // enable RX_FIFO, clear RXFFINT,


       return; // end of function, return value is void

    }

     

  • Alright, thanks for the pointer. That code works. Now I can send the slave address through the bus. However, that's all I can send. None of the remaining data in FIFO get sent.

    Code:

     

    I2caRegs.I2CMDR.all = 0x0000; // reset mode

    I2caRegs.I2CPSC.all = 4;

    I2caRegs.I2CCLKL = 4000;

    I2caRegs.I2CCLKH = 6000;

    I2caRegs.I2CMDR.all = 0x0020;

    I2caRegs.I2CFFTX.all = 0x6000;

     

    I2caRegs.I2CSAR = 0x001A; // <-- This is all that's sent as I monitor the bus from oscilloscope

    I2caRegs.I2CCNT = 10;

    I2caRegs.I2CDXR = 0x0001;

    I2caRegs.I2CDXR = 0x0002;

    I2caRegs.I2CDXR = 0x0004;

    I2caRegs.I2CDXR = 0x0008;

    I2caRegs.I2CDXR = 0x0010;

    I2caRegs.I2CDXR = 0x0011;

    I2caRegs.I2CDXR = 0x0012;

    I2caRegs.I2CDXR = 0x0014;

    I2caRegs.I2CDXR = 0x0018;

    I2caRegs.I2CDXR = 0x0020;

     

    I2caRegs.I2CMDR.all = 0x6E20; //0x2E20;

    while (I2caRegs.I2CSTR.bit.SCD != 1) {}

    I2caRegs.I2CSTR.bit.SCD = 1;

    I'm assuming the I2C module will wait for ACK signal from the slave before proceeding sending the next data from the FIFO? Or will it just run through?

    Thanks for your help, I can make a little progress at least.

     

  • Yes, the module will wait for an ACK before sending data.  Did you run the test with your I2C slave connected (powered, proper slave address, etc.)?  Also don't forget proper pull-up resistor values.  Your code here looks good so I'm not quite sure what the problem could be.

  • Pretty sure the I2C slave is connected. It's TLV320AIC23B (datasheet: http://www.ti.com/lit/ds/symlink/tlv320aic23b.pdf, device address is at page20). I used 1M-ohm resistor. Although I'm not sure if the codec chip is still working - yesterday I accidentally put a 3.8V supply to it. I'll try again with another chip tomorrow.

    Thanks a bunch.

  • Yeah, it looks like you have the slave address right, assuming you've tied !CS to ground.  1M is probably too big for a pull-up value, most people use between 1k and 10k I think.  Also, make sure the MODE pin on the codec is hardwired to ground.

  • Turns out (probably) the I2C from the MCU violates the hold time required by the slave. When the SCL goes low, the SDIN changes value almost at the same time, thus not giving enough hold time. Is there any way I can delay the SDIN data change so that the data line is stable when SCL changes? This is the settings I use.

    I2caRegs.I2CPSC.all = 4;

    I2caRegs.I2CCLKL = 1000;

    I2caRegs.I2CCLKH = 500;

    Thanks

  • Actually, never mind. I finally got everything working, thanks a lot to you.

    I just wired SCLK and SDIN backwards - apart from the 1M-ohm resistor. I switched to 4K7 and everything works just fine.

  • Yay, I'm so glad it worked out.  Good luck with everything!