TMS570LS3137: Read over I2C

I’m trying to write and read from a Microchip 24AA01 EEPROM over the I2C1 of the TMS570LS3137. I configured the I2C driver with HALCoGen (version 3.00.00) in master mode, address size = 7 bits, count = 8 bits and baud rate = 100 kHz. I had to correct the generated initialization sequence: I2CMDR.BC = 0 instead of 7 and I2CMDR.FDF = 1 (otherwise it doesn’t work) instead of 0. At this time I can write to the EEPROM, but the reading still fails since the second start condition isn’t set correctly. I should set Start Bit - Device Address - Internal Address – Start Bit – Device Address (with read) – Response 0 - … - Response N – Stop Bit, but on the I2C bus I get Start Bit - Device Address - Internal Address– Device Address (with read) – Start Bit – Response 0. My read function is:

// Set the bus in master and transmitter mode and set the START condition

I2C->MDR |= I2C_MASTER | I2C_TRANSMITTER | I2C_START_COND;

// Send the slave address

i2cSendByte(I2C, slaveDeviceAddress);

// Send the internal address

i2cSendByte(I2C, (Uint8)readAddress);

// Set the bus in master, repeat and receiver mode and set the START condition

I2C->MDR &= ~I2C_TRANSMITTER;

I2C->MDR |= I2C_MASTER | I2C_REPEATMODE | I2C_START_COND;

// Send the slave address (for reading)

i2cSendByte(I2C, slaveDeviceAddress | 0x01);

// Receive n-1 bytes

while (readLength > 1)

{

  *readBuffer++ = i2cReceiveByte(I2C);

  readLength--;

}

// Receive the last bytes (and set the STOP condition)

I2C->MDR |= I2C_STOP_COND;

*readBuffer = i2cReceiveByte(I2C);

// Wait until the bus isn't busy and the master mode bit is cleared

while (I2C->STR & I2C_BUSBUSY);

while (I2C->MDR & I2C_MASTER);

  • In reply to Pratip Kumar:

    Hi Daniel,

    Try with the attached file and see if it helps. I'll close on this ticket , you may raise a new one if you need further help.

    7635.i2c.zip

    -Pratip

  • In reply to Pratip Kumar:

    Pratip

     I’m back from vacation ;-)

     With the I2C Tips <http://processors.wiki.ti.com/index.php/I2C_Tips> I could solve the problems with the I2C! I have configured the I2C with RM=0, FDF=0 and SAR=0x50 (=0xA0>>1).

     I have seen that you are using HALCoGen version 03.01.00, I still have version 03.00.00! Is the newer version already available, or when will it be?

    Thanks Daniel

  • In reply to daniel.dueringer:

    Daniel,

    I'm glad that the I2C tips page helped solve your issue!  HALCoGen 3.01 is a TI internal release.  The next HALCoGen update will happen 1H2012.

  • In reply to Brian Fortman:

    I would like to know what is the purpose of the SAR register if, anyway, we have to send it in each message:

    «

    ...

    // Send the slave address

    i2cSendByte(I2C, slaveDeviceAddress);   

    ... 

    » 

    What it is handled exactly by the i2c controller? The ACK? The slave address?

    I have generated the Halcogen code, it`s fine but I still don't know how to use it. It doesn't work.

    I communicate as a Master to a single slave (light transmitter ISL76683 from TI). Do you have some example? (Other than from Halcogen).

    Simon 

  • In reply to Simon lapointe:

    Hmmm...no response from the TI guys.  Some guesses. The SAR is not used when the controller is in Free Data Format mode. In that mode you must manage the entire transaction. In the non FDF mode, SAR is used by I2C controller to automatically send the start bit, slave address and read/write bit automatically.

  • In reply to Simon lapointe:

    Hi Simon

    If you configured the Free Data Format = 0, then in the SAR register you have to set the device's slave address. I had to shift the address 1 bit to the right (slave address = 0xA0, SAR = 0x50)! In FDF = 0, i2cSendByte(I2C, slaveDeviceAddress); isn't necessary, it is handled by the I2C HW.

    I had to correct the initialization (i2cInit()) generated by HALCoGen:
       i2cREG1->MDR = /* nack mode                          */   (0)
                      /* free running                       */ | (0)
                      /* start condition - master mode only */ | (0)
                      /* stop condition                     */ | (I2C_STOP_COND)
                      /* Master/Slave mode                  */ | (I2C_MASTER)
                      /* Transmitter/receiver               */ | (I2C_TRANSMITTER)
                      /* expanded address                   */ | (I2C_7BIT_AMODE)
                      /* repeat mode                        */ | (0)
                      /* digital loopback                   */ | (0)
                      /* start byte - master only           */ | (0)
                      /* free data format                   */ | (0)
                      /* bit count                          */ | (0); // 8 bits

    and (for 100kHz)
       i2cREG1->CLKH = 0x23;
       i2cREG1->CLKL = 0x23;

    Ciao Daniel

  • In reply to daniel.dueringer:

    Thanks for your response Daniel.

    Still some problem tough the chip responds, it acks but at the end my clock signal stays low, so it hangs there. The device address is sent correctly, I see it on the scope.

    I'm just trying to read as master mode, I performe a single read. I configure the clock around 10Khz. This is the sequence, sorry it's a little bit to read:

     //********************** Begin Init
    
     I2cRegsSt::I2cmdr mdr;
     mdr.all = 0;
     mdr.bit.nIRS = 0; //I2C reset.
     i2cPtr->i2cmdr.all = mdr.all; //Apply change.
    
     //mdr.bit.STT = 1; //start condition - master mode only
     mdr.bit.STP = 1; //stop condtion
     mdr.bit.MST = 1; //Master/Slave mode
     mdr.bit.TRX = 1; //Transmitter/receiver
     //mdr.bit.DLB = 1; //Loopback.
     mdr.bit.BC = I2C_8_BIT; //Bit count.
    
     //Apply change.
     i2cPtr->i2cmdr.all = mdr.all; //Still in reset at this point.
    
     /** - Disable all interrupts */
     //HALCOGEN i2cREG1->IMR = 0x7FU; // ??????????
     i2cPtr->i2cimr.all = 0;
    
     ////Config clock around 10Khz.
     i2cPtr->i2cpsc.all = 0;
     i2cPtr->i2cpsc.bit.PSC = 10; //Set prescale.
    
     //set clock rate.
     i2cPtr->i2cckh.all = 0;
     i2cPtr->i2cckh.bit.CLKH = 393;
     i2cPtr->i2cckl.all = 0;
     i2cPtr->i2cckl.bit.CLKL = 393;
    
     //set i2c pins functional mode.
     i2cPtr->i2cpfnc.all = 0;
     i2cPtr->i2cpfnc.bit.PINFUNC = 0;
    
     //set i2c pins default output value
     I2cRegsSt::I2cdout i2cdout;
     i2cdout.all = 0;
     i2cdout.bit.SCLOUT = 1;
     i2cdout.bit.SDAOUT = 1;
     i2cPtr->i2cdout.all = i2cdout.all; //Apply change.
    
     //set i2c pins output direction.
     I2cRegsSt::I2cpdir i2cpdir;
     i2cpdir.all = 0;
     i2cpdir.bit.SCLDIR = 1;
     i2cpdir.bit.SDADIR = 1;
     i2cPtr->i2cpdir.all = i2cpdir.all; //Apply change.
    
     //set i2c pins open drain enable.
     I2cRegsSt::I2cpdr i2cpdr;
     i2cpdr.all = 0;
     i2cpdr.bit.SCLPDR = 0;
     i2cpdr.bit.SDAPDR = 0;
     i2cPtr->i2cpdr.all = i2cpdr.all; //Apply change.
    
     //set i2c pins pullup/pulldown enable.
     I2cRegsSt::I2cpdis i2cpdis;
     i2cpdis.all = 0;
     i2cpdis.bit.SCLPDIS = 0;
     i2cpdis.bit.SDAPDIS = 0;
     i2cPtr->i2cpdis.all = i2cpdis.all; //Apply change.
    
     //set i2c pins pullup/pulldown select.
     I2cRegsSt::I2cpsel i2cpsel;
     i2cPtr->i2cpsel.all = 0;
     i2cpsel.bit.SCLPSEL = 1;
     i2cpsel.bit.SDAPSEL = 1;
     i2cPtr->i2cpsel.all = i2cpsel.all; //Apply change.
    
     //set interrupt disable.
     i2cPtr->i2cimr.all = 0;
    
     mdr.bit.nIRS = 1; // I2C out of reset.
     i2cPtr->i2cmdr.all = mdr.all; //Apply change.
    
     //********************** End of Init
    
     //Set slave address.
     i2cPtr->i2csar.bit.SA = 0x44;
    
     //Set in receive mode.
     I2cRegsSt::I2cmdr mdr;
     mdr.all = i2cPtr->i2cmdr.all;
     mdr.bit.TRX = 0; //Transmitter/receiver bit.
     mdr.bit.MST = 1; //Master/Slave mode
     mdr.bit.STP = 1; //stop condition - master mode only
     i2cPtr->i2cmdr.all = mdr.all; //Apply change.
    
     //Send register to read.
     while (i2cPtr->i2cstr.bit.TXRDY == 0) //wait.
     {} //Blank line.
    
     i2cPtr->i2cdxr.bit.DATATX = 4; //Register is 4 for this chip.
    
     //Set start condition.
     I2cRegsSt::I2cmdr mdr;
     mdr.all = i2cPtr->i2cmdr.all;
     mdr.bit.STT = 1; //start condition - master mode only
     i2cPtr->i2cmdr.all = mdr.all; //Apply change.
    
     //Receive.
     while( ! ((i2cPtr->i2cstr.bit.RXRDY) || (i2cPtr->i2cstr.bit.ARDY)) )
     {} //Blank line. Wait.
    
     // If a NACK occurred then SCL is held low and STP bit cleared
     if ( i2cPtr->i2cstr.bit.NACK )
     {
     // send STP to end transfer.
     I2cRegsSt::I2cmdr mdr;
     mdr.all = i2cPtr->i2cmdr.all;
     mdr.bit.STP = 1;
     i2cPtr->i2cmdr.all = mdr.all; //Apply change.
    
     // clear NACK bit.
     I2cRegsSt::I2cstr str;
     str.all = i2cPtr->i2cstr.all;
     str.bit.NACK = 1;
     i2cPtr->i2cstr.all = str.all; //Apply change.
     *error = True;
     return 0;
     }
    
     //Read the data.
     return i2cPtr->i2cdrr.bit.DATARX;

     

  • In reply to Simon lapointe:

    Sorry for the late answer!

    Here the errors I found in the initialization:
    mdr.bit.BC = 0;
    i2cPtr
    ->i2cpfnc.bit.PINFUNC = 0;

    And for read:
    I set the CNT register with the number of bytes to read.

  • In reply to daniel.dueringer:

    Great, the fix is on the CNT register, it works now. My mdr.bit.BC was already 0.

    Thanks so lot.

    Simon 

  • In reply to daniel.dueringer:

    Hello Daniel,

    Since your code is working smoothly , could you please share the code as I am also working on I2C protocol with the TMS570 3137 evaluation board.

    Thanks.