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.

IWR6843AOPEVM: Delay between two I2C messages when using IWR6843AOPEVM as a I2C slave

Part Number: IWR6843AOPEVM
Other Parts Discussed in Thread: IWR6843

Hello,

I would like to use I2C to send data to another device. In this case, the IWR6843AOPEVM is the slave and the other device is the master. Basically the master wants to read a register inside the radar sensor. So the code is just a I2CSlave_write() inside a loop.

//Loop inside thread
while(1)
{
    retVal = I2CSlave_write(i2cHandle, &txData, 1);
    if(retVal == false)
    {
        System_printf("Write failed\n");
    }
    else
    {
        System_printf("Write Success\n");
    
        txData[0]++;
    }
}

My problem is similar to the one described in these two threads: 

  1. https://e2e.ti.com/support/sensors-group/sensors/f/sensors-forum/1054081/iwr6843isk-ods-issue-on-i2c-slave-driver-api?tisearch=e2e-sitesearch&keymatch=6843-i2c-slave#
  2. RTOS/AWR1642: Read Issue from I2C Slave - Sensors forum - Sensors - TI E2E support forums

Indeed, I would like to read from the slave every 5 to 10 ms, but this makes the slave wait forever after the second I2CSlave_write() command. However, if I wait ~200 ms before sending a new "read command", it works without any problems.

I see, that the answer from the first thread I linked is that this problem would be patched in the next SDK. I am using SDK 3.6 and still have this problem.

Has it been patched? If not, is there a solution to this problem?

Thanks in advance.

Best regards,

Julien

  • Hello Julien,

    Let me look into this further with what did and did not change between SDKs, please give me more time. Appreciate it.

    Best Regards,

    Pedrhom 

  • Hello Julien,

    Can you start by confirming to me whether the test I2C program within the SDK does or does not have this delay issue for you?

    Best Regards,

    Pedrhom

  • Hello Pedrhom,

    Thank you for your answer.

    I can confirm that I am using the test program within the SDK. I just modified the i2cBlockingModeTest() function, so that it would loop at I2CSlaveWrite() (like the code in my question) because that is the behaviour needed in my application.

    The first write from the slave is always a success, but when the second request from the master comes to quickly, both SCL and SDA are pulled low and it blocks. So, yes, the issue is still there.

    Best Regards,

    Julien

  • Hello Pedrhom,

    It has been a couple of days and I have not really made any progress on my end. Have you found anything or do you, perhaps, have some more hints on what may be causing this problem?

    Thank you in advance.

    Best regards,

    Julien

  • Hi Julien,

    Apologies for the delay here while we look into this internally. In the meantime, would you mind sharing the modified test file you are using so that we can create a 1:1 test on our end?

    Best Regards,
    Alec

  • Hi Alec,

    I am using this file for my tests. I hope that it will help you.

    2626.slave.c
    /*
     *   @file  slave.c
     *
     *   @brief
     *      Unit Test code for I2C Slave driver
     *
     *  \par
     *  NOTE:
     *      (C) Copyright 2017 Texas Instruments, Inc.
     *
     *  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.
     */
    
    /**************************************************************************
     *************************** Include Files ********************************
     **************************************************************************/
    
    /* Standard Include Files. */
    #include <stdint.h>
    #include <stdlib.h>
    #include <stddef.h>
    #include <string.h>
    #include <stdio.h>
    #include <math.h>
    
    /* BIOS/XDC Include Files. */
    #include <xdc/std.h>
    #include <xdc/cfg/global.h>
    #include <xdc/runtime/IHeap.h>
    #include <xdc/runtime/System.h>
    #include <xdc/runtime/Error.h>
    #include <xdc/runtime/Memory.h>
    #include <ti/sysbios/BIOS.h>
    #include <ti/sysbios/knl/Task.h>
    #include <ti/sysbios/knl/Event.h>
    #include <ti/sysbios/knl/Semaphore.h>
    #include <ti/sysbios/knl/Clock.h>
    #include <ti/sysbios/heaps/HeapBuf.h>
    #include <ti/sysbios/heaps/HeapMem.h>
    #include <ti/sysbios/knl/Event.h>
    #include <ti/sysbios/family/arm/v7a/Pmu.h>
    
    /* mmWave SK Include Files: */
    #include <ti/common/sys_common.h>
    #include <ti/drivers/soc/soc.h>
    #include <ti/drivers/i2c/I2CSlave.h>
    #include <ti/drivers/pinmux/pinmux.h>
    #include <ti/drivers/esm/esm.h>
    #include <ti/utils/testlogger/logger.h>
    #include <ti/drivers/osal/HwiP.h>
    
    /**************************************************************************
     *************************** Global Definitions ***************************
     **************************************************************************/
    /** \brief Number of messages sent */
    #define I2C_TEST_MESSAGE_COUNT          100
    #define I2C_TEST_BLOCKING_MODE          1
    
    /**
     * @brief
     *  Initialize the MCPI Log Message Buffer
     */
    
    /* Global Variables */
    volatile uint32_t       testSelection = 0;
    volatile uint32_t       gTransferDone = 0;
    volatile uint32_t       gTransferErrors = 0, gTransferCount = 0;
    uint8_t                 rxData[16];
    uint8_t                 txData[16];
    uint32_t                rxTicks[I2C_TEST_MESSAGE_COUNT];
    uint32_t                txTicks[I2C_TEST_MESSAGE_COUNT];
    uint32_t                minRxTicks;
    uint32_t                maxRxTicks;
    uint32_t                minTxTicks;
    uint32_t                maxTxTicks;
    uint32_t                totalTxTicks;
    uint32_t                totalRxTicks;
    
    /**
     *  @b Description
     *  @n
     *      This function starts the PMU counter.
     *
     *   @param[in] counter
     *      Counter id used for benchmarking
     *
     *  @retval
     *      Not Applicable.
     */
    void Test_benchmarkStart(uint32_t counter)
    {
        /* Initialize counter to count cycles */
        Pmu_configureCounter(counter, 0x11, FALSE);
    
        /* Reset PMU counter */
        Pmu_resetCount(counter);
    
        /* Start PMU counter */
        Pmu_startCounter(counter);
    }
    
    /**
     *  @b Description
     *  @n
     *      This function stops a PMU counter and returns the current
     *      counter value.
     *
     *   @param[in] counter
     *      Counter id used for benchmarking
     *
     *  @retval
     *      Current PMU counter value.
     */
    uint32_t Test_benchmarkStop(uint32_t counter)
    {
        /* Stop PMU counter */
        Pmu_stopCounter(counter);
    
        /* Read PMU counter */
        return (Pmu_getCount(counter));
    }
    
    /**
     *  @b Description
     *  @n
     *      Platform specific intializations.
     *
     *  @retval
     *      Success     - 0
     *  @retval
     *      Error       - <0
     */
    
    static int32_t PlatformInit(void)
    {
    #if (defined(SOC_XWR14XX))
        /* Setup the PINMUX to bring out the XWR14xx I2C pins */
        Pinmux_Set_OverrideCtrl(SOC_XWR14XX_PINR3_PADAH, PINMUX_OUTEN_RETAIN_HW_CTRL, PINMUX_INPEN_RETAIN_HW_CTRL);
        Pinmux_Set_FuncSel(SOC_XWR14XX_PINR3_PADAH, SOC_XWR14XX_PINR3_PADAH_I2C_SDA);
        Pinmux_Set_OverrideCtrl(SOC_XWR14XX_PINP4_PADAI, PINMUX_OUTEN_RETAIN_HW_CTRL, PINMUX_INPEN_RETAIN_HW_CTRL);
        Pinmux_Set_FuncSel(SOC_XWR14XX_PINP4_PADAI, SOC_XWR14XX_PINP4_PADAI_I2C_SCL);
    #elif (defined(SOC_XWR16XX))
        /* Setup the PINMUX to bring out the XWR16xx I2C pins */
        Pinmux_Set_OverrideCtrl(SOC_XWR16XX_PINF13_PADAH, PINMUX_OUTEN_RETAIN_HW_CTRL, PINMUX_INPEN_RETAIN_HW_CTRL);
        Pinmux_Set_FuncSel(SOC_XWR16XX_PINF13_PADAH, SOC_XWR16XX_PINF13_PADAH_I2C_SDA);
    
        Pinmux_Set_OverrideCtrl(SOC_XWR16XX_PING14_PADAI, PINMUX_OUTEN_RETAIN_HW_CTRL, PINMUX_INPEN_RETAIN_HW_CTRL);
        Pinmux_Set_FuncSel(SOC_XWR16XX_PING14_PADAI, SOC_XWR16XX_PING14_PADAI_I2C_SCL);
    #elif (defined(SOC_XWR18XX))
        /* Setup the PINMUX to bring out the XWR18xx I2C pins */
        Pinmux_Set_OverrideCtrl(SOC_XWR18XX_PINF13_PADAH, PINMUX_OUTEN_RETAIN_HW_CTRL, PINMUX_INPEN_RETAIN_HW_CTRL);
        Pinmux_Set_FuncSel(SOC_XWR18XX_PINF13_PADAH, SOC_XWR18XX_PINF13_PADAH_I2C_SDA);
    
        Pinmux_Set_OverrideCtrl(SOC_XWR18XX_PING14_PADAI, PINMUX_OUTEN_RETAIN_HW_CTRL, PINMUX_INPEN_RETAIN_HW_CTRL);
        Pinmux_Set_FuncSel(SOC_XWR18XX_PING14_PADAI, SOC_XWR18XX_PING14_PADAI_I2C_SCL);
    #elif (defined(SOC_XWR68XX))
        /* Setup the PINMUX to bring out the XWR68xx I2C pins */
        Pinmux_Set_OverrideCtrl(SOC_XWR68XX_PINF13_PADAH, PINMUX_OUTEN_RETAIN_HW_CTRL, PINMUX_INPEN_RETAIN_HW_CTRL);
        Pinmux_Set_FuncSel(SOC_XWR68XX_PINF13_PADAH, SOC_XWR68XX_PINF13_PADAH_I2C_SDA);
    
        Pinmux_Set_OverrideCtrl(SOC_XWR68XX_PING14_PADAI, PINMUX_OUTEN_RETAIN_HW_CTRL, PINMUX_INPEN_RETAIN_HW_CTRL);
        Pinmux_Set_FuncSel(SOC_XWR68XX_PING14_PADAI, SOC_XWR68XX_PING14_PADAI_I2C_SCL);
    #endif
    
        return 0;
    }
    
    static int32_t i2cBlockingModeTest()
    {
        I2CSlave_Handle     i2cHandle;
        I2CSlave_Params     i2cParams;
        bool                retVal = false;
        int32_t             errCode = 0;
        uint32_t            arg;
        uint8_t*            pDataTxBegin = NULL;
    
        /* Reset the transmit and receive buffer */
        memset(&rxData, 0, sizeof (rxData));
        memset(&txData, 0, sizeof (txData));
    
        /* Initialize the I2C Slave driver */
        I2CSlave_init();
    
        /* Initialize the I2C driver default parameters */
        I2CSlave_Params_init(&i2cParams);
    
        i2cParams.transferMode = I2CSLAVE_MODE_BLOCKING;
        i2cParams.slaveAddress = 0x65;
    
        /* Open the I2C Slave driver */
        i2cHandle = I2CSlave_open(0, &i2cParams);
    
        if (i2cHandle == NULL)
        {
            System_printf ("Error: I2C Driver Open failed\n");
            return -1;
        }
        System_printf ("Debug: I2C Slave Open passed\n");
    
        /* Configure the I2C device in expand address mode. */
        arg = 0;
        errCode = I2CSlave_control (i2cHandle, I2C_CMD_ADDR_MODE, (void* )&arg);
        if (errCode < 0)
        {
            System_printf ("Error: I2C control Set XA failed [Error code %d]\n", errCode);
            return -1;
        }
        System_printf ("Debug: I2C Slave Control passed\n");
    
    // Slave register definition - to be changed accordingly by customer to ensure dynamic updates.
    // 6 registers with fixed values for testing purposes.
        txData[0] = 0x44;
        txData[1] = 0x77;
        txData[2] = 0x33;
        txData[3] = 0xAA;
        txData[4] = 0x22;
        txData[5] = 0x66;
    
        while (1)
        {
    //deb_gp
            /* Slave Read-Write */
            // Read the I2C register index, write the contents back to the master
            // Tested in Repeated start mode.
    
    //        retVal = I2CSlave_read_write(i2cHandle, &rxData, &txData, 1);
    //
    //        if (retVal == false)
    //        {
    //            System_printf ("Error: I2C Slave read-write failed\n");
    //            return -1;
    //        }
    //        else
    //        {
    //            System_printf ("Debug: I2C Slave read-write passed %x\n",rxData[0] );
    //        }
    
    //        retVal = I2CSlave_read(i2cHandle, rxData, 1);
    //        if(retVal == false)
    //        {
    //            System_printf("Read failed\n");
    //        }
    //        else
    //        {
    //            System_printf("Read succes : 0x%02x\n",rxData[0]);
    //        }
    
            // Without this the I2C message always start at txData[1] instead of txData[0]
            pDataTxBegin = &txData[0];
            pDataTxBegin--;
    
            // Write to master
            retVal = I2CSlave_write(i2cHandle, pDataTxBegin, 6);
            if(retVal == false)
            {
                System_printf("Write failed\n");
                return -1;
            }
            else
            {
                System_printf("Write Success\n");
            }
    
        }
    
        /* Close I2C Slave driver */
        return 0;
    }
    
    /**
     *  @b Description
     *  @n
     *      System Initialization Task which initializes the various
     *      components in the system.
     *
     *  @retval
     *      Not Applicable.
     */
    static void Test_initTask(UArg arg0, UArg arg1)
    {
        int32_t         retVal = 0;
    
        /* Initialize the platform */
        retVal = PlatformInit();
        if (retVal < 0)
        {
            BIOS_exit(0);
        }
    
    //    while (1)
    //    {
    //        System_printf ("*******************************************************\n");
    //        System_printf ("I2C Slave Unit Test Menu                    \n");
    //        System_printf ("Please select the type of test to execute:  \n");
    //        System_printf ("1. I2C Blocking mode test                   \n");
    //        System_printf ("*******************************************************\n");
    //        System_printf ("> Enter your selection: ");
    //
    //        while (testSelection == 0);
    //
    //        /* Validate the selection: */
    //        if (testSelection == I2C_TEST_BLOCKING_MODE)
    //            break;
    //    }
    
    //    if (testSelection == I2C_TEST_BLOCKING_MODE)
    //    {
    //        System_printf("Debug: Blocking mode testing\n");
            retVal = i2cBlockingModeTest();
    //    }
        if (retVal < 0)
        {
            System_printf("Debug: I2C Slave testing failed\n");
        }
    
    
        /* Exit BIOS */
        BIOS_exit(0);
    
        return;
    }
    
    /**
     *  @b Description
     *  @n
     *      This is the entry point into the unit test code
     *
     *  @retval
     *      Not Applicable.
     */
    int32_t main (void)
    {
    	Task_Params     taskParams;
        SOC_Handle      socHandle;
        SOC_Cfg         socCfg;
        int32_t         errCode;
    
        /* Initialize the ESM: Dont clear errors as TI RTOS does it */
        ESM_init(0U);
    
        /* Initialize the SOC confiugration: */
        memset ((void *)&socCfg, 0, sizeof(SOC_Cfg));
    
        /* Populate the SOC configuration: */
        socCfg.clockCfg = SOC_SysClock_INIT;
    
        /* Initialize the SOC Module: This is done as soon as the application is started
         * to ensure that the MPU is correctly configured. */
        socHandle = SOC_init (&socCfg, &errCode);
        if (socHandle == NULL)
        {
            System_printf ("Error: SOC Module Initialization failed [Error code %d]\n", errCode);
            return -1;
        }
    
        /* Initialize the Task Parameters. */
        Task_Params_init(&taskParams);
        taskParams.stackSize = 6*1024;
        Task_create(Test_initTask, &taskParams, NULL);
    
        /* Start BIOS */
    	BIOS_start();
        return 0;
    }
    
    

    Best regards,

    Julien

  • Hi Julien,

    Thank for sending your file. Allow us some time to investigate internally. Expect a response within 24-48 hours, and feel free to ping back here if not.

    Regards, 

    Luke

  • Hi Julien,

    We are still looking into this internally. Thank you for your patience.

    - Luke

  • Hi Julien,

    How much data is being sent in the test program? Is it possible that the master is trying to respond with a ton of data and it goes too long when you are trying to fast loop? You mention a 200ms delay makes the write work, but 5 or 10ms is too fast. Have you tested delay times between 200 down to 10ms? At what delay time does the write fail?

    Regards,

    Luke

  • Hi Luke,

    As it is just a test a the moment, the master asks to only read 1 byte from the slave. I use a STM32 nucleo board as a master and use the following code.

    /************ Code on the nucleo Board (I2C master)************/
    
    // Ask slave to read one byte 
    ret = HAL_I2C_Master_Receive(&hi2c1, I2C_SLAVE_ADDR, I2CBuffer,1, HAL_MAX_DELAY);
    
    if (ret != HAL_OK)
    {
        // Reading fails
    }
    
    // Delay between calls in ms
    HAL_Delay(200);

    In this configuration, the code of the master blocks until all the bytes have been sent by the slave. This means that the delay only starts after the message has been successfully received (here, the message from the slave is 0x44).

    If the delay becomes too short, both I2C lines go low indefinitely and the only way to recover from this state is to reset the IWR6843. Both lines go low just after receiving the address and the R/W bit from the master.

    Always in this configuration (1 byte asked from the master), the time delay where it fails is always 116ms-117ms.

    I tried to increase the data size to 100 bytes and, then, 1000 bytes just to test if the delay would change. The size I would normally send is between 500 bytes and 900 bytes. In these cases, the communication crashes at 118ms-120ms, so it does change a little based on the load.

    I hope this can help you.

    Regards,

    Julien

  • Hey Julien,

    Thank you for providing more context. I am going to see if I can replicate this behavior and have looped in our SDK team as well. II will let you know the results of the investigation.

    Regards,

    Luke

  • Hi Julien,

    I am confirming that this is a bug in our SDK and we have submitted a ticket and will be looked at in a future release. 

    Thanks for your patience.

    Regards,
    Luke

  • Hi Luke,

    Thanks for looking into this problem. This is good to know.

    Best regards,

    Julien