I2C not working on LM3S9B90

Hey all!

I've been trying to get the I2C to work but failed. Any ideas highly appreciated.

I want to use the 2nd channel (I2C1) as a master, but cannot even see a single motion on the pins.
The pins + PCB themselves are OK, I checked via port toggles - all fine. Pullups are where they should be.

And - to add an info about me and my skill-level: I had no trouble at all writing an I2C interrupt/state machine driver from scratch on ARM7

Here is my code:

Code:


 

somewhere 
else in advance this line was called

SysCtlClockSet(SYSCTL_SYSDIV_4 SYSCTL_USE_PLL SYSCTL_OSC_MAIN SYSCTL_XTAL_12MHZ);

then the init part

SysCtlPeripheralEnable
(SYSCTL_PERIPH_GPIOG); 
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOJ); 
GPIOPinTypeI2C(SYSCTL_PERIPH_GPIOGGPIO_PIN_1); 
GPIOPinTypeI2C(SYSCTL_PERIPH_GPIOJGPIO_PIN_0); 
SysCtlPeripheralEnable(SYSCTL_PERIPH_I2C1); 
I2CMasterInitExpClk(I2C1_MASTER_BASESysCtlClockGet(), 0);

and 
the very first data sequence does not give any changes on the line and Busy always stays true

// SEND START 
I2CMasterSlaveAddrSet(I2C1_MASTER_BASEaddress,0I2CMasterDataPut(I2C1_MASTER_BASE,*data++);
I2CMasterControl(I2C1_MASTER_BASE,I2C_MASTER_CMD_BURST_SEND_START);

<
no signal changelines remain 1>
<
btwPCB checked -> OK>

//THIS REMAINS TRUE FOREVER
while(I2CMasterBusy(I2C1_MASTER_BASE







an interesting fact about the toggle test I made:

After the toggles, I tried to revert the pintype through these calls to OD with pullup:

Code:


 
GPIOPinTypeI2C
(SYSCTL_PERIPH_GPIOGGPIO_PIN_1); 
GPIOPinTypeI2C(SYSCTL_PERIPH_GPIOJGPIO_PIN_0); 








After all, I am surprisingly stuck, so any help would be REALLLY welcome

cheers
sakul

37 Replies

  • Hi sakul,
    Is it possible that you could zip up your project and send it to me at support_lmi@ti.com?
    Sue
  • Sue,
    I can send you the entire project, but the point is, if you go back 5 or 6 posts or so, I already posted THE ENTIRE CODE that i am using in order to just get the clock pin to move after main().

    It is just 15 lines of bare code. I tried it in the flavour "StellarisWare" and with plain register accesses ..
    Will strip the project back to the bare minimum tomorrow and send the entire Keil project then.

    In the meantime thanks to all for attention, ideas and participation
  • Hi sakul,
    I appreciate you sending the project. I know you had posted your code, but having the project makes things easier and speedier for us.
    Regards,
    Sue
  • sakul,

    I worked on the I2C issue you are having and I was able to successfully view the I2C0SCL and I2C0SDA signals on the EKK-LM3S9B90 using a scope.

    Here's what I did:

    1) Used 9kOHM pull-ups on PB2 and PB3 (I used a 5V regulated supply for convenience of wiring, but 3.3V will work just fine)

    2) Modified the code to not use the internal pull-ups. They are not strong enough (i.e. quick enough) for I2C operation.

    3) Removed "SysCtlPeripheralReset(SYSCTL_PERIPH_I2C0);" that you call in the for(;;) loop. This will essentially put the I2C0 in the starting state, overwriting all the master and clock setup you did previously.

    Here is the code I used:

    //
    // Setup clock for 20Mhz
    //
    SysCtlClockSet(SYSCTL_SYSDIV_10 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ);

    //
    // Turn on I2S0 and reset to a known state
    //
    SysCtlPeripheralEnable(SYSCTL_PERIPH_I2C0);
    SysCtlPeripheralReset(SYSCTL_PERIPH_I2C0);

    //
    // Configure the PortB pins for I2C0
    //
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);

    //
    // Set GPIO Pins for Open-Drain operation
    //
    GPIOPadConfigSet(GPIO_PORTB_BASE, GPIO_PIN_3, GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_OD);
    GPIOPadConfigSet(GPIO_PORTB_BASE, GPIO_PIN_2, GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_OD);

    //
    // Give control to the I2C Module
    //
    GPIODirModeSet(GPIO_PORTB_BASE, GPIO_PIN_3, GPIO_DIR_MODE_HW);
    GPIODirModeSet(GPIO_PORTB_BASE, GPIO_PIN_2, GPIO_DIR_MODE_HW);

    //
    // Enable and Initalize Master module and Master Clk using 100kbps
    //
    I2CMasterInitExpClk(I2C0_MASTER_BASE, SysCtlClockGet(), 0);

    //
    // Set the slave address, and set the Master to Transmit mode
    //
    I2CMasterSlaveAddrSet(I2C0_MASTER_BASE, 0x3C, false);

    //
    // Place the character to be sent in the data register
    //
    I2CMasterDataPut(I2C0_MASTER_BASE, 'J');

    //
    // Initiate send of character from Master to Slave
    //
    I2CMasterControl(I2C0_MASTER_BASE, I2C_MASTER_CMD_SINGLE_SEND);

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

    while(1){}


    Please try this setup with the provided code and let me know if you see the signals on PB2 and PB3.

    Alex
  • Alex, again many thanx for your attention and time.

    I took your code right from the post. The only thing I changed was SYSCTL_XTAL_12MHZ instead of your 16. And I added a LED at SYSCTL_PERIPH_GPIOF for a convenient trigger. The pullups I already had soldered there were 10k, so I ignored the difference.

    Result: Not a single move.


    IMPORTANT HINT FOR OTHER USERS OF TEMPEST CLASS DEVICES:
    the above sample code by TI Alex will work only on I2C0, as the two I/O pins needed for this interface default to I2C0 after reset (for bootloader usage)
    I2C1 defaults to GPIO and thus needs additional code to set the IO multiplexer to proper values (check GPIOPinConfigure() in Stellaris docs)

    Post edited by: sakul, at: 2010/03/10 16:51
  • Peter2009, you mentioned a "big bug" in I2CMasterSlaveAddrSet() in one of your previous posts. As far as I can tell, this function is fine but, looking at your solution, I think I see what's wrong. You are assuming 8 bit I2C addresses which include the read/write bit. The API, however, assumes 7 bit addresses (the 8 bit address shifted right 1 bit) and a separate parameter to indicate whether you are going to be doing a read or write operation to that slave.

    For every I2C driver that uses a 7 bit address, there is another that uses 8 bit address definitions so it is very important to know which you are working with and shift your addresses if required to match the parameter definitions. We just happen to use the 7 bit version.
  • Sakul,

    Please could you run exactly the code Alex posted with only the crystal frequency change in the SysCtlClockSet call (assuming your board has a 12MHz crystal rather than the 16MHz one on the eval kit) and see what happens? If you see the same failure (nothing on the output), take a look at the contents of the I2C Master Control and Status Register at 0x40020004 and post what you see there.

    I spent a couple of days last week investigating an I2C problem that has been seen on some Tempest chips that results in exactly the symptom you are seeing. It looks like a chip test escape since it's only seen on some ICs but in the failing cases, the status reports arbitration lost (bit 4 set) and a power cycle is required to clear the error.

    If you have more than 1 board or if you can try the test on more than 1 chip, that would be helpful too.
  • -> Dave Peter "big bug"
    ACK - I checked this and stepped thru, cannot see a bug
    its only a matter of viewpoint regarding the shift of the address

    -> Dave
    will do.

    We got two of our own boards here and they behaved the same all the time - but they were obiously out of the same lot. Will try one of our LMI eva boards asap.

    more tomorrow
  • TI Dave,

    Thank you for your comment.
    My opinion is that as the I2C communication works on 8 bit bases it is not practical to use 7 bit address as the address and the direction bit is transmitted together in a byte.
    For example if the manufacturer of my slave chip says that the address is 0xD0/0xD1 it requires additional program step to shift it first right by one to be able to input it into I2CMasterSlaveAddrSet() which will shift it back left and after that will add the direction bit.
    None of the APIs in my practice works in this way.
    That's why I decided to use the direct register access (without shifting).

    Peter2009
  • TI Dave,

    Thank you for your comment.
    My opinion is that as the I2C communication works on 8 bit bases it is not practical to use 7 bit address as the address and the direction bit is transmitted together in a byte.
    For example if the manufacturer of my slave chip says that the address is 0xD0/0xD1 it requires additional program step to shift it first right by one to be able to input it into I2CMasterSlaveAddrSet() which will shift it back left and after that will add the direction bit.
    None of the APIs in my practice works in this way.
    That's why I decided to use the direct register access (without shifting).

    Peter2009