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.

TMS320F28035: Interrupt driven I2C block write

Part Number: TMS320F28035

I am trying to go from the Example_2803xI2C_eeprom program which send 4 bytes but not a complete block. My program can not spin in the interrupt for long enough to send 64 characters. I am working on changing the interrupt routine so when the four bytes in the buffer are send the interrupt routine will send the next 4 until the whole block is sent.

Any examples or suggestiong

  • I suggest using FIFO mode. You can set the transmit interrupt level to trigger another interrupt whenever the FIFO is empty.

  • I am using FIFO mode. The problem is after sending the first 4 bytes I reload reload the I2CDXR with the next 4 bytes and the bytes 4 - 7 are are sent. After this no TXFFINTs occur. Any suggestions on what why I do not get an interrupt after loading FIFO the third time
  • So you only get one interrupt? Are you clearing the PIEACK bit for the interrupt? What's your TX interrupt level set to?
  • I have this at the end of thei2c_int1a_isr interrupt
    " // Enable future I2C (PIE Group 8) interrupts"
    " PieCtrlRegs.PIEACK.all = PIEACK_GROUP8;"
    and have the TX interrupt level set to 1.
    I noticed the example has the I2C cmd set like this I2caRegs.I2CMDR.all = 0x6E20; and was setting it like this to understand what was being set.
    I2caRegs.I2CMDR.bit.BC = 0; // Bit Count = 0, sets 8 bit byte
    I2caRegs.I2CMDR.bit.FDF = 0; // Free Data Format off
    I2caRegs.I2CMDR.bit.STB = 0; // Start Byte off
    I2caRegs.I2CMDR.bit.IRS = 0; // reset I2C
    I2caRegs.I2CMDR.bit.IRS = 1; // release I2C from reset
    I2caRegs.I2CMDR.bit.DLB = 0; // Digital loop back mode off
    I2caRegs.I2CMDR.bit.RM = 0; // Repeat mode off
    I2caRegs.I2CMDR.bit.XA = 0; // Expanded address mode off, 7 bit addressing
    I2caRegs.I2CMDR.bit.TRX = 1; // Transmit mode on
    I2caRegs.I2CMDR.bit.MST = 1; // Master mode on
    I2caRegs.I2CMDR.bit.STP = 1; // Generate a stop condition when internal data counter reaches 0
    I2caRegs.I2CMDR.bit.STT = 1; // Generate a start condition
    I2caRegs.I2CMDR.bit.FREE = 0; // let I2C keep running
    I2caRegs.I2CMDR.bit.NACKMOD = 0; // normal ACK mode.

    Is this format ok?

    To help with debugging I have stripped my code to just send a 64 byte block. I am new to the TI forums. Is it ok to post my code?

    Thanks for your help.
  • Yes, please do post your code.
  • This code is stripped down to just sending one 64 byte block of code with a start and stop. I reset the hardware before each time I run the code. I have removed the read support and just am trying to send the 64 bytes once.

    //###########################################################################
    //
    //! \addtogroup f2803x_example_list
    //! <h1>I2C EEPROM(i2c_eeprom)</h1>
    //!
    //! This program requires an external I2C EEPROM connected to
    //! the I2C bus at address 0x50.
    //! This program will write 1-14 words to EEPROM and read them back.
    //! The data written and the EEPROM address written to are contained
    //! in the message structure, \b I2cMsgOut. The data read back will be
    //! contained in the message structure \b I2cMsgIn1.
    //!
    //! \note This program will only work on kits that have an on-board I2C EEPROM.
    //! (e.g. F2803x eZdsp)
    //!
    //! \b Watch \b Variables \n
    //! - I2cMsgIn1
    //! - I2cMsgOut
    //
    //###########################################################################
    // $TI Release: F2803x C/C++ Header Files and Peripheral Examples V130 $
    // $Release Date: May 8, 2015 $
    // $Copyright: Copyright (C) 2009-2015 Texas Instruments Incorporated -
    // http://www.ti.com/ ALL RIGHTS RESERVED $
    //###########################################################################

    #include "DSP28x_Project.h" // Device Headerfile and Examples Include File
    #include "FeTypes.h"
    // Note: I2C Macros used in this example can be found in the
    // DSP2803x_I2C_defines.h file

    // Prototype statements for functions found within this file.

    __interrupt void i2c_int1a_isr(void);
    void pass(void);
    void fail(void);
    extern void EepromWP_ClrVal(void); // not write protected
    extern void EepromWP_SetVal(void); // write protected;
    extern void I2CA_Init(void);
    extern void InitI2cGpio(void);
    extern bool I2C_EE_CheckBus(void);


    #define I2C_ERROR 0xFFFF
    #define I2C_ARB_LOST_ERROR 0x0001
    #define I2C_NACK_ERROR 0x0002
    #define I2C_BUS_BUSY_ERROR 0x1000
    #define I2C_STP_NOT_READY_ERROR 0x5555
    #define I2C_NO_FLAGS 0xAAAA
    #define I2C_SUCCESS 0x0000

    // Clear Status Flags
    #define I2C_CLR_AL_BIT 0x0001
    #define I2C_CLR_NACK_BIT 0x0002
    #define I2C_CLR_ARDY_BIT 0x0004
    #define I2C_CLR_RRDY_BIT 0x0008
    #define I2C_CLR_SCD_BIT 0x0020

    // Interrupt Source Messages
    #define I2C_NO_ISRC 0x0000
    #define I2C_ARB_ISRC 0x0001
    #define I2C_NACK_ISRC 0x0002
    #define I2C_ARDY_ISRC 0x0003
    #define I2C_RX_ISRC 0x0004
    #define I2C_TX_ISRC 0x0005
    #define I2C_SCD_ISRC 0x0006
    #define I2C_AAS_ISRC 0x0007

    // I2CMSG structure defines
    #define I2C_NO_STOP 0
    #define I2C_YES_STOP 1
    #define I2C_RECEIVE 0
    #define I2C_TRANSMIT 1
    #define I2C_MAX_BUFFER_SIZE 4

    // I2C Slave State defines
    #define I2C_NOTSLAVE 0
    #define I2C_ADDR_AS_SLAVE 1
    #define I2C_ST_MSG_READY 2

    // I2C Slave Receiver messages defines
    #define I2C_SND_MSG1 1
    #define I2C_SND_MSG2 2

    // I2C State defines
    #define I2C_IDLE 0
    #define I2C_SLAVE_RECEIVER 1
    #define I2C_SLAVE_TRANSMITTER 2
    #define I2C_MASTER_RECEIVER 3
    #define I2C_MASTER_TRANSMITTER 4

    // I2C Message Commands for I2CMSG struct
    #define I2C_MSGSTAT_INACTIVE 0x0000
    #define I2C_MSGSTAT_SEND_WITHSTOP 0x0010
    #define I2C_MSGSTAT_WRITE_BUSY 0x0011
    #define I2C_MSGSTAT_SEND_NOSTOP 0x0020
    #define I2C_MSGSTAT_SEND_NOSTOP_BUSY 0x0021
    #define I2C_MSGSTAT_RESTART 0x0022
    #define I2C_MSGSTAT_READ_BUSY 0x0023


    #define I2C_SLAVE_ADDR 0x50
    #define I2C_EEPROM_HIGH_ADDR 0x00
    #define I2C_EEPROM_LOW_ADDR 0x30
    #define FIFO_SIZE (4)
    #define PACKET_SIZE (64)


    /* 16-bit register (big endian) */

    typedef struct {
    Uint8 MsgCommand;
    Uint8 MsgSlaveAddress;
    Uint8 NumBytesToSend;
    Uint8 NumBytesSent;
    Uint8 SendBuffer[PACKET_SIZE];
    }I2CMSG_OUT;
    I2CMSG_OUT I2cMsgOut;

    Uint16 EEpromWriteDataBlock(void);

    void main(void)
    {
    Uint16 Error;
    Uint16 i;

    I2cMsgOut.MsgCommand = I2C_IDLE;
    I2cMsgOut.MsgSlaveAddress = I2C_SLAVE_ADDR;
    I2cMsgOut.NumBytesToSend = PACKET_SIZE;
    I2cMsgOut.NumBytesSent = 0;
    for( i = 0; i < PACKET_SIZE; i++)
    {
    I2cMsgOut.SendBuffer[i] = i;
    }



    // Step 1. Initialize System Control:
    // PLL, WatchDog, enable Peripheral Clocks
    // This example function is found in the DSP2803x_SysCtrl.c file.
    InitSysCtrl();

    // Step 2. Initialize GPIO:
    // This example function is found in the DSP2803x_Gpio.c file and
    // illustrates how to set the GPIO to it's default state.
    // InitGpio();
    // Setup only the GP I/O only for I2C functionality
    InitI2CGpio();

    EepromWP_SetVal();
    // Enable an GPIO output on GPIO7, set it high
    // Step 3. Clear all interrupts and initialize PIE vector table:
    // Disable CPU interrupts
    DINT;

    // Initialize PIE control registers to their default state.
    // The default state is all PIE interrupts disabled and flags
    // are cleared.
    // This function is found in the DSP2803x_PieCtrl.c file.
    InitPieCtrl();

    // Disable CPU interrupts and clear all CPU interrupt flags:
    IER = 0x0000;
    IFR = 0x0000;

    // Initialize the PIE vector table with pointers to the shell Interrupt
    // Service Routines (ISR).
    // This will populate the entire table, even if the interrupt
    // is not used in this example. This is useful for debug purposes.
    // The shell ISR routines are found in DSP2803x_DefaultIsr.c.
    // This function is found in DSP2803x_PieVect.c.
    InitPieVectTable();

    // Interrupts that are used in this example are re-mapped to
    // ISR functions found within this file.
    EALLOW; // This is needed to write to EALLOW protected registers
    PieVectTable.I2CINT1A = &i2c_int1a_isr;
    EDIS; // This is needed to disable write to EALLOW protected registers

    // Step 4. Initialize the I2C Peripheral:
    I2CA_Init();



    // Enable interrupts required for this example

    // Enable I2C interrupt 1 in the PIE: Group 8 interrupt 1
    PieCtrlRegs.PIEIER8.bit.INTx1 = 1;

    // Enable CPU INT8 which is connected to PIE group 8
    IER |= M_INT8;
    EINT;

    I2caRegs.I2CMDR.bit.IRS = 0;
    I2caRegs.I2CMDR.bit.IRS = 1; //reset I2c

    I2cMsgOut.MsgCommand = I2C_MSGSTAT_SEND_WITHSTOP;

    //////////////////////////////////
    // Write data to EEPROM section //
    //////////////////////////////////

    // Check the outgoing message to see if it should be sent.
    // In this example it is initialized to send with a stop bit.
    if( I2cMsgOut.MsgCommand == I2C_MSGSTAT_SEND_WITHSTOP )
    {
    Error = EEpromWriteDataBlock();
    // If communication is correctly initiated, set msg status to busy
    // and update CurrentMsgPtr for the interrupt service routine.
    // Otherwise, do nothing and try again next loop. Once message is
    // initiated, the I2C interrupts will handle the rest. Search for
    // i2c_int1a_isr in the i2c_eeprom_isr.c file.
    if (Error == I2C_SUCCESS)
    {

    //I2cMsgOut.MsgCommand = I2C_MSGSTAT_WRITE_BUSY;
    }
    } // end of write section
    for(;;)
    {
    i++ ;
    }
    ///////////////////////////////////
    // Read data from EEPROM section //
    ///////////////////////////////////

    } // end of main

    #define CLEAR_FFRX_REG (0)
    #define CLEAR_FFTX_REG (0)
    #define TX_FF_INT_LEVEL (1)

    void InitI2CGpio()
    {
    EALLOW;

    /* Enable internal pull-up for the selected pins */
    // Pull-ups can be enabled or disabled disabled by the user.
    // This will enable the pullups for the specified pins.
    GpioCtrlRegs.GPBPUD.bit.GPIO32 = 0; // Enable pull-up for GPIO32 (SDAA)
    GpioCtrlRegs.GPBPUD.bit.GPIO33 = 0; // Enable pull-up for GPIO33 (SCLA)


    /* Set qualification for selected pins to asynch only */
    // This will select asynch (no qualification) for the selected pins.


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

    /* Configure I2C pins using GPIO regs*/
    GpioCtrlRegs.GPBMUX1.bit.GPIO32 = 1; // Configure GPIO32 for SDAA operation
    GpioCtrlRegs.GPBMUX1.bit.GPIO33 = 1; // Configure GPIO33 for SCLA operation


    // Enable GPIO output on GPIO17, set it high
    GpioCtrlRegs.GPAPUD.bit.GPIO17 = 0; // Enable pullup on GPIO17
    GpioDataRegs.GPASET.bit.GPIO17 = 1; // Load output latch
    GpioCtrlRegs.GPAMUX2.bit.GPIO17 = 0; // GPIO17 = GPIO17
    GpioCtrlRegs.GPADIR.bit.GPIO17 = 1; // GPIO17 = output


    EDIS;
    }


    Uint16 EEpromWriteDataBlock( void )
    {
    Uint8 i;

    // I2CFFRX = 0
    I2caRegs.I2CSAR = I2cMsgOut.MsgSlaveAddress;

    // Check if bus busy
    if (I2caRegs.I2CSTR.bit.BB == 1)
    {
    return I2C_BUS_BUSY_ERROR;
    }


    I2caRegs.I2CCNT = PACKET_SIZE;

    I2cMsgOut.MsgCommand = I2C_MSGSTAT_SEND_WITHSTOP;
    EepromWP_SetVal();

    I2caRegs.I2CMDR.bit.BC = 0; // Bit Count = 0, sets 8 bit byte
    I2caRegs.I2CMDR.bit.FDF = 0; // Free Data Format off
    I2caRegs.I2CMDR.bit.STB = 0; // Start Byte off
    I2caRegs.I2CMDR.bit.IRS = 0; // reset I2C
    I2caRegs.I2CMDR.bit.IRS = 1; // release I2C from reset
    I2caRegs.I2CMDR.bit.DLB = 0; // Digital loop back mode off
    I2caRegs.I2CMDR.bit.RM = 0; // Repeat mode off
    I2caRegs.I2CMDR.bit.XA = 0; // Expanded address mode off, 7 bit addressing
    I2caRegs.I2CMDR.bit.TRX = 1; // Transmit mode on
    I2caRegs.I2CMDR.bit.MST = 1; // Master mode on
    I2caRegs.I2CMDR.bit.STP = 1; // Generate a stop condition when internal data counter reaches 0
    I2caRegs.I2CMDR.bit.STT = 1; // Generate a start condition
    I2caRegs.I2CMDR.bit.FREE = 0; // let I2C keep running
    I2caRegs.I2CMDR.bit.NACKMOD = 0; // normal ACK mode.

    I2caRegs.I2CEMDR.bit.BCM = 0; //

    I2caRegs.I2CIER.all = 0; // use FF interrupts

    for( i = 0; i < FIFO_SIZE ; i++ )
    {
    I2caRegs.I2CDXR = I2cMsgOut.SendBuffer[ I2cMsgOut.NumBytesSent++ ];
    }
    I2caRegs.I2CFFTX.bit.TXFFRST = 0; // reset TX FIFO
    I2caRegs.I2CFFTX.bit.TXFFIL = TX_FF_INT_LEVEL; // trigger interrupt when buffer has one byte left to send
    I2caRegs.I2CFFTX.bit.TXFFIENA = 1; // enable transmit FIFI interrupt
    I2caRegs.I2CFFTX.bit.TXFFRST = 1; // enable TF TIFO operation
    I2caRegs.I2CFFTX.bit.TXFFINTCLR = 1; // clears transmit FIFI interrupt as recommended by spufz9d table 21
    I2caRegs.I2CFFTX.bit.I2CFFEN = 1; // enable FF mode

    // I2CFFTX = 0x60A1

    return I2C_SUCCESS;
    }

    __interrupt void i2c_int1a_isr(void) // I2C-A
    {
    Uint16 i, IntSource;
    IntSource = I2caRegs.I2CISRC.all;

    if( IntSource == I2C_TX_ISRC )
    {
    if( I2cMsgOut.MsgCommand == I2C_MSGSTAT_SEND_WITHSTOP )
    {
    // check interrupt source
    // if(( IntSource == I2C_TX_ISRC ) ||
    // ( I2caRegs.I2CFFTX.bit.TXFFINT == 1 ))
    if( I2caRegs.I2CFFTX.bit.TXFFINT == 1 )
    {
    I2caRegs.I2CFFTX.bit.TXFFINTCLR = 1; // clear interrupt
    I2caRegs.I2CFFTX.bit.TXFFIENA = 0; // disable the interrupt
    if( I2cMsgOut.NumBytesSent <= I2cMsgOut.NumBytesToSend ){
    // TX buffer should be empty, reload
    for( i = 0; i < FIFO_SIZE; i++ )
    {
    I2caRegs.I2CDXR = I2cMsgOut.SendBuffer[ I2cMsgOut.NumBytesSent++ ];
    }
    I2caRegs.I2CFFTX.bit.TXFFIENA = 1; // re-enable the interrupt
    }
    else
    {
    EepromWP_ClrVal();
    I2cMsgOut.MsgCommand = I2C_MSGSTAT_INACTIVE;
    }
    }
    }
    }
    // Enable future I2C (PIE Group 8) interrupts
    PieCtrlRegs.PIEACK.all = PIEACK_GROUP8;
    }

    void EepromWP_ClrVal(void) // not write protected
    {
    GpioDataRegs.GPACLEAR.bit.GPIO17 = 1; // Load output latch // EEPROM not write protect
    }

    void EepromWP_SetVal(void) // write protected;
    {
    GpioDataRegs.GPASET.bit.GPIO17 = 1; // Load output latch = 1; // EEPROM not write protect
    }

    void InitI2cGpio()
    {
    EALLOW;

    /* Enable internal pull-up for the selected pins */
    // Pull-ups can be enabled or disabled disabled by the user.
    // This will enable the pull ups for the specified pins.
    GpioCtrlRegs.GPBPUD.bit.GPIO32 = 0; // Enable pull-up for GPIO32 (SDAA)
    GpioCtrlRegs.GPBPUD.bit.GPIO33 = 0; // Enable pull-up for GPIO33 (SCLA)


    /* Set qualification for selected pins to asynch only */
    // This will select asynch (no qualification) for the selected pins.


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

    /* Configure I2C pins using GPIO regs */
    GpioCtrlRegs.GPBMUX1.bit.GPIO32 = 1; // Configure GPIO32 for SDAA operation
    GpioCtrlRegs.GPBMUX1.bit.GPIO33 = 1; // Configure GPIO33 for SCLA operation

    // Enable GPIO outputs on GPIO8 - GPIO11, set it high
    GpioCtrlRegs.GPAPUD.bit.GPIO17 = 0; // Enable pullup on GPIO17
    GpioDataRegs.GPASET.bit.GPIO17 = 1; // Load output latch
    GpioCtrlRegs.GPAMUX2.bit.GPIO17 = 0; // GPIO17 = GPIO17
    GpioCtrlRegs.GPADIR.bit.GPIO17 = 1; // GPIO17 = output

    EDIS;
    }

    void I2CA_Init(void)
    {
    // Initialize I2C
    I2caRegs.I2CSAR = 0x0050; // Slave address - EEPROM control code

    I2caRegs.I2CPSC.all = 6; // Prescaler - need 7-12 Mhz on module clk
    I2caRegs.I2CCLKL = 500;//10; // NOTE: must be non zero
    I2caRegs.I2CCLKH = 500;//5; // NOTE: must be non zero
    I2caRegs.I2CIER.all = 0x24; // Enable SCD & ARDY interrupts

    I2caRegs.I2CMDR.all = 0x0020; // Take I2C out of reset
    // Stop I2C when suspended
    I2caRegs.I2CFFTX.all = 0x6000; // Enable FIFO mode and TXFIFO

    I2caRegs.I2CFFRX.all = 0; // reset RXFFINT,

    return;
    }
  • Have you checked the SCL and SDA lines with an oscilloscope to make sure the slave isn't NACKing or holding SCL low? What are the values in the I2CSTR, I2CMDR, and I2CFFTX registers after you fail to get the second interrupt?
  • I found a connection issue. Currently I send four bytes and I never get an interrupt! After sending the forth byte, SDA is high and the SCL is low. The I2CSTR is 0x1010, the I2CMDR is 0x4E20 and the I2CFFTX 0x60A1.

    Uint16 EEpromWriteDataBlock( void )
    {
    Uint16 i;
    if (I2caRegs.I2CMDR.bit.STP == 1)
    {
    return I2C_STP_NOT_READY_ERROR;
    }
    I2caRegs.I2CSAR = I2cMsgOut.MsgSlaveAddress;

    // Check if bus busy
    if (I2caRegs.I2CSTR.bit.BB == 1)
    {
    return I2C_BUS_BUSY_ERROR;
    }
    I2caRegs.I2CCNT = PACKET_SIZE;
    for( i = 0; i < FIFO_SIZE ; i++ )
    { // included 2 address bytes and first 2 data bytes.
    I2caRegs.I2CDXR = I2cMsgOut.SendBuffer[ I2cMsgOut.NumBytesSent++ ];
    }
    I2cMsgOut.MsgCommand = I2C_MSGSTAT_SEND_WITHSTOP;
    EepromEnableWriting();
    I2caRegs.I2CFFTX.all = 0x6021;
    I2caRegs.I2CIER.all = 0x20;// dtr 0x20; // use FF interrupts
    I2caRegs.I2CMDR.all = 0x6E20;
    return I2C_SUCCESS;
    }

    I have a Beagle I2C analyzer I will be looking at it next. Any idea what is wrong?
  • Did you set up the interrupts correctly in the PIE. Note that the I2C FIFO interrupt is on a different channel than the normal/status interrupts.
  • Thunk, thunk. Keyboard impression in forehead. Totally missed the PIE changes. I was looking at the ISRs and missed the PIE. I will look at the PIE today.

    Again thanks