AnsweredAssumed Answered

I2C (TWI) question on ADSP-21479

Question asked by alevy on Jul 22, 2013
Latest reply on Jul 23, 2013 by Harshit.Gaharwar

Hi-

 

I'm trying to get the I2C peripheral working, and running into a problem on the first transfer I attempt.  In the scope captures that I've attached, SDA is the yellow trace, SCL is the blue trace.

 

You can see in StartCondition.JPG that both SDA and SCL are pulled high to approximately 3V before the transfer.  When I run my "InitI2CWrite()" function, I see SDA gets driven low, then SCL is driven low 4us later.  After that, SDA stays low until I reset the chip.

 

SCL does not behave as expected, either.  It stays low for a very long time, then goes high for a short time.  There are some cases where it's high for approximately 60ns, and some where it's high for 1us.  As you can see in Nonperiodic.JPG, SCL does not appear to be periodic.

 

The final issue I'm having is that I never reach a breakpoint I've set inside the I2C ISR.

 

Please see the code below for how I'm initializing the device.  I'm trying to have SCL be a 50% duty cycle wave operating at 400 kHz.  I have tried dropping the frequency to 100 kHz with no apparent change.  Any advice you could provide would be greatly appreciated.

 

// PCLK freq = 133
// Desired internal I2C clk freq = 10 MHz per the ADI HRM
// 133 / 10 = 13.3, round to 13 for TWI_10MHZ_DIVISOR
#define TWI_10MHZ_DIVISOR   (13)

// Internal I2C clk freq = fPCLK / TWI_10MHZ_DIVISOR = 10.23 MHz
// Desired I2C frequency = 400 kHz
// fIntClk / fI2C = 25.6, round to 26
// Desired duty cycle = 50%, so use 13 for
// each of the high and low tick counts

// Set the following to 1 for 100 kHz, 0 for 400 kHz
#if 0
#define TWI_HI_CLK_DIV      ((4 * 13) << 8)
#define TWI_LO_CLK_DIV      (4 * 13)
#else
#define TWI_HI_CLK_DIV      (13 << 8)
#define TWI_LO_CLK_DIV      (13)
#endif

#define TWI_CLK_DIV         (TWI_HI_CLK_DIV | TWI_LO_CLK_DIV)

// Used to clear out IRQ priority level 15 for use by the TWI/I2C
#define IRQ_P15_BITS        (P15I0 | P15I1 | P15I2 | P15I3 | P15I4)

// TWI = I2C in ADI parlance.
// Shift by 15 to get it into the P15I space of the PICR2 register.
// See figure A-6 of the ADSP-214xx reference manual rev 1.1 for details.
#define P15_I2C_EN          (TWII_ENCODING << 15)

// The TWIMCTL register has an 8-bit "data transfer count" field used to
// indicate the number of data bytes to transfer.
#define TWIMCTL_COUNT_SHIFT (6)

// Bit field definitions for I2C conditions
#define I2C_8_BIT_DATA          0x00
#define I2C_16_BIT_DATA         0x01    // Set to use 16 bit data, clear to use 8 bit data.
#define I2C_REPEAT_START        0x02    // Set if you don't want to have a STOP condition when count expires, but another START instead.
#define I2C_BUF_IRQ_EN          0x10    // If you want IRQs each time the buffer is empty (Tx) or filled (Rx) (NOT exclusive of I2C_XFER_COM_IRQ_EN)
#define I2C_XFER_COM_IRQ_EN     0x20    // If you want IRQs at the end of the transfer (NOT exclusive of I2C_BUF_EMPTY_IRQ_EN)

void InitI2C(void)
{

    unsigned int uiTemp;

    // Route the I2C peripheral to DPI PB13 (SDA) and PB14 (SCL).
    // I2C works as an open-drain interface, so we never drive it high.
    // Connect the input of oth SDA and SCL low so that it is driven low
    // whenever the PBEN gets set high, as controlled by the TWI peripheral.
    SRU2(LOW, DPI_PB13_I);
    SRU2(TWI_DATA_PBEN_O, DPI_PBEN13_I);
    SRU2(DPI_PB13_O, TWI_DATA_I);
    SRU2(LOW, DPI_PB14_I);
    SRU2(TWI_CLK_PBEN_O, DPI_PBEN14_I);

     // First, read whatever is stored in Programmable Interrupt Control
    // Register 2.  Clear out the bits responsible for IRQ 15, then overwrite
    // them with the bits so that the TWI (I2C) ISR fires with priority level 15
    uiTemp = *pPICR2;
    uiTemp &= ~(IRQ_P15_BITS);
    uiTemp |= P15_I2C_EN;
    *pPICR2 = uiTemp;

    *pTWIMITR = TWI_10MHZ_DIVISOR | TWIEN;  // Set up reference clock and enable the TWI
    *pTWIDIV = TWI_CLK_DIV;                 // SCL clock divider, high and low

    interruptsnsm(SIG_P15, I2C_ISR);

    return;

} // InitI2C()

void InitI2CWrite(int iDeviceAddr, int iData1, int iData2, int iCount, int iI2CCond)
{

    int iIRQMask;

    // Write address
    *pTWIMADDR = iDeviceAddr;

    // Set up first piece of data and FIFO controller based on 1 or 2 byte Tx
    if (I2C_16_BIT_DATA == (iI2CCond & I2C_16_BIT_DATA)) {
        // The low-order byte is sent first in 16-bit mode
        I2C_WRITE_FIFO_16(iData1, iData2);
        *pTWIFIFOCTL = TWITXINT2 | KVHBHD;
    } else {
        I2C_WRITE_FIFO_8(iData1);
        *pTWIFIFOCTL = KVHBHD;
    }

    iIRQMask = TWIMERR;  // Always interrupt if we've had an error
    // Enable master transfer complete and TX FIFO service interrupts as needed
    if (I2C_BUF_IRQ_EN == (iI2CCond & I2C_BUF_IRQ_EN)) {
        iIRQMask |= TWITXINT;
    }
    if (I2C_XFER_COM_IRQ_EN == (iI2CCond & I2C_XFER_COM_IRQ_EN)) {
        iIRQMask |= TWIMCOM;
    }
    *pTWIIMASK = iIRQMask;

    // Set up for Master Tx with iCount data bytes before the TX_COMPLETE IRQ.
    if (I2C_REPEAT_START == (iI2CCond & I2C_REPEAT_START)) {
        *pTWIMCTL = (iCount << TWIMCTL_COUNT_SHIFT) | TWIMEN | TWIMTX | TWIRSTART;
    } else {
        *pTWIMCTL = (iCount << TWIMCTL_COUNT_SHIFT) | TWIMEN | TWIMTX;
    }

    return;

} // InitI2CWrite()

void main(void)
{
    InitI2C();
    InitI2CWrite(0x30,    // Device address
                          0x07,    // Data byte 1
                          0x01,    // Data byte 2
                          2,          // Count
                          I2C_16_BIT_DATA | I2C_XFER_COM_IRQ_EN);     // I2C Conditions
} // main()

 

Attachments

Outcomes