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.

AWR2944: how to verify LVDS data path with known data

Part Number: AWR2944

Tool/software:

Hi,

I am going to verify the LVDS trasmmiting capacity, and need to setup a enviroment to test whether the lvds signal is ok:

1.  generate konwn data to adcbuf(for example, 0x01, 0x02, 0x03... ,0xFe,0xFF)

2. send the known data through LVDS

3. capture data with DCA1000

4. compareed the output and the input data

How to setup environment to fullfill this requirement?

Are there some example available?

Thanks.

  • Hello liu,

    You can refer the example application present in: Mmwavestudio CLI Gettingstartedguide

    Please use this as reference. 

    The above application uses the ADC data streaming.
    If you want to use the custom data, you can instead implement software streaming of LVDS data in CBUFF. 
    There is no such reference for that and you will need to perform this on your own, it is pretty straight forward once you go through the API's as they are very similar to the hardware streaming example.

    I would advise you to take the cbuff streaming test case: C:\ti\mmwave_mcuplus_sdk_04_06_00_01\mmwave_mcuplus_sdk_04_06_00_01\ti\utils\test\cbuff_stream and just modify this with the software streaming API's.

    Reagrds,
    Saswat Kumar

  • Does it  possible to test the path from adcBuf to lvds with  Test Pattern Generator as described in ' 8.1.2 Test Pattern Generator Support
    '  in TRM document. 

    This is a patch to generate data with 'Test Pattern Generator', but there is no data can be Streamed out.

     
     #define WF_DEFAULT  0
     #define WF_SP       1
    -#define WAVEFORM_TYPE WF_SP
    +#define WF_CONTINUOUS 2
    +#define WAVEFORM_TYPE WF_CONTINUOUS
     
     /** @addtogroup TEST_CONTROL_PATH_CONFIG_DEFINITIONS
      @{ */
    @@ -131,7 +132,7 @@
      * @brief
      * This macro defines the number of ADC Samples.
      */
    -#if WAVEFORM_TYPE == WF_DEFAULT
    +#if WAVEFORM_TYPE != WF_SP
     #define TESTSOURCE_NUM_ADC_SAMPLES         (256U)
     #elif WAVEFORM_TYPE == WF_SP
     #define TESTSOURCE_NUM_ADC_SAMPLES         (512U)
    @@ -695,6 +696,59 @@ exit:
         return (retVal);
     }
     
    +int32_t LVDSStream_startTestStreaming(ADCBuf_Handle adcBufHandle, uint16_t numSamples, uint32_t numClks)
    +{
    +    int32_t retVal = 0;
    +
    +    uint32_t numOfSamples = numSamples;
    +    uint32_t numOfClks = numClks;
    +
    +    printf("numOfSamples: %d\n", numOfSamples);
    +
    +    retVal = ADCBuf_control(adcBufHandle, ADCBufMMWave_CMD_START_CONTINUOUS_MODE, (void *)&numOfSamples);
    +    if (retVal < 0)
    +    {
    +        test_print("Error: ADCBuf Control for Continuous Mode Failed with error[%d]\n", retVal);
    +        goto exit;
    +    }
    +
    +    printf("numOfClks: %d\n", numOfClks);
    +    retVal =  ADCBuf_control(adcBufHandle, ADCBufMMWave_CMD_START_TEST_PATTERN,(void *)&numOfClks);
    +    if (retVal < 0)
    +    {
    +        test_print("Error: ADCBuf Control for Test Pattern Failed with error[%d]\n", retVal);
    +        goto exit;
    +    }
    +
    +exit:
    +    return retVal;
    +
    +}
    +int32_t LVDSStream_testGenConfig(ADCBuf_Handle adcBufHandle, uint16_t period, uint16_t numSamples)
    +{
    +    int32_t retVal = 0;
    +    uint8_t i;
    +    ADCBuf_TestPatternConf testPatternConf;
    +    /* fill the test pattern*/
    +    testPatternConf.period = period;
    +    testPatternConf.numSamples = numSamples;
    +
    +    for(i = 0; i < 4; i++) {
    +        testPatternConf.rxConfig[i].rxIOffset = i;
    +        testPatternConf.rxConfig[i].rxIInc = i;
    +        testPatternConf.rxConfig[i].rxQOffset = i;
    +        testPatternConf.rxConfig[i].rxQInc = i;
    +    }
    +
    +    retVal = ADCBuf_control(adcBufHandle, ADCBufMMWave_CMD_CONF_TEST_PATTERN, (void *)&testPatternConf);
    +    if (retVal < 0)
    +    {
    +        test_print("Error: ADCBuf Control for Test Pattern Failed with error[%d]\n", retVal);
    +    }
    +
    +    return retVal;
    +}
    +
     /**
      *  @b Description
      *  @n
    @@ -917,7 +971,11 @@ static ADCBuf_Handle LVDSStream_ADCBufOpen(void)
         ADCBuf_Params_init(&ADCBufparams);
         ADCBufparams.chirpThresholdPing = 1;
         ADCBufparams.chirpThresholdPong = 1;
    +#if WAVEFORM_TYPE == WF_CONTINUOUS
    +    ADCBufparams.continousMode  = 1;
    +#else
         ADCBufparams.continousMode  = 0;
    +#endif
     
         /* Open ADCBUF driver */
         ADCBufHandle = ADCBuf_open(0, &ADCBufparams);
    @@ -1025,8 +1083,22 @@ static void LVDSStream_initTask(void* args)
         LVDSStream_configLVDSHwData(0);
     
         /* Configure BSS. */
    -    LVDSStream_mmWaveInit();
    +#if WAVEFORM_TYPE == WF_CONTINUOUS
    +    if(LVDSStream_testGenConfig(gLVDSStreamMCB.adcBufHandle, 1000, TESTSOURCE_NUM_ADC_SAMPLES) != 0)
    +    {
    +        test_print("Error: GNE configuration failed\n");
    +        return;
    +    }
    +    else
    +    {
    +        LVDSStream_startTestStreaming(gLVDSStreamMCB.adcBufHandle, TESTSOURCE_NUM_ADC_SAMPLES, 1);
    +    }
    +
    +    ClockP_sleep(5);
     
    +#else
    +    LVDSStream_mmWaveInit();
    +#endif
         if(CBUFF_deactivateSession (gLVDSStreamMCB.lvdsStream.hwSessionHandle, &errCode) < 0)
         {
             test_print("CBUFF HW session deactivation error %d.\n", errCode);

    Could you please review this patch, and give some suggestion to fix this problem.

    Thanks.

  • Hello Liu,

    If you are performing just the test pattern generator in the application, I would suggest you to use the cbuff_stream. First test whether the application works on your end.
    Then modify that for the test pattern data.

    Regards,
    Saswat Kumar

  • sure, the application works on the EVM. but there are no data streamed out with lvds.

    The procedures are:

  • Hello liu,

    Are you running the original application or the modified application?

    Regards,
    Saswat Kumar

  • The original applciation  works well(1. waveform generation ok, 2. streaming data ok).

    Modified application is modified as the patch, and the implementation procedure as the picture shows,

    The modified application can not stream out the data generated by 'Test pattern generator'

  • Hello Liu,

    Can you first check in your ADC if you are getting the populated test data or not?
    Also is it not easier to use the Sw streaming, instead of doing a test pattern?

    Regards,
    Saswat Kumar

  • Hi, I have implement the test pattern. 

    There may be some problem in lvds streaming using lane1+2(Tested with EVM and self-designed radar board)

    The test case is

    1.  set a test object with test pattern

    2. capture data with DCA1000

    Result:

    with EVM:

    1. capture 3 group of samples, all data same

    with self-designed radar board

    1. capture 3 group of samples, almost 50% of data differs

    As the data show, maybe lane1 or lane2 fails with interference,  

    so I tested transimit adc sample with lvds lane1 or lane2 configuration.

    It succecess, if only with lane1 enabled,

        initCfg.enableECC                 = 0U;
        initCfg.crcEnable                 = 1U;
        /* Up to 1 SW session + 1 HW session can be configured for each frame. Therefore max session is 2. */
        initCfg.maxSessions               = 2U;
        initCfg.enableDebugMode           = false;
        initCfg.interface                 = CBUFF_Interface_LVDS;
        initCfg.outputDataFmt             = CBUFF_OutputDataFmt_16bit;
        initCfg.lvdsCfg.crcEnable         = 0U;
        initCfg.lvdsCfg.msbFirst          = 1U;
        /* Enable all lanes available on the platform*/
        
        initCfg.lvdsCfg.lvdsLaneEnable    = 0x1U;
        
        initCfg.lvdsCfg.ddrClockMode      = 1U;
        initCfg.lvdsCfg.ddrClockModeMux   = 1U;
    

    But if only with lane2 enalbed, MmwDemo_LVDSStream_HwTriggerFrameDone won't triggered.

        initCfg.enableECC                 = 0U;
        initCfg.crcEnable                 = 1U;
        /* Up to 1 SW session + 1 HW session can be configured for each frame. Therefore max session is 2. */
        initCfg.maxSessions               = 2U;
        initCfg.enableDebugMode           = false;
        initCfg.interface                 = CBUFF_Interface_LVDS;
        initCfg.outputDataFmt             = CBUFF_OutputDataFmt_16bit;
        initCfg.lvdsCfg.crcEnable         = 0U;
        initCfg.lvdsCfg.msbFirst          = 1U;
        /* Enable all lanes available on the platform*/
        
        initCfg.lvdsCfg.lvdsLaneEnable    = 0x2U;
        
        initCfg.lvdsCfg.ddrClockMode      = 1U;
        initCfg.lvdsCfg.ddrClockModeMux   = 1U;
    

    Question:

    1. how to transmmit adc samples with only lane2 enabled, is it supported or not?

  • Hello Liu,

    0x2 in lvds lane enable means you are only enabling the second lane.
    If you use 0x3 that means you are enabling both the lanes:
    0x1 - 01
    0x2 - 10
    0x3 - 11
    Bit 1 is for first lane and bit 2 is for second lane

    Regards,
    Saswat Kumar

  • yes, the problem is if set lvds lane enable to 0x02,  MmwDemo_LVDSStream_HwTriggerFrameDone can not be triggered correctly.

    /* Populate the configuration: */
        sessionCfg.executionMode          = CBUFF_SessionExecuteMode_HW;
        sessionCfg.edmaHandle             = gMmwMssMCB.edmaHandle;
        sessionCfg.allocateEDMAChannelFxn = MmwDemo_LVDSStream_EDMAAllocateCBUFFHwChannel;
        sessionCfg.freeEDMAChannelFxn     = MmwDemo_LVDSStream_EDMAFreeCBUFFHwChannel;
        
        sessionCfg.frameDoneCallbackFxn   = MmwDemo_LVDSStream_HwTriggerFrameDone;
        
        sessionCfg.dataType               = CBUFF_DataType_REAL;
        sessionCfg.u.hwCfg.dataMode       = (CBUFF_DataMode)subFrameCfg->adcBufCfg.chInterleave;

    if set lvds_lane_enable to 0x01, it works correctly. 

    what's the difference with these two configurations?

  • Hello Liu,

    Can you test one thing and let me know, if you use 0x2 not in modified but default application is it functional?

    or is 0x2 giving issues only with the custom application?

    Regards,
    Saswat Kumar

  • If change lvdsLaneEnable to 0x02, in default application

    it logs as the following:

    It locates :

    which means 'gMmwMssMCB.stats.isLastFrameDataProcessed' is not correctly set

    BTW: set lvdsLaneEnable to 0x01 works well

  • Hello Liu,

    Can you send me your source example application, so I can try to recreate?

    Regards,
    Saswat Kumar

  • Sure, you can just apply this patch to the default demo of sdk(version: 04_06_00_01)

    diff --git a/ti/demo/awr294x/mmw/mss/mmw_lvds_stream.c b/ti/demo/awr294x/mmw/mss/mmw_lvds_stream.c
    index d739af2..e143d9a 100644
    --- a/ti/demo/awr294x/mmw/mss/mmw_lvds_stream.c
    +++ b/ti/demo/awr294x/mmw/mss/mmw_lvds_stream.c
    @@ -229,7 +229,7 @@ int32_t MmwDemo_LVDSStreamInit (void)
         initCfg.lvdsCfg.crcEnable         = 0U;
         initCfg.lvdsCfg.msbFirst          = 1U;
         /* Enable all lanes available on the platform*/
    -    initCfg.lvdsCfg.lvdsLaneEnable    = 0x3U;
    +    initCfg.lvdsCfg.lvdsLaneEnable    = 0x2U;
         initCfg.lvdsCfg.ddrClockMode      = 1U;
         initCfg.lvdsCfg.ddrClockModeMux   = 1U;
     
    diff --git a/ti/demo/awr294x/mmw/mss/mss_main.c b/ti/demo/awr294x/mmw/mss/mss_main.c
    index 0e712ab..09b1715 100644
    --- a/ti/demo/awr294x/mmw/mss/mss_main.c
    +++ b/ti/demo/awr294x/mmw/mss/mss_main.c
    @@ -3283,6 +3283,7 @@ void mmwDemo_mssUartDataExportTask(void* args)
         {
             /* Export the Data: */
             SemaphoreP_pend(&gMmwMssMCB.UartExportSemHandle, SystemP_WAIT_FOREVER);
    +        CLI_write("Frame Done\n");
             if ((gMmwMssMCB.ptrResult.size[0]) == sizeof(DPC_ObjectDetection_ExecuteResult)){
                 MmwDemo_handleObjectDetResult();
             }
    

    or you can provide an email , and I'll send the example package to you.

  • Furthermore, you should send the commands of  ti\demo\awr294x\mmw\profiles\tdm_awr2944\profile_LVDS.cfg to your board, and it will recreate this error scenario.

  • Hello liu,

    are you not using the cbuff stream application which I recommend? 

    Also you can just zip the folder and upload here, its hard to understand from the patch as it only has a few lines, i wanted your code with the test pattern enabled and streaming to test.

    the demo has a lot of other functionality, so to only test lvds, I would not suggest the application. That is the reason I recommended you to use cbuff stream.

    it is easier to debug a unit test case like cbuff stream unlike the demo.

    Regards,

    Saswat Kumar

  • Hi, as suggested, the modified cbuff_stream source code as the attatchment

    Test result:

    1.  if Test source enabled, with lvdsLaneEnable = 0x03

    1.1 data capture: OK

    1.2 data content: same between each capture

    2. if Test source enabled, with  with lvdsLaneEnable = 0x01 or 0x021

    1.1 MMWave_start can not be launched

    1.2 data capture: NG

    1.3 No data streaming out

    please apply this patch to your code

    diff --git a/ti/utils/test/cbuff_stream/awr294x/main_mss.c b/ti/utils/test/cbuff_stream/awr294x/main_mss.c
    index d446e07..e5dfd30 100644
    --- a/ti/utils/test/cbuff_stream/awr294x/main_mss.c
    +++ b/ti/utils/test/cbuff_stream/awr294x/main_mss.c
    @@ -112,6 +112,7 @@
     #include <ti/common/syscommon.h>
     #include <ti/utils/testlogger/logger.h>
     #include <ti/utils/test/cbuff_stream/lvds_stream.h>
    +#include <ti/control/mmwavelink/include/rl_sensor.h>
     
     /** @addtogroup TEST_CONTROL_PATH_CONFIG_DEFINITIONS
      @{ */
    @@ -150,7 +151,7 @@
      * @brief
      * This macro defines the number of frame.
      */
    -#define TESTSOURCE_NUM_FRAMES              (2U)
    +#define TESTSOURCE_NUM_FRAMES              (10U)
     
     /**
     @}
    @@ -162,6 +163,7 @@
     #define APP_TASK_STACK_SIZE  (8*1024U)
     #define APP_CTRL_TASK_STACK_SIZE (6*1024U)
     
    +#define LVDS_TEST_SOURCE_ENABLE 1
     /**************************************************************************
      *************************** Global Variables *****************************
      **************************************************************************/
    @@ -682,6 +684,37 @@ exit:
         return (retVal);
     }
     
    +#if LVDS_TEST_SOURCE_ENABLE
    +rlReturnVal_t  enableTestSource()
    +{
    +    rlReturnVal_t retVal = RL_RET_CODE_OK;
    +    rlTestSource_t testSourceData =
    +    {
    +        .testObj[0] = {102, 2, 5698, 0, 0, 0, 100, 1256, 2589, 225, 2489, 12256, 112},
    +        // .testObj[1] = {10, 5, 0, 5, 5, 5, 255, 0, 216, 2251, 341, 556, 5112},
    +        .rxAntPos[0] = {15, 15},
    +        .rxAntPos[1] = {15, 15},
    +        .rxAntPos[2] = {15, 15},
    +        .rxAntPos[3] = {15, 15},
    +        .reserved0 = 0,
    +        .miscFunCtrl=1,
    +    };
    +
    +    rlTestSourceEnable_t testSourceEnableData =
    +    {
    +        .tsEnable = 1,
    +        .reserved = 0,
    +    };
    +
    +    uint8_t deviceMap=0x1;
    +    retVal = rlSetTestSourceConfig (deviceMap, &testSourceData);
    +    //enable test source
    +    retVal = rlTestSourceEnable(deviceMap, &testSourceEnableData);
    +
    +    return retVal;
    +}
    +#endif
    +
     /**
      *  @b Description
      *  @n
    @@ -780,6 +813,14 @@ void LVDSStream_mmWaveInit (void)
         memset ((void *)&calibrationCfg, 0, sizeof(MMWave_CalibrationCfg));
         LVDSStream_populateDefaultCalibrationCfg (&calibrationCfg, MMWave_DFEDataOutputMode_FRAME);
     
    +#if LVDS_TEST_SOURCE_ENABLE
    +    retVal = enableTestSource();
    +    if(retVal != RL_RET_CODE_OK)
    +    {
    +        printf("Error: Failed to enable test source\n");
    +        return;
    +    }
    +#endif
         /************************************************************************
          * Start the mmWave:
          ************************************************************************/
    diff --git a/ti/utils/test/cbuff_stream/lvds_stream.c b/ti/utils/test/cbuff_stream/lvds_stream.c
    index fb8a07b..4c1345e 100644
    --- a/ti/utils/test/cbuff_stream/lvds_stream.c
    +++ b/ti/utils/test/cbuff_stream/lvds_stream.c
    @@ -206,6 +206,7 @@ int32_t LVDSStream_Init (void)
         initCfg.lvdsCfg.msbFirst          = 1U;
         /* Enable all lanes available on the platform*/
         /* 2 lanes supported by AWR294x */
    +    /* change lvdsLaneEnable to 0x01(lane1 enabed) or 0x02(lane2 enable)*/
         initCfg.lvdsCfg.lvdsLaneEnable    = 0x3U;
         initCfg.lvdsCfg.ddrClockMode      = 1U;
         initCfg.lvdsCfg.ddrClockModeMux   = 1U;
    

    or replace with the following c file

    /**
     *   @file  lvds_stream.c
     *
     *   @brief
     *      Implements LVDS stream functionality.
     *
     *  \par
     *  NOTE:
     *      (C) Copyright 2020 - 2021 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 ********************************
     **************************************************************************/
    #include <stdint.h>
    #include <string.h>
    #include <stdio.h>
    
    /* MCU+SDK Include Files. */
    #include <kernel/dpl/DebugP.h>
    #include <drivers/edma.h>
    
    /* MMWSDK Include Files. */
    #include <ti/common/syscommon.h>
    #include <ti/utils/hsiheader/hsiheader.h>
    
    /* CBUFF Stream Include Files */
    #include <ti/utils/test/cbuff_stream/lvds_stream.h>
    
    extern LVDSStream_MCB    gLVDSStreamMCB;
    
    LVDSUserDataHeader_t lvdsUserHeader;
    
    /**
     *  @b Description
     *  @n
     *      Allocates Shawdow paramset
     */
    static void allocateEDMAShadowChannel(EDMA_Handle handle, uint32_t *param)
    {
        int32_t             testStatus = SystemP_SUCCESS;
    
        testStatus = EDMA_allocParam(handle, param);
        DebugP_assert(testStatus == SystemP_SUCCESS);
    
        return;
    }
    
    /**
     *  @b Description
     *  @n
     *      Allocates EDMA resource
     */
    void allocateEDMAChannel(EDMA_Handle handle,
        uint32_t *dmaCh,
        uint32_t *tcc,
        uint32_t *param
    )
    {
        int32_t             testStatus = SystemP_SUCCESS;
        uint32_t            baseAddr, regionId;
        EDMA_Config        *config;
        EDMA_Object        *object;
    
        config = (EDMA_Config *) handle;
        object = config->object;
    
        if((object->allocResource.dmaCh[*dmaCh/32] & (1U << *dmaCh%32)) != (1U << *dmaCh%32))
        {
            testStatus = EDMA_allocDmaChannel(handle, dmaCh);
            DebugP_assert(testStatus == SystemP_SUCCESS);
    
            testStatus = EDMA_allocTcc(handle, tcc);
            DebugP_assert(testStatus == SystemP_SUCCESS);
    
            testStatus = EDMA_allocParam(handle, param);
            DebugP_assert(testStatus == SystemP_SUCCESS);
    
            baseAddr = EDMA_getBaseAddr(handle);
            DebugP_assert(baseAddr != 0);
    
            regionId = EDMA_getRegionId(handle);
            DebugP_assert(regionId < SOC_EDMA_NUM_REGIONS);
    
            /* Request channel */
            EDMA_configureChannelRegion(baseAddr, regionId, EDMA_CHANNEL_TYPE_DMA,
                *dmaCh, *tcc, *param, 0);
       }
    
        return;
    }
    
    
     /**
     *  @b Description
     *  @n
     *      This function initializes/configures the LVDS
     *      streaming EDMA resources.
     *
     *  @retval
     *      Success -   0
     *  @retval
     *      Error   -   <0
     */
    void LVDSStream_EDMAInit (void)
    {
        uint32_t index = 0;
    
        gLVDSStreamMCB.lvdsStream.hwSessionEDMAChannelAllocatorIndex = 0;
    
        /* Populate the LVDS Stream HW Session EDMA Channel Table: */              
        gLVDSStreamMCB.lvdsStream.hwSessionEDMAChannelTable[0].chainChannelsId       = LVDS_STREAM_HW_SESSION_EDMA_CH_0;
        gLVDSStreamMCB.lvdsStream.hwSessionEDMAChannelTable[0].shadowLinkChannelsId  = LVDS_STREAM_HW_SESSION_EDMA_SHADOW_CH_0;
        gLVDSStreamMCB.lvdsStream.hwSessionEDMAChannelTable[1].chainChannelsId       = LVDS_STREAM_HW_SESSION_EDMA_CH_1;
        gLVDSStreamMCB.lvdsStream.hwSessionEDMAChannelTable[1].shadowLinkChannelsId  = LVDS_STREAM_HW_SESSION_EDMA_SHADOW_CH_1;
        gLVDSStreamMCB.lvdsStream.hwSessionEDMAChannelTable[2].chainChannelsId       = LVDS_STREAM_HW_SESSION_EDMA_CH_2;
        gLVDSStreamMCB.lvdsStream.hwSessionEDMAChannelTable[2].shadowLinkChannelsId  = LVDS_STREAM_HW_SESSION_EDMA_SHADOW_CH_2;
        gLVDSStreamMCB.lvdsStream.hwSessionEDMAChannelTable[3].chainChannelsId       = LVDS_STREAM_HW_SESSION_EDMA_CH_3;
        gLVDSStreamMCB.lvdsStream.hwSessionEDMAChannelTable[3].shadowLinkChannelsId  = LVDS_STREAM_HW_SESSION_EDMA_SHADOW_CH_3;
        gLVDSStreamMCB.lvdsStream.hwSessionEDMAChannelTable[4].chainChannelsId       = LVDS_STREAM_HW_SESSION_EDMA_CH_4;
        gLVDSStreamMCB.lvdsStream.hwSessionEDMAChannelTable[4].shadowLinkChannelsId  = LVDS_STREAM_HW_SESSION_EDMA_SHADOW_CH_4;
        gLVDSStreamMCB.lvdsStream.hwSessionEDMAChannelTable[5].chainChannelsId       = LVDS_STREAM_HW_SESSION_EDMA_CH_5;
        gLVDSStreamMCB.lvdsStream.hwSessionEDMAChannelTable[5].shadowLinkChannelsId  = LVDS_STREAM_HW_SESSION_EDMA_SHADOW_CH_5;
        gLVDSStreamMCB.lvdsStream.hwSessionEDMAChannelTable[6].chainChannelsId       = LVDS_STREAM_HW_SESSION_EDMA_CH_6;
        gLVDSStreamMCB.lvdsStream.hwSessionEDMAChannelTable[6].shadowLinkChannelsId  = LVDS_STREAM_HW_SESSION_EDMA_SHADOW_CH_6;
        gLVDSStreamMCB.lvdsStream.hwSessionEDMAChannelTable[7].chainChannelsId       = LVDS_STREAM_HW_SESSION_EDMA_CH_7;
        gLVDSStreamMCB.lvdsStream.hwSessionEDMAChannelTable[7].shadowLinkChannelsId  = LVDS_STREAM_HW_SESSION_EDMA_SHADOW_CH_7;
        gLVDSStreamMCB.lvdsStream.hwSessionEDMAChannelTable[8].chainChannelsId       = LVDS_STREAM_HW_SESSION_EDMA_CH_8;
        gLVDSStreamMCB.lvdsStream.hwSessionEDMAChannelTable[8].shadowLinkChannelsId  = LVDS_STREAM_HW_SESSION_EDMA_SHADOW_CH_8;
        gLVDSStreamMCB.lvdsStream.hwSessionEDMAChannelTable[9].chainChannelsId       = LVDS_STREAM_HW_SESSION_EDMA_CH_9;
        gLVDSStreamMCB.lvdsStream.hwSessionEDMAChannelTable[9].shadowLinkChannelsId  = LVDS_STREAM_HW_SESSION_EDMA_SHADOW_CH_9;
        gLVDSStreamMCB.lvdsStream.hwSessionEDMAChannelTable[10].chainChannelsId      = LVDS_STREAM_HW_SESSION_EDMA_CH_10;
        gLVDSStreamMCB.lvdsStream.hwSessionEDMAChannelTable[10].shadowLinkChannelsId = LVDS_STREAM_HW_SESSION_EDMA_SHADOW_CH_10;
    
        for (index=0; index < 11; index++)
        {
            allocateEDMAChannel(gLVDSStreamMCB.edmaHandle, &gLVDSStreamMCB.lvdsStream.hwSessionEDMAChannelTable[index].chainChannelsId,
                                &gLVDSStreamMCB.lvdsStream.hwSessionEDMAChannelTable[index].chainChannelsId,
                                &gLVDSStreamMCB.lvdsStream.hwSessionEDMAChannelTable[index].chainChannelsId);
    
            allocateEDMAShadowChannel(gLVDSStreamMCB.edmaHandle, &gLVDSStreamMCB.lvdsStream.hwSessionEDMAChannelTable[index].shadowLinkChannelsId);
        }
    }
    
     /**
     *  @b Description
     *  @n
     *      This is the LVDS streaming init function. 
     *      It initializes the necessary modules
     *      that implement the streaming.
     *
     *  @retval
     *      Success -   0
     *  @retval
     *      Error   -   <0
     */
    int32_t LVDSStream_Init (void)
    {
        CBUFF_InitCfg           initCfg;
        int32_t                 retVal = MINUS_ONE;
        int32_t                 errCode;
        int32_t                 status = SystemP_SUCCESS;
    
        /*************************************************************************************
         * Open the CBUFF Driver:
         *************************************************************************************/
        memset ((void *)&initCfg, 0, sizeof(CBUFF_InitCfg));
    
        /* Populate the configuration: */
        initCfg.enableECC                 = 0U;
        initCfg.crcEnable                 = 1U;
        /* Up to 1 SW session + 1 HW session can be configured for each frame. Therefore max session is 2. */
        initCfg.maxSessions               = 2U;
        initCfg.enableDebugMode           = false;
        initCfg.interface                 = CBUFF_Interface_LVDS;
        initCfg.outputDataFmt             = CBUFF_OutputDataFmt_16bit;
        initCfg.lvdsCfg.crcEnable         = 0U;
        initCfg.lvdsCfg.msbFirst          = 1U;
        /* Enable all lanes available on the platform*/
        /* 2 lanes supported by AWR294x */
        /* change lvdsLaneEnable to 0x01(lane1 enabed) or 0x02(lane2 enable)*/
        initCfg.lvdsCfg.lvdsLaneEnable    = 0x3U;
        initCfg.lvdsCfg.ddrClockMode      = 1U;
        initCfg.lvdsCfg.ddrClockModeMux   = 1U;
    
        /* Initialize the CBUFF Driver: */
        gLVDSStreamMCB.lvdsStream.cbuffHandle = CBUFF_open (&initCfg, &errCode);
        if (gLVDSStreamMCB.lvdsStream.cbuffHandle == NULL)
        {
            /* Error: Unable to initialize the CBUFF Driver */
            test_print("Error: CBUFF_open failed with [Error=%d]\n", errCode);
            goto exit;
        }
    
    
        /* User data buffer is involved in LVDS streaming.
         * The 64 byte alignment is a speculative workaround for an issue where
         * EDMA is not completing transfer. */
        gLVDSStreamMCB.lvdsStream.userDataHeader = &lvdsUserHeader;
        
    
        /* Initialize the HSI Header Module: */
        if (HSIHeader_init (&initCfg, &errCode) < 0)
        {
            /* Error: Unable to initialize the HSI Header Module */
            test_print("Error: HSIHeader_init failed with [Error=%d]\n", errCode);
            goto exit;
        }
    
        /* Populate EDMA resources */
        LVDSStream_EDMAInit();
        
        /* Initialize semaphores */
        status = SemaphoreP_constructBinary(&gLVDSStreamMCB.lvdsStream.hwFrameDoneSemHandle, 0);
        DebugP_assert(SystemP_SUCCESS == status);
    
        retVal = 0;
    
    exit:
        return retVal;
    }
    
    /**
     *  @b Description
     *  @n
     *      Function that allocates CBUFF-EDMA channel
     *
     *  @param[in]  ptrEDMAInfo
     *      Pointer to the EDMA Information
     *  @param[out]  ptrEDMACfg
     *      Populated EDMA channel configuration
     *
     */
    static void LVDSStream_EDMAAllocateCBUFFChannel
    (
        CBUFF_EDMAInfo*         ptrEDMAInfo,
        CBUFF_EDMAChannelCfg*   ptrEDMACfg
    )
    {
        if(ptrEDMAInfo->dmaNum == 0)
        {
            ptrEDMACfg->chainChannelsId      = LVDS_STREAM_CBUFF_EDMA_CH_0;
    
            allocateEDMAChannel(gLVDSStreamMCB.edmaHandle, &ptrEDMACfg->chainChannelsId,
                                &ptrEDMACfg->chainChannelsId, &ptrEDMACfg->chainChannelsId);
    
            ptrEDMACfg->shadowLinkChannelsId = LVDS_STREAM_CBUFF_EDMA_SHADOW_CH_0;
    
            allocateEDMAShadowChannel(gLVDSStreamMCB.edmaHandle, &ptrEDMACfg->shadowLinkChannelsId);
        }
        else if(ptrEDMAInfo->dmaNum == 1)
        {
            ptrEDMACfg->chainChannelsId      = LVDS_STREAM_CBUFF_EDMA_CH_1;
    
            allocateEDMAChannel(gLVDSStreamMCB.edmaHandle, &ptrEDMACfg->chainChannelsId,
                                &ptrEDMACfg->chainChannelsId, &ptrEDMACfg->chainChannelsId);
    
            ptrEDMACfg->shadowLinkChannelsId = LVDS_STREAM_CBUFF_EDMA_SHADOW_CH_1;
    
            allocateEDMAShadowChannel(gLVDSStreamMCB.edmaHandle, &ptrEDMACfg->shadowLinkChannelsId);
        }
        else
        {
            /* Max of 2 CBUFF sessions can be configured*/
            // MmwDemo_debugAssert (0);
        }
    }
    
    /**
     *  @b Description
     *  @n
     *      This is the registered CBUFF EDMA channel allocation function
     *      which allocates EDMA channels for CBUFF HW Session
     *
     *  @param[in]  ptrEDMAInfo
     *      Pointer to the EDMA Information
     *  @param[out]  ptrEDMACfg
     *      Populated EDMA channel configuration
     *
     *  @retval
     *      Success -   0
     *  @retval
     *      Error   -   <0
     */
    static int32_t LVDSStream_EDMAAllocateCBUFFHwChannel
    (
        CBUFF_EDMAInfo*         ptrEDMAInfo,
        CBUFF_EDMAChannelCfg*   ptrEDMACfg
    )
    {
        int32_t         retVal = MINUS_ONE;
        LVDSStream_MCB_t *streamMCBPtr =  &gLVDSStreamMCB.lvdsStream;
    
        if(ptrEDMAInfo->isFirstEDMAChannel)
        {
            LVDSStream_EDMAAllocateCBUFFChannel(ptrEDMAInfo, ptrEDMACfg);
            retVal = 0;
        }
        else
        {
    
            /* Sanity Check: Are there sufficient EDMA channels? */
            if (streamMCBPtr->hwSessionEDMAChannelAllocatorIndex >= LVDS_STREAM_HW_SESSION_MAX_EDMA_CHANNEL)
            {
                /* Error: All the EDMA channels are allocated */
                test_print ("Error: LVDSStream_EDMAAllocateCBUFFChannel failed. HW channel index=%d\n", 
                                streamMCBPtr->hwSessionEDMAChannelAllocatorIndex);
                goto exit;
            }
    
            /* Copy over the allocated EDMA configuration. */
            memcpy ((void *)ptrEDMACfg,
                    (void*)&streamMCBPtr->hwSessionEDMAChannelTable[streamMCBPtr->hwSessionEDMAChannelAllocatorIndex],
                    sizeof(CBUFF_EDMAChannelCfg));
    
            /* Increment the allocator index: */
            streamMCBPtr->hwSessionEDMAChannelAllocatorIndex++;
    
            /* EDMA Channel allocated successfully */
            retVal = 0;
        }    
    
    exit:
        return retVal;
    }
    
    /**
     *  @b Description
     *  @n
     *      This is the registered CBUFF EDMA channel free function which frees EDMA channels
     *      which had been allocated for use by a CBUFF HW Session
     *
     *  @retval
     *      Not applicable
     */
    static void LVDSStream_EDMAFreeCBUFFHwChannel (CBUFF_EDMAChannelCfg* ptrEDMACfg)
    {
        uint8_t    index;
        LVDSStream_MCB_t *streamMCBPtr =  &gLVDSStreamMCB.lvdsStream;
    
        if((ptrEDMACfg->chainChannelsId == LVDS_STREAM_CBUFF_EDMA_CH_0) ||
           (ptrEDMACfg->chainChannelsId == LVDS_STREAM_CBUFF_EDMA_CH_1))
        {
            /*This is the CBUFF trigger channel. It is not part of the resource table so
              nothing needs to be done*/
            goto exit;  
        }
    
        for (index = 0U; index < LVDS_STREAM_HW_SESSION_MAX_EDMA_CHANNEL; index++) 
        {
            /* Do we have a match? */
            if (memcmp ((void*)ptrEDMACfg,
                        (void*)&streamMCBPtr->hwSessionEDMAChannelTable[index],
                        sizeof(CBUFF_EDMAChannelCfg)) == 0)
            {
                /* Yes: Decrement the HW Session index */
                streamMCBPtr->hwSessionEDMAChannelAllocatorIndex--;
                goto exit;
            }
        }
    
        /* Sanity Check: We should have had a match. An assertion is thrown to indicate that the EDMA channel
         * being cleaned up does not belong to the table*/
        // MmwDemo_debugAssert (0);
    
    exit:
        return;
    }
    
    
    /**
     *  @b Description
     *  @n
     *      This function deletes the hardware session and any HSI
     *      header associated with it. 
     *
     *  @retval
     *      Not applicable
     */
    void LVDSStream_DeleteHwSession (void)
    {
        int32_t     errCode;
        LVDSStream_MCB_t* streamMcb = &gLVDSStreamMCB.lvdsStream;
        
        /* Delete session*/
        if (CBUFF_close (streamMcb->hwSessionHandle, &errCode) < 0)
        {
            /* Error: Unable to delete the session. */
            test_print ("Error: LVDSStream_DeleteHwSession CBUFF_close failed. Error code %d\n", errCode);
            return;
        }
        
        streamMcb->hwSessionHandle = NULL;
        
        /* Did we stream out with the HSI Header? */
        if (streamMcb->isHwSessionHSIHeaderAllocated == true)
        {
            /* Delete the HSI Header: */
            if (HSIHeader_deleteHeader (&streamMcb->hwSessionHSIHeader, &errCode) < 0)
            {
                /* Error: Unable to delete the HSI Header */
                test_print ("Error: LVDSStream_DeleteHwSession HSIHeader_deleteHeader failed. Error code %d\n", errCode);
                return;
            }
    
            streamMcb->isHwSessionHSIHeaderAllocated = false;
        }
    }
    
    /**
     *  @b Description
     *  @n
     *      This is the registered callback function which is invoked after the
     *      frame done interrupt is received for the hardware session.
     *
     *  @param[in]  sessionHandle
     *      Handle to the session
     *
     *  @retval
     *      Not applicable
     */
    static void LVDSStream_HwTriggerFrameDone (CBUFF_SessionHandle sessionHandle)
    {
        int32_t     errCode;
    
        /* Increment stats*/
        gLVDSStreamMCB.lvdsStream.hwFrameDoneCount++;
    
        if(sessionHandle != NULL)
        {
            /* There are 2 cases to consider:
            Only one subframe configured (legacy frame):
            If there is a software session configured for this subframe, we need to 
            deactivate the HW session here. 
    
            More than one subframe configured:
            If there is more than one subframe we need to deactivate the HW
            session here as other subframes may have configured a HW session.
            In this case (more than one subframe), the HW session is always created
            and activated in the application code */
            if(gLVDSStreamMCB.subFrameCfg[0].lvdsStreamCfg.isSwEnabled == 1)
            {
                if(CBUFF_deactivateSession (sessionHandle, &errCode) < 0)
                {
                    /* Error: Unable to deactivate the session. */
                    DebugP_assert(0);
                    return;
                }
            }
        }
        else
        {
            DebugP_assert(0);
        }
    
        SemaphoreP_post(&gLVDSStreamMCB.lvdsStream.hwFrameDoneSemHandle);
    }
    
    /**
     *  @b Description
     *  @n
     *      This is the LVDS streaming config function. 
     *      It configures the sessions for the LVDS streaming.
     *
     *  @retval
     *      Success -   0
     *  @retval
     *      Error   -   <0
     */
    int32_t LVDSStream_HwConfig (uint8_t subFrameIndx)
    {
        CBUFF_SessionCfg          sessionCfg;
        LVDSStream_MCB_t* streamMcb = &gLVDSStreamMCB.lvdsStream;
        int32_t                   errCode;
        int32_t                   retVal = MINUS_ONE;
        LVDSStream_SubFrameCfg       *subFrameCfg = &gLVDSStreamMCB.subFrameCfg[subFrameIndx];
    
        memset ((void*)&sessionCfg, 0, sizeof(CBUFF_SessionCfg));
        
        /* Populate the configuration: */
        sessionCfg.executionMode          = CBUFF_SessionExecuteMode_HW;
        sessionCfg.edmaHandle             = gLVDSStreamMCB.edmaHandle;
        sessionCfg.allocateEDMAChannelFxn = LVDSStream_EDMAAllocateCBUFFHwChannel;
        sessionCfg.freeEDMAChannelFxn     = LVDSStream_EDMAFreeCBUFFHwChannel;
        sessionCfg.frameDoneCallbackFxn   = LVDSStream_HwTriggerFrameDone;
        sessionCfg.dataType               = CBUFF_DataType_REAL;
        sessionCfg.u.hwCfg.dataMode       = (CBUFF_DataMode)subFrameCfg->adcBufCfg.chInterleave;
        
        /* Populate the HW Session configuration: */
        sessionCfg.u.hwCfg.adcBufHandle      = gLVDSStreamMCB.adcBufHandle;
        sessionCfg.u.hwCfg.numADCSamples     = subFrameCfg->numAdcSamples;
        sessionCfg.u.hwCfg.numChirpsPerFrame = subFrameCfg->numChirpsPerSubFrame;
        sessionCfg.u.hwCfg.chirpMode         = subFrameCfg->adcBufCfg.chirpThreshold;
        sessionCfg.u.hwCfg.opMode            = CBUFF_OperationalMode_CHIRP;
        
        switch(subFrameCfg->lvdsStreamCfg.dataFmt)
        {
            case LVDS_STREAM_CFG_DATAFMT_ADC:
                sessionCfg.u.hwCfg.dataFormat = CBUFF_DataFmt_ADC_DATA;
            break;
            case LVDS_STREAM_CFG_DATAFMT_CP_ADC_CQ:
                sessionCfg.u.hwCfg.dataFormat = CBUFF_DataFmt_CP_ADC_CQ;
                sessionCfg.u.hwCfg.cqSize[0] = 0;
                sessionCfg.u.hwCfg.cqSize[1] = HSIHeader_toCBUFFUnits(subFrameCfg->sigImgMonTotalSize);
                sessionCfg.u.hwCfg.cqSize[2] = HSIHeader_toCBUFFUnits(subFrameCfg->satMonTotalSize);
            break;
            default:
                test_print ("Error: lvdsStreamCfg dataFmt %d is invalid\n", subFrameCfg->lvdsStreamCfg.dataFmt);
            break;
        }
    
        if(subFrameCfg->lvdsStreamCfg.isHeaderEnabled)
        {
            /* Create the HSI Header to be used for the HW Session: */ 
            if (HSIHeader_createHeader (&sessionCfg, false, &(streamMcb->hwSessionHSIHeader), &errCode) < 0)
            {
                /* Error: Unable to create the HSI Header; report the error */
                test_print("Error: LVDSStream_config unable to create HW HSI header with [Error=%d]\n", errCode);
                goto exit;
            }
            
            streamMcb->isHwSessionHSIHeaderAllocated = true;
    
            /* Setup the header in the CBUFF session configuration: */
            sessionCfg.header.size    = HSIHeader_getHeaderSize(&streamMcb->hwSessionHSIHeader);
            sessionCfg.header.address = (uint32_t)&(streamMcb->hwSessionHSIHeader);
        }
    
        /* Create the HW Session: */
        streamMcb->hwSessionHandle = CBUFF_createSession (gLVDSStreamMCB.lvdsStream.cbuffHandle, &sessionCfg, &errCode);
    
        if (streamMcb->hwSessionHandle == NULL)
        {
            /* Error: Unable to create the CBUFF hardware session */
            test_print("Error: LVDSStream_config unable to create the CBUFF hardware session with [Error=%d]\n", errCode);
            goto exit;
        }
    
        /* Control comes here implies that the LVDS Stream has been configured successfully */
        retVal = 0;
    
    exit:
        return retVal;
    }
    
    /**
    *  @b Description
    *  @n
    *      High level API for configuring Hw session. Deletes h/w session if it exists,
    *      configures desired configuration input and activates the h/w session
    *  @param[in]  subFrameIndx Index of sub-frame
    *
    *  @retval
    *      None
    */
    void LVDSStream_configLVDSHwData(uint8_t subFrameIndx)
    {
        int32_t retVal;
    
        /* Delete previous CBUFF HW session if one was configured */
        if(gLVDSStreamMCB.lvdsStream.hwSessionHandle != NULL)
        {
            LVDSStream_DeleteHwSession();
        }
    
        /* Configure HW session */
        if (LVDSStream_HwConfig(subFrameIndx) < 0)
        {
            test_print("Failed LVDS stream HW configuration\n");
        }
    
        /* If HW LVDS stream is enabled, start the session here so that ADC samples will be
        streamed out as soon as the first chirp samples land on ADC*/
        if(CBUFF_activateSession(gLVDSStreamMCB.lvdsStream.hwSessionHandle, &retVal) < 0)
        {
            test_print("Failed to activate CBUFF session for LVDS stream HW. errCode=%d\n",retVal);
        }
        
        test_print("Debug: CBUFF HW Trigger configured successfully.\n");
    }
    

    /*
     *   @file  main_mss.c
     *
     *   @brief
     *      Unit Test code for the mmWave 
     *
     *  \par
     *  NOTE:
     *      (C) Copyright 2020- 2021 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.
     */
     /* ============================================================================
      */
     /** 
     *   @file  main_mss.c
     *
     *   @brief
     *      CBUFF Stream application code
     */
    
     /** @mainpage MSS/DSS CBUFF Steam Application for AWR294X
     *
     * ## Introduction #
     *
     * CBUFF Stream: This application can be executed on either MSS or DSS.
     *  The CBUFF Stream application on AWR294X is responsible for following:
     *   - Setup the control path through MMWave module.
     *   - Setup data path to stream ADC data over LVDS interface.
     *  
     *  The application initializes the modules for the control & datapath. This 
     *  would imply the configurations of the following modules:-
     *   1. Control path - Communication with BSS over mailbox to configure the
     *      sensor with hardcoded configuration to open mmWave control module.
     *   2. Data Path - Configuration of ADCBUF and CBUFF  module to stream 
     *      ADC data received from BSS on to LVDS interface.
     *
     * ## Configuration #
     *
     * The application uses hardcoded configuration for the chirp, profile and frame. 
     * This configuration is then passed to the BSS via the mmWave control module.
     * 
     * Below are the configuration details for control path:
     * 
     *  \ref TESTSOURCE_NUM_RX_ANTENNAS
     * 
     *  \ref TESTSOURCE_NUM_ADC_SAMPLES
     * 
     *  \ref TEST_SOURCE_NUM_LOOPS
     * 
     *  \ref TESTSOURCE_CHIRP_START_INDEX
     * 
     *  \ref TESTSOURCE_CHIRP_END_INDEX
     * 
     *  \ref TESTSOURCE_NUM_FRAMES
     *
     */
    /* ============================================================================
     */
    
    /**************************************************************************
     *************************** Include Files ********************************
     **************************************************************************/
    #define DebugP_LOG_ENABLED 1
    
    /* Standard Include Files. */
    #include <stdint.h>
    #include <stdlib.h>
    #include <stddef.h>
    #include <string.h>
    #include <stdio.h>
    
    /* MCU+SDK Include Files: */
    #include <ti/utils/test/cbuff_stream/awr294x/mssgenerated/ti_drivers_config.h>
    #include <ti/utils/test/cbuff_stream/awr294x/mssgenerated/ti_board_config.h>
    #include <ti/utils/test/cbuff_stream/awr294x/mssgenerated/ti_drivers_open_close.h>
    #include <ti/utils/test/cbuff_stream/awr294x/mssgenerated/ti_board_open_close.h>
    #include <kernel/dpl/DebugP.h>
    #include <kernel/dpl/AddrTranslateP.h>
    #include <kernel/dpl/DebugP.h>
    #include "FreeRTOS.h"
    #include "task.h"
    
    /* mmWave SDK Include Files: */
    #include <ti/control/mmwave/mmwave.h>
    #include <ti/common/syscommon.h>
    #include <ti/utils/testlogger/logger.h>
    #include <ti/utils/test/cbuff_stream/lvds_stream.h>
    #include <ti/control/mmwavelink/include/rl_sensor.h>
    
    /** @addtogroup TEST_CONTROL_PATH_CONFIG_DEFINITIONS
     @{ */
    
     /**
     * @brief
     * This macro defines the number of receive antennas.
     */
    #define TESTSOURCE_NUM_RX_ANTENNAS         (4U)
    
     /**
     * @brief
     * This macro defines the number of ADC Samples.
     */
    #define TESTSOURCE_NUM_ADC_SAMPLES         (256U)
    
     /**
     * @brief
     * This macro defines the number of chirps.
     */
    #define TEST_SOURCE_NUM_LOOPS              (1U)
    
     /**
     * @brief
     * This macro defines the chirp start index.
     */
    #define TESTSOURCE_CHIRP_START_INDEX       (0U)
    
     /**
     * @brief
     * This macro defines the chirp end index.
     */
    #define TESTSOURCE_CHIRP_END_INDEX         (0U)
    
     /**
     * @brief
     * This macro defines the number of frame.
     */
    #define TESTSOURCE_NUM_FRAMES              (10U)
    
    /**
    @}
    */
    
    /* FreeRTOS Task declarations. */
    #define APP_TASK_PRI         (5U)
    #define APP_CTRL_TASK_PRI    (7U)
    #define APP_TASK_STACK_SIZE  (8*1024U)
    #define APP_CTRL_TASK_STACK_SIZE (6*1024U)
    
    #define LVDS_TEST_SOURCE_ENABLE 1
    /**************************************************************************
     *************************** Global Variables *****************************
     **************************************************************************/
    TaskHandle_t    gAppTask;
    StaticTask_t    gAppTaskObj;
    
    TaskHandle_t    gMmwCtrlTask;
    StaticTask_t    gMmwCtrlTaskObj;
    
     /**
     * @brief
     * LVDS Stream MCB.
     */
    LVDSStream_MCB    gLVDSStreamMCB;
    
     /**
     * @brief
     * Test main task stack variable.
     */
    StackType_t gAppTskStackMain[APP_TASK_STACK_SIZE] __attribute__((aligned(32)));
    
     /**
     * @brief
     * MMWave control task stack variable.
     */
    StackType_t gCtrlTskStack[APP_CTRL_TASK_STACK_SIZE] __attribute__((aligned(32)));
    
    /**
     * @brief
     *  Initialize the MCPI Log Message Buffer
     */
    MCPI_LOGBUF_INIT(9216);
    
    LVDSStream_ADCBufCfg adcbufconfig = 
    {
        1,
        0,
        1,
        1
    };
    
    /**************************************************************************
     *********************** mmWave Unit Test Functions ***********************
     **************************************************************************/
    
    /**
     *  @b Description
     *  @n
     *      Utility function which populates the profile configuration with
     *      well defined defaults.
     *
     *  @param[out]  ptrProfileCfg
     *      Pointer to the populated profile configuration
     *
     *  @retval
     *      Not applicable
     */
    static void LVDSStream_populateDefaultProfileCfg (rlProfileCfg_t* ptrProfileCfg)
    {
        /* Initialize the profile configuration: */
        memset ((void*)ptrProfileCfg, 0, sizeof(rlProfileCfg_t));
    
        /* Populate the *default* profile configuration: */
        ptrProfileCfg->profileId             = 0;
        ptrProfileCfg->startFreqConst        = (uint32_t) ((float)77 * (1U << 26) / 3.6);
        ptrProfileCfg->idleTimeConst         = 100 * 1000 / 10;
        ptrProfileCfg->adcStartTimeConst     = 6 * 1000 / 10;
        ptrProfileCfg->rampEndTime           = 60 * 1000 /10;
        ptrProfileCfg->txOutPowerBackoffCode = 0;
        ptrProfileCfg->txPhaseShifter        = 0;
        ptrProfileCfg->freqSlopeConst        = 30 * 1000 / 48;
        ptrProfileCfg->txStartTime           = 0 * 1000 / 10;
        ptrProfileCfg->numAdcSamples         = TESTSOURCE_NUM_ADC_SAMPLES;
        ptrProfileCfg->digOutSampleRate      = 10000;
        ptrProfileCfg->hpfCornerFreq1        = 0;
        ptrProfileCfg->hpfCornerFreq2        = 0;
        ptrProfileCfg->rxGain                = 30;
    }
    
    /**
     *  @b Description
     *  @n
     *      Utility function which populates the chirp configuration with
     *      well defined defaults.
     *
     *  @param[out]  ptrChirpCfg
     *      Pointer to the populated chirp configuration
     *
     *  @retval
     *      Not applicable
     */
    static void LVDSStream_populateDefaultChirpCfg (rlChirpCfg_t* ptrChirpCfg)
    {
        /* Initialize the chirp configuration: */
        memset ((void*)ptrChirpCfg, 0, sizeof(rlChirpCfg_t));
    
        /* Populate the chirp configuration: */
        ptrChirpCfg->chirpStartIdx   = 0;
        ptrChirpCfg->chirpEndIdx     = 0;
        ptrChirpCfg->profileId       = 0;
        ptrChirpCfg->startFreqVar    = 0;
        ptrChirpCfg->freqSlopeVar    = 0;
        ptrChirpCfg->idleTimeVar     = 0;
        ptrChirpCfg->adcStartTimeVar = 0;
        ptrChirpCfg->txEnable        = 1;
    }
    
    /**
     *  @b Description
     *  @n
     *      The function is used to populate the default open configuration.
     *
     *  @param[out]  ptrOpenCfg
     *      Pointer to the open configuration
     *
     *  @retval
     *      Not applicable
     */
    static void LVDSStream_populateDefaultOpenCfg (MMWave_OpenCfg* ptrOpenCfg)
    {
        /* Initialize the open configuration: */
        memset ((void*)ptrOpenCfg, 0, sizeof(MMWave_OpenCfg));
    
        /* Setup the frequency for calibrations. */
        ptrOpenCfg->freqLimitLow  = 760U;
        ptrOpenCfg->freqLimitHigh = 810U;
    
        /* Enable start/stop async events */
        ptrOpenCfg->disableFrameStartAsyncEvent = false;
        ptrOpenCfg->disableFrameStopAsyncEvent  = false;
    
        /* Initialize the channel configuration: */
        ptrOpenCfg->chCfg.rxChannelEn = (1U << TESTSOURCE_NUM_RX_ANTENNAS) - 1U;
        ptrOpenCfg->chCfg.txChannelEn = 0x1;
        ptrOpenCfg->chCfg.cascading   = 0;
        ptrOpenCfg->chCfg.cascadingPinoutCfg   = (1U << 5U); /* Disbale OSC_CLKOUT */
    
        /* Initialize the low power mode configuration: */
        ptrOpenCfg->lowPowerMode.lpAdcMode     = 0; /* regular ADC mode */
    
        /* Initialize the ADCOut configuration: */
        ptrOpenCfg->adcOutCfg.fmt.b2AdcBits   = 2; /* 16 bit */
        ptrOpenCfg->adcOutCfg.fmt.b2AdcOutFmt = 0; /* real */
    
        /* No custom calibration: */
        ptrOpenCfg->useCustomCalibration        = false;
        ptrOpenCfg->customCalibrationEnableMask = 0x0;
    
        /* calibration monitoring base time unit
         * setting it to one frame duration as the test doesnt support any 
         * monitoring related functionality
         */
        ptrOpenCfg->calibMonTimeUnit            = 1;
    }
    
    /**
     *  @b Description
     *  @n
     *      The function is used to populate the default control configuration
     *      in chirp configuration mode
     *
     *  @param[out]  ptrCtrlCfg
     *      Pointer to the control configuration
     *
     *  @retval
     *      Not applicable
     */
    static void LVDSStream_populateDefaultChirpControlCfg (MMWave_CtrlCfg* ptrCtrlCfg)
    {
        rlProfileCfg_t      profileCfg;
        rlChirpCfg_t        chirpCfg;
        int32_t             errCode;
        MMWave_ChirpHandle  chirpHandle;
    
        /* Initialize the control configuration: */
        memset ((void*)ptrCtrlCfg, 0, sizeof(MMWave_CtrlCfg));
    
        /* This is frame mode configuration */
        ptrCtrlCfg->dfeDataOutputMode = MMWave_DFEDataOutputMode_FRAME;
    
        /* Populate the profile configuration: */
        LVDSStream_populateDefaultProfileCfg (&profileCfg);
    
        /* Create the profile: */
        ptrCtrlCfg->u.frameCfg[0].profileHandle[0] = MMWave_addProfile (gLVDSStreamMCB.mmWaveHandle, &profileCfg, &errCode);
        if (ptrCtrlCfg->u.frameCfg[0].profileHandle[0] == NULL)
        {
            test_print ("Error: Unable to add the profile [Error code %d]\n", errCode);
            MCPI_setFeatureTestResult ("MMWave Add Profile", MCPI_TestResult_FAIL);
            return;
        }
        MCPI_setFeatureTestResult ("MMWave Add Profile", MCPI_TestResult_PASS);
    
        /**************************************************************************************************
         * Unit Test: Verify the Full Configuration Profile API
         **************************************************************************************************/
        {
            rlProfileCfg_t          profileCfgTmp;
            uint32_t                numProfiles;
            MMWave_ProfileHandle    tmpProfileHandle;
    
            /* Verify the number of profiles */
            if (MMWave_getNumProfiles (gLVDSStreamMCB.mmWaveHandle, &numProfiles, &errCode) < 0)
            {
                test_print ("Error: Unable to get the number of profiles [Error code %d]\n", errCode);
                MCPI_setFeatureTestResult ("MMWave Get Number Profile", MCPI_TestResult_FAIL);
                return;
            }
            if (numProfiles != 1U)
            {
                test_print ("Error: Invalid number of profiles detected [%d]\n", numProfiles);
                MCPI_setFeatureTestResult ("MMWave Get Number Profile", MCPI_TestResult_FAIL);
            }
            MCPI_setFeatureTestResult ("MMWave Get Number Profile", MCPI_TestResult_PASS);
    
            /* Get the profile handle: */
            if (MMWave_getProfileHandle (gLVDSStreamMCB.mmWaveHandle, 0U, &tmpProfileHandle, &errCode) < 0)
            {
                test_print ("Error: Unable to get the profile handle [Error code %d]\n", errCode);
                MCPI_setFeatureTestResult ("MMWave Get Profile Handle", MCPI_TestResult_FAIL);
            }
            if (tmpProfileHandle != ptrCtrlCfg->u.frameCfg[0].profileHandle[0])
            {
                test_print ("Error: Invalid profile handle detected\n");
                MCPI_setFeatureTestResult ("MMWave Get Profile Handle", MCPI_TestResult_FAIL);
            }
            MCPI_setFeatureTestResult ("MMWave Get Profile Handle", MCPI_TestResult_PASS);
    
            /* Get the profile configuration */
            if (MMWave_getProfileCfg (ptrCtrlCfg->u.frameCfg[0].profileHandle[0], &profileCfgTmp, &errCode) < 0)
            {
                test_print ("Error: Unable to get the profile configuration [Error code %d]\n", errCode);
                MCPI_setFeatureTestResult ("MMWave Get Profile", MCPI_TestResult_FAIL);
                return;
            }
            if (memcmp ((void*)&profileCfg, (void*)&profileCfgTmp, sizeof(rlProfileCfg_t)) != 0)
            {
                test_print ("Error: Invalid profile configuration detected\n");
                MCPI_setFeatureTestResult ("MMWave Get Profile", MCPI_TestResult_FAIL);
                return;
            }
            MCPI_setFeatureTestResult ("MMWave Get Profile", MCPI_TestResult_PASS);
        }
    
        /* Populate the default chirp configuration */
        LVDSStream_populateDefaultChirpCfg (&chirpCfg);
    
        /* Add the chirp to the profile: */
        chirpHandle = MMWave_addChirp (ptrCtrlCfg->u.frameCfg[0].profileHandle[0], &chirpCfg, &errCode);
        if (chirpHandle == NULL)
        {
            test_print ("Error: Unable to add the chirp [Error code %d]\n", errCode);
            MCPI_setFeatureTestResult ("MMWave Add Chirp", MCPI_TestResult_FAIL);
            return;
        }
        MCPI_setFeatureTestResult ("MMWave Add Chirp", MCPI_TestResult_PASS);
    
        /**************************************************************************************************
         * Unit Test: Verify the Full Configuration Chirp API
         **************************************************************************************************/
        {
            rlChirpCfg_t        chirpCfgTmp;
            uint32_t            numChirps;
            MMWave_ChirpHandle  chirpHandleTmp;
    
            /* Get the number of chirps attached to the profile */
            if (MMWave_getNumChirps (ptrCtrlCfg->u.frameCfg[0].profileHandle[0], &numChirps, &errCode) < 0)
            {
                test_print ("Error: Unable to get the number of chirps [Error code %d]\n", errCode);
                MCPI_setFeatureTestResult ("MMWave Get Number of Chirps", MCPI_TestResult_FAIL);
                return;
            }
            if (numChirps != 1U)
            {
                test_print ("Error: Invalid number of chirps detected [%d]\n", numChirps);
                MCPI_setFeatureTestResult ("MMWave Get Number of Chirps", MCPI_TestResult_FAIL);
                return;
            }
            MCPI_setFeatureTestResult ("MMWave Get Number of Chirps", MCPI_TestResult_PASS);
    
            /* Get the Chirp Handle */
            if (MMWave_getChirpHandle (ptrCtrlCfg->u.frameCfg[0].profileHandle[0], 1U, &chirpHandleTmp, &errCode) < 0)
            {
                test_print ("Error: Unable to get the chirp handle [Error code %d]\n", errCode);
                MCPI_setFeatureTestResult ("MMWave Get Chirp Handle", MCPI_TestResult_FAIL);
                return;
            }
            if (chirpHandleTmp != chirpHandle)
            {
                test_print ("Error: Chirp handle validation failed [Error code %d]\n", errCode);
                MCPI_setFeatureTestResult ("MMWave Get Chirp Handle", MCPI_TestResult_FAIL);
                return;
            }
            MCPI_setFeatureTestResult ("MMWave Get Chirp Handle", MCPI_TestResult_PASS);
    
            /* Get the chirp configuration */
            if (MMWave_getChirpCfg (chirpHandle, &chirpCfgTmp, &errCode) < 0)
            {
                test_print ("Error: Unable to get the profile configuration [Error code %d]\n", errCode);
                MCPI_setFeatureTestResult ("MMWave Get Chirp", MCPI_TestResult_FAIL);
                return;
            }
            if (memcmp ((void*)&chirpCfg, (void*)&chirpCfgTmp, sizeof(rlChirpCfg_t)) != 0)
            {
                test_print ("Error: Invalid chirp configuration detected\n");
                MCPI_setFeatureTestResult ("MMWave Get Chirp Configuration", MCPI_TestResult_FAIL);
                return;
            }
            MCPI_setFeatureTestResult ("MMWave Get Chirp Configuration", MCPI_TestResult_PASS);
        }
    
        /* Populate the frame configuration: */
        ptrCtrlCfg->u.frameCfg[0].frameCfg.chirpStartIdx      = TESTSOURCE_CHIRP_START_INDEX;
        ptrCtrlCfg->u.frameCfg[0].frameCfg.chirpEndIdx        = TESTSOURCE_CHIRP_END_INDEX;
        ptrCtrlCfg->u.frameCfg[0].frameCfg.numLoops           = TEST_SOURCE_NUM_LOOPS;
        ptrCtrlCfg->u.frameCfg[0].frameCfg.numFrames          = TESTSOURCE_NUM_FRAMES;
        ptrCtrlCfg->u.frameCfg[0].frameCfg.numAdcSamples      = TESTSOURCE_NUM_ADC_SAMPLES;
        ptrCtrlCfg->u.frameCfg[0].frameCfg.framePeriodicity   = 10 * 1000000 / 5;
        ptrCtrlCfg->u.frameCfg[0].frameCfg.triggerSelect      = 1;
        ptrCtrlCfg->u.frameCfg[0].frameCfg.frameTriggerDelay  = 0;
    
        return;
    }
    
    
    /**
     *  @b Description
     *  @n
     *      Registered event function which is invoked when an event from the
     *      BSS is received.
     *
     *  @param[in]  msgId
     *      Message Identifier
     *  @param[in]  sbId
     *      Subblock identifier
     *  @param[in]  sbLen
     *      Length of the subblock
     *  @param[in]  payload
     *      Pointer to the payload buffer
     *
     *  @retval
     *      Always return 0 to pass the event to the peer domain- there is no more peer domain, this can be void
     */
    static int32_t LVDSStream_eventFxn(uint8_t devIndex, uint16_t msgId, uint16_t sbId, uint16_t sbLen, uint8_t *payload)
    {    
        uint16_t asyncSB = RL_GET_SBID_FROM_UNIQ_SBID(sbId);
        
        /* Process the received message: */
        switch (msgId)
        {
            case RL_RF_ASYNC_EVENT_MSG:
            {
                /* Received Asychronous Message: */
                switch (asyncSB)
                {
                    case RL_RF_AE_INITCALIBSTATUS_SB:
                    {
                        rlRfInitComplete_t*  ptrRFInitCompleteMessage;
                        uint32_t            calibrationStatus;
    
                        /* Get the RF-Init completion message: */
                        ptrRFInitCompleteMessage = (rlRfInitComplete_t*)payload;
                        calibrationStatus = ptrRFInitCompleteMessage->calibStatus & 0x1FFFU;
    
                        /* Display the calibration status: */
                        
                        DebugP_log("Debug: Init Calibration Status = 0x%x\n", calibrationStatus);;
                        break;
                    }
                }
            }
        }
        return 0;
    }
    
    
    /**
     *  @b Description
     *  @n
     *      The function is used to populate the default calibration
     *      configuration which is passed to start the mmWave module
     *
     *  @retval
     *      Not applicable
     */
    static void LVDSStream_populateDefaultCalibrationCfg (MMWave_CalibrationCfg* ptrCalibrationCfg, MMWave_DFEDataOutputMode dfeOutputMode)
    {
        /* Populate the calibration configuration: */
        ptrCalibrationCfg->dfeDataOutputMode                          = dfeOutputMode;
        ptrCalibrationCfg->u.chirpCalibrationCfg.enableCalibration    = false;
        ptrCalibrationCfg->u.chirpCalibrationCfg.enablePeriodicity    = false;
        ptrCalibrationCfg->u.chirpCalibrationCfg.periodicTimeInFrames = 10U;
        ptrCalibrationCfg->u.chirpCalibrationCfg.reportEn             = 0;
        return;
    }
    
    
    /**
     *  @b Description
     *  @n
     *      The task is used to provide an execution context for the mmWave
     *      control task
     *
     *  @retval
     *      Not Applicable.
     */
    static void LVDSStream_ctrlTask(void* args)
    {
        int32_t errCode;
    
        while (1)
        {
            /* Execute the mmWave control module: */
            if (MMWave_execute (gLVDSStreamMCB.mmWaveHandle, &errCode) < 0)
                test_print ("Error: mmWave control execution failed [Error code %d]\n", errCode);
        }
    }
    
    /**
     *  @b Description
     *  @n
     *      Function configures ADCBuf driver with data path parameters parsed from configurations
     *
     *  @param[in] adcBufHandle   ADCBuf driver handle
     *  @param[in] rxChannelEn    rx channel enable bit mask as described in rlChanCfg_t in rl_sensor.h
     *  @param[in] chirpThreshold  Chirp threshold
     *  @param[in] chanDataSize   Data size of the ADC channel
     *  @param[in] adcBufCfg     pointer to ADCBuf configuration
     *  @param[out] rxChanOffset  pointer to rx channel offset in the ADC buffer,
     *                            for each of enabled rx antenna
     *
     *
     *  @retval
     *      Success -   0
     *      Fail        < 0, one of ADCBuf driver error codes
     */
    int32_t LVDSStream_ADCBufConfig
    (
        ADCBuf_Handle         adcBufHandle,
        uint16_t              rxChannelEn,
        uint8_t               chirpThreshold,
        uint32_t              chanDataSize,
        LVDSStream_ADCBufCfg  *adcBufCfg,
        uint16_t              *rxChanOffset
    )
    {
        ADCBuf_dataFormat   dataFormat;
        ADCBuf_RxChanConf   rxChanConf;
        int32_t             retVal = 0U;
        uint8_t             channel;
        uint32_t            rxChanMask = 0xF;
        int32_t             rxChanOffsetIndx = 0;
    
        /* ADCBuf requires argument pointer at 4bytes boundary*/
        uint32_t            chirpThresholdVal = chirpThreshold;
    
        /*****************************************************************************
         * Data path :: ADCBUF driver Configuration
         *****************************************************************************/
        /* Populate data format from configuration */
        dataFormat.adcOutFormat       = adcBufCfg->adcFmt;
        dataFormat.channelInterleave  = adcBufCfg->chInterleave;
        dataFormat.sampleInterleave   = adcBufCfg->iqSwapSel;
    
        /* Disable all ADCBuf channels */
        if ((retVal = ADCBuf_control(adcBufHandle, ADCBufMMWave_CMD_CHANNEL_DISABLE, (void *)&rxChanMask)) < 0)
        {
           test_print("Error: Disable ADCBuf channels failed with [Error=%d]\n", retVal);
            goto exit;
        }
    
        retVal = ADCBuf_control(adcBufHandle, ADCBufMMWave_CMD_CONF_DATA_FORMAT, (void *)&dataFormat);
        if (retVal < 0)
        {
            goto exit;
        }
    
        memset((void*)&rxChanConf, 0, sizeof(ADCBuf_RxChanConf));
    
        /* Enable Rx Channels */
        for (channel = 0; channel < SYS_COMMON_NUM_RX_CHANNEL; channel++)
        {
            if(rxChannelEn & (0x1U << channel))
            {
                /* Populate the receive channel configuration: */
                rxChanConf.channel = channel;
                retVal = ADCBuf_control(adcBufHandle, ADCBufMMWave_CMD_CHANNEL_ENABLE, (void *)&rxChanConf);
                if (retVal < 0)
                {
                    test_print("Error: MSS ADCBuf Control for Channel %d Failed with error[%d]\n", channel, retVal);
                    goto exit;
                }
                /* Offset starts from 0 for the first channel */
                rxChanOffset[rxChanOffsetIndx++] = rxChanConf.offset;
    
                /* Calculate offset for the next channel */
                rxChanConf.offset  += chanDataSize * chirpThresholdVal;
            }
        }
    
        /* Set ping/pong chirp threshold: */
        retVal = ADCBuf_control(adcBufHandle, ADCBufMMWave_CMD_SET_PING_CHIRP_THRESHHOLD,
                                (void *)&chirpThresholdVal);
        if(retVal < 0)
        {
            test_print("Error: ADCbuf Ping Chirp Threshold Failed with Error[%d]\n", retVal);
            goto exit;
        }
        retVal = ADCBuf_control(adcBufHandle, ADCBufMMWave_CMD_SET_PONG_CHIRP_THRESHHOLD,
                                (void *)&chirpThresholdVal);
        if(retVal < 0)
        {
            test_print("Error: ADCbuf Pong Chirp Threshold Failed with Error[%d]\n", retVal);
            goto exit;
        }
    
    exit:
        return (retVal);
    }
    
    #if LVDS_TEST_SOURCE_ENABLE
    rlReturnVal_t  enableTestSource()
    {
        rlReturnVal_t retVal = RL_RET_CODE_OK;
        rlTestSource_t testSourceData =
        {
            .testObj[0] = {102, 2, 5698, 0, 0, 0, 100, 1256, 2589, 225, 2489, 12256, 112},
            // .testObj[1] = {10, 5, 0, 5, 5, 5, 255, 0, 216, 2251, 341, 556, 5112},
            .rxAntPos[0] = {15, 15},
            .rxAntPos[1] = {15, 15},
            .rxAntPos[2] = {15, 15},
            .rxAntPos[3] = {15, 15},
            .reserved0 = 0,
            .miscFunCtrl=1,
        };
    
        rlTestSourceEnable_t testSourceEnableData =
        {
            .tsEnable = 1,
            .reserved = 0,
        };
    
        uint8_t deviceMap=0x1;
        retVal = rlSetTestSourceConfig (deviceMap, &testSourceData);
        //enable test source
        retVal = rlTestSourceEnable(deviceMap, &testSourceEnableData);
    
        return retVal;
    }
    #endif
    
    /**
     *  @b Description
     *  @n
     *      Test implementation
     *
     *  @retval
     *      Not Applicable.
     */
    void LVDSStream_mmWaveInit (void)
    {
        MMWave_InitCfg          initCfg;
        MMWave_CtrlCfg          ctrlCfg;
        MMWave_OpenCfg          openCfg;
        int32_t                 errCode;
        MMWave_CalibrationCfg   calibrationCfg;
        int32_t                 retVal;
        MMWave_ErrorLevel       errorLevel;
        int16_t                 mmWaveErrorCode;
        int16_t                 subsysErrorCode;
        
        /* Initialize the configuration: */
        memset ((void *)&initCfg, 0, sizeof(MMWave_InitCfg));
    
        initCfg.domain                  = MMWave_Domain_MSS;
        initCfg.eventFxn                = LVDSStream_eventFxn;
        initCfg.linkCRCCfg.crcBaseAddr  = (uint32_t) AddrTranslateP_getLocalAddr(CONFIG_CRC0_BASE_ADDR);
        initCfg.linkCRCCfg.useCRCDriver = 1U;
        initCfg.linkCRCCfg.crcChannel   = CRC_CHANNEL_1;
        initCfg.cfgMode                 = MMWave_ConfigurationMode_FULL;
    
        /* Initialize and setup the mmWave Control module */
        gLVDSStreamMCB.mmWaveHandle = MMWave_init (&initCfg, &errCode);
        if (gLVDSStreamMCB.mmWaveHandle == NULL)
        {
            /* Error: Unable to initialize the mmWave control module */
            MMWave_decodeError (errCode, &errorLevel, &mmWaveErrorCode, &subsysErrorCode);
    
            /* Debug Message: */
            test_print ("Error Level: %s mmWave: %d Subsys: %d\n",
                           (errorLevel == MMWave_ErrorLevel_ERROR) ? "Error" : "Warning",
                           mmWaveErrorCode, subsysErrorCode);
    
            /* Log into the MCPI Test Logger: */
            MCPI_setFeatureTestResult ("MMWave MSS Initialization", MCPI_TestResult_FAIL);
            return;
        }
        
        test_print ("MMWave MSS Initialization\n");
    
        /*****************************************************************************
         * Launch the mmWave control execution task
         * - This should have a higher priroity than any other task which uses the
         *   mmWave control API
         *****************************************************************************/
        gMmwCtrlTask = xTaskCreateStatic( LVDSStream_ctrlTask,
                                          "test_ctrl_task",
                                          APP_CTRL_TASK_STACK_SIZE,
                                          NULL,
                                          APP_CTRL_TASK_PRI,
                                          gCtrlTskStack,
                                          &gMmwCtrlTaskObj );
    
        configASSERT(gMmwCtrlTask != NULL);
    
        LVDSStream_populateDefaultOpenCfg (&openCfg);
        LVDSStream_populateDefaultChirpControlCfg (&ctrlCfg); /* regular frame config */
        
        /************************************************************************
         * Open the mmWave:
         ************************************************************************/
        if (MMWave_open (gLVDSStreamMCB.mmWaveHandle, &openCfg, NULL, &errCode) < 0)
        {
            /* Error: Unable to configure the mmWave control module */
            test_print ("Error: mmWave open failed [Error code %d]\n", errCode);
            MCPI_setFeatureTestResult ("MMWave MSS Open", MCPI_TestResult_FAIL);
            return;
        }
       
        test_print ("MMWave MSS Open done.\n");
    
        /************************************************************************
         * Configure the mmWave:
         ************************************************************************/
        if (MMWave_config (gLVDSStreamMCB.mmWaveHandle, &ctrlCfg, &errCode) < 0)
        {
            /* Error: Unable to configure the mmWave control module */
            test_print ("Error: mmWave configuration failed [Error code %d]\n", errCode);
            MCPI_setFeatureTestResult ("MMWave MSS Configuration", MCPI_TestResult_FAIL);
            return;
        }
    
        
        test_print ("MMWave MSS Configuration done\n");
    
        /* Populate the calibration configuration: */
        memset ((void *)&calibrationCfg, 0, sizeof(MMWave_CalibrationCfg));
        LVDSStream_populateDefaultCalibrationCfg (&calibrationCfg, MMWave_DFEDataOutputMode_FRAME);
    
    #if LVDS_TEST_SOURCE_ENABLE
        retVal = enableTestSource();
        if(retVal != RL_RET_CODE_OK)
        {
            printf("Error: Failed to enable test source\n");
            return;
        }
    #endif
        /************************************************************************
         * Start the mmWave:
         ************************************************************************/
        if (MMWave_start (gLVDSStreamMCB.mmWaveHandle, &calibrationCfg, &errCode) < 0)
        {
            /* Error: Unable to configure the mmWave control module */
            test_print ("Error: mmWave start failed [Error code %d]\n", errCode);
            MCPI_setFeatureTestResult ("MMWave MSS Start", MCPI_TestResult_FAIL);
            return;
        }
    
        /* Wait for the CBUFFtransfers to be complete. */
        while(gLVDSStreamMCB.lvdsStream.hwFrameDoneCount != TESTSOURCE_NUM_FRAMES)
        {
            /* Sleep and poll again: */
            ClockP_usleep(1 * 1000);
        }
    
        /************************************************************************
         * Stop the mmWave:
         ************************************************************************/
        retVal = MMWave_stop (gLVDSStreamMCB.mmWaveHandle, &errCode);
        if (retVal < 0)
        {
            /* Error: Stopping the sensor failed. Decode the error code. */
            MMWave_decodeError (errCode, &errorLevel, &mmWaveErrorCode, &subsysErrorCode);
    
            /* Debug Message: */
            test_print ("Error Level: %s mmWave: %d Subsys: %d\n",
                           (errorLevel == MMWave_ErrorLevel_ERROR) ? "Error" : "Warning",
                           mmWaveErrorCode, subsysErrorCode);
    
            /* Did we fail because of an error? */
            if (errorLevel == MMWave_ErrorLevel_ERROR)
            {
                /* Error Level: The test has failed. */
                MCPI_setFeatureTestResult ("MMWave MSS Stop", MCPI_TestResult_FAIL);
                return;
            }
            else
            {
                /* Informational Level: The test has passed. Fall through...*/
            }
        }
        test_print ("MMWave MSS Stop done.\n");
    
        /************************************************************************
         * Close the mmWave:
         ************************************************************************/
        if (MMWave_close (gLVDSStreamMCB.mmWaveHandle, &errCode) < 0)
        {
            /* Error: Unable to configure the mmWave control module */
            test_print ("Error: mmWave close failed [Error code %d]\n", errCode);
            MCPI_setFeatureTestResult ("MMWave MSS Close", MCPI_TestResult_FAIL);
            return;
        }
        MCPI_setFeatureTestResult ("MMWave MSS Close", MCPI_TestResult_PASS);
        test_print ("MMWave MSS close done.\n");
        
        /************************************************************************
         * Deinitialize the mmWave module:
         ************************************************************************/
        if (MMWave_deinit(gLVDSStreamMCB.mmWaveHandle, &errCode) < 0)
        {
            /* Error: Unable to deinitialize the mmWave control module */
            test_print ("Error: mmWave Deinitialization failed [Error code %d]\n", errCode);
            MCPI_setFeatureTestResult ("MMWave MSS Deinitialized", MCPI_TestResult_FAIL);
            return;
        }
        MCPI_setFeatureTestResult ("MMWave MSS Deinitialized", MCPI_TestResult_PASS);
        
        return;
    }
    
    /**
     *  @b Description
     *  @n
     *      Function initializes and opens ADCBuf driver
     *
     *
     *  @retval
     *      Success -   ADCBuf driver handle
     *      Fail        NULL
     */
    static ADCBuf_Handle LVDSStream_ADCBufOpen(void)
    {
        ADCBuf_Params       ADCBufparams;
        ADCBuf_Handle       ADCBufHandle = NULL;
    
        /* Initialize the ADCBUF */
        ADCBuf_init();
    
        /*****************************************************************************
         * Start ADCBUF driver:
         *****************************************************************************/
        /* ADCBUF Params initialize */
        ADCBuf_Params_init(&ADCBufparams);
        ADCBufparams.chirpThresholdPing = 1;
        ADCBufparams.chirpThresholdPong = 1;
        ADCBufparams.continousMode  = 0;
    
        /* Open ADCBUF driver */
        ADCBufHandle = ADCBuf_open(0, &ADCBufparams);
    
        return ADCBufHandle;
    }
    
    
    /**
     *  @b Description
     *  @n
     *      Perform Data path driver open 
     *
     *  @retval
     *      Not Applicable.
     */
    static void LVDSStream_dataPathOpen(void)
    {
        gLVDSStreamMCB.adcBufHandle = LVDSStream_ADCBufOpen();
        if(gLVDSStreamMCB.adcBufHandle == NULL)
        {
            test_print ("Error: unable to open ADCBUFF instance.\n");
        }
    
        test_print("Debug: ADCBUF Instance %p has been opened successfully.\n", gLVDSStreamMCB.adcBufHandle);
    }
    
    /**
     *  @b Description
     *  @n
     *      System Initialization Task which initializes the various
     *      components in the system.
     *
     *  @retval
     *      Not Applicable.
     */
    static void LVDSStream_initTask(void* args)
    {
        int32_t             errCode;
        uint16_t            rxChanOffset[4];
    
        Drivers_open();
        Board_driversOpen();
    
        /* Debug Message: */
        test_print ("******************************************\n");
        test_print ("Debug: Launching LVDS Streaming Application.\n");
        test_print ("******************************************\n");
    
        /* Configure HSI Clock. */
        HW_WR_REG32(CSL_MSS_TOPRCM_U_BASE + CSL_MSS_TOPRCM_HSI_CLK_SRC_SEL, 0x333);
    
        gLVDSStreamMCB.edmaHandle = gEdmaHandle[CONFIG_EDMA0];
        
        /* Initialize LVDS streaming components */
        if ((errCode = LVDSStream_Init()) < 0 )
        {
            test_print ("Error: MSS LVDS stream init failed with Error[%d]\n",errCode);
            return;
        }
    
        test_print("Debug: CBUFF interface initialized successfully.\n");
        
        /* Configure Pad registers for LVDS. */
        HW_WR_REG32(CSL_MSS_TOPRCM_U_BASE + CSL_MSS_TOPRCM_LVDS_PAD_CTRL0 , 0x0);
        HW_WR_REG32(CSL_MSS_TOPRCM_U_BASE + CSL_MSS_TOPRCM_LVDS_PAD_CTRL1 , 0x02000000);
        
        /*The delay below is needed only if the DCA1000EVM is being used to capture the data traces.
          This is needed because the DCA1000EVM FPGA needs the delay to lock to the
          bit clock before they can start capturing the data correctly. */
        ClockP_usleep(HSI_DCA_MIN_DELAY_MSEC * 1000);
    
        /* Configure ADCBUF module. */
        LVDSStream_dataPathOpen();
        
        /* Configure ADCBUF driver. */
        errCode = LVDSStream_ADCBufConfig(gLVDSStreamMCB.adcBufHandle,
                                     15,
                                     1,
                                     ((TESTSOURCE_NUM_ADC_SAMPLES * 2) + 15U) / 16U * 16U,
                                     &adcbufconfig,
                                     &rxChanOffset[0]);
        
        if (errCode < 0)
        {
            test_print("Error: ADCBuf config failed with error[%d]\n", errCode);
            return;
        }
        
        gLVDSStreamMCB.subFrameCfg[0].numAdcSamples = TESTSOURCE_NUM_ADC_SAMPLES;
        gLVDSStreamMCB.subFrameCfg[0].numChirpsPerSubFrame = TEST_SOURCE_NUM_LOOPS;
        gLVDSStreamMCB.subFrameCfg[0].adcBufCfg.chirpThreshold = 1;
        gLVDSStreamMCB.subFrameCfg[0].lvdsStreamCfg.dataFmt = LVDS_STREAM_CFG_DATAFMT_ADC;
    
        gLVDSStreamMCB.subFrameCfg[0].lvdsStreamCfg.isHeaderEnabled = false;
        gLVDSStreamMCB.subFrameCfg[0].lvdsStreamCfg.isSwEnabled = false;
        gLVDSStreamMCB.subFrameCfg[0].adcBufCfg.chInterleave = 1; /* non-interleaved */
        
        /* Configure HW LVDS stream for the ADC Date that will start upon
         * ADC Capture Complete */
        LVDSStream_configLVDSHwData(0);
    
        /* Configure BSS. */
        LVDSStream_mmWaveInit();
    
        if(CBUFF_deactivateSession (gLVDSStreamMCB.lvdsStream.hwSessionHandle, &errCode) < 0)
        {
            test_print("CBUFF HW session deactivation error %d.\n", errCode);
            /* Error: Unable to deactivate the session. */
            DebugP_assert(0);
            return;
        }
        test_print("CBUFF HW session deactivated.\n");
    
        /* Close CBUFF HW Session. */
        LVDSStream_DeleteHwSession();
    
        test_print("------ end of test --------\n");
        test_print ("All tests have passed!!\n");
    
        vTaskDelete(NULL);
    }
    
    /**
     *  @b Description
     *  @n
     *      Entry point into the mmWave Unit Test
     *
     *  @retval
     *      Not Applicable.
     */
    int32_t main (void)
    {
        /* init SOC specific modules */
        System_init();
        Board_init();
    
        /* This task is created at highest priority, it should create more tasks and then delete itself */
        gAppTask = xTaskCreateStatic( LVDSStream_initTask,
                                      "test_task_main",
                                      APP_TASK_STACK_SIZE,
                                      NULL,
                                      APP_TASK_PRI,
                                      gAppTskStackMain,
                                      &gAppTaskObj );
        configASSERT(gAppTask != NULL);
    
        /* Start the scheduler to start the tasks executing. */
        vTaskStartScheduler();
    
        /* The following line should never be reached because vTaskStartScheduler()
        will only return if there was not enough FreeRTOS heap memory available to
        create the Idle and (if configured) Timer tasks.  Heap management, and
        techniques for trapping heap exhaustion, are described in the book text. */
        DebugP_assertNoLog(0);
    }
    

    Best regards.

  • Hello Liu,

    If you are getting good data with the 0x3 and it is working right, what is the specific reason to use only a single lane?
    Your end goal is to get data on both lanes together right?

    Regards,
    Saswat Kumar

  • Hi, it test good in EVM, but in self-designed, as post processed result by algothim engineer, lane1 is disturbed, lane2 is OK, so there is need to streaming out the adc data only with lane2 for further processing

  • Hello Liu,

    So, I identified the issue due to which the application was not working:

    First go to the file: C:\ti\mmwave_mcuplus_sdk_04_06_00_01\mcu_plus_sdk_awr294x_09_00_00_15\source\drivers\cbuff\v0\cbuff_lvds.c

    In CBUFF_openLVDS function, modify the last section of this code:

    This is just a fix only for 2nd lane as I have hard coded the values.

    Then rebuild the library using the command:

    gmake -s -f makefile.awr294x drivers_r5f.ti-arm-clang drivers_c66.ti-c6000             

    Then rebuild the application again.

    This should make the application functional now.

    Regards,
    Saswat Kumar