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.

Problems with I2C interface master transmitter without interrupts

Hello,

I want to write some data out the I2C port and I'm really close.  I am looking at the signals on a scope to verify what's going on, and I see that it works fine for the first transfer (a total of 3 bytes).  I see the start, address, and two bytes of data (all acknowledged), followed by a stop.  I'm generating a chip select on a GPIO line and I see it assert and de-assert at the right time as well so it's just about perfect.

The big problem is that nothing happens after that.  Same routine, but no clock, no data, nothing.  I've even tried to reset the I2C module between calls to the routine, but still nothing.  So I'm guessing I'm missing some sort of reset or status clearing but I haven't been able to figure out what it is.

I'm not using interrupts because I have other interrupts that I don't want to interfere with.  I am using the transmit FIFO.

 

Here's the routine that writes the data:

 

void  i2ca_xmit( Uint16 devAddr, Uint16 regAddr, Uint16 data)

{

    Uint16 timeout;

 

    // Setup the slave (device) address

    I2caRegs.I2CSAR = devAddr;

 

    // Always send two bytes: register address + data.

    I2caRegs.I2CCNT = 2;

 

    //  Assert the select line so the receiver will listen.

    GpioDataRegs.GPCDAT.bit.GPIO87 = 0;

    DELAY_US(10);

 

    // Write the data to the transmit FIFO.

    I2caRegs.I2CDXR = regAddr;

    I2caRegs.I2CDXR = data;

 

    //  Generate a START condition to send out the data.

    I2caRegs.I2CMDR.bit.STT = 1;

 

    //  This will give the bus a chance to start.

    DELAY_US(10);

 

    //  We're going to wait for a stop, so clear the status bit.

    I2caRegs.I2CSTR.bit.SCD = 1;

 

    //  Wait until the stop condition is detected.

    timeout = 350;

    while((I2caRegs.I2CSTR.bit.SCD == 0) && (timeout > 0))

    {

        DELAY_US(1);

        --timeout;

    }

 

    //  Turn off the select line.

    DELAY_US(10);

    GpioDataRegs.GPCDAT.bit.GPIO87 = 1;

 

    //  Make sure the I2C bus is stopped.

    I2caRegs.I2CMDR.bit.STT  = 0;

}

 

Here's the init routine:

 

void

i2ca_init()

{

    I2caRegs.I2CSTR.all = 0xff;     // Reset all status bits.

    I2caRegs.I2CMDR.all = 0;        // Reset the I2C module.

    I2caRegs.I2CIER.all = 0;        // Disable all interrupts.

 

    //  Enable the clock for the I2C module.

    EALLOW;

    SysCtrlRegs.PCLKCR0.bit.I2CAENCLK  = 1;

    EDIS;

 

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

    //  Initialize the I/O pins for I2C bus.

    //  GPIO32:  SDA

    //  GPIO33:  SCL

    //  GPIO87:  SEL*

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

    EALLOW;

    //  GPIO32:  SDA.  Enable pullup, no synchronizing the input, use I2C.

    GpioCtrlRegs.GPBPUD.bit.GPIO32   = 0;   // Enable pull-up for GPIO32 (SDAA)

    GpioCtrlRegs.GPBQSEL1.bit.GPIO32 = 3;   // Asynch input GPIO32 (SDAA)

    GpioCtrlRegs.GPBMUX1.bit.GPIO32  = 1;   // Configure GPIO32 for SDAA

 

    //  GPIO33:  SCL.  Enable pullup, no synchronizing the input, use I2C.

    GpioCtrlRegs.GPBPUD.bit.GPIO33   = 0;   // Enable pull-up for GPIO33 (SCLA)

    GpioCtrlRegs.GPBQSEL1.bit.GPIO33 = 3;   // Asynch input GPIO33 (SCLA)

    GpioCtrlRegs.GPBMUX1.bit.GPIO33  = 1;   // Configure GPIO33 for SCLA

 

    //  GPIO87:  SEL*.  Make it an output, drive it high (not selected).

    GpioCtrlRegs.GPCDIR.bit.GPIO87   = 1;

    GpioDataRegs.GPCDAT.bit.GPIO87   = 1;

    EDIS;

 

    //  Divide the 150 MHz DSP clock down for the I2C module clock.

    //  The module clock must be between 7-12 MHz.

    //  Dividing by 15 gives a 10 MHz clock.

    I2caRegs.I2CPSC.all = 14;

 

    //  Create a 50% duty cycle clock for SCL from the 10 MHz module clock.

    //  The actual divider is 5 more than what is programmed into the register.

    //  Value = 20:  10 MHz / (2*25) = 200KHz or 5 uSec per bit.

    I2caRegs.I2CCLKL    = 20;

    I2caRegs.I2CCLKH    = 20;

 

    I2caRegs.I2CSAR     = 0x69;       // Slave address.

    I2caRegs.I2COAR     = 0x05;       // Own address.

 

    //  Let the I2C run when the DSP is halted with the debugger.

    I2caRegs.I2CMDR.bit.FREE = 1;

 

    //  Master transmitter, 8 bits per byte.

    I2caRegs.I2CMDR.bit.MST  = 1;

    I2caRegs.I2CMDR.bit.TRX  = 1;

 

    //  Release reset for I2C module.

    I2caRegs.I2CMDR.bit.IRS = 1;

 

    //  This will wait for a bit to allow the bus busy bit to update.

    DELAY_US(50);

 

    //  Always generate a stop condition after each data transfer.

    I2caRegs.I2CMDR.bit.STP  = 1;

 

    I2caRegs.I2CFFTX.all = 0;       // Reset/Disable the TXFIFO.

    I2caRegs.I2CFFTX.all = 0x6002;  // Enable FIFO mode and TXFIFO

 

}

  • Well I think I figured out an answer to my own question.  After a transfer completes (I2C STOP condition), the I2C module clears the master bit (I2CMDR MST bit).  Of course I didn't notice this in the docs until after I got it working.....  At any rate, this is the change I made to the transmit routine to get it working:

     

    Instead of just:

     

        //  Generate a START condition to send out the data.

        I2caRegs.I2CMDR.bit.STT = 1;

    I used:
        //  Set master transmitter with auto-stop, then start the transfer.
        I2caRegs.I2CMDR.bit.MST  = 1;
        I2caRegs.I2CMDR.bit.TRX  = 1;
        I2caRegs.I2CMDR.bit.STP  = 1;
        I2caRegs.I2CMDR.bit.STT  = 1;
    I also removed the last line in the transmit routine (setting the stop bit to 0), this also seems to be automatic.
    So now everything is working as it should.
    -Mark