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.

RTOS/AM5728: I2C write time inconsistency

Part Number: AM5728

Tool/software: TI-RTOS

Hi,

I am using i2c3 bus for the code download of around 1150kb data. Usually it is taking 4-8 secs to download, but sometimes the download time is shooting upto 40-50 secs. 

On time profiling the whole download process the extra time consumption seems around the I2C write, particularly around the I2C_v1_hwiFxnMaster function. Another observation was adding the log_prints in driver seems to help, but adding same amount of delay is not helping.  

I tried probing SCA, clock speed is constant 400kbps. 

Any idea what might be causing additional delay and how to overcome it?

Thanks & Regards,

Raksha

  • The RTOS team have been notified. They will respond here.
  • Hi,

    Can you elaborate what version of the P-SDK RTOS software is used? And which driver example you refer to for testing download? What is the other side of I2C3 connection? Which is master and which is slave? Download means AM5728 writing to the other side?

    Regards, Eric
  • Hi,

    I am using  PROCESSOR-SDK-RTOS-AM57X - pdk_am57xx_1_0_7.

    Here, I2C is the master and on the slave side we have MOD and DEMOD devices. I am using I2C bus 3 to write to those devices.

    Here is the snippet :

    while(1)
    {

    (memcpy(&aTxBuffer[1], (SL_Firmware + read_idx), bytes_read));

    aTxBufferSize = bytes_read + 1;

    status = I2C_nByteWrite(eI2C_BUS3,I2cAddress,&aTxBuffer[0],aTxBufferSize);

    if(I2C_STS_SUCCESS != status) {

    Log_print1(Diags_USER1,": Write firmware through I2C failed with status %d.\n", status);
    return SL_CODE_DW_FAILED;
    }


    if(read_idx == 0)
    Log_print1(Diags_USER1,": SL code download started for 0x%x", I2cAddress);

    fw_bytes -= bytes_read;
    read_idx += bytes_read;

    if (fw_bytes == 0)
    {
    Log_print1(Diags_USER1,": SL code download done for 0x%x", I2cAddress);
    break;
    }

    if (fw_bytes <= bytes_read)
    bytes_read = fw_bytes;

    Task_sleep(1) ;

    }

    Thanks & Regards,

    Raksha 

  • Hi,

    This looks to be your own test code and you had a top level function I2C_nByteWrite. What TI I2C driver API you called inside? Can you explain how do you profile the I2C_v1_hwiFxnMaster() and found out the issue? I need to understand how to reproduce your issue.

    Regards, Eric
  • Hi,

    ByteWrite function is as follow :

    int8_t I2C_nByteWrite(uint8_t bus_no,uint8_t slave_addr,void *pu8_data,uint8_t wrbytes)
    {
    int16_t transfer = 0;

    I2C_Transaction i2cTransaction;
    I2C_transactionInit(&i2cTransaction);
    i2cTransaction.slaveAddress = slave_addr;
    i2cTransaction.writeBuf = pu8_data;
    i2cTransaction.writeCount = wrbytes;
    i2cTransaction.timeout = I2C_TRANSACTION_TIMEOUT;   /* 2ms */ 

    transfer = I2C_transfer(i2c_bus_handle_st[bus_no].i2c_handle, &i2cTransaction);

    if(transfer == I2C_STS_SUCCESS)
    {
    return transfer;
    }
    else
    {
    Log_print2(Diags_USER1," : Data Transfer at bus no %d failed with transfer status %d ",(uint32_t)bus_no,transfer);
    return I2C_STATUS_ERROR;

    }

    }

    And for time profiling :

    static inline uint64_t ReadTime(void) {
    uint64_t timeVal;
    uint32_t low;
    uint32_t high = 0;
    low = TSCL;
    high = TSCH;
    timeVal = _itoll(high, low);
    return timeVal;
    }

    Thanks & Regards,

    Raksha

  • Hi,

    Were you able to reproduce the issue? Any reason for the time inconsistency. 

    Thanks & regards.

    Rakha

  • Hi,

    Sorry for the late response! I tested I2C bus with 400kbps and used a timer to track the time spend for each I2C_transfer for 100 times:

       time[loop] = TSCL;

       status = I2C_transfer(handle, &i2cTransaction);

       spend[loop] = TSCL - time[loop];

    The time spend is quite consistent,  I can't reproduce your issue.

    Regards, Eric

  • Hi Eric,

    Can you please share the I2C config parameters other than bit rate, that you are using for I2C_socSetInitCfg() & I2C_Params_init() ?

    Thanks & Regards,

    Raksha

  • Hi,

    I was able to regenerate the I2C write time inconsistency issue with TI pdk_am57xx_1_0_7  I2C eeprom example. I am taking example present in pdk_am57xx_1_0_7/packages/ti/drv/i2c/example/eeprom_read,  modifying it as per requirement while keeping basic configuration same. 

    Impending changes in the application:

    while(1)
    {
    memcpy(&txBuf[1], (mod + idx), wrcount);  /* mod is pointer to array of 45932 bytes */

    I2C_transactionInit(&i2cTransaction);
    i2cTransaction.slaveAddress = I2C_EEPROM_ADDR;  /* slave address = 0x50 */
    i2cTransaction.writeBuf = (uint8_t *)&txBuf[0];
    i2cTransaction.writeCount = I2C_EEPROM_ADDR_SIZE + wrcount;  /* wrcount = 30 */
    i2cTransaction.readBuf = (uint8_t *)&rxBuf[0];
    i2cTransaction.readCount = 0;
    i2cTransaction.timeout = I2C_TRANSACTION_TIMEOUT;
    transferStatus = I2C_transfer(handle, &i2cTransaction);


    if(I2C_STS_SUCCESS != transferStatus)
    {
    System_printf("Write Data Transfer failed with transfer status %d \n",transferStatus);
    }

    bytes -= wrcount;
    idx += wrcount;

    if (bytes == 0)
    break;

    if (bytes <= wrcount)
    wrcount = bytes;

    Task_sleep(4);
    }

    And then using http://processors.wiki.ti.com/index.php/Linux_IPC_on_AM57xx#Adding_IPC_to_an_existing_TI_RTOS_application_on_the_DSP to create final application.

    With this, time is not at all consistent. Hope you can reproduce the same and help to solve it.

    Thanks & Regards,

    Raksha

  • Hi,

    Can you clarify just run your pdk_am57xx_1_0_7/packages/ti/drv/i2c/example/eeprom_read on DSP core alone WITHOUT Linux, are you able to see the transfer timing variation?

    Regards, Eric
  • Hi,

    Also I tried your suggested code modification:

    - I used pdk_am57xx_1_0_11\packages\MyExampleProjects\I2C_BasicExample_idkAM572x_c66xExampleProject,

    - attached is the main_eeprom_read.c where my code is under "PROFILE"

    /**
     *  \file   main_eeprom_read.c
     *
     *  \brief  Example application main file. This application will read the data
     *          from eeprom and compares it with the known data.
     *
     */
    
    /*
     * Copyright (C) 2014 - 2017 Texas Instruments Incorporated - http://www.ti.com/
     *
     * Redistribution and use in source and binary forms, with or without
     * modification, are permitted provided that the following conditions
     * are met:
     *
     * Redistributions of source code must retain the above copyright
     * notice, this list of conditions and the following disclaimer.
     *
     * Redistributions in binary form must reproduce the above copyright
     * notice, this list of conditions and the following disclaimer in the
     * documentation and/or other materials provided with the
     * distribution.
     *
     * Neither the name of Texas Instruments Incorporated nor the names of
     * its contributors may be used to endorse or promote products derived
     * from this software without specific prior written permission.
     *
     * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     *
     */
    
    #ifndef BARE_METAL
    /* XDCtools Header files */
    #include <xdc/std.h>
    #include <xdc/cfg/global.h>
    #include <xdc/runtime/System.h>
    #include <xdc/runtime/Error.h>
    
    /* BIOS Header files */
    #include <ti/sysbios/BIOS.h>
    #include <ti/sysbios/knl/Task.h>
    #endif
    
    #include <stdio.h>
    #include <string.h>
    
    /* TI-RTOS Header files */
    #include <ti/drv/i2c/I2C.h>
    #include <ti/drv/i2c/soc/I2C_soc.h>
    #include <ti/drv/i2c/test/eeprom_read/src/I2C_log.h>
    #include <ti/drv/i2c/test/eeprom_read/src/I2C_board.h>
    
    #if defined (SOC_AM335X) || defined (SOC_AM437x)
    /* EEPROM data -Board specific */
    extern char eepromData[I2C_EEPROM_RX_LENGTH];
    #endif
    
    /**********************************************************************
     ************************** Macros ************************************
     **********************************************************************/
    
    #define I2C_TRANSACTION_TIMEOUT         (2000U)
    
    
    /**********************************************************************
     ************************** Internal functions ************************
     **********************************************************************/
    
    /* Data compare function */
    bool CompareData(char *expData, char *rxData, unsigned int length);
    
    /**********************************************************************
     ************************** Global Variables **************************
     **********************************************************************/
    
    #if defined (idkAM572x)
    char eepromData[I2C_EEPROM_TEST_LENGTH] = {0x55, 0x33, 0xEE, 0x41, 0x4D, 0x35, 0x37, 0x32,
                                  0x49, 0x44};
    #elif defined(idkAM574x)
    char eepromData[I2C_EEPROM_TEST_LENGTH] = {0x55, 0x33, 0xEE, 0x41, 0x4D, 0x35, 0x37, 0x34,
                                  0x49, 0x44};
    #elif defined (idkAM571x)
    char eepromData[I2C_EEPROM_TEST_LENGTH] = {0x55, 0x33, 0xEE, 0x41, 0x4D, 0x35, 0x37, 0x31,
                                  0x49, 0x44};
    #elif defined (evmAM572x)
    char eepromData[I2C_EEPROM_TEST_LENGTH] = {0x55, 0x33, 0xEE, 0x41, 0x4d, 0x35, 0x37, 0x32,
                                  0x50, 0x4d};
    #elif defined (evmDRA72x)
    char eepromData[I2C_EEPROM_TEST_LENGTH] = {0x33, 0x55, 0xAA, 0x4A, 0x36, 0x45, 0x43, 0x4F,
                                  0x43, 0x50};
    #elif defined (evmDRA75x)
    char eepromData[I2C_EEPROM_TEST_LENGTH] = {0xEE, 0x33, 0x55, 0xAA, 0x35, 0x37, 0x37, 0x37,
                                  0x78, 0x43};
    #elif defined (evmDRA78x)
    char eepromData[I2C_EEPROM_TEST_LENGTH] = {0x33, 0x55, 0xAA, 0x41, 0x44, 0x41, 0x53, 0x2D,
                                  0x4C, 0x4F};
    #elif defined (evmK2H) || defined (evmK2K) || defined (evmK2E) || defined (evmK2L) || defined (evmK2G) || defined (evmC6678) || defined (evmC6657) || defined (iceK2G) || defined (evmOMAPL137)
    char eepromData[I2C_EEPROM_TEST_LENGTH] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                                  0x00, 0x00};
    #else
    #endif
    
    /*
     *  ======== Board_initI2C ========
     */
    bool Board_initI2C(void)
    {
        Board_initCfg boardCfg;
        Board_STATUS  boardStatus;
    #if defined (idkAM571x)
        Board_IDInfo  id;
    #endif
        I2C_HwAttrs   i2c_cfg;
    #if defined (evmK2G)
        Board_SoCInfo socInfo;
    #endif
    
        /* Get the default I2C init configurations */
        I2C_socGetInitCfg(I2C_EEPROM_INSTANCE, &i2c_cfg);
    
        /* Modify the default I2C configurations if necessary */
    
        /* Set the default I2C init configurations */
        I2C_socSetInitCfg(I2C_EEPROM_INSTANCE, &i2c_cfg);
    
    #if defined(evmK2E) || defined(evmC6678)
        boardCfg = BOARD_INIT_MODULE_CLOCK |
            BOARD_INIT_UART_STDIO;
    #else
        boardCfg = BOARD_INIT_PINMUX_CONFIG |
            BOARD_INIT_MODULE_CLOCK |
            BOARD_INIT_UART_STDIO;
    #endif
        boardStatus = Board_init(boardCfg);
        if (boardStatus != BOARD_SOK)
        {
            return (false);
        }
    
    #if defined (idkAM571x)
        boardStatus = Board_getIDInfo(&id);
        if (boardStatus != BOARD_SOK)
        {
            return (false);
        }
        memcpy(eepromData, &id.header[I2C_EEPROM_TEST_ADDR],
               BOARD_EEPROM_HEADER_LENGTH - I2C_EEPROM_TEST_ADDR);
        memcpy(&eepromData[BOARD_EEPROM_HEADER_LENGTH - I2C_EEPROM_TEST_ADDR],
               id.boardName,
               I2C_EEPROM_TEST_LENGTH - BOARD_EEPROM_HEADER_LENGTH + I2C_EEPROM_TEST_ADDR);
    #endif
    
    #if defined (evmK2G)
        /* Read the SoC info to get the System clock value */
        Board_getSoCInfo(&socInfo);
        if(socInfo.sysClock != BOARD_SYS_CLK_DEFAULT)
        {
            /* Get the default I2C init configurations */
            I2C_socGetInitCfg(I2C_EEPROM_INSTANCE, &i2c_cfg);
            /* Update the I2C functional clock based on CPU clock - 1G or 600MHz */
            i2c_cfg.funcClk = socInfo.sysClock/I2C_MODULE_CLOCK_DIVIDER;
            /* Set the default I2C init configurations */
            I2C_socSetInitCfg(I2C_EEPROM_INSTANCE, &i2c_cfg);
        }
    #endif
    
        return (true);
    }
    
    #define PROFILE
    #ifdef PROFILE
      uint32_t time[1000];
      unsigned int cregister volatile TSCL;
    #endif
    /*
     *  ======== test function ========
     */
    void i2c_test(UArg arg0, UArg arg1)
    {
        I2C_Params i2cParams;
        I2C_Handle handle = NULL;
        I2C_Transaction i2cTransaction;
        char txBuf[I2C_EEPROM_TEST_LENGTH + I2C_EEPROM_ADDR_SIZE] = {0x00, };
        char rxBuf[I2C_EEPROM_TEST_LENGTH] = {0x00, };
        bool status,test_pass=FALSE;
        int16_t transferStatus;
    #ifdef PROFILE
        char txArray[12000];
        uint32_t wrcount = 30, bytes = 12000, idx = 0, loop = 0, prevT = 0;
        TSCL = 0;
    #endif
    
        /* Set the I2C EEPROM write/read address */
        txBuf[0] = (I2C_EEPROM_TEST_ADDR >> 8) & 0xff; /* EEPROM memory high address byte */
        txBuf[1] = I2C_EEPROM_TEST_ADDR & 0xff;        /* EEPROM memory low address byte */
    
        I2C_init();
    
        I2C_Params_init(&i2cParams);
    
        handle = I2C_open(I2C_EEPROM_INSTANCE, &i2cParams);
    
    #ifndef PROFILE
        I2C_transactionInit(&i2cTransaction);
        i2cTransaction.slaveAddress = I2C_EEPROM_ADDR;
        i2cTransaction.writeBuf = (uint8_t *)&txBuf[0];
        i2cTransaction.writeCount = I2C_EEPROM_ADDR_SIZE;
        i2cTransaction.readBuf = (uint8_t *)&rxBuf[0];
        i2cTransaction.readCount = I2C_EEPROM_TEST_LENGTH;
        i2cTransaction.timeout   = I2C_TRANSACTION_TIMEOUT;
        transferStatus = I2C_transfer(handle, &i2cTransaction);
    #else
        while(loop < 1000)
        {
            memcpy(&txBuf[1], &txArray[idx], wrcount); /* mod is pointer to array of 45932 bytes */
    
            I2C_transactionInit(&i2cTransaction);
            i2cTransaction.slaveAddress = I2C_EEPROM_ADDR; /* slave address = 0x50 */
            i2cTransaction.writeBuf = (uint8_t *)&txBuf[0];
            i2cTransaction.writeCount = I2C_EEPROM_ADDR_SIZE + wrcount; /* wrcount = 30 */
            i2cTransaction.readBuf = (uint8_t *)&rxBuf[0];
            i2cTransaction.readCount = 0;
            i2cTransaction.timeout = I2C_TRANSACTION_TIMEOUT;
    
            prevT =  TSCL;
            transferStatus = I2C_transfer(handle, &i2cTransaction);
            time[loop++] = TSCL - prevT;
    
            if(I2C_STS_SUCCESS != transferStatus)
            {
                System_printf("Write Data Transfer failed with transfer status %d \n",transferStatus);
            }
    
            bytes -= wrcount;
            idx += wrcount;
    
            if (bytes == 0)
            break;
    
            if (bytes <= wrcount)
            wrcount = bytes;
    
            Task_sleep(4);
        }
    #endif
        if(I2C_STS_SUCCESS != transferStatus)
        {
            I2C_log("\n Data Transfer failed with transfer status %d \n",transferStatus);
            test_pass=FALSE;
            goto exit_test;
        }
    
        I2C_close(handle);
    
    #if defined (evmK2H) || defined (evmK2K) || defined (evmK2E) || defined (evmK2L) || defined (evmK2G) || defined (iceK2G) || defined (evmC6678)  || defined (evmC6657) || defined (iceK2G) || defined (evmOMAPL137)
        /* EEPROM not programmed on K2 EVMs, copy rx data to eepromData
           so it can pass the test */
        memcpy(eepromData, rxBuf, I2C_EEPROM_TEST_LENGTH);
    #endif
        status = CompareData(&eepromData[0], &rxBuf[0], I2C_EEPROM_TEST_LENGTH);
        if(TRUE == status)
        {
            I2C_log("\n EEPROM data matched \n");
           test_pass=TRUE;
        }
        else
        {
           test_pass=FALSE;
        }
    
    exit_test:
    
       if(TRUE == test_pass)
       {
           UART_printStatus("\n All tests have passed. \n");
        }
        else
        {
            UART_printStatus("\n Some tests have failed. \n");
        }
    
        while (1) {
    
        }
    }
    
    /*
     *  ======== main ========
     */
    int main(void)
    {
        if (Board_initI2C() == false)
        {
            return (0);
        }
    
    #if defined (SOC_AM335X) || defined (SOC_AM437x) || defined (SOC_OMAPL137)
    	Task_Handle task;
    	Error_Block eb;
    
        Error_init(&eb);
    
        task = Task_create(i2c_test, NULL, &eb);
        if (task == NULL) {
            System_printf("Task_create() failed!\n");
            BIOS_exit(0);
        }
    #endif
    
        /* Start BIOS */
        BIOS_start();
        return (0);
    }
    
    /*
     *  ======== CompareData ========
     */
    bool CompareData(char *expData, char *rxData, unsigned int length)
    {
        uint32_t idx = 0;
        uint32_t match = 1;
        bool retVal = false;
    
        for(idx = 0; ((idx < length) && (match != 0)); idx++)
        {
            if(*expData != *rxData) match = 0;
            expData++;
            rxData++;
        }
    
        if(match == 1) retVal = true;
    
        return retVal;
    }
    

    I didn't see any big variation.

    Regards, Eric

  • Hi,

    If I run pdk_am57xx_1_0_7/packages/ti/drv/i2c/example/eeprom_read on DSP core alone WITHOUT Linux, I am not seeing time variation.

    But if I using ccs application build through http://processors.wiki.ti.com/index.php/Linux_IPC_on_AM57xx#Adding_IPC_to_an_existing_TI_RTOS_application_on_the_DSP and running this binary as remote application when linux boots up, I am seeing time variation.

    Also, note that I am not debugging with JTAG here, so you might want to print time taken at the end of transaction. 

    Thanks & Regards,

    Raksha

  • Hi,

    Thanks for the info! I will ask my colleague in Linux/IPC team for further help.

    Regards, Eric
  • Hi, Raksha,

    Does your DSP application configure I2C? When you have LInux running on ARM, is I2C disabled on the ARM side? If it is not disabled, could you delete i2c1 and i2c3 nodes in Linux dts file, am57xx-beagle-x15-common.dtsi and give it a try?

    Rex
  • Hi,

    Yes, DSP is configuring I2C and I am disabling it from ARM. Still the results are same.

    I cannot delete the i2c1 node, because it is used by other devices, but I tried by deleting i2c3 node, it is not making any difference.

    Thanks & Regards,

    Raksha 

  • Hi, Raksha,

    When you run your test with i2c3 disabled on linux side, were you using PDK example which accesses EEPROM for you test or the other of your own application? PDK example accessing EEPROM uses i2c1.

    Rex
  • Hi Rex,

    EEPROM is on I2C1,  I2C3 I tried with my own application.

    Were you able to recreate the issue with eeprom? If not I can share my eeprom project and dtb file with you.

    And if you are not facing problem on your side can share the i2c configuration and dtb changes you are making ?

    Thanks & Regards,

    Raksha

  • Hi, Raksha,

    Testing using EEPROM is not an option. Linux Kernel needs to read the content to boot up. We won't be able to test on I2C3 either because our EVM doesn't have any device connected to it. Could you measure the I2C3 clk with and without Linux running to see if it is running at the same speed? This is the only logical reason we can think of which may affects the result.

    Rex