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.

Hercules HALCoGen I2C Issue

Other Parts Discussed in Thread: HALCOGEN

Hi all,

I am trying to use i2c to communicate with IRThermo MLX90614, which requires sending an address byte first then a read of three bytes (no stop bit) after sending the address.

Using HALCoGen, I generated the required code, enabling the required mux pins etc...

As per the TRM for TMS570LC43:

To start with I need to set i2c transmitter as "(Repeat) Start" with RM=0, STT=1 and STP=0, which works fine and I see it on the logic analyzer, but that is how far it goes, as I have a check statement: while(i2cIsBusBusy(i2c1) == true);

In the table, it says "Repeat n", but how "n" is set?

I have tried many approaches:

1- I set i2cSetCount which define how many bytes but it cause the CPU to generate the stop bit!

2- Removing the check statement will cause the program to go further, but it gets stuck when it tries to receive data (probably bus busy)

3- I have tried to reset the i2c before I reconfigure as a receiving master, but still nothing happening when trying to receive data.

#define MLX90614_ADDRESS 0x5A

i2cInit();

uint8 sensTemp[3];

i2cSetMode(i2c1, I2C_MASTER);
i2cSetSlaveAdd(i2c1, MLX90614_ADDRESS);
i2cSetDirection(i2c1, I2C_TRANSMITTER);
i2cSetStart(i2c1);
i2cSendByte(i2c1, 0x07);

while(i2cIsBusBusy(i2c1) == true);

i2c1->MDR = 0;

for(i = 0; i< 10000 ; i++);

i2cSetSlaveAdd(i2c1, MLX90614_ADDRESS);
i2cSetDirection(i2c1, I2C_RECEIVER);
i2cSetCount(i2c1,3);
i2cSetMode(i2c1, I2C_MASTER);

i2cSetStop(i2c1);
i2cSetStart(i2c1);
i2cReceive(i2c1, 3, sensTemp);
while(i2cIsBusBusy(i2c1) == true);
while(i2cIsStopDetected(i2c1) == 0);
i2cClearSCD(i2c1);

Here is what I see on the logic analyzer:

For the sequence to work, the MC shall send a start bit after what is showing in the screen shot.

Regards

Fouad

#Edit#

Looking at the TRM again, it seems I meet the prerequisite for a reapted start!

Is there any HALCoGen drivers programming deference?

Regards

Fouad

  • I have asked one of the I2C experts to look at this.
  • Hi Bob,

    Thank you for forwarding my question to TI i2c expert.

    Further investigation on the issue, I came across some further findings. To start with, here is my setup:

    PC with Windows 7 Pro.

    HALCoGen 04.05.02

    CCS 6.1.1.00022

    Launchpad XL2-570LC43(A) Rev(A1)

    TRM: TMS570LC43x 16/32-Bit Literature Number: SPNU563 May 2014

    Now:

    HALCoGen help document states i2cIsMasterReady:

    Indicates whether MST bit is set or cleared to indicate that stop condition was generated. This API should be called after Master Tx or Rx to check if the transaction is complete.

    Parameters
    [in] i2c - i2c module base address
    Returns
    boolean value to indicate whether MST bit is cleared after STOP bit is generated.
    • TRUE, if MST bit is cleared.
    • FALSE, if MST bit is set. 

    In the TRM:

    In HL_i2c.c

    /** @fn i2cIsMasterReady(i2cBASE_t *i2c)
    *   @brief Indicates whether MST bit is set or cleared to indicate that stop
    *   condition was generated. This API should be called after Master Tx or Rx
    *   to check if the transaction is complete.
    *   @param[in] i2c   - i2c module base address
    *   @return boolean value to indicate whether MST bit is cleared after STOP bit is generated.
    *           - TRUE, if MST bit is cleared.
    *           - FALSE, if MST bit is set.
    */
    /* SourceId : I2C_SourceId_025 */
    /* DesignId : I2C_DesignId_025 */
    /* Requirements : HL_CONQ_I2C_SR33 */
    bool i2cIsMasterReady(i2cBASE_t *i2c)
    {
        bool retVal = 0U;
    /* USER CODE BEGIN (60) */
    /* USER CODE END */
    
        /* check if MST bit is cleared. */
        if((i2c->MDR & I2C_MASTER) == 0)
        {
            retVal = true;
        }
        else
        {
            retVal = false;
        }
        return retVal;
    
    /* USER CODE BEGIN (61) */
    /* USER CODE END */

    In HL_i2c_.

    /** @enum i2cMode
    * @brief Alias names for i2c modes
    * This enumeration is used to provide alias names for I2C modes:
    */
    enum i2cMode
    {
    I2C_FD_FORMAT = 0x0008U, /* Free Data Format */
    I2C_START_BYTE = 0x0010U,
    I2C_RESET_OUT = 0x0020U, I2C_RESET_IN = 0x0000U,
    I2C_DLOOPBACK = 0x0040U,
    I2C_REPEATMODE = 0x0080U, /* In Master Mode only */
    I2C_10BIT_AMODE = 0x0100U, I2C_7BIT_AMODE = 0x0000U,
    I2C_TRANSMITTER = 0x0200U, I2C_RECEIVER = 0x0000U,
    I2C_MASTER = 0x0400U, I2C_SLAVE = 0x0000U,
    I2C_STOP_COND = 0x0800U, /* In Master Mode only */
    I2C_START_COND = 0x2000U, /* In Master Mode only */
    I2C_FREE_RUN = 0x4000U,
    I2C_NACK_MODE = 0x8000U
    };

    The above example is just to show that what is supposed to check for a Master busy, is checking if the bus is in master or slave mode! Is it a bug, misinterpretation or I am missing the point?

    I have managed to get i2c to work in repeat start; However, I had to rely on me doing most of the checks by coding other than utilizing HALCoGen function calls!

    Using a reference point from:

    http://processors.wiki.ti.com/index.php/I2C_Tips#Repeated_Start

    Here is the code (I didn't use i2cReceive function as it got stuck every few times in the HL_i2c.c, which look like some interrupt handling dependency, so I used for loop):

    #define i2c1 i2cREG1
    
    // Start the transmitting part
    while(i2cIsBusBusy (i2c1) == true);
    
    i2c1->MDR = I2C_RESET_OUT;          // To set the MDR with I"C is out of reset
    i2cSetMode(i2c1, I2C_MASTER);
    i2cSetSlaveAdd(i2c1, SLAVE_ADDRESS);
    i2cSetDirection(i2c1, I2C_TRANSMITTER);
    i2cSetCount(i2c1, 1);
    i2cSetStart(i2c1);
    while((i2c1->STR & (I2C_TX | I2C_ARDY)) == false);   // To wait for the tx ready and register access ready
    i2cSendByte(i2c1, SLAVE_WORD_ADDRESS);
    
    // Start receiving the data from slave
    // wait for ARDY before beginning the read phase of the transaction
    while((i2c1->STR & I2C_ARDY) == false);
    i2c1->MDR = I2C_RESET_OUT;           // To set the MDR with I"C is out of reset
    
    i2cSetMode(i2c1, I2C_MASTER);
    i2cSetDirection(i2c1, I2C_RECEIVER);
    i2cSetCount(i2c1, 3);
    i2cSetStop(i2c1);
    i2cSetStart(i2c1);
    
    // To receive three bytes
    uint8 j;
    for(j = 0; j < 3; j++)
    {
    	while((i2c1->STR &(I2C_RX | I2C_ARDY)) == true);
    	sensTemp[j] = i2c1->DRR;
    }
    
    while(i2cIsBusBusy (i2c1) == true);
    /* Wait until Stop is detected */
    while(i2cIsStopDetected(i2c1) == false);
    /* Clear the Stop condition */
    i2cClearSCD(i2c1);

    Does it look like a bug in HAALCoGen for TMS570LC43x?

    Regards

    Fouad

  • Hello Fouad,

    Attached is I2C code I developed to write/read one RTC timer for one customer. I use repeat mode for reading the data from timer. Hope it helpful.

    Regards,8446.sys_main.c

    QJ

     

  • Hello QJ,

    Thank you for your reply,

    I have posted almost the same code in my last post, thanks for confirming the code; However, in my case, the only difference was ( I had to set nRIS to "1") for the code to work, at least it worked.

    My other concern was about the documentation as it was misleading when it came to "i2cIsMasterReady", which I explained in my last post as well, sorry for the trouble but I had to dive in HALCoGen generated code to figure that "i2cIsMasterReady" was not doing what it was supposed to! Unless I misunderstood it!

    Regards

    Fouad

  • Hi Fouad,

    Hi so just looking at this thread:

    1) it seems like the issues you had w. the software got resolved. Is this correct?

    2) last thread seems to raise a question about the technical reference manual description for 'i2clsMasterReady' or something in HalCoGen named 'i2clsMasterReady'.

    Appreciate your feedback on (2) would you please provide a bit more context regarding #2 - if it is something that is confusing we want to review it and see if there is anything we can change -but I am not sure if we are talking about a driver file from HalCoGen or a section in the manual... also would be great if you can explain in a sentence or two what you found confusing so we know what to clarify.

    Thanks and Best Regards,
    Anthony
  • Hi Anthony,

    Thank you for your reply.

    1- Indeed, this has been resolved.

    2- I believe the description in HALCoGen documentation is not correct. I have attached a screenshot:

    But the actual implementation of the function is checking if the i2c bus is in master or slave mode!

    Point 2 is more of a feedback to TI.

    Regards

    Fouad

  • Hi Fouad,

    Yes I can see where the name of the function is odd.    

    But it does seem to be doing what it says it does.    It's tied back to the definition of the MST bit which has a double meaning, so that in the context described in the API documentation (call after master Tx or Rx) the MST bit just indicates that the previous transfer completed with a STOP condition - which means that you could START a new transaction on the bus if you are a master.


  • Hi Anthony,

    Thanks for clarification.

    Regards

    Fouad

  • Hi Fouad,

    Can you please share the full code? i am also stuck with the same problem.

  • Hi Hassan,

    I will share it if I can locate it :( But can you tell me what is it that you are stuck with, is it the same sensor or you need the sequence on I2C, if you can tell me what exactly needed, if I can't locate the code I will try to re-do it.

  • Thankyou Fouad for your reply..
    i am doing that on RM46x mcu and myahrs+ IMU
    i am using your code that you have posted here. i have changed a bit of your code..

    Here is the code

    int32_t I2CReceive(int32_t SLAVE_ADDRESS, int8_t reg)
    {
    while(i2cIsBusBusy (i2c1) == true);
    i2c1->MDR = I2C_RESET_OUT;
    i2cSetMode(i2c1, I2C_MASTER);
    i2cSetSlaveAdd(i2c1, SLAVE_ADDRESS);
    i2cSetDirection(i2c1, I2C_TRANSMITTER);
    i2cSetCount(i2c1, 1);
    i2cSetStart(i2c1);
    while((i2c1->STR & (I2C_TX | I2C_ARDY)) == false); // To wait for the tx ready and register access ready
    i2cSendByte(i2c1, reg);
    // Start receiving the data from slave
    // wait for ARDY before beginning the read phase of the transaction
    while((i2c1->STR & I2C_ARDY) == false);
    i2c1->MDR = I2C_RESET_OUT; // To set the MDR with I"C is out of reset

    i2cSetMode(i2c1, I2C_MASTER);
    i2cSetDirection(i2c1, I2C_RECEIVER);
    i2cSetCount(i2c1, 1);

    i2cSetStart(i2c1);

    // To receive one byte
    uint8 j;
    for(j = 0; j < 1; j++)
    {
    while((i2c1->STR &(I2C_RX | I2C_ARDY)) == true);
    sensTemp[j] = i2c1->DRR;

    }
    i2cSetStop(i2c1);
    while(i2cIsBusBusy (i2c1) == true);
    /* Wait until Stop is detected */
    while(i2cIsStopDetected(i2c1) == false);
    /* Clear the Stop condition */
    i2cClearSCD(i2c1);
    return sensTemp[0];
    }

    i changed the i2cSetStop(i2c1) position from above the loop and pasted it down the loop as you can see.
    at first i were getting nothing in the DRR register from the data registers of the IMU but got the default values from the id register etc. and then i tried the I2CRECEIVEDBYTE and that got stuck for the infinte time..
    after that i removed the pullup resistors form the sda and scl line and i started getting the output from the data registers.i dont know why and dont know wether i am getting the right values or not. Even now i am getting the output both with and without the pullup resistor.
    i am confused that how is that happeneing?
  • Let's start with hardware:

    As per this link: github.com/.../tutorial

    1- You need to have pull-up resistors (you need to connect them to 3.3V as RM46x is 3.3V)

    2- What is the power source for your board? Does the board have on board regulator and what is the board voltage?

    3- It is hard for me without a datasheet!! Maybe the sensor datasheet?

    Software:

    1- Can you point me on which one is the one you are trying to achieve from the snapshot:

    Fouad

  • Hi again,

    I am not sure the change you have done has any impact!

    I think you are trying to achieve number (2) from the snapshot I sent, then I think the code you used is fine (you can get the i2cSetStop(i2c1); back to its place.

    I think you need to look at your hardware. It is a good idea to get some logic analyzer so you can see what is happening.

    In one of my previous posts to your post, I have mentioned hardware, and here is further clarification on those points:
    It is always good practice to use the same voltage level unless you use level sifter. RM46x is 3.3V and your board has I2C at 3.3v, so you make sure you have the pull-up resistors tied to 3.3V.

    I am not sure what is the power source for your board and if it has voltage regulator at 3.3v or not.

    I can't see why your code shouldn't work!!

    I hope this helps

    Fouad
  • Thank you for your reply. yes i am using 5k pull up resistors between the line and trying to acheive the 2nd from the snap shot. whenever i put the i2cSetStop(i2c1) back to its place it gives nothing and the DRR register always contains 0 in it..
    Ca you please suggest me some good logic analyzer as i am new to all these things. Thank you
  • Hi,

    You can get something like Saleae logic analyzer, or just google "USB Logic Analyzer" and you can find cheap ones on ebay, just make sure it has decent software.

    Fouad

  • Hi,

    Just though if you missed something in HalCoGen, it could be that you are using another peripheral that has a pinmux conflict.

  • Hi Fouad,

    thank you dor your reply. Here is my pinmux & i2c settings

  • Hi Hassan,

    Sorry I didn't have time to go through it thoroughly, but quick test you can do is to increase the data count in HALCoGen to more than "1", re-generate code and compile.

    I would like to know what sensor you are trying to communicate with and if there is any available datasheet for?

    Regards

    Fouad

  • here is the IMU link that i am using and all the information about the IMU is given in the link and there isnt any data sheet..

    I am trying to get 1 byte every time so does increasing the data count helps?

  • you mean to say sensor in the IMU?
  • Hi,

    Yes the sensor on the IMU.

    The data count in HALCoGen will end up in the i2cInit(), depending on the configuration you do in HALCoGen and in coding after calling i2cInit(), it might have impact on the "stop bit" generated from the I2C master, but to be sure I will need to check the TRM and the code generated from HALCogen, which I am hoping to do over the weekend, but I can't promise.

    1- You can start with the hints I have given you above

    2- In such cases, logic analyzer is a great help as you can tell if the "stop bit" has occurred on the bus.

    3- I assume that you use TI CCS, then you can debug the code and check the changes happening in the i2c registers

    Regards

    Fouad

  • Hi Fouad,

     Thanks.Yes i got a logic analyzer and saw the output it is generating the stop bit at the end of the transmission.

    and also i debug the code but there isnt any problem during debug step by step.

  • Hi Hassan,

    What I see on the logic analyzer is exactly what you are doing in code, you are reading from I2C slave with address 0x20  at register address 0x22 (C_ACC_X_LOW) for one byte and you are getting the value of 0xD8.

    Fouad

  • Hello,

     Thank you Fouad.Yes i got this output after putting some delay at the end of the receive function.I forgot to mention that.

    I think now i am having the correct output.

    Thank you for your help. 

  • Hello Hassan,

    I am glad you got it to work.

    Fouad

  • Hello Fouad,

    Sorry to distrub you again. But now i need to do multiple byte reads..minimum of 6 bytes. For the write byte i am using the same as of previous code. But now for the read bytes i am changing the i2csetcount  from 1 to 6 and also the loop value from 1 to 6. But its not working,the Data register value doesnt chnge after it reads from the first register.

    Do i need to add something in the code to send the repeated start? also i might be missing something in the Halcogen?

    I am having Count = 6 and Bit Count = 8 bit in Halcogen and also do i need to check the Enable Repeat mode?

  • That is what i am getting..Third byte comes after too much time and also the stop bit comes after that.
  • Hi,

    I think you have done the right thing by changing the count.
    It is not clear on the snapshot, but I assume acks are in place; However, are you running your code in debugging? Do you have any delay loops? Do you send something over serial?

    What I can see in the snapshot is that the microcontroller has a break of 5 ms, as there is no clock!
  • The more information you send me when you ask, the more I can analyze and when I reply, I can have better view of what is happening on your setup
  • Sorry for the less information.
    Yes i am running the code in the debugging.
    Yes i have a delay loop after every register reading.
    I am reading the value on the SCI.

    The ACKs are in place.But from the third bit the mirocontroller has a break of 5ms and some times more then 5ms and also after the six bit it has a few ms break and then the stop bit.
    Here is the code.



    void main(void)
    {
    /* USER CODE BEGIN (3) */
    uint8 NumberOfChars0, Ax1l,Ax1h;


    sciInit();
    i2cInit();

    while(1){

    Ax1l= I2CReceive(ACCEL_SLAVE_ADDR, reg);; //Reading from 0x23
    NumberOfChars0=ltoa(Ax1l,(char *)res0);
    sciSend(scilinREG,2,(unsigned char *)"0x");
    sciSend(scilinREG,NumberOfChars0,res0);
    sciSend(scilinREG,2,(unsigned char *)"\r\n");
    };
    /* USER CODE END */
    }

    int32_t I2CReceive(int32_t SLAVE_ADDRESS, int8_t reg)
    {
    int delay =0;
    while(i2cIsBusBusy (i2c1) == true);
    i2c1->MDR = I2C_RESET_OUT;
    i2cSetMode(i2c1, I2C_MASTER);
    i2cSetSlaveAdd(i2c1, SLAVE_ADDRESS);
    i2cSetDirection(i2c1, I2C_TRANSMITTER);
    i2cSetCount(i2c1, 1);
    i2cSetStart(i2c1);
    while((i2c1->STR & (I2C_TX | I2C_ARDY)) == false); // To wait for the tx ready and register access ready
    i2cSendByte(i2c1, reg);
    // Start receiving the data from slave
    // wait for ARDY before beginning the read phase of the transaction
    while((i2c1->STR & I2C_ARDY) == false);
    i2c1->MDR = I2C_RESET_OUT; // To set the MDR with I"C is out of reset

    i2cSetMode(i2c1, I2C_MASTER);
    i2cSetDirection(i2c1, I2C_RECEIVER);
    i2cSetCount(i2c1, 6);

    i2cSetStart(i2c1);
    i2cSetStop(i2c1);
    // To receive six byte
    uint8 j;
    for(j = 0; j < 6; j++)
    {
    while((i2c1->STR &(I2C_RX | I2C_ARDY)) == true);
    sensTemp[j] = i2c1->DRR;


    for(delay=0;delay<10000;delay++);

    }



    while(i2cIsBusBusy (i2c1) == true);
    /* Wait until Stop is detected */
    while(i2cIsStopDetected(i2c1) == false);
    /* Clear the Stop condition */
    i2cClearSCD(i2c1);

    return sensTemp[0];
    }
  • Hi,

    I can't see anything wrong in the code, I used similar code to read 3 bytes with no issues.

    I think the issue is on the sensor side (which is slow), here is the explanation as I see it:

    1- while((i2c1->STR &(I2C_RX | I2C_ARDY)) == true); this statement makes sure that the RX buffer is ready to be read, which could be why you face some pauses while reading.

    2- while(i2cIsBusBusy (i2c1) == true);
    /* Wait until Stop is detected */
    while(i2cIsStopDetected(i2c1) == false);
    /* Clear the Stop condition */
    i2cClearSCD(i2c1); These statement make sure that the busy is not busy any more before transmitting the stop bit, which could be why you face the last pause before the stop bit.

    Do you have access to another microcontroller where you have access to off the shelf code? If yes then use the other microcontroller with the logic analyzer connected and observe its behavior, then you have a reference to what the communication is like with the IMU you have over I2C.

  • It seems it has a sketch for Arduino, if you have one, you can test with it and record your logic analyzer as a reference point
  • Ok thank you.I will try to test it with the arduino.

  • Hello Fouad,

    Finally i got the 6 bytes of data without any problem.

    Actually the problem is in the Halcogen drivers. I think if someone have configured the Halcogen right then there should not be any problem in the communication.

    I am really thankful to you for your help. Without your help it might not be happened.Thanks

  • Hello Hassan,

    I came across the some issues with HALCoGen as well and I managed my way around it.

    I am glad that you managed to get it to work.

  • Hi Hassan,
    Can you let us know what problems you see with the HalCoGen drivers and how did you workaround it?
  • Hi Charles,
    I dont exactly know about the problem. But i think it was my mistake. i managed to make my code run by enabling the interupt in the Halcogen.
  • Hi Hassan,
    Is it possible for you to paste your latest working code for the benefit of the community? I'm sure many people will find it useful interfacing with the IMU. Thanks.
  • Hi,

    Here is the code.

    int32_t I2CReceive(int32_t SLAVE_ADDRESS, int8_t reg)

    {

    int delay =0;
    while(i2cIsBusBusy (i2c1) == true);
    i2c1->MDR = I2C_RESET_OUT;
    i2cSetMode(i2c1, I2C_MASTER);
    i2cSetSlaveAdd(i2c1, SLAVE_ADDRESS);
    i2cSetDirection(i2c1, I2C_TRANSMITTER);
    i2cSetCount(i2c1, 1);
    i2cSetStart(i2c1);
    while((i2c1->STR & (I2C_TX_INT | I2C_ARDY)) == false); // To wait for the tx ready and register access ready
    i2cSendByte(i2c1, reg);
    // Start receiving the data from slave
    // wait for ARDY before beginning the read phase of the transaction
    while((i2c1->STR & I2C_ARDY) == false);
    i2c1->MDR = I2C_RESET_OUT; // To set the MDR with I"C is out of reset

    i2cSetMode(i2c1, I2C_MASTER);
    i2cSetDirection(i2c1, I2C_RECEIVER);
    i2cSetCount(i2c1, 6);

    i2cSetStart(i2c1);
    i2cSetStop(i2c1);
    i2cReceive(i2c1, DATA_COUNT, EulerVal);  //To receive 6 bytes of Data

    while(i2cIsBusBusy (i2c1) == true);

    /* Wait until Stop is detected */
    while(i2cIsStopDetected(i2c1) == false);
    /* Clear the Stop condition */
    i2cClearSCD(i2c1);

    for(delay=0;delay<10000;delay++);

    return EulerVal;
    }