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.

Interrupt based I2C on Stellaris LM4f232h5qd

Other Parts Discussed in Thread: SYSBIOS

Hi,

I am very new to Stellaris LM4F232 controller. I have to implement Interrupt based I2C communication on LM4F232 (as a master). For that i am refering following code.

#define STATE_IDLE         0
#define STATE_WRITE_NEXT   1
#define STATE_WRITE_FINAL  2
#define STATE_WAIT_ACK     3
#define STATE_SEND_ACK     4
#define STATE_READ_ONE     5
#define STATE_READ_FIRST   6
#define STATE_READ_NEXT    7
#define STATE_READ_FINAL   8
#define STATE_READ_WAIT    9

//*****************************************************************************
//
// The variables that track the data to be transmitted or received.
//
//*****************************************************************************
static unsigned char *g_pucData = 0;
static unsigned long g_ulCount = 0;

//*****************************************************************************
//
// The current state of the interrupt handler state machine.
//
//*****************************************************************************
static volatile unsigned long g_ulState = STATE_IDLE;

//*****************************************************************************
//
// The error routine that is called if the driver library encounters an error.
//
//*****************************************************************************
#ifdef DEBUG
void
__error__(char *pcFilename, unsigned long ulLine)
{
}
#endif

//*****************************************************************************
//
// The I2C interrupt handler.
//
//*****************************************************************************
void
I2CIntHandler(void)
{
    //
    // Clear the I2C interrupt.
    //
    I2CMasterIntClear(I2C0_MASTER_BASE);

    //
    // Determine what to do based on the current state.
    //
    switch(g_ulState)
    {
        //
        // The idle state.
        //
        case STATE_IDLE:
        {
            //
            // There is nothing to be done.
            //
            break;
        }

        //
        // The state for the middle of a burst write.
        //
        case STATE_WRITE_NEXT:
        {
            //
            // Write the next byte to the data register.
            //
            I2CMasterDataPut(I2C0_MASTER_BASE, *g_pucData++);
            g_ulCount--;

            //
            // Continue the burst write.
            //
            I2CMasterControl(I2C0_MASTER_BASE, I2C_MASTER_CMD_BURST_SEND_CONT);

            //
            // If there is one byte left, set the next state to the final write
            // state.
            //
            if(g_ulCount == 1)
            {
                g_ulState = STATE_WRITE_FINAL;
            }

            //
            // This state is done.
            //
            break;
        }

        //
        // The state for the final write of a burst sequence.
        //
        case STATE_WRITE_FINAL:
        {
            //
            // Write the final byte to the data register.
            //
            I2CMasterDataPut(I2C0_MASTER_BASE, *g_pucData++);
            g_ulCount--;

            //
            // Finish the burst write.
            //
            I2CMasterControl(I2C0_MASTER_BASE,
                             I2C_MASTER_CMD_BURST_SEND_FINISH);

            //
            // The next state is to wait for the burst write to complete.
            //
            g_ulState = STATE_SEND_ACK;

            //
            // This state is done.
            //
            break;
        }

        //
        // Wait for an ACK on the read after a write.
        //
        case STATE_WAIT_ACK:
        {
            //
            // See if there was an error on the previously issued read.
            //
            if(I2CMasterErr(I2C0_MASTER_BASE) == I2C_MASTER_ERR_NONE)
            {
                //
                // Read the byte received.
                //
                I2CMasterDataGet(I2C0_MASTER_BASE);

                //
                // There was no error, so the state machine is now idle.
                //
                g_ulState = STATE_IDLE;

                //
                // This state is done.
                //
                break;
            }

            //
            // Fall through to STATE_SEND_ACK.
            //
        }

        //
        // Send a read request, looking for the ACK to indicate that the write
        // is done.
        //
        case STATE_SEND_ACK:
        {
            //
            // Put the I2C master into receive mode.
            //
            I2CMasterSlaveAddrSet(I2C0_MASTER_BASE, 0x50, true);

            //
            // Perform a single byte read.
            //
            I2CMasterControl(I2C0_MASTER_BASE, I2C_MASTER_CMD_SINGLE_RECEIVE);

            //
            // The next state is the wait for the ack.
            //
            g_ulState = STATE_WAIT_ACK;

            //
            // This state is done.
            //
            break;
        }

        //
        // The state for a single byte read.
        //
        case STATE_READ_ONE:
        {
            //
            // Put the I2C master into receive mode.
            //
            I2CMasterSlaveAddrSet(I2C0_MASTER_BASE, 0x50, true);

            //
            // Perform a single byte read.
            //
            I2CMasterControl(I2C0_MASTER_BASE, I2C_MASTER_CMD_SINGLE_RECEIVE);

            //
            // The next state is the wait for final read state.
            //
            g_ulState = STATE_READ_WAIT;

            //
            // This state is done.
            //
            break;
        }

        //
        // The state for the start of a burst read.
        //
        case STATE_READ_FIRST:
        {
            //
            // Put the I2C master into receive mode.
            //
            I2CMasterSlaveAddrSet(I2C0_MASTER_BASE, 0x50, true);

            //
            // Start the burst receive.
            //
            I2CMasterControl(I2C0_MASTER_BASE,
                             I2C_MASTER_CMD_BURST_RECEIVE_START);

            //
            // The next state is the middle of the burst read.
            //
            g_ulState = STATE_READ_NEXT;

            //
            // This state is done.
            //
            break;
        }

        //
        // The state for the middle of a burst read.
        //
        case STATE_READ_NEXT:
        {
            //
            // Read the received character.
            //
            *g_pucData++ = I2CMasterDataGet(I2C0_MASTER_BASE);
            g_ulCount--;

            //
            // Continue the burst read.
            //
            I2CMasterControl(I2C0_MASTER_BASE,
                             I2C_MASTER_CMD_BURST_RECEIVE_CONT);

            //
            // If there are two characters left to be read, make the next
            // state be the end of burst read state.
            //
            if(g_ulCount == 2)
            {
                g_ulState = STATE_READ_FINAL;
            }

            //
            // This state is done.
            //
            break;
        }

        //
        // The state for the end of a burst read.
        //
        case STATE_READ_FINAL:
        {
            //
            // Read the received character.
            //
            *g_pucData++ = I2CMasterDataGet(I2C0_MASTER_BASE);
            g_ulCount--;

            //
            // Finish the burst read.
            //
            I2CMasterControl(I2C0_MASTER_BASE,
                             I2C_MASTER_CMD_BURST_RECEIVE_FINISH);

            //
            // The next state is the wait for final read state.
            //
            g_ulState = STATE_READ_WAIT;

            //
            // This state is done.
            //
            break;
        }

        //
        // This state is for the final read of a single or burst read.
        //
        case STATE_READ_WAIT:
        {
            //
            // Read the received character.
            //
            *g_pucData++  = I2CMasterDataGet(I2C0_MASTER_BASE);
            g_ulCount--;

            //
            // The state machine is now idle.
            //
            g_ulState = STATE_IDLE;

            //
            // This state is done.
            //
            break;
        }
    }
}

//*****************************************************************************
//
// Write to the Atmel device.
//
//*****************************************************************************
void
AtmelWrite(unsigned char *pucData, unsigned long ulOffset,
           unsigned long ulCount)
{
    //
    // Save the data buffer to be written.
    //
    g_pucData = pucData;
    g_ulCount = ulCount;

    //
    // Set the next state of the interrupt state machine based on the number of
    // bytes to write.
    //
    if(ulCount != 1)
    {
        g_ulState = STATE_WRITE_NEXT;
    }
    else
    {
        g_ulState = STATE_WRITE_FINAL;
    }

    //
    // Set the slave address and setup for a transmit operation.
    //
    I2CMasterSlaveAddrSet(I2C0_MASTER_BASE, 0x50 | (ulOffset >> 8), false);

    //
    // Place the address to be written in the data register.
    //
    I2CMasterDataPut(I2C0_MASTER_BASE, ulOffset);

    //
    // Start the burst cycle, writing the address as the first byte.
    //
    I2CMasterControl(I2C0_MASTER_BASE, I2C_MASTER_CMD_BURST_SEND_START);

    //
    // Wait until the I2C interrupt state machine is idle.
    //
    while(g_ulState != STATE_IDLE)
    {
    }
}

//*****************************************************************************
//
// Read from the Atmel device.
//
//*****************************************************************************
void
AtmelRead(unsigned char *pucData, unsigned long ulOffset,
          unsigned long ulCount)
{
    //
    // Save the data buffer to be read.
    //
    g_pucData = pucData;
    g_ulCount = ulCount;

    //
    // Set the next state of the interrupt state machine based on the number of
    // bytes to read.
    //
    if(ulCount == 1)
    {
        g_ulState = STATE_READ_ONE;
    }
    else
    {
        g_ulState = STATE_READ_FIRST;
    }

    //
    // Start with a dummy write to get the address set in the EEPROM.
    //
    I2CMasterSlaveAddrSet(I2C0_MASTER_BASE, 0x50 | (ulOffset >> 8), false);

    //
    // Place the address to be written in the data register.
    //
    I2CMasterDataPut(I2C0_MASTER_BASE, ulOffset);

    //
    // Perform a single send, writing the address as the only byte.
    //
    I2CMasterControl(I2C0_MASTER_BASE, I2C_MASTER_CMD_SINGLE_SEND);

    //
    // Wait until the I2C interrupt state machine is idle.
    //
    while(g_ulState != STATE_IDLE)
    {
    }
}

//*****************************************************************************
//
// This example demonstrates the use of the I2C block to connect to an Atmel
// AT24C08A EEPROM.
//
//*****************************************************************************
int
main(void)
{
    unsigned char pucData[16];
    unsigned long ulIdx;

    //
    // Set the clocking to run directly from the crystal.
    //
    SysCtlClockSet(SYSCTL_SYSDIV_1 | SYSCTL_USE_OSC | SYSCTL_OSC_MAIN |
                   SYSCTL_XTAL_6MHZ);

    //
    // Init the PDC and the LCD.
    //
    PDCInit();
    PDCLCDInit();
    PDCLCDBacklightOn();

    //
    // Enable the peripherals used by this example.
    //
    SysCtlPeripheralEnable(SYSCTL_PERIPH_I2C0);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);

    //
    // Indicate that the I2C example is running.
    //
    PDCLCDSetPos(0, 0);
    PDCLCDWrite("I2C running...", 14);

    //
    // Enable processor interrupts.
    //
    IntMasterEnable();

    //
    // Configure the appropriate pins to be I2C instead of GPIO.
    //
    GPIOPinTypeI2C(GPIO_PORTB_BASE, GPIO_PIN_2 | GPIO_PIN_3);

    //
    // Initialize the I2C master.
    //
    I2CMasterInitExpClk(I2C0_MASTER_BASE, SysCtlClockGet(), false);

    //
    // Enable the I2C interrupt.
    //
    IntEnable(INT_I2C0);

    //
    // Enable the I2C master interrupt.
    //
    I2CMasterIntEnable(I2C0_MASTER_BASE);

    //
    // Write a data=address pattern into the first 16 bytes of the Atmel
    // device.
    //
    for(ulIdx = 0; ulIdx < 16; ulIdx++)
    {
        pucData[ulIdx] = ulIdx;
    }
    AtmelWrite(pucData, 0, 16);

    //
    // Read back the first 16 bytes of the Atmel device and verify that it
    // contains the data it should.
    //
    AtmelRead(pucData, 0, 16);
    for(ulIdx = 0; ulIdx < 16; ulIdx++)
    {
        if(pucData[ulIdx] != ulIdx)
        {
            PDCLCDSetPos(0, 1);
            PDCLCDWrite("Data error.", 11);
            while(1)
            {
            }
        }
    }

    //
    // Success.
    //
    PDCLCDSetPos(0, 1);
    PDCLCDWrite("Success.", 8);

    //
    // Finished.
    //
    while(1)
    {
    }
}

I have some Questions in this code

1. Why "STATE_WAIT_ACK  and STATE_SEND_ACK" states are used.(We dont do these steps while polling based transmission). Actually we finish sending of data after sending I2C_MASTER_CMD_BURST_SEND_FINISH.

2. As we will get interrupt after sending each byte.  is it neccesory to check transmission error at start of  ISR Routine. why in this code error is check at state STATE_WAIT_ACK? i.e after compliting whole transaction(after getting STOP bit) .

  • I agree with your assessment of those two states.  I have implemented a lot of I2C code based on the example you're referring to (the biggest being the SMBus stack in StellarisWare/utils) and have typically excluded those states since they aren't really useful.  I also don't understand why a read operation would be requested after a failed NACK on a write...  I also agree that error checking should be done at the beginning of each ISR.  In my implementations, I simply read the I2CMCSR to see if errors occurred before doing any data processing.  I believe this to be a much safer implementation than this example.

  • Hi Eric

    Thanks for your suggestion, i removed that two states and my code is working fine.

  • I too am working with the new M4 class CPU and having an issue registering my I2C ISR in CC5. I have tried adding the Startup_ccs.c and modifying the handler there and just simply adding this line in my InitI2C routine:

    IntRegister (I2C0_MASTER_BASE,I2CIntHandler);   // Hook the ISR

    In either cazse I get the following linker error:

    <Linking>

    >> WARNING: --code_state=32 is invalid for Cortex-M (ignored)

    "../lm4f232h5qd.cmd", line 37: error #10099-D: run placement fails for object

    ".vtable", size 0x26c (page 0). Available ranges:

    SRAM size: 0x8000 unused: 0x7cac max hole: 0x7cac

    error #10010: errors encountered during linking; "Test Processor.out" not

    built

    Thoughts? Thanks, Jeff

  • Hi Jeff,

    That's not an error I've seen before.  It seems like there is either a problem with the way you are declaring your interrupt handler or the way your project settings are set up.  Would you be able to post your startup file and the “.cmd” file for this project? Also, did you create this project from scratch? If so,  you may want to try copying the C from this project into an already working project from StellarisWare (maybe the hello example?) and re-type the relevant changes to the startup file to see if the pre-made project settings eliminate the problem.

    Regards,

    Christian

  • Jeffrey Jacobson said:
    just simply adding this line in my InitI2C routine:IntRegister (I2C0_MASTER_BASE,I2CIntHandler);   // Hook the ISR

    Beware when poster (or boss) uses "simply!"  Rarely simple.  Earlier poster succeeded without "Registering" his interrupts - your "simple" is likely cause...

    From SW-DRL-UG-8555 pg 246: Re: Function IntRegister

    "The use of this function (directly or indirectly via a peripheral driver interrupt register function) moves the interrupt vector table from flash to SRAM"  Therefore, care must be taken when linking the application to ensure that the SRAM vector table is located at the beginning of SRAM; otherwise the NVIC does not look in the correct portion of memory for the vector table...

    Suggest that you model original poster's interrupt format - master intRegister in the future...

  • I used an existing sys/bios example called 'typical' as my starting point and used the examples people have posted to move forward. My simply statement was in reference to making the call per the examples to hook my ISR without the need to add startup files. That is what did not work. Its amazing to me that with all the people out there that there is not a single FULL sample that actually works. I need mine to be interrupt driven not just force bytes out like the examples show. Also, not able to see a working example using Port B pins 2 & 3.

    So, I went back to the 'original' poster and that code does not work either. I have had a TI FAE out here for a full day and he cant get it to link or work so its not just me. It would be great if at the end of fixing someone's issue, the complete solution is posted instead of bits and pieces that only fix their problem but not the rest of us who do not have all the hidden, at there are tons of them, tricks that need to be done to SYS/BIOS to get it to work.

    Sorry for venting but I am no closer to solving my issue then I was last Thursday.

    My goal is to use Port B I2C0 as a interrupt driven I2C interface on  the LM4F232 part using SYS/BIOS and the dev kit.

    I will keep looking and trying things. When I find the solution, I will for sure post the complete solution not just bits & pieces.

  • I used the 'typical' example under sys/Bios as my starting point. Again, I am trying to get this to work under SYS/BIOS. When you create that project there is no startup file added...

    I will keep looking for help with this. Thanks, Jeff

  • I feel your pain - did offer what I believed to be logical (and documented) solution.  And - minus your SYS/BIOS - I did get the original "LMI" version of poster's interrupt driven I2C to work several years back.

    Suspect that the relative "newness" of SYS/BIOS may be magnifying your issue - often such developments require time to earn full, "bullet-proof" status.

    As both marketing & tech guy - the more you can do to influence others to adopt SYS/BIOS - the more resources TI can direct in this direction.  (to my mind - the features/functions/benefits of SYS/BIOS have not appeared in any convincing fashion yet on this forum...)  Wish you well - this issue outside my areas of contribution...

  • Thank you for your help as it has proven to be outstanding!

    We will figure this out

    Jeff

  • Well the patient is now back at least among the living. I am able to get the ISR hooked using the hwi of sys/bios so at this point I am past that. I am watching the code and for some reason in my write code, I get the start with the address followed by an extra (unexpected) data byte. The call that I think is doing it is:

        //
        // Start the burst cycle, writing the address as the first byte.
        //
        I2CMasterControl(I2C0_MASTER_BASE, I2C_MASTER_CMD_BURST_SEND_START);

    The whole write routine is:

    //*****************************************************************************
    //
    // Write to the I2C device.
    //
    //*****************************************************************************
    void I2CWrite(unsigned char *pucData, unsigned long ulBaseAddress, unsigned long ulOffset,unsigned long ulCount)
    {
        //
        // Save the data buffer to be written.
        //
        g_pucData = pucData;
        g_ulCount = ulCount;

        //
        // Set the next state of the interrupt state machine based on the number of
        // bytes to write.
        //
        if(ulCount != 1)
        {
            g_ulState = STATE_WRITE_NEXT;
        }
        else
        {
            g_ulState = STATE_WRITE_FINAL;
        }

        //
        // Set the slave address and setup for a transmit operation.
        //
        I2CMasterSlaveAddrSet(I2C0_MASTER_BASE, ulBaseAddress | (ulOffset >> 8), false);

        //
        // Start the burst cycle, writing the address as the first byte.
        //
        I2CMasterControl(I2C0_MASTER_BASE, I2C_MASTER_CMD_BURST_SEND_START);

        //
        // Wait until the I2C interrupt state machine is idle.
        //
        while(g_ulState != STATE_IDLE);
    }

    Any thoughts why that line would initiate a data byte to be sent?

    When I get this fully bugged out today, I will post the solution to this also!

    Thanks, Jeff

  • Jeffrey Jacobson said:
    followed by an extra (unexpected) data byte

    Would ease, speed, enhance remote diagnosis if you could "seed" or otherwise identify the source mechanism for said (unexpected) data byte.

    In my (non SYS-BIOS) experience - I2CMasterControl w/param CMD_BURST_SEND_START causes the I2C transfer of: Slave Adr, R/W bit, and the byte specified by your I2CMasterDataPut() instruction - thus 2 bytes are transferred.  You state "extra" byte - but not the number of bytes transferred.  My findings are that 2 bytes (Slave Adr & R/W bit and the byte defined by I2CMasterDataPut() are both emitted by function, "I2CMasterControl" with the parameter as specified, above.

    Hope this sheds some light - I have scope traces (and causal nexus code) showing 2 & 3 byte transfers if you believe that would assist...  (again all w/o SYS-BIOS)

  • I agree with your findings. If my code sends 1 byte or 2 bytes, all is well as I do not use the function

                I2CMasterControl(I2C0_MASTER_BASE, I2C_MASTER_CMD_BURST_SEND_CONT);

    However, if I have > 2 bytes and that call is used, my scope (which has built in I2C sniffer) has random issues with the timing. Never when count is < 3. The code I am using came from the forum and I have been tweaking it here and there. (Assume INIT works which it does) so in my main I have code that writes 3 bytes by:

        //
        // Write a data=address pattern into the first 16 bytes of the I2C
        // device.
        //
        for(ulIdx = 0; ulIdx < 16; ulIdx++) pucData[ulIdx] = ulIdx+1;

        I2CWrite(pucData, ulBaseAddress, 0, 3);

    then in the I2C routines, the write procedure looks like:


    //*****************************************************************************
    //
    // Write to the I2C device.
    //
    //*****************************************************************************
    void I2CWrite(unsigned char *pucData, unsigned long ulBaseAddress, unsigned long ulOffset,unsigned long ulCount)
    {
        //
        // Save the data buffer to be written.
        //
        g_pucData = pucData;
        g_ulCount = ulCount;

        //
        // Set the next state of the interrupt state machine based on the number of
        // bytes to write.
        //
        if(ulCount > 2 ) //!= 1)
        {
            g_ulState = STATE_WRITE_NEXT;
        }
        else
        {
            g_ulState = STATE_WRITE_FINAL;
        }

        //
        // Set the slave address and setup for a transmit operation.
        //
        I2CMasterSlaveAddrSet(I2C0_MASTER_BASE, ulBaseAddress | (ulOffset >> 8), false);

        //
        // Write the first byte to the data register.
        //
        I2CMasterDataPut(I2C0_MASTER_BASE, *g_pucData++);
        g_ulCount--;

         //
        // Start the burst cycle, writing the address as the first byte.
        //
        I2CMasterControl(I2C0_MASTER_BASE, I2C_MASTER_CMD_BURST_SEND_START);

        //
        // Delay until transmission completes
        //
        while(I2CMasterBusy(I2C0_MASTER_BASE))
        {
        }
    }

    Then in the interrupt handler state machine I have:

    //*****************************************************************************
    //
    // The I2C interrupt handler.
    //
    //*****************************************************************************
    void I2CIntHandler(void)
    {
        //
        // Clear the I2C interrupt.
        //
        I2CMasterIntClear(I2C0_MASTER_BASE);

        //
        // Determine what to do based on the current state.
        //
        switch(g_ulState)
        {
            //
            // The idle state.
            //
            case STATE_IDLE:
            {
                //
                // There is nothing to be done.
                //
                break;
            }

            //
            // The state for the middle of a burst write.
            //
            case STATE_WRITE_NEXT:
            {
                //
                // Write the next byte to the data register.
                //
                I2CMasterDataPut(I2C0_MASTER_BASE, *g_pucData++);
                g_ulCount--;

                //
                // Continue the burst write.
                //
                I2CMasterControl(I2C0_MASTER_BASE, I2C_MASTER_CMD_BURST_SEND_CONT);

                //
                // If there is one byte left, set the next state to the final write
                // state.
                //
                if(g_ulCount == 1)
                {
                    g_ulState = STATE_WRITE_FINAL;
                }

                //
                // This state is done.
                //
                break;
            }

            //
            // The state for the final write of a burst sequence.
            //
            case STATE_WRITE_FINAL:
            {
                //
                // Write the final byte to the data register.
                //
                I2CMasterDataPut(I2C0_MASTER_BASE, *g_pucData++);
                g_ulCount--;

                //
                // Finish the burst write.
                //
                I2CMasterControl(I2C0_MASTER_BASE,I2C_MASTER_CMD_BURST_SEND_FINISH);

                 //
                // The next state is to wait for the burst write to complete.
                //
                g_ulState = STATE_IDLE;

                //
                // This state is done.
                //
                break;
            }
    }

    Again, if the case STATE_WRITE_NEXT: gets used, timing is not correct and it does not talk to my I2C slave device. Do I have the code correct in that case meaning do I also need to put the net byte in the register? Is there any delay or checking needed between the Start and Cont???

    Any help would be great. Thanks in advance, Jeff



  • Forgive me - slaving away @ dungeon - will try for more in-depth tonight from home.  I would add I2CMasterErr() after each I2C transfer - this fnt. checks for Ack Errors (Adr & Data) and Loss of Bus Arbitration.  Always wise/safest to include such checks.  SW-DRL-UG-8555 pg 206 details this fnt.

    We generated 2 byte I2C transfer via I2CMasterControl() w CMD_BURST_SEND_START param and 3 byte transfer via final I2CMasterControl() w CMD_BURST_SEND_FINISH param sent after initial 2 byte transfer.  The CMD_BURST_SEND_CONT param is required for transfers in excess of 3 bytes - and eliminates further I2C Start/Stop sequences.  (the SEND_START generates the I2C Start Condx - the SEND_FINISH generates the I2C Stop Condx.)  Some slaves may require a renewed start condition - post their initial addressing - in depth read of slave data sheet should reveal.  Hope that this helps - will try to expand later - jammed presently...  

    Update:  just dawned - (haven't checked your code) be sure to employ I2CMasterBusy after each/every I2C transfer.  IIRC this caused not the addition of a byte but the "loss" of the put byte when I neglected this test...

     

  • As promised. I have working code with the Dev Kit and SYS/BIOS. I had to hook the ISR using a hwi as the startup file nor the register int handler worked. My .cfg looks like:

    var hwi1Params = new Hwi.Params();
    hwi1Params.instance.name = "hwi1";
    hwi1Params.priority = 25;
    hwi1Params.eventId = 24;
    Program.global.hwi1 = Hwi.create(24, "&I2CIntHandler", hwi1Params);

    Then, I used someone elses code from the forum and modified it to work with my hardware. The EEPROM uses 2 byte addressing so the write & reads will need to be made more generic for other types of I2C devices. My goal was to get SYS/BIOS and M4 to work. My hardware for testing is:

    In the main I have the following which just calls the init of the I2C and then for simplicity, just runs a 1 second timer that writes a byte to the EEPROM and then on the next second reads a byte from the EEPROM.

    Void main()
    {
        InitI2C();            // Initialize the I2C port

        BIOS_start();         // Enable interrupts and start SYS/BIOS
    }

    volatile unsigned char ucValue = 0;
    volatile unsigned char ucState = 0;

    Void clk0Fxn(UArg arg0)
    {
        unsigned char pucData[16];
        unsigned long ulBaseAddress = SLAVE_ADDRESS;

        if(!ucState)
        {
            pucData[0] = 0x00;
            if(ucValue++ == 255)
                ucValue = 0;
            pucData[1] = ucValue;
            pucData[2] = ucValue;
            I2CWrite(pucData, ulBaseAddress, 3);
        }
        else
        {
            pucData[0] = 0x00;
            pucData[1] = ucValue;
            pucData[2] = 0x00;
            pucData[3] = 0x00;
            I2CRead(pucData, ulBaseAddress, 1);
        }
        ucState ^= 0xff;    // flip it for next time
    }

    Now the I2C code is as follows: (this is not the most efficient but it works and I send this to help others get started)

    /*
     * I2C.c
     */
    #include "LCM.h"
    #include "MyI2C.h"

    //*****************************************************************************
    //
    // The variables that track the data to be transmitted or received.
    //
    //*****************************************************************************
    static unsigned char *g_pucData = 0;
    static unsigned long g_ulCount = 0;

    //*****************************************************************************
    //
    // The current state of the interrupt handler state machine.
    //
    //*****************************************************************************
    static volatile unsigned long g_ulState = STATE_IDLE;

    //*****************************************************************************
    //
    // The error routine that is called if the driver library encounters an error.
    //
    //*****************************************************************************
    #ifdef DEBUG
    void
    __error__(char *pcFilename, unsigned long ulLine)
    {
    }
    #endif

    //*****************************************************************************
    //
    // The I2C initialization.
    //
    //*****************************************************************************
    Void InitI2C(void)
    {
        //
        // The I2C0 peripheral must be enabled before use.
        //
        SysCtlPeripheralEnable(SYSCTL_PERIPH_I2C0);

        //
        // For this example I2C0 is used with PortB[3:2].  The actual port and
        // pins used may be different on your part, consult the data sheet for
        // more information.  GPIO port B needs to be enabled so these pins can
        // be used.
        //
        SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);


        //
        // Configure the pin muxing for I2C0 functions on port B2 and B3.
        //
        GPIOPinConfigure(GPIO_PB2_I2C0SCL);
        GPIOPinConfigure(GPIO_PB3_I2C0SDA);

        //
        // Select the I2C function for these pins.  This function will also
        // configure the GPIO pins pins for I2C operation, setting them to
        // open-drain operation with weak pull-ups.  Consult the data sheet
        // to see which functions are allocated per pin.
        //
        GPIOPinTypeI2CSCL(GPIO_PORTB_BASE, GPIO_PIN_2);
        GPIOPinTypeI2C(GPIO_PORTB_BASE, GPIO_PIN_3);

        //
        // Enable and initialize the I2C0 master module.  Use the system clock for
        // the I2C0 module.  The last parameter sets the I2C data transfer rate.
        // If false the data rate is set to 100kbps and if true the data rate will
        // be set to 400kbps.  For this example we will use a data rate of 100kbps.
        //
        I2CMasterInitExpClk(I2C0_MASTER_BASE, SysCtlClockGet(), false);

        //
        // Enable the I2C master interrupt.
        //
        I2CMasterIntEnableEx(I2C0_MASTER_BASE, I2C_MASTER_INT_DATA);

        //
        // Enable the I2C interrupt.
        //
        IntEnable(INT_I2C0);
    }

    //*****************************************************************************
    //
    // The I2C interrupt handler.
    //
    //*****************************************************************************
    void I2CIntHandler(void)
    {
        //
        // Clear the I2C interrupt.
        //
        I2CMasterIntClear(I2C0_MASTER_BASE);

        //
        // Determine what to do based on the current state.
        //
        switch(g_ulState)
        {
            //
            // The idle state.
            //
            case STATE_IDLE:
            {
                //
                // There is nothing to be done.
                //
                break;
            }

            //
            // The state for the middle of a burst write.
            //
            case STATE_WRITE_NEXT:
            {
                //
                // Write the next byte to the data register.
                //
                I2CMasterDataPut(I2C0_MASTER_BASE, *g_pucData++);
                g_ulCount--;

                //
                // Continue the burst write.
                //
                I2CMasterControl(I2C0_MASTER_BASE, I2C_MASTER_CMD_BURST_SEND_CONT | 8);

                //
                // If there is one byte left, set the next state to the final write
                // state.
                //
                if(g_ulCount == 1)
                {
                    g_ulState = STATE_WRITE_FINAL;
                }

                //
                // This state is done.
                //
                break;
            }

            //
            // The state for the final write of a burst sequence.
            //
            case STATE_WRITE_FINAL:
            {
                //
                // Write the final byte to the data register.
                //
                I2CMasterDataPut(I2C0_MASTER_BASE, *g_pucData++);
                g_ulCount--;

                //
                // Finish the burst write.
                //
                I2CMasterControl(I2C0_MASTER_BASE,I2C_MASTER_CMD_BURST_SEND_FINISH | 8);

                //
                // Delay until transmission completes
                //
                while(I2CMasterBusy(I2C0_MASTER_BASE))
                {
                }

                //
                // The next state is to wait for the burst write to complete.
                //
                g_ulState = STATE_IDLE;

                //
                // This state is done.
                //
                break;
            }

            //
            // The state for a single byte read.
            //
            case STATE_READ_ONE:
            {
                //
                // Put the I2C master into receive mode.
                //
                I2CMasterSlaveAddrSet(I2C0_MASTER_BASE, SLAVE_ADDRESS, true);

                //
                // Perform a single byte read.
                //
                I2CMasterControl(I2C0_MASTER_BASE, I2C_MASTER_CMD_SINGLE_RECEIVE);

                //
                // The next state is the wait for final read state.
                //
                g_ulState = STATE_READ_FINAL;

                //
                // This state is done.
                //
                break;
            }

            //
            // The state for the start of a burst read.
            //
            case STATE_READ_FIRST:
            {
                //
                // Put the I2C master into receive mode.
                //
                I2CMasterSlaveAddrSet(I2C0_MASTER_BASE, SLAVE_ADDRESS, true);

                //
                // Start the burst receive.
                //
                I2CMasterControl(I2C0_MASTER_BASE,
                                 I2C_MASTER_CMD_BURST_RECEIVE_START);

                //
                // The next state is the middle of the burst read.
                //
                g_ulState = STATE_READ_NEXT;

                //
                // This state is done.
                //
                break;
            }

            //
            // The state for the middle of a burst read.
            //
            case STATE_READ_NEXT:
            {
                //
                // Read the received character.
                //
                *g_pucData++ = I2CMasterDataGet(I2C0_MASTER_BASE);
                g_ulCount--;

                //
                // Continue the burst read.
                //
                I2CMasterControl(I2C0_MASTER_BASE,
                                 I2C_MASTER_CMD_BURST_RECEIVE_CONT);

                //
                // If there are two characters left to be read, make the next
                // state be the end of burst read state.
                //
                if(g_ulCount == 2)
                {
                    g_ulState = STATE_READ_FINAL;
                }

                //
                // This state is done.
                //
                break;
            }

            //
            // The state for the end of a burst read.
            //
            case STATE_READ_FINAL:
            {
                //
                // Read the received character.
                //
                *g_pucData++ = I2CMasterDataGet(I2C0_MASTER_BASE);
                g_ulCount--;

                //
                // Finish the burst read.
                //
                I2CMasterControl(I2C0_MASTER_BASE,
                                 I2C_MASTER_CMD_BURST_RECEIVE_FINISH);

                //
                // The next state is the wait for final read state.
                //
                g_ulState = STATE_IDLE;

                //
                // This state is done.
                //
                break;
            }

            //
            // This state is for the final read of a single or burst read.
            //
            case STATE_READ_WAIT:
            {
                //
                // Read the received character.
                //
                *g_pucData++  = I2CMasterDataGet(I2C0_MASTER_BASE);
                g_ulCount--;

                //
                // The state machine is now idle.
                //
                g_ulState = STATE_IDLE;

                //
                // This state is done.
                //
                break;
            }

            case STATE_WRITE_ADDRESS:
            {
                //
                // Write the next byte to the data register.
                //
                I2CMasterDataPut(I2C0_MASTER_BASE, *g_pucData++);
                g_ulCount--;

                //
                // Continue the burst write.
                //
                I2CMasterControl(I2C0_MASTER_BASE, I2C_MASTER_CMD_BURST_SEND_CONT);

                //
                // The state machine is now get the data byte.
                //
                g_ulState = STATE_READ_ONE;

                //
                // This state is done.
                //
                break;
            }

        }
    }


    //*****************************************************************************
    //
    // Write to the I2C device.
    //
    //*****************************************************************************
    void I2CWrite(unsigned char *pucData, unsigned long ulBaseAddress, unsigned long ulCount)
    {
        //
        // Save the data buffer to be written.
        //
        g_pucData = pucData;
        g_ulCount = ulCount;

        //
        // Set the next state of the interrupt state machine based on the number of
        // bytes to write.
        //
        if(ulCount > 2 ) //!= 1)
        {
            g_ulState = STATE_WRITE_NEXT;
        }
        else
        {
            g_ulState = STATE_WRITE_FINAL;
        }

        //
        // Set the slave address and setup for a transmit operation.
        //
        I2CMasterSlaveAddrSet(I2C0_MASTER_BASE, ulBaseAddress, false);

        //
        // Write the first byte to the data register.
        //
        I2CMasterDataPut(I2C0_MASTER_BASE, *g_pucData++);
        g_ulCount--;

        //
        // Start the burst cycle, writing the address as the first byte.
        //
        I2CMasterControl(I2C0_MASTER_BASE, I2C_MASTER_CMD_BURST_SEND_START | 8);

        //
        // Wait until the I2C interrupt state machine is idle.
        //
        while(g_ulState != STATE_IDLE);
    }

    //*****************************************************************************
    //
    // Read from the I2C device.
    //
    //*****************************************************************************
    void I2CRead(unsigned char *pucData, unsigned long ulBaseAddress, unsigned long ulCount)
    {
        //
        // Save the data buffer to be read.
        //
        g_pucData = pucData;
        g_ulCount = ulCount;

        //
        // Set the next state of the interrupt state machine based on the number of
        // bytes to read.
        //
        if(ulCount == 1)
        {
            g_ulState = STATE_WRITE_ADDRESS;
        }
        else
        {
            g_ulState = STATE_READ_FIRST;
        }

        //
        // Start with a dummy write to get the address set in the EEPROM.
        //
        I2CMasterSlaveAddrSet(I2C0_MASTER_BASE, ulBaseAddress, false);

        //
        // Write the first byte to the data register.
        //
        I2CMasterDataPut(I2C0_MASTER_BASE, *g_pucData++);
        g_ulCount--;

        //
        // Start the burst cycle, writing the address as the first byte.
        //
        I2CMasterControl(I2C0_MASTER_BASE, I2C_MASTER_CMD_BURST_SEND_START | 8);

        //
        // Wait until the I2C interrupt state machine is idle.
        //
        while(g_ulState != STATE_IDLE);
    }


    In the MyI2C.h file is:


    /*
     * MyI2C.h
     */

    #ifndef I2C_H_
    #define I2C_H_

    #define STATE_IDLE                 0
    #define STATE_WRITE_NEXT           1
    #define STATE_WRITE_FINAL          2
    #define STATE_WAIT_ACK             3
    #define STATE_SEND_ACK             4
    #define STATE_READ_ONE             5
    #define STATE_READ_FIRST           6
    #define STATE_READ_NEXT            7
    #define STATE_READ_FINAL           8
    #define STATE_READ_WAIT            9
    #define STATE_WRITE_ADDRESS    10


    //*****************************************************************************
    //
    // Set the address for slave module. This is a 7-bit address sent in the
    // following format:
    //                      [A6:A5:A4:A3:A2:A1:A0:RS]
    //
    // A zero in the "RS" position of the first byte means that the master
    // transmits (sends) data to the selected slave, and a one in this position
    // means that the master receives data from the slave.
    //
    //*****************************************************************************
    #define SLAVE_ADDRESS     0x50        // This is for U2 on the -320 PCB

    extern void I2CIntHandler(void);
    extern void I2CRead(unsigned char *pucData, unsigned long ulBaseAddress,unsigned long ulCount);
    extern void I2CWrite(unsigned char *pucData, unsigned long ulBaseAddress, unsigned long ulCount);
    extern void InitI2C(void);

    #endif /* I2C_H_ */

    In the LCM.h file is:

    /*
     * LCM.h
     *
     *  Created on: Mar 15, 2012
     */

    #ifndef LCM_H_
    #define LCM_H_

    #include <string.h>
    #include <xdc/std.h>
    #include <xdc/runtime/System.h>

    #include <ti/sysbios/BIOS.h>
    #include <ti/sysbios/knl/Clock.h>
    #include <ti/sysbios/hal/Hwi.h>
    #include <ti/sysbios/knl/Swi.h>
    #include <ti/sysbios/hal/Timer.h>

    #include "\stellarisware\inc\lm4f232h5qd.h"
    #include "\stellarisware\inc\hw_types.h"
    #include "\stellarisware\inc\hw_ints.h"
    #include "\stellarisware\inc\hw_memmap.h"
    #include "\stellarisware\driverlib\interrupt.h"
    #include "\stellarisware\inc\hw_i2c.h"
    #include "\stellarisware\driverlib\sysctl.h"
    #include "\stellarisware\driverlib\i2c.h"
    #include "\stellarisware\driverlib\gpio.h"
    #include "\stellarisware\utils\uartstdio.h"
    #include "\stellarisware\driverlib\pin_map.h"

    #endif /* LCM_H_ */

    I hope this works for anybody struggling with the I2C and SYS/BIOS and this processor. If there are fixes or someone rewrite the above to make it more generic, please post so the rest of us can benefit from it.

    To the people who helped me get this going, thank you!

    Jeff



  • why you are not register your interrupt handler with following API. in the absense of this API is this possible to for system to invoked interrupt hander 

    void
    I2CIntRegister(unsigned long ulBase,
    void (*pfnHandler)(void))