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.

TUSB3410 and I2C

Other Parts Discussed in Thread: TUSB3410

I want to write to an EEPROM via the I2C bus and I'm following the steps in the data manual (SLLS519G). I'm finding that I need to put a delay between successive page writes, so the sequence is: send address, send 32 bytes, delay, send address, send 32 bytes ...

I'm waiting for TXE every time I set I2CDAO, as in the data manual.

If I don't delay only the first 32 bytes are written and the rest aren't.

Am I missing something or should there be a delay and if so how long (or does it depend on the EEPROM used?)

  • The EEPROM manual (it's an ST M24C64) says to set the device address, and then poll for ACK on the i2c bus (SDA low); if there's no ACK then the E2 is not ready, so repeat the start/device address sequence until it is. 

    So, how do I check if there's an ACK or not using the TUSB's registers?

  • Well, it doesn't seem too busy in here. Maybe if I just try the write several times with a short delay?

     int retry = 3;
    while ((write(...) != NO_ERROR) && (--retry > 0))
    {
    delay();
    }

     What do you think?

     Pete

  • The page-write operation is initiated in the same way as byte write, with the exception that a stop condition is not generated after the first EPROM [DATA] is transmitted. The following describes the sequence of writing 32 bytes in page mode.

    Device Address + EPROM [High Byte]

    The MCU clears bit 0 (SWR) in the I2CSTA register. This forces the I2C controller to not generate a stop condition after the contents of the I2CDAO register are transmitted.

    The MCU writes the device address (bit 0 (R/W) = 0) to the I2CADR register (write operation).

    The MCU writes the high byte of the EEPROM address into the I2CDAO register

    Bit 3 (TXE) in the I2CSTA register is cleared (indicating busy).

    The contents of the I2CADR register are transmitted to the device (preceded by start condition on SDA).

    The contents of the I2CDAO register are transmitted to the device (EEPROM address).

    Bit 3 (TXE) in the I2CSTA register is set and interrupts the MCU, indicating that the I2CDAO register contents have been transmitted.

    EPROM [Low Byte]

    The MCU writes the low byte of the EEPROM address into the I2CDAO register.

    Bit 3 (TXE) in the I2CSTA register is cleared (indicates busy).

    The contents of the I2CDAO register are transmitted to the device (EEPROM address).

    Bit 3 (TXE) in the I2CSTA register is set and interrupts the MCU, indicating that the I2CDAO register contents have been transmitted.

    EPROM [DATA]—31 Bytes

    The data to be written to the EEPROM are written by the MCU into the I2CDAO register.

    Bit 3 (TXE) in the I2CSTA register is cleared (indicates busy).

    The contents of the I2CDAO register are transmitted to the device (EEPROM data).

    Bit 3 (TXE) in the I2CSTA register is set and interrupts the MCU, indicating that the I2CDAO register contents have been transmitted.

    This operation repeats 31 times.

    EPROM [DATA]—Last Byte

    The MCU sets bit 0 (SWR) in the I2CSTA register. This forces the I2C controller to generate a stop condition after the contents of the I2CDAO register are transmitted.

    The MCU writes the last date byte to be written to the EEPROM, into the I2CDAO register.

    Bit 3 (TXE) in the I2CSTA register is cleared (indicates busy).

    The contents of the I2CDAO register are transmitted to EEPROM (EEPROM data).

    Bit 3 (TXE) in the I2CSTA register is set and interrupts the MCU, indicating that the I2CDAO register contents have been transmitted.

    The I2C controller generates a stop condition after the contents of the I2CDAO register are transmitted.

  • Thanks for your reply. It looks like you've pasted me a section from the data manual that I referred to in my first post. To clarify what I'm doing: 

    WORD index = 0;
    BYTE err = NO_ERROR;
    while ((err == NO_ERROR) && (index < SIZE))
    {
     err = i2cWrite(0, index, 32, &buffer[index]);
     index += 32;
    }

    Where i2cWrite is a function taken directly from the TI Bootcode Source Listing SLLC139. It writes the first 32 byte chunk but not subsequent ones. The manual for the EEPROM I'm using says that if it is not ready to write, it will not acknowledge the device select. So my question is: can I detect when the device select is not acknowledged or do I just retry the i2cWrite a number of times with pauses (assuming that if the function fails, say,  5 times in a row there's a hardware error).

    Looking at the steps you posted:

    The MCU writes the device address (bit 0 (R/W) = 0) to the I2CADR register (write operation).

    The MCU writes the high byte of the EEPROM address into the I2CDAO register

    Bit 3 (TXE) in the I2CSTA register is cleared (indicating busy).

    The procedure could fail when I2CADR is set, but there's no step for checking that. Or is the address not transmitted until I2CDAO is written?

    Pete

    
    

     

  • The following is a code portion taken from our EEPROM burner's FW source code.

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

    BYTE i2cWrite(BYTE bDeviceAddress, WORD wAddress, WORD wNumber, PBYTE pbDataArray)
    {
        BYTE bTemp,bHiAddress;
       
        bI2CSTA &= ~(I2CSTA_SRD | I2CSTA_SWR);  // clear SRD and SWR bit

        // If error, return a value other than zero.
        if(wNumber == 0x00) return NO_ERROR;

        if(bDeviceCategory == I2C_CATEGORY_1){
            // cat 1
            bI2CADR = (BYTE)(wAddress << 1);
        }else{
            // cat 2 or 3
            bTemp    = bDeviceAddress & MASK_I2C_DEVICE_ADDRESS;    // write device address and RW=0
            bTemp    = bTemp << 1;                          
            bTemp   |= BIT_I2C_DEVICE_TYPE_MEMORY;                  // add control code

            // check if data address is higher than 0xff in cat 2 device
            if((bDeviceCategory == I2C_CATEGORY_2) && (wAddress > 0x00ff)){
                bHiAddress  = (BYTE)(wAddress >> 8) & MASK_I2C_DEVICE_ADDRESS;
                bHiAddress  = bHiAddress << 1;
                bTemp      |= bHiAddress;
            }
            bI2CADR = bTemp;                            // write out device address

            if(bDeviceCategory == I2C_CATEGORY_3){
                bI2CDAO  =  (BYTE)(wAddress >> 8);      // write out high byte of address
                if(i2cWaitForWrite() != NO_ERROR) return ERROR;     // bus error
            }

            bI2CDAO  =  (BYTE)(wAddress & 0xff);        // write out low byte of address
            if(i2cWaitForWrite() != NO_ERROR) return ERROR;         // bus error
        }

        // SRD should be cleared.
        while(wNumber > 1){
            bI2CDAO = *pbDataArray++;
            if(i2cWaitForWrite() != NO_ERROR) return ERROR;          // bus error
            wNumber--;
        }

        // write the last byte
        bI2CSTA |= I2CSTA_SWR;                          // set SWR bit
        bI2CDAO  = *pbDataArray;                        // write out the data

        if(i2cWaitForWrite() != NO_ERROR) return ERROR;             // bus error
        return NO_ERROR;
    }

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

    I can notice from there that some delays are being inserted (i2cWaitForWrite), and SDR bit is being cleared... Let me know if it's useful.

  • Right, the code portion you've quoted is exactly what I meant by "... i2cWrite is a function taken directly from the TI Bootcode Source Listing SLLC139"

    I've got a category 3 device, so looking at the code for i2cWrite, it does this:

    1. write out device address
    2. write out high byte of the address
    3. wait
    4. write out low byte of the address
    5. wait
    6. write out first data byte
    7. wait
    8. write out second byte...etc etc

    You will notice there's no wait between steps 1 & 2. i2cWaitForWrite is not a time delay, it polls the TXE bit which indicates that the data has been sent. My EEPROM manual says that if it is not ready to receive the next command, it does not acknowledge the device address byte. So how can I check if the device is ready using the TUSB's controller. What I want is

    1. write out device address
    2. If not acknowledged go to step 1
    3. write out high byte of the address
    4. wait
    5. write out low byte of the address
    6. wait
    7. write out first data byte
    8. wait
    9. write out second byte...etc etc

    Do you see what I mean?

  • In case of the TUSB3410 device accesses a Cat 3 device like this: Two bytes of data are written to addresses i and i+1. Two bytes of data address, A15 to A0, are sent out before the data bytes (Take a look at the attached Write-I2C-Cat3.jpg).

    Note: There are certain restrictions to the types of EEPROM devices that can be used. I2C EEPROM devices available on the market can be grouped by the way they are addressed on the I2C bus. It is necessary to consider this when selecting a device for use with a TI USB controller, since some types are not supported with some controllers, and in some cases the device address may need to be configured differently depending on the type.

  • I appreciate the time you're spending to help me, and I think we're getting to the heart of it now. I have code that I'm confident will correctly write data to the EEPROM, and I am confident because the TI docs are clear, and also because I based my code on the TI bootcode example. The problem is that if I do writing in a loop, the first one will succeed and the next write will fail. I know the reason for this - to quote the EEPROM manual:

    During the internal Write cycle, the device disconnects itself from the bus, and writes a copy of the data from its internal latches to the memory cells. The maximum Write time (tw) is shown in Table 17 and Table 18 , but the typical time is shorter. To make use of this, a polling sequence can be used by the bus master. The sequence, as shown in Figure 10 , is:

    1. Initial condition: a Write cycle is in progress.

    2. Step 1: the bus master issues a Start condition followed by a device select code (the first byte of the new instruction).

    3. Step 2: if the device is busy with the internal Write cycle, no Ack will be returned and the bus master goes back to Step 1. If the device has terminated the internal Write cycle, it responds with an Ack, indicating that the device is ready to receive the second part of the instruction (the first byte of this instruction having been sent during Step 1).

    I have attached their figure 10 (with my annotations in red) which shows how they think it should be done. My question is, how do I do the part marked ???, detect when the EEPROM is busy? By the way the EEPROM is one that is supported by the TUSB (it is listed in the TUSB burner manual), so no worries there.

    Peter

  • How about this part of the M24C64 EEPROM’s datasheet?

     

    4.3 Acknowledge bit (ACK): The acknowledge bit is used to indicate a successful byte transfer. The bus transmitter, whether it be bus master or slave device, releases Serial Data (SDA) after sending eight bits of data. During the 9th clock pulse period, the receiver pulls Serial Data (SDA) Low to acknowledge the receipt of the eight data bits.

     

    If you can somehow write one byte data transfers, one after the other you could monitor each ACK. This is just to make some experimentation. Please let me know if it makes sense.

  • Actually I have resorted to putting in a delay for now. But..., what I would like to know is - how do I test the acknowledge bit with the TUSB?

    Thanks for your help.

  • I'm not sure if any bits in I2CSTA (I2C Status and Control Register) can help you out to test the ack in the E2.

    Regards,

    Ismael

  • I'm not sure either. Can anyone tell me which bits in I2CSTA would help here? That's the answer I'm looking for.

    Thanks,

    Peter

  • You can maybe check for TXE (bit 3) and see if the transmitter ir full or empty.

  • I will certainly try that but it will take me a couple of days to get around to it.

    Thanks,

    Peter

  • I have tried and it didn't work. Here is some more code, which should clarify. This is my EEPROM writer, taken from the TI Bootcode but simplified because I know which type of device I'm talking to.

    BYTE i2cWrite(WORD wAddress, WORD wNumber, __code BYTE* pbDataArray)
    {
        // If error, return a value other than zero.
        if(wNumber == 0x00) return NO_ERROR;
        bI2CSTA &= ~(I2CSTA_SWR);  // clear SWR bit

        bI2CADR = BIT_I2C_DEVICE_TYPE_MEMORY;  // write out device address
        bI2CDAO  =  (BYTE)(wAddress >> 8);      // write out high byte of address
        if(i2cWaitForWrite() != NO_ERROR) return ERROR;     // bus error

        bI2CDAO  =  (BYTE)(wAddress & 0xff);        // write out low byte of address
        if(i2cWaitForWrite() != NO_ERROR) return ERROR;         // bus error

        // SRD should be cleared.
        while(wNumber > 1){
            bI2CDAO = *pbDataArray++;
            if(i2cWaitForWrite() != NO_ERROR) return ERROR;          // bus error
            wNumber--;
        }

        // write the last byte
        bI2CSTA |= I2CSTA_SWR;                          // set SWR bit
        bI2CDAO  = *pbDataArray;                        // write out the data

        if(i2cWaitForWrite() != NO_ERROR) return ERROR;             // bus error

        return NO_ERROR;
    }

    I call this repeatedly (here just writing the same sequence of bytes over and over)

    #define CHUNK_SIZE 0x20 

     /* Copy data */
     while (size > 0) {
      err = i2cWrite(ptr, CHUNK_SIZE, chunk);
      if (err != NO_ERROR) break;
      RESET_WATCHDOG;
      ptr += CHUNK_SIZE;
      size -= CHUNK_SIZE;
     }

    This only ever writes 32 bytes and then stops.

    Now. If I add a time delay of 10ms after the i2cWrite() it's OK, but I wonder if it's possible to do better - for example what if a different make of EEPROM needed a different time delay?

    So as you suggested I put in a poll for TXE around the line that sets the address like this:

     do {
      bI2CADR = BIT_I2C_DEVICE_TYPE_MEMORY;                            // write out device address
      RESET_WATCHDOG;
     } while ((bI2CSTA & I2CSTA_TXE) == 0);

    but this just hangs forever.

    Please can you advise?

    Thanks,

    Peter

  • Hi all,

    I did try this (see my later post) and it did not work - maybe because I'm doing it wrong. Please can you advise?

    In the TUSB3410 data manual it describes TXE like this:

    TXE = 0 Transmitter is full. This bit is cleared when the MCU writes a byte to the I2CDAO register.

    TXE = 1 Transmitter is empty. The I2C controller sets this bit when the contents of the I2CDAO register are

    copied to the SDA shift register.

    However my problem is that the EEPROM won't ACK the address set (i.e setting I2CADR) while it's busy writing - this happens before I get around to setting I2CDAO.

    I'm sure I'm missing something, if you could post a couple of lines of code that would help.

    Peter