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.

C5509A and Setting I2C I2CCLKH register

Hi All,

Has anyone successfully set this register with a value?  I have tried all available means and still get random results.

First attempt was using the I2C_Setup structure as follows:

I2C_Setup I2Csetup = {
    0,   // 7 bit address mode
    0x0000,  // own address, dont care if master
    104,  // clkout value (Mhz), need to use the macro under Timing.c
    400,  // I2C clock rate, 10 to 400 KHz
    0,   // 8 bits/byte to be received or tansmitted
    0,    // DLB mode off, 1 = on
    1   // FREE mode on, 0 = off
};

then calling

I2C_setup(&I2CSetup);

The prescaler is set to 8 which is correct, the i2cclkl is set to 0xF and I have seen values for i2cclkh as 0x08, 0x05, 0x04 and 0x01.  Even with these values I get a consistent 800 ns high pulse width on the clock which is within the spec of the ADV7180 that I am trying to communicate with.  No response from the chip even with a General Call.

So, I tried using the I2C_Config structure as follows:

I2C_Config I2Cconfig = {
    0x0000,  // I2COAR
    0x0000,  // I2CIER
    0xFFFF,  // I2CSTR
    0x000F,  // I2CCLKL
    0x000F,  // I2CCLKH
    0x0001,  // I2CCNT
    0x0000,  // I2CSAR
    0x4620,  // I2CMDR
    0xFFFF,  // I2CISRC
    0x0008  // I2CPSC
};

with a call to

I2C_config(&I2Cconfig);

Same result when reading the config.  Clkh is one of the 4 values listed above.

So, next I try setting the registers directly after the call to I2C_config.

 I2C_RSET(I2CMDR, 0x4600);
 I2C_RSET(I2CCLKL, 0x1F);
 I2C_RSET(I2CCLKH, 0x1F);
 I2C_RSET(I2CMDR, 0x4620);
 

Same result.

 

Any ideas other than what I have tried so far?  Am I doing something out of sequence?

Thanks,

Jim

 

  • Jim: Glad to hear it is working for you now.

    Note: fyi, Jim worked this directly with me via Outlook. He needed to "manually" configure I2CCLKL and I2CCLKH and also showed him the need to set the I2C BB (Bus Busy) Bit .

    Regards,

    Naser

  • Hi Naser,

     

    Why not post the complete workaround, since more people are probably struggling with the same problem?

     

    Regards

    Henrik

     

  • Henrik Fransson said:

    Why not post the complete workaround, since more people are probably struggling with the same problem?

    Yes, please!  I am having similar issues where I2C_setup doesn't produce the requested clock behavior, and setting I2CCLKL / I2CCLKH doesn't always seem to work. Is there a restriction on when these values can be set, as there is for IPSC? The I2C reference guide makes no mention of this.

  • All,

     

    Unfortuantely Naser was laid off from TI.  I dug through our email exchanges and found the best answer which is copied below.  I'll look for the code sample he sent me and see if I can post that as well.

     

    Naser,
     
    The busy bit reset did the trick.  That was the only thing I was missing.
     
    Many thanks on the quick turn around!
     
    Jim


    From: Salameh, Naser [mailto:nsalameh@ti.com]
    Sent: Monday, September 29, 2008 3:08 PM
    To: Malone, Jim
    Cc: Elwood, Kevin; Levin, Travis
    Subject: RE: 5509A DSP and I2C

    HI Jim:
    Unfortunately, the clock divider values in registers I2CCLKL and I2CCLKH are hard coded to 15 in the I2C_setup function. You can observe this by going  through the I2C_setup function implementation in csl55xx.src file in the lib folder of   your CSL installation. Please see the attached CSL source file.
                                                                                            
    The value was hard coded to allow support of a broad range of I2C devices without user  intervention. To eliminate the problem you need to set the proper clock divider values  using a direct function call to I2C_RSET ().
     
    I have attahced a sample code of zip that fixes the problem.
     
    This test case sets the CPU clock frequency at 96 MHz, a prescale value of 11 (calculated by the CSLs) and 220 in I2CCLKL and I2CCLKH.

    This test case use fixed version of I2C_setup function mainly adding the following line after setting IPSC:

    I2C_FSET(I2CMDR,IRS,1); /* */

    This "fixed" version will provide a I2C clock of ~ 17.7 kHz which is the expected value.

    Now, if you remove i2c_setup.c from the project, CCS will extract that function from the CSL libraries automatically.

    The resulting I2C frequency will then be 200 kHz which is cause by IPSC value not to be taken in account. This is the expected behavior of the I2C module as mentioned in its user's guide:

    "

    The prescaler must be initialized only while the I2C module is in the reset state (IRS = 0 in I2CMDR). The prescaled frequency takes effect only when IRS is changed to 1. Changing the IPSC value while IRS = 1 has no effect.

    "

    http://focus.ti.com/general/docs/techdocsabstract.tsp?abstractName=spru146d

    This means we have  a wrong implementation of the CSL for IPSC from day 1.

    -----------------------------------------

    For code readability, this test case also works around 2 other issues:

    1st) the BB bug reported in sprz200d which the unsupported following workaround fixes to this test's case sake

    /* This works around Advisory I2C_6 of sprz200d where BB does not reflect proper Bus Busy status*/

    I2C_FSET(I2CSTR,BB,0x1); /* Writing a 1 to BB Bus busy bit is supposed to clear it*/

    2nd) the unimplemented automatic baud rate parameter calculation "Uint16 rate Desired Transfer rate (10−400 kbps)" of I2C_Setup function see p 128 of spru433j. For this, one needs to "manually" configure I2CCLKL and I2CCLKH once setup is completed which is a legitimate way to configure the I2C:

    /* Initializes I2C registers using initialization structure */

    I2C_setup(&Init);

    /* Need to calcualte I2CCLKL & I2CCLKH manually has functionnality not fully miplmented in CSL*/

    I2C_RSET(I2CCLKL,220); /* Clock Divider Low register */

    I2C_RSET(I2CCLKH,220); /* Clock Divider High register */

    Regards,
    Naser

  • Sample code from Naser's example he sent to me.

     

        /* This works around Advisory I2C_6 of sprx200d where BB does not reflect proper Bus Busy status*/
       
        I2C_FSET(I2CSTR,BB,0x1); /* Writing a 1 to BB Bus busy bit is supposed to clear it*/
                           
        /* Initializes I2C registers using initialization structure */
        I2C_setup(&Init); 
       
       
        /* Need to calcualte I2CCLKL & I2CCLKH manually has functionnality not fully miplmented in CSL*/
        I2C_RSET(I2CCLKL,220);    /* Clock Divider Low register */
        I2C_RSET(I2CCLKH,220);    /* Clock Divider High register */

    Hope all of this helps!

    Jim

  • Thanks, this was helpful. Once I realized that TI's CSL initialization function was ignoring the clock info and doing something arbitrary, I wrote a function that queries my current clock frequency and manually adjusts the I2C prescale and divider values to appropriate values. I had some subsequent bus-busy problems, but these turned out not to be related to the BB flag issues previously documented. It was my fault for not isolating a remote branch of the I2C bus before I removed the power from it. Once the bus gets stuck like that, you can't write to the I2C multiplexer chip to fix the problem. Solution: don't do that!

    David

     

  • Since I've been working on some issues related to this thread I thought I would make a comment.  Despite the fact that the CSL User Guide recommends using I2C_setup rather than I2C_config, I personally recommend using I2C_config.  Here are my reasons:

    1. I2C_setup supposedly gives you better abstraction from the hardware since you are able to "just tell it" what frequency you would like the I2C SCL pin to run.  However, as we all know from this thread that functionality is not actually implemented in the I2C_setup function!  It simply hard codes a value of 15 into the I2CCLKL and I2CCLKH registers!  Rather than add extra lines of code, it seems cleaner/simpler to use I2C_config where you pass in the appropriate values for these registers as part of the config structure.
    2. I2C_setup also suffers from the issue that it sets IRS=1 before it has configured I2CPSC.  The I2C_config function on the other hand writes the I2CPSC register first so this isn't an issue for this function.

    Brad