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.

DIY I2C setup failure, cannot write I2C_PSC

Other Parts Discussed in Thread: OMAP3530

I am trying to set up a proper I2C driver (none of the SMBus stuff will do), so following the path laid out in spru98c, CH18, section 1.5.

I'm doing my initial experiments in CCS3.3 (CCS4 is still flakey it seems).

Using I2C2.

I try to set the prescaler divisor to 8 by writing 7 to the register I2C_PSC at 0x48072030, but write fails, the register still contains 0.

I am using our own device connected via a Blackhawk USB560 JTAG emulator - have done plenty of similar stuff with other registers.

I also cannot change any I2C_PSC register from the debugger.

Does anyone have any idea what could be wrong?

/Paul

  • Is that I2C device enabled through the PRCM and is the interface clock on?

  • Hi Brad, thanks for the speedy response.

    I'm (blindly) following the instructions in spruf98c. That is to say I have enabled the F and I clocks for I2C2. I haven't got to the initialize part yet - it says first configure the module. I assumed that all the registers need to and can be set first. Is that right?

    /Paul

  • Are these the bits you configured:

    CM_FLCKEN1_CORE[16]

    CM_ICLKEN1_CORE[16]

    If you open a memory window to the I2C registers do all of them  show their default values?  For example does I2C_SA = 0x000003FF?

    So can you still not configure I2C_PSC?  What happens when you write to it?  Can you do it through a memory window?

     

  • Yes Brad, I set those bits,  I2C_SA is 0x3FF, in both words actually. No, I can't write to I2C_PSC, and I can't change it in a memory window.

    /Paul

  • Did you see this note in the TRM:

    "The I2Ci registers are limited to 16 bit and 8 bit data accesses, 32 bit data
    access is not allowed and can corrupt register content."

    The fact that 0x3FF is in both words sounds like perhaps the wrong size accesses are being performed.

  • Oh dear, no, I did not see that, may explain things, but it is 00.30 h here so I'll look into it tomorrow. Thanks.

  • But I did not set the 0x3FF in I2C_SA, don't know how it got there, or set by the Linux kernel which I had booted up earlier.

    /Paul

  • The I2C_SA register has a hardware default of 0x000003FF, so it's expected to be that value rather than 0x03FF03FF which I believe was a result of a 32-bit access instead of a 16-bit access.  That's probably the issue you're having with I2C_PSC as well.

    Brad

  • Indeed Brad, using 16-bit access I am able to write I2C_PSC. The weird thing is that the follwoing code

    uint16 set_bits_in_reg_16(uint32 areg, uint16 mask)
    {//changed this so arg passed for reg is just a 32-bit int
        register uint16 u;
        register uint16* pReg;

        pReg = (uint16*)areg;
        u = *pReg;
        u |= mask;
        *pReg = u;
        return *pReg;
    }

    writes the same value to the low and high words. I wonder how that can happen.

    If I manually write in the memory window this not the case..

    As noted, I2C_SA, contains 03FF 03FF but this is not my doing. Moreover I cannot change it from the memory window.

    What is the underlying mechanism? Is it necessary to read and write back the upper word unchanged to be sure?

    /Paul

  • Now I also observed that even with byte access, writing to I2C_OA0 to set the I2C2 module's own 7-bit address, the same value gets written to the high word as well,

    /Paul

  • How are you reading back this data to verify?  Are you using a memory window in CCS?  If so, we should verify that the CCS memory map has been configured to define that space as 16-bit access only (if you're even using CCS).  Have you tried using code that makes 16-bit accesses to read back the top and bottom half of the register?

    Brad

  • I'm looking at the CCS Memory Window, set to 8-bit - Ti Style.

  • 01.30 here [|-)], so continuing tomorrow

  • Are you using the omap3530_cortexA.gel file in your CCS configuration?  If so, it defines the memory map like this for I2C:

     GEL_MapAddStr(0x48070000, 0, 0x00001000, "R|W|AS2", 0);  /* I2C1 - module (msi2cocp_func.doc)*/
        GEL_MapAddStr(0x48071000, 0, 0x00001000, "R|W|AS2", 0);  /* I2C1 - L4 interconnect */
        GEL_MapAddStr(0x48072000, 0, 0x00001000, "R|W|AS2", 0);  /* I2C2 - module (msi2cocp_func.doc)*/
        GEL_MapAddStr(0x48073000, 0, 0x00001000, "R|W|AS2", 0);  /* I2C2 - L4 interconnect */

    The "AS2" means that the access width is 2 bytes, so even if you put the memory window as a 32-bit display it should still be doing 16-bit accesses.  (Though on the flip side, if you're NOT using the gel file than regardless of the display size I think you might be getting 32-bit accesses.  I'm not sure for that case.)

  • Brad, I wasn't using that GEL file but now I am. The results are the same. I may try using CCS4 on my 32-bit machine (64-bit Windows not supported [:(] ), running Win7. Any other tips, or should I just push ahead and see if I get anything working?

    /Paul

  • FYI, I've been using CCS 4 on my home computer.  I'm running Windows 7 x64 RC.  I haven't really had any issues with it.  The only "problem" was for the automatic updates to work in CCS I needed to launch CCS as administrator for that session.  It's not technically supported, but I don't think you'll have any/many issues.

  • but, even weirder, if I do

    set_bits_in_reg_16(I2C2_OA0, OMAP_I2C_ADDR);
     clear_bits_in_reg_16(I2C2_OA0+2, 0xFFFF);

    to clear just the upper word, both words get cleared to 0!

    I cannot make any sense of this - silicon erratum?

    /Paul

  • Hi Paul,

    This is neither a bug nor an error, but quite normal for many of the registers in the TI OMAP series. The "feature" happens since basically address A and A+2 is referring to the same physical register since the 2nd less important bit is left out of the address decoding logic for the register (in order to save silicon-area).

    You can therefore rest assured that this won't cause you any problems except that you need to live with the fact that the registers are mirrored. In general a reserved register area might how many "funny" things (and can't be expected to be 0 unless specifically noted), and this is basically just such an item you hit. 

    I hope this gave an explanation to your frustration?
      Søren

  • Thanks Sören, that does clarify everything!

    /Paul

  • Hi Søren,

    me again, back at the I2C register enigma. I am still having a hard time understanding the register access rules.

    Let me illustrate. I want to write the I2C_EN bit to the I2C_CON register, in my case it is I2C2.

    I have tried 4 ways:

        *((uint16*)I2C2_CON) = I2C_EN; //doesn't work
        *((uint8*)I2C2_CON+1) = I2C_EN>>8; //works
        *((uint32*)I2C2_CON) = (uint32)I2C_EN; //doesn't work
        *((uint32*)I2C2_CON) = ((uint32)I2C_EN<<16)|I2C_EN; //works

    When I say "works" I mean the memory view shows

    0x48072024    8000    8000

    while "doesn't work" means both words there are 0000.

    Can you explain what is going on?

    I see in the Linux driver code the following:

    omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN);

    which reduces to a __raw_writew call, but I don't actually understand what that does differently to what I am doing in the first option above.

    Recapitulating, I'm still using CCS3 and a Blackhawk USB560 JTAG emulator.

  • P.S. unless of course __raw_writew does a byte-wise write, as I see that this code

        *((uint 8*)I2C2_CON+1) = I2C_EN>>8; //works
        *((uint8*)I2C2_CON) = 0; //works

    does the business correctly. However, I am still baffled why the 16-bit write doesn't work, and the "doubled-up" 32-bit write does.

    /Paul

  • Hi Paul,

    Hmm - Really strange - I'll think about it while sleeping and hopefully have an idea by tomorrow :-) - Meanwhile please double check all your macros, #defines etc. to make 100% sure you aren't fooled by something "stupid". What you describe is really strange...

    __raw_writew do a 16-bit access unless I'm totally off... 

    Best regards
      Søren