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.

Concerto Experimenter Kit I2C EEPROM communication

Hi,

I'm trying here to communicate with the builtin EEPROM on the concerto experimenter kit but it seems that the I2C0_Master peripheral prefers to not load the data and then just hangs busy for ever.

I'm setting up the I2C controller as per example:

 SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
 SysCtlPeripheralEnable(SYSCTL_PERIPH_I2C0);
 GPIOPinConfigure(GPIO_PB6_I2C0SDA);
 GPIOPinConfigure(GPIO_PB7_I2C0SCL);
 GPIOPinTypeI2C(GPIO_PORTB_BASE, GPIO_PIN_6 | GPIO_PIN_7);
 I2CMasterInitExpClk(I2C0_MASTER_BASE, SysCtlClockGet(SYSTEM_CLOCK_SPEED), false);

and then trying to run a very simple code, just for testing purposes for now:

void I2CWriteTest(void) {
 i2cCurrentAddress = I2C_SLV_ADDR_EEPROM; // Get the EEPROM address from the #defines
 unsigned char put = 'a'; // random char just to write something
 I2CMasterSlaveAddrSet(I2C0_MASTER_BASE, i2cCurrentAddress, I2C_WRITE);
 I2CMasterDataPut(I2C0_MASTER_BASE, put);
 I2CMasterControl(I2C0_MASTER_BASE, I2C_MASTER_CMD_SINGLE_SEND);
 UARTprintf(UART_DEBUG, "checkpoint1"); // Post on the UART0
 while (I2CMasterBusy(I2C0_MASTER_BASE)) {} // wait for the controller to finish
 UARTprintf(UART_DEBUG, "checkpoint2"); // Post on the UART0
}

This code always pass through checkpoint1, but never checkpoint2.
While debugging and I press Pause, I can see the processor is locked inside the while.
I2C_SLV_ADDR_EEPROM is 0x50 or b1010000 (as per manual address is _1_0_1_0_A2_A1_A0_RW) and the Experimenter drawing shows as all to GND.
Analysing the registries when pausing the code I can see I2CMSA = 0x000000A0 meaning that I2CMasterSlaveAddrSet correctly set the 0x50 and added the I2C_WRITE bit at the end of it.
Also on the registries and moving the software step by step using F6 I can see that I2CMDR is always = 0x00000000, even thou I put an 'a' in there.

Is my EEPROM addressing wrong? Is the code wrong? What am I missing?


Thanks!

  • I've been gathering some more data on the hope that someone might help me find the answer.

    I've ran step-by-step both I2C_loopback example and my code comparing the I2C master registers, here is the results:

    Code step Status word I2C loopback status my code status
    Processor finished config I2C Master Control/Status controller idle, bus not busy, no error controller idle, bus not busy, no error
    I2C Master Configuration master EN, slave EN, loopback EN master EN
    I2CMasterDataPut(DATA) - no change in any word no change in any word
    I2CMasterControl(SEND) I2C Master Control/Status controller busy, bus busy controller busy
    I2CSlaveDataGet I2C Master Control/Status controller is idle, bus not busy, no error -
    while (I2CMasterBusy()) {} I2C Master Control/Status controller is idle, bus not busy, no error controller busy

    as you can see my controller gets busy forever, but the bus never gets busy. I wonder if there's any resistor, capacitor or whatever missing on the experimenter kit to make that EEPROM works.

    Despite the different clock speed (my board is 100/100MHz and the example is 150/75MHz) that generates a different Master Timer Period and the slave functions, I don't see any difference in the code.

    Please, the EEPROM is there on the experimenter kit, someone MUST HAVE programmed it (and before anyone suggest: yes, the jumpers are there on the connectivity mux connecting GPIO14-15 to the EEPROM).

    thanks!

  • I've been retrying all possible combinations and read this forum up and down and still nothing.

    I decided to go back to as basic as possible just to make sure there's nothing else influencing it.

    So I started a new project, included f28m35/v120/mware folder, added startup_ccs.c, added F28M35x_generic_M3_RAM.cmd (also tried with F28M35H52C1.cmd), added driverlib.lib and put the following code:

    /*
    * main.c
    */

    #include "inc/hw_types.h"
    #include "inc/hw_sysctl.h"
    #include "inc/hw_memmap.h"

    #include "driverlib/sysctl.h"
    #include "driverlib/gpio.h"
    #include "driverlib/i2c.h"

    void main(void) {

    /*
    * SETUP
    * ============================================
    */

    // Disable Protection
    HWREG(SYSCTL_MWRALLOW) = 0xA5A5A5A5;

    // Sets up PLL, M3 running at 100MHz and C28 running at 100MHz
    SysCtlClockConfigSet(SYSCTL_USE_PLL | (SYSCTL_SPLLIMULT_M & 0xA) | SYSCTL_SYSDIV_1 | SYSCTL_M3SSDIV_1 | SYSCTL_XCLKDIV_4);

    // Disable clock supply for the watchdog modules
    SysCtlPeripheralDisable(SYSCTL_PERIPH_WDOG1);
    SysCtlPeripheralDisable(SYSCTL_PERIPH_WDOG0);

    // Peripherals Enable
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_I2C0);
    SysCtlPeripheralReset(SYSCTL_PERIPH_I2C0);

    /*
    * Setup the I2C bus
    * ============================================
    */
    GPIOPinConfigure(GPIO_PB6_I2C0SDA);
    GPIOPinConfigure(GPIO_PB7_I2C0SCL);
    GPIOPinTypeI2C(GPIO_PORTB_BASE, GPIO_PIN_7 | GPIO_PIN_6);

    I2CMasterInitExpClk(I2C0_MASTER_BASE, SysCtlClockGet(SYSTEM_CLOCK_SPEED), false);

    /*
    * RUN
    * ============================================
    */
    unsigned char data = 'a';
    while (true) {
    I2CMasterSlaveAddrSet(I2C0_MASTER_BASE, 0x50, false);
    I2CMasterDataPut(I2C0_MASTER_BASE, data);
    I2CMasterControl(I2C0_MASTER_BASE, I2C_MASTER_CMD_SINGLE_SEND);
    while (I2CMasterBusy(I2C0_MASTER_BASE)) {
    }

    }

    }

    There's nothing more to it, just that! That's the whole i2c_test_m3 project! No ethernet, no uart, no gpio, no timers (that my full project is using).

    The connectivity MUX is connected as follows:
    Pins 1 to 15 -> all set to Ethernet communication
    Pins 16 to 19 -> not connected/not used
    Pins 20 to 25-> all set to M3_I2C0 and M3_SSI to be used on the EEPROM I2C and microSD card respectively.
    Pins 26 to end -> not connected/not used

    Also jumper J6 is set to pins 2-3 (enabling write to the EEPROM)

    And then I ran this code step by step while watching the registers and got absolutely the same result:

    - Enables and reset: the I2CMCS go to 0x20 (I2C is idle).
    - I2CMasterInitExpClk: master timer got some value x31 and master configuration indicates that master is enabled
    - I2CMasterSlaveAddrSet: Master Slave Address goes to 0xA0 (0x50 with a bit shift)
    - I2CMasterDataPut: nothing changes
    - I2CMasterControl: and the damn thing goes to Busy and locks in there

    this thread http://e2e.ti.com/support/microcontrollers/stellaris_arm_cortex-m3_microcontroller/f/471/t/59371.aspx seems to indicate that might be some bad configuration of the GPIOs but I can't see where, also, all other threads I've read are doing exactly the same thing.

    I'm honestly starting to think that it's some faulty component!

    help anyone ????

  • Hi Ronaldo,

    The issue you are seeing is likely caused by the fact that pin PB7 comes up in a 'locked' state.  This means that the pin configuration (muxing, direction, etc) is fixed and needs to be unlocked before you can configure it.

    To do this, you will need to call the GPIOPinUnlock() function before you configure PB7:

    GPIOPinUnlock(GPIO_PORTB_BASE, GPIO_PIN_7);

    Regards,
    Harrison 

  • Hi Harrison,

    thanks for the answer, this was driving me crazy, plus it could cost me my job. I included the line and now it works.

    The following text might appear a bit angry, it's because I am very, also they are not directed to Harrison in no way, he was the only one who wanted to help and I'm grateful for his help.

    But the biggest questions remain unanswered, and those questions are for TI as a company:

    WHY THIS FUNCTION IS SO POORLY DOCUMENTED??? and WHAT ARE THE OTHER PINS THAT MIGHT CAUSE ME THE SAME PROBLEM (that also are protected)???

    Given how basics the usage of this function is, and by 'basics' I mean - you can't have X peripheral running without using it - why it's not further documented? why it's not on any of the examples? Why did I have to waste so many hours (money) of my company, a TI customer, because of something like this?

    Regards,

  • and in case anyone lands in this thread, to program the F28M35x Concerto MCU is very easy, and anyone that thinks otherwise shouldn't be programming anything

    defines:

     

    #define I2C_Rx_BUFFER_SIZE 22
    #define I2C_Tx_BUFFER_SIZE 22

    #define I2C_SLV_ADDR_EEPROM 0x50
    #define I2C_READ true
    #define I2C_WRITE false
    #define I2C_EEPROM_SIZE 20

    #define I2CWhileMasterBusy while (I2CMasterBusy(I2C0_MASTER_BASE)) {}

    unsigned char i2cBufferTx[I2C_Tx_BUFFER_SIZE];
    unsigned char i2cBufferRx[I2C_Rx_BUFFER_SIZE];
    unsigned char i2cCurrentAddress;

    SETUP:

    	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_I2C0);
    SysCtlPeripheralReset(SYSCTL_PERIPH_I2C0);

    GPIOPinUnlock(GPIO_PORTB_BASE, GPIO_PIN_7); // I hate so much TexasInstrument for this function, so necessary and so poorly documented!
    GPIOPinConfigure(GPIO_PB6_I2C0SDA);
    GPIOPinConfigure(GPIO_PB7_I2C0SCL);
    GPIOPinTypeI2C(GPIO_PORTB_BASE, GPIO_PIN_6 | GPIO_PIN_7);

    I2CMasterInitExpClk(I2C0_MASTER_BASE, SysCtlClockGet(SYSTEM_CLOCK_SPEED), false);

     

    READ EEPROM:

    	i2cCurrentAddress = I2C_SLV_ADDR_EEPROM;
    I2CMasterSlaveAddrSet(I2C0_MASTER_BASE, i2cCurrentAddress, I2C_WRITE);

    // Dummy Write to set the future read address
    I2CMasterDataPut(I2C0_MASTER_BASE, 0); // address zero in the EEPROM memory
    I2CMasterControl(I2C0_MASTER_BASE, I2C_MASTER_CMD_BURST_SEND_START);
    I2CWhileMasterBusy

    I2CMasterDataPut(I2C0_MASTER_BASE, 0); // address zero in the EEPROM memory
    I2CMasterControl(I2C0_MASTER_BASE, I2C_MASTER_CMD_BURST_SEND_CONT);
    I2CWhileMasterBusy

    // Start reading the address 0x00
    I2CMasterSlaveAddrSet(I2C0_MASTER_BASE, i2cCurrentAddress, I2C_READ);

    int i;
    for (i = 0; i < I2C_EEPROM_SIZE; i++) {

    switch (i) {
    case 0:
    I2CMasterControl(I2C0_MASTER_BASE, I2C_MASTER_CMD_BURST_RECEIVE_START);
    break;
    case I2C_EEPROM_SIZE - 1:
    I2CMasterControl(I2C0_MASTER_BASE, I2C_MASTER_CMD_BURST_RECEIVE_FINISH);
    break;
    default:
    I2CMasterControl(I2C0_MASTER_BASE, I2C_MASTER_CMD_BURST_RECEIVE_CONT);
    break;
    }

    I2CWhileMasterBusy
    i2cBufferRx[i] = I2CMasterDataGet(I2C0_MASTER_BASE);

    }

    i2cCurrentAddress = 0;

     

    WRITE EEPROM:

    	i2cCurrentAddress = I2C_SLV_ADDR_EEPROM;
    I2CMasterSlaveAddrSet(I2C0_MASTER_BASE, i2cCurrentAddress, I2C_WRITE);

    int i;
    for (i = 0; i < I2C_EEPROM_SIZE + 2; i++) { // +2 for the address byte
    I2CMasterDataPut(I2C0_MASTER_BASE, i2cBufferTx[i]);
    switch (i) {
    case 0:
    I2CMasterControl(I2C0_MASTER_BASE, I2C_MASTER_CMD_BURST_SEND_START);
    break;
    case I2C_EEPROM_SIZE + 1:
    I2CMasterControl(I2C0_MASTER_BASE, I2C_MASTER_CMD_BURST_SEND_FINISH);
    break;
    default:
    I2CMasterControl(I2C0_MASTER_BASE, I2C_MASTER_CMD_BURST_SEND_CONT);
    break;
    }
    I2CWhileMasterBusy
    }

     

    Easy!

  • It seems that only PB7 pin is locked because of  NMI selected on PB7 at reset.

    Miro Petrovic

  • Ok  thanks i was just battling  the same problem the I2c clk on PB7 never would run until it was unlocked

  • I have reviewed the loopback example for I2C as well as tried to implement Ronaldo's code above. The difference in my case is that I must use the M3 alternate port F for the I2C clock and data. I cannot get the proper output signals. In my case, I am trying to read the 6 byte MAC address from an Atmel AT24MAC402. The part requires an address of 0xb in the upper half of the byte and I have set my device address to 3 using jumpers. So my device address byte should appear as 0xb6. The memory location at which I need to begin reading in the device is 0x9a.

    Note, the 0xb differs from the normal I2C start code of 0xa. Ronaldo used 0x50, I believe, and I don't understand whyhe used that value. Perhaps therein lies my own misunderstanding the key to my problem? 

    Is there an issue with the M3 Alternate registers? Is there more setup involved?

    Thanks for any help.

    Pat

    Here is my code:

    Initialization

    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_I2C0);
     // configure EEPROM (I2C on PF0,1)
     GPIOPinConfigure(GPIO_PF0_I2C0SDA);
     GPIOPinConfigure(GPIO_PF1_I2C0SCL);
     GPIOPinTypeI2C(GPIO_PORTF_BASE, GPIO_PIN_0 | GPIO_PIN_1);

    Service:

     // write device EUI address to EEPROM
        I2CMasterSlaveAddrSet(I2C0_MASTER_BASE, 0xb6, false);
        // Place the word address data to be sent in the data register
        I2CMasterDataPut(I2C0_MASTER_BASE, 0x9a); //&ulDataTx[0]);
        // Initiate send of data from the master. 
        I2CMasterControl(I2C0_MASTER_BASE, I2C_MASTER_CMD_BURST_SEND_START); //SINGLE_SEND);
        while (I2CMasterBusy(I2C0_MASTER_BASE)){}
        // Place the word address data to be sent in the data register
        I2CMasterDataPut(I2C0_MASTER_BASE, 0x9a); //&ulDataTx[0]);
        // Initiate send of data from the master. 
        I2CMasterControl(I2C0_MASTER_BASE, I2C_MASTER_CMD_BURST_SEND_CONT); //SINGLE_SEND);
        while (I2CMasterBusy(I2C0_MASTER_BASE)){}
        // initiate read process
        I2CMasterSlaveAddrSet(I2C0_MASTER_BASE, 0xb6, true);
        // Send data from the master to the slave.
        for(ulindex = 0; ulindex < 6; ulindex++)
        {
      switch (ulindex)
      {
      case 0:
          // Initiate send of data from the master. 
          I2CMasterControl(I2C0_MASTER_BASE, I2C_MASTER_CMD_BURST_RECEIVE_START);
          break;
      case 5:
          I2CMasterControl(I2C0_MASTER_BASE, I2C_MASTER_CMD_BURST_RECEIVE_FINISH);
          break;
             // Read the data from the slave.
            default:
          I2CMasterControl(I2C0_MASTER_BASE, I2C_MASTER_CMD_BURST_RECEIVE_CONT);
          break;
      }
            // Wait until master module is done transferring.
            while(I2CMasterBusy(I2C0_MASTER_BASE)){}
            ulDataRx[ulindex] = I2CMasterDataGet(I2C0_MASTER_BASE);
        }

    //////////

        
    Below are two waveforms, first of the entire sequence, second to show detail of the first few bytes.