【TI毫米波雷达】CLI模块初始化,demo工程覆写CLI控制指令代码的操作方式(以IWR6843AOP为例)

【TI毫米波雷达】CLI模块初始化,demo工程覆写CLI控制指令代码的操作方式(以IWR6843AOP为例)

本文主要针对demo工程 通过覆写CLI配置 跳过CLI配置命令 以此来达到自动配置参数 并控制雷达的功能
在此期间不开启CLI和相关初始化 只是针对CLI控制函数进行仿写

还有一种自动配置命令的方法 是在CLI初始化后调用内部指令进行配置 请看下一篇文章:

文章目录

  • CLI Utility(CLI模块)
    • CLI串口
    • CLI初始化
    • CLI内部函数和结构体(基本雷达参数配置命令)
    • CLI命令格式
    • CLI_task循环
  • 覆写CLI控制指令
    • CLI重构
    • `MmwDemo_CLISensorStart`函数重构
  • 附录:结构框架
    • 雷达基本原理叙述
    • 雷达天线排列位置
    • 芯片框架
    • Demo工程功能
    • CCS工程导入
    • 工程叙述
      • Software Tasks
      • Data Path
      • Output information sent to host
        • List of detected objects
        • Range profile
        • Azimuth static heatmap
        • Azimuth/Elevation static heatmap
        • Range/Doppler heatmap
        • Stats information
        • Side information of detected objects
        • Temperature Stats
        • Range Bias and Rx Channel Gain/Phase Measurement and Compensation
        • Streaming data over LVDS
        • Implementation Notes
        • How to bypass CLI
        • Hardware Resource Allocation

CLI Utility(CLI模块)

CLI模块可以将一组串口(通常是command串口0 波特率为115200)配置为一种类似于shell指令的控制模块
可以通过这些配置后的CLI命令进行参数配置、控制雷达等
也可以自己写命令来执行相应的函数
以下是手册原文:

The CLI utility library provides a simple CLI console over the specified serial port.

The CLI library provides the following features:

Simple command parser
Applications can register their own custom commands
mmWave Extension support which handles the well defined mmWave control commands.
The CLI header file should be included in an application as follows:

#include <ti/utils/cli/cli.h>

The CLI library provides an mmWave extension library which provides predefined CLI command handlers for the mmWave configuration commands. The mmWave configuration is stored internally and an application can use CLI_getMMWaveExtensionConfig to get a copy of this configuration. This can then be used to configure the mmWave

CLI串口

在IWR6843AOP中 有两组串口
这里控制串口的引脚为:
SOC_XWR68XX_PINN4_PADBDSOC_XWR68XX_PINN4_PADBD

    /* Setup the PINMUX to bring out the UART-1 */Pinmux_Set_OverrideCtrl(SOC_XWR68XX_PINN5_PADBE, PINMUX_OUTEN_RETAIN_HW_CTRL, PINMUX_INPEN_RETAIN_HW_CTRL);    Pinmux_Set_FuncSel(SOC_XWR68XX_PINN5_PADBE, SOC_XWR68XX_PINN5_PADBE_MSS_UARTA_TX);Pinmux_Set_OverrideCtrl(SOC_XWR68XX_PINN4_PADBD, PINMUX_OUTEN_RETAIN_HW_CTRL, PINMUX_INPEN_RETAIN_HW_CTRL);    Pinmux_Set_FuncSel(SOC_XWR68XX_PINN4_PADBD, SOC_XWR68XX_PINN4_PADBD_MSS_UARTA_RX);/* Setup the PINMUX to bring out the UART-3 */Pinmux_Set_OverrideCtrl(SOC_XWR68XX_PINF14_PADAJ, PINMUX_OUTEN_RETAIN_HW_CTRL, PINMUX_INPEN_RETAIN_HW_CTRL);Pinmux_Set_FuncSel(SOC_XWR68XX_PINF14_PADAJ, SOC_XWR68XX_PINF14_PADAJ_MSS_UARTB_TX);

也就是以下引脚: 配置为MSS_UART功能
在这里插入图片描述

CLI初始化

在CLI初始化结构体CLI_Cfg中 可以对CLI进行配置

CLI_Cfg     cliCfg;cliCfg.cliPrompt                    = "mmwDemo:/>";  //每次命令开头的报文cliCfg.cliBanner                    = demoBanner;  //开启时的输出cliCfg.cliUartHandle                = gMmwMCB.commandUartHandle;  //串口句柄cliCfg.taskPriority                 = taskPriority;  //CLI线程优先级cliCfg.socHandle                    = gMmwMCB.socHandle;  //soc句柄cliCfg.mmWaveHandle                 = gMmwMCB.ctrlHandle;  //毫米波雷达句柄cliCfg.enableMMWaveExtension        = 1U;cliCfg.usePolledMode                = true;cliCfg.overridePlatform             = true;

命令参数则是由该结构体下的tableEntry数组来确定
有多少个就配置多少个数组
这里是用户自定义命令

		cliCfg.tableEntry[cnt].cmd            = "sensorStart";cliCfg.tableEntry[cnt].helpString     = "[doReconfig(optional, default:enabled)]";cliCfg.tableEntry[cnt].cmdHandlerFxn  = MmwDemo_CLISensorStart;

最后调用CLI_open 即可

/* Open the CLI: */if (CLI_open (&cliCfg) < 0){System_printf ("Error: Unable to open the CLI\n");return;}System_printf ("Debug: CLI is operational\n");return;

CLI内部函数和结构体(基本雷达参数配置命令)

内部函数包括以下:

static int32_t CLI_MMWaveVersion (int32_t argc, char* argv[]);
static int32_t CLI_MMWaveFlushCfg (int32_t argc, char* argv[]);
static int32_t CLI_MMWaveDataOutputMode (int32_t argc, char* argv[]);
static int32_t CLI_MMWaveChannelCfg (int32_t argc, char* argv[]);
static int32_t CLI_MMWaveADCCfg (int32_t argc, char* argv[]);
static int32_t CLI_MMWaveProfileCfg (int32_t argc, char* argv[]);
static int32_t CLI_MMWaveChirpCfg (int32_t argc, char* argv[]);
static int32_t CLI_MMWaveFrameCfg (int32_t argc, char* argv[]);
static int32_t CLI_MMWaveAdvFrameCfg (int32_t argc, char* argv[]);
static int32_t CLI_MMWaveSubFrameCfg (int32_t argc, char* argv[]);
static int32_t CLI_MMWaveLowPowerCfg (int32_t argc, char* argv[]);
static int32_t CLI_MMWaveContModeCfg (int32_t argc, char* argv[]);
static int32_t CLI_MMWaveBPMCfgAdvanced (int32_t argc, char* argv[]);

对应命令字在CLI_CmdTableEntry gCLIMMWaveExtensionTable[]中体现
如:

	{"version",
#ifdef CLI_MMWAVE_HELP_SUPPORT"No arguments",
#elseNULL,
#endifCLI_MMWaveVersion}

需要注意的是 这里的命令函数都是静态static声明 所以只能由CLI库下的函数调用
如:

/***  @b Description*  @n*      This is the CLI Handler for the frame configuration command**  @param[in] argc*      Number of arguments*  @param[in] argv*      Arguments**  \ingroup CLI_UTIL_INTERNAL_FUNCTION**  @retval*      Success -   0*  @retval*      Error   -   <0*/
static int32_t CLI_MMWaveFrameCfg (int32_t argc, char* argv[])
{rlFrameCfg_t    frameCfg;/* Sanity Check: Minimum argument check */if (argc != 8){CLI_write ("Error: Invalid usage of the CLI command\n");return -1;}/* Sanity Check: Frame configuration is valid only for the Frame orAdvanced Frame Mode: */if (gCLIMMWaveControlCfg.dfeDataOutputMode != MMWave_DFEDataOutputMode_FRAME){CLI_write ("Error: Configuration is valid only if the DFE Output Mode is Chirp\n");return -1;}/* Initialize the frame configuration: */memset ((void *)&frameCfg, 0, sizeof(rlFrameCfg_t));/* Populate the frame configuration: */frameCfg.chirpStartIdx      = atoi (argv[1]);frameCfg.chirpEndIdx        = atoi (argv[2]);frameCfg.numLoops           = atoi (argv[3]);frameCfg.numFrames          = atoi (argv[4]);frameCfg.framePeriodicity   = (uint32_t)((float)atof(argv[5]) * 1000000 / 5);frameCfg.triggerSelect      = atoi (argv[6]);frameCfg.frameTriggerDelay  = (uint32_t)((float)atof(argv[7]) * 1000000 / 5);/* Save Configuration to use later */memcpy((void *)&gCLIMMWaveControlCfg.u.frameCfg.frameCfg, (void *)&frameCfg, sizeof(rlFrameCfg_t));return 0;
}

这里获取到命令相关信息后 调用该函数 然后把相关参数配置到gCLIMMWaveControlCfg结构体中
该结构体也是一个内部结构体
所以需要通过两个外部函数来访问这些参数:

extern void    CLI_getMMWaveExtensionConfig(MMWave_CtrlCfg* ptrCtrlCfg);
extern void    CLI_getMMWaveExtensionOpenConfig(MMWave_OpenCfg* ptrOpenCfg);

这两个函数的功能就是把内部结构体的参数全部copy到传入的结构体地址内

当然 也有静态函数是直接调用了mmwave中的函数来进行直接配置
如:

/***  @b Description*  @n*      This is the CLI Handler for the BPM configuration.**  @param[in] argc*      Number of arguments*  @param[in] argv*      Arguments**  \ingroup CLI_UTIL_INTERNAL_FUNCTION**  @retval*      Success -   0*  @retval*      Error   -   <0*/
static int32_t CLI_MMWaveBPMCfgAdvanced (int32_t argc, char* argv[])
{   rlBpmChirpCfg_t         bpmChirpCfg;int32_t                 errCode;/* Sanity Check: Minimum argument check */if (argc != 4){CLI_write ("Error: Invalid usage of the CLI command\n");return -1;}/* Sanity Check: BPM Chirp configuration is valid only for the Frame orAdvanced Frame Mode: */if ((gCLIMMWaveControlCfg.dfeDataOutputMode != MMWave_DFEDataOutputMode_FRAME) &&(gCLIMMWaveControlCfg.dfeDataOutputMode != MMWave_DFEDataOutputMode_ADVANCED_FRAME)){CLI_write ("Error: BPM Configuration is valid only if the DFE Output Mode is frame or advanced frame\n");return -1;}/* Initialize the chirp configuration: */memset ((void *)&bpmChirpCfg, 0, sizeof(rlBpmChirpCfg_t));/* Populate the chirp configuration: */bpmChirpCfg.chirpStartIdx   = atoi (argv[1]);bpmChirpCfg.chirpEndIdx     = atoi (argv[2]);bpmChirpCfg.constBpmVal     = atoi (argv[3]);/* Add the BPM chirp configuration to the list */if (MMWave_addBpmChirp (gCLI.cfg.mmWaveHandle, &bpmChirpCfg, &errCode) == NULL){/* Error: Unable to add the BPM configuration. Return the error code. */return errCode;}return 0;}

CLI命令格式

CLI在进行命令配置的时候 需要用到以下结构体类型

typedef struct CLI_CmdTableEntry_t
{/*** @brief   Command string*/char*               cmd;/*** @brief   CLI Command Help string*/char*               helpString;/*** @brief   Command Handler to be executed*/CLI_CmdHandler      cmdHandlerFxn;
}CLI_CmdTableEntry;

其中 cmd为命令字 helpString为帮助信息 cmdHandlerFxn为函数指针
该回调函数类型为:

/*** @brief   CLI command handler:**  @param[in]  argc*      Number of arguments*  @param[in]  argv*      Pointer to the arguments**  @retval*      Success     - 0*  @retval*      Error       - <0*/
typedef int32_t (*CLI_CmdHandler)(int32_t argc, char* argv[]);

所以 命令函数也需要按这个格式来声明

如命令:"adcCfg 2 1"
调用函数为:

static int32_t CLI_MMWaveADCCfg (int32_t argc, char* argv[]);

adcCfg 是命令字
传入到函数中时 argc=3

argv={"adcCfg","2","1"}

也就是说 argc表示的是命令字+参数个数的总个数 由于命令字有且仅有一个 所以又等于参数个数+1
argv是存放命令字+参数的列表 argv[0]为命令字 后面为参数

这在函数中也能看到:

static int32_t CLI_MMWaveADCCfg (int32_t argc, char* argv[])
{rlAdcOutCfg_t   adcOutCfg;int32_t         retVal = 0;/* Sanity Check: Minimum argument check */if (argc != 3)  //长度不为3就表示错误{CLI_write ("Error: Invalid usage of the CLI command\n");return -1;}/* Initialize the ADC Output configuration: */memset ((void *)&adcOutCfg, 0, sizeof(rlAdcOutCfg_t));/* Populate the ADC Output configuration: */adcOutCfg.fmt.b2AdcBits   = atoi (argv[1]);  //第一个参数"2"adcOutCfg.fmt.b2AdcOutFmt = atoi (argv[2]);  //第二个参数"1"/* Save Configuration to use later */memcpy((void *)&gCLIMMWaveOpenCfg.adcOutCfg, (void *)&adcOutCfg, sizeof(rlAdcOutCfg_t));return retVal;
}

CLI_task循环

CLI初始化以后 在函数CLI_open中会建立一个CLI_task线程 其优先级就是配置时的CLI优先级
该函数原型如下:

/***  @b Description*  @n*      This is the CLI Execution Task**  \ingroup CLI_UTIL_INTERNAL_FUNCTION**  @retval*      Not Applicable.*/
static void CLI_task(UArg arg0, UArg arg1)
{uint8_t                 cmdString[256];char*                   tokenizedArgs[CLI_MAX_ARGS];char*                   ptrCLICommand;char                    delimitter[] = " \r\n";uint32_t                argIndex;CLI_CmdTableEntry*      ptrCLICommandEntry;int32_t                 cliStatus;uint32_t                index;/* Do we have a banner to be displayed? */if (gCLI.cfg.cliBanner != NULL){/* YES: Display the banner */CLI_write (gCLI.cfg.cliBanner);}/* Loop around forever: */while (1){/* Demo Prompt: */CLI_write (gCLI.cfg.cliPrompt);/* Reset the command string: */memset ((void *)&cmdString[0], 0, sizeof(cmdString));/* Read the command message from the UART: */UART_read (gCLI.cfg.cliUartHandle, &cmdString[0], (sizeof(cmdString) - 1));/* Reset all the tokenized arguments: */memset ((void *)&tokenizedArgs, 0, sizeof(tokenizedArgs));argIndex      = 0;ptrCLICommand = (char*)&cmdString[0];/* comment lines found - ignore the whole line*/if (cmdString[0]=='%') {CLI_write ("Skipped\n");continue;}/* Set the CLI status: */cliStatus = -1;/* The command has been entered we now tokenize the command message */while (1){/* Tokenize the arguments: */tokenizedArgs[argIndex] = strtok(ptrCLICommand, delimitter);if (tokenizedArgs[argIndex] == NULL)break;/* Increment the argument index: */argIndex++;if (argIndex >= CLI_MAX_ARGS)break;/* Reset the command string */ptrCLICommand = NULL;}/* Were we able to tokenize the CLI command? */if (argIndex == 0)continue;/* Cycle through all the registered CLI commands: */for (index = 0; index < gCLI.numCLICommands; index++){ptrCLICommandEntry = &gCLI.cfg.tableEntry[index];/* Do we have a match? */if (strcmp(ptrCLICommandEntry->cmd, tokenizedArgs[0]) == 0){/* YES: Pass this to the CLI registered function */cliStatus = ptrCLICommandEntry->cmdHandlerFxn (argIndex, tokenizedArgs);if (cliStatus == 0){CLI_write ("Done\n");}else{CLI_write ("Error %d\n", cliStatus);}break;}}/* Did we get a matching CLI command? */if (index == gCLI.numCLICommands){/* NO matching command found. Is the mmWave extension enabled? */if (gCLI.cfg.enableMMWaveExtension == 1U){/* Yes: Pass this to the mmWave extension handler */cliStatus = CLI_MMWaveExtensionHandler (argIndex, tokenizedArgs);}/* Was the CLI command found? */if (cliStatus == -1){/* No: The command was still not found */CLI_write ("'%s' is not recognized as a CLI command\n", tokenizedArgs[0]);}}}
}

在这里会进入一个死循环

	/* Loop around forever: */while (1){

该循环中 先发送头文字 CLI_write (gCLI.cfg.cliPrompt); 然后一直读取UART串口UART_read (gCLI.cfg.cliUartHandle, &cmdString[0], (sizeof(cmdString) - 1));
接收串口以后 开始判断命令并调用相应的函数
如果命令为'%'开头则跳过
最后分割字符串、比较字符串 再执行相应函数

覆写CLI控制指令

在out_of_box的demo工程中 可以通过覆写CLI初始化部分函数来达到跳过CLI配置命令的目的

CLI重构

根据官方手册 跳过CLI配置需要以下几个步骤:
在这里插入图片描述
但是按照这个来 完全没用
会在配置时报错参数无效/冲突等等
但是 首先还是覆写CLI初始化函数 使其只执行我们定义的函数

void MmwDemo_CLIInit (uint8_t taskPriority)
{if(Remix_Flag){MmwDemo_sensorConfig_task();}else{CLI_Cfg     cliCfg;char        demoBanner[256];uint32_t    cnt;/* Create Demo Banner to be printed out by CLI */sprintf(&demoBanner[0],"******************************************\n" \"xWR64xx MMW Demo %02d.%02d.%02d.%02d\n"  \"******************************************\n",MMWAVE_SDK_VERSION_MAJOR,MMWAVE_SDK_VERSION_MINOR,MMWAVE_SDK_VERSION_BUGFIX,MMWAVE_SDK_VERSION_BUILD);
...
...

在我们自定义的函数中 仿照命令配置函数的方式来写各个配置函数 同时 通过上位机确定想要的配置:
当然 无关紧要的函数可以省去

void MmwDemo_sensorConfig_task(void)
{int32_t         errCode;/* Sanity Check: We need the mmWave handle to work. */if (gMmwMCB.ctrlHandle == NULL){return;}/* Initialize the mmWave control configuration: */memset ((void *)&gMmwMCB.cfg.ctrlCfg, 0, sizeof(MMWave_CtrlCfg));mmwave_freq_scale_factor = SOC_getDeviceRFFreqScaleFactor(gMmwMCB.socHandle, &errCode);if(errCode < 0){return;}CLI_Remix_sensorStop();CLI_Remix_flushCfg();CLI_Remix_dfeDataOutputMode(1);CLI_Remix_channelCfg(15,7,0);CLI_Remix_adcCfg(2,1);CLI_Remix_adcbufCfg(-1,0,1,1,1);CLI_Remix_profileCfg(0,60,47,7,57.14,0,0,70,1,272,5535,0,0,158);CLI_Remix_chirpCfg(0,0,0,0,0,0,0,1);CLI_Remix_chirpCfg(1,1,0,0,0,0,0,2);CLI_Remix_chirpCfg(2,2,0,0,0,0,0,4);CLI_Remix_frameCfg(0,2,16,0,50,1,0);CLI_Remix_lowPower(0,0);CLI_Remix_guiMonitor(-1,1,1,0,0,0,1);CLI_Remix_cfarCfg(-1,0,2,8,4,3,0,15,1);CLI_Remix_cfarCfg(-1,1,0,4,2,3,1,15,1);CLI_Remix_multiObjBeamForming(-1,1,0.5);CLI_Remix_clutterRemoval(-1,0);CLI_Remix_calibDcRangeSig(-1,0,-5,8,256);CLI_Remix_extendedMaxVelocity(-1,0);CLI_Remix_lvdsStreamCfg(-1,0,0,0);CLI_Remix_compRangeBiasAndRxChanPhase(0.0,1,0,-1,0,1,0,-1,0,1,0,-1,0,1,0,-1,0,1,0,-1,0,1,0,-1,0);CLI_Remix_measureRangeBiasAndRxChanPhase(0,1.5,0.2);CLI_Remix_CQRxSatMonitor(0,3,5,121,0);CLI_Remix_CQSigImgMonitor(0,89,6);CLI_Remix_analogMonitor(0,0);CLI_Remix_aoaFovCfg(-1,-90,90,-90,90);CLI_Remix_cfarFovCfg(-1,0,0,9.48);CLI_Remix_cfarFovCfg(-1,1,-4,4.00);CLI_Remix_calibData(0,0,0);CLI_Remix_sensorStart();return;
}

另外 正如之前所说 内部SDK的函数在覆写时 直接把配置参数给到我们用户自定义的结构体gMmwMCB中即可
比如配置chirp profile frame的函数:

void CLI_Remix_profileCfg(int a1,float a2,float a3,float a4,float a5,int a6,int a7,float a8,float a9,int a10,int a11,int a12,int a13,int a14)
{rlProfileCfg_t          profileCfg;uint8_t                 index;int32_t                 errCode;MMWave_ProfileHandle    profileHandle;MMWave_ProfileHandle*   ptrBaseCfgProfileHandle;/* Sanity Check: Profile configuration is valid only for the Frame orAdvanced Frame Mode: */if ((gMmwMCB.cfg.ctrlCfg.dfeDataOutputMode != MMWave_DFEDataOutputMode_FRAME) &&(gMmwMCB.cfg.ctrlCfg.dfeDataOutputMode != MMWave_DFEDataOutputMode_ADVANCED_FRAME)){//CLI_write ("Error: Configuration is valid only if the DFE Output Mode is Frame or Advanced Frame\n");return;}if (gMmwMCB.cfg.ctrlCfg.dfeDataOutputMode == MMWave_DFEDataOutputMode_FRAME){ptrBaseCfgProfileHandle = &gMmwMCB.cfg.ctrlCfg.u.frameCfg.profileHandle[0U];}else{ptrBaseCfgProfileHandle = &gMmwMCB.cfg.ctrlCfg.u.advancedFrameCfg.profileHandle[0U];}/* Initialize the profile configuration: */memset ((void *)&profileCfg, 0, sizeof(rlProfileCfg_t));/* Populate the profile configuration: */profileCfg.profileId             = a1;/* Translate from GHz to [1 LSB = gCLI_mmwave_freq_scale_factor * 1e9 / 2^26 Hz] units* of mmwavelink format */profileCfg.startFreqConst        = (uint32_t) (((float)a2) * (1U << 26) /mmwave_freq_scale_factor);/* Translate below times from us to [1 LSB = 10 ns] units of mmwavelink format */profileCfg.idleTimeConst         = (uint32_t)((float)a3 * 1000 / 10);profileCfg.adcStartTimeConst     = (uint32_t)((float)a4 * 1000 / 10);profileCfg.rampEndTime           = (uint32_t)((float)a5 * 1000 / 10);profileCfg.txOutPowerBackoffCode = a6;profileCfg.txPhaseShifter        = a7;/* Translate from MHz/us to [1 LSB = (gCLI_mmwave_freq_scale_factor * 1e6 * 900) / 2^26 kHz/uS]* units of mmwavelink format */profileCfg.freqSlopeConst        =     (int16_t)((float)a8 * (1U << 26) /((mmwave_freq_scale_factor * 1e3) * 900.0));/* Translate from us to [1 LSB = 10 ns] units of mmwavelink format */profileCfg.txStartTime           = (int32_t)(((float)a9) * 1000 / 10);profileCfg.numAdcSamples         = a10;profileCfg.digOutSampleRate      = a11;profileCfg.hpfCornerFreq1        = a12;profileCfg.hpfCornerFreq2        = a13;profileCfg.rxGain                = a14;/* Search for a free space in the mmWave configuration block: */for (index = 0U; index < MMWAVE_MAX_PROFILE; index++){/* Did we get a free entry? */if (ptrBaseCfgProfileHandle[index] == NULL){/* YES: We can add the profile. */break;}}if (index == MMWAVE_MAX_PROFILE){/* Error: All the profiles have been exhausted */return;}/* Add the profile to the mmWave module: */profileHandle = MMWave_addProfile (gMmwMCB.ctrlHandle, &profileCfg, &errCode);if (profileHandle == NULL){/* Error: Unable to add the profile. Return the error code back */return;}/* Record the profile: */ptrBaseCfgProfileHandle[index] = profileHandle;return;
}
void CLI_Remix_chirpCfg(int a1,int a2,int a3,float a4,float a5,float a6,float a7,int a8)
{rlChirpCfg_t            chirpCfg;MMWave_ProfileHandle    profileHandle;int32_t                 errCode;/* Sanity Check: Chirp configuration is valid only for the Frame orAdvanced Frame Mode: */if ((gMmwMCB.cfg.ctrlCfg.dfeDataOutputMode != MMWave_DFEDataOutputMode_FRAME) &&(gMmwMCB.cfg.ctrlCfg.dfeDataOutputMode != MMWave_DFEDataOutputMode_ADVANCED_FRAME)){//CLI_write ("Error: Configuration is valid only if the DFE Output Mode is Chirp\n");return;}/* Initialize the chirp configuration: */memset ((void *)&chirpCfg, 0, sizeof(rlChirpCfg_t));/* Populate the chirp configuration: */chirpCfg.chirpStartIdx   = a1;chirpCfg.chirpEndIdx     = a2;chirpCfg.profileId       = a3;/* Translate from Hz to number of [1 LSB = (gCLI_mmwave_freq_scale_factor * 1e9) / 2^26 Hz]* units of mmwavelink format */chirpCfg.startFreqVar    = (uint32_t) ((float)a4 * (1U << 26) /(mmwave_freq_scale_factor * 1e9));/* Translate from KHz/us to number of [1 LSB = (gCLI_mmwave_freq_scale_factor * 1e6) * 900 /2^26 KHz/us]* units of mmwavelink format */chirpCfg.freqSlopeVar    = (uint16_t) ((float)a5 * (1U << 26) /((mmwave_freq_scale_factor * 1e6) * 900.0));/* Translate from us to [1 LSB = 10ns] units of mmwavelink format */chirpCfg.idleTimeVar     = (uint32_t)((float)a6 * 1000.0 / 10.0);/* Translate from us to [1 LSB = 10ns] units of mmwavelink format */chirpCfg.adcStartTimeVar = (uint32_t)((float)a7 * 1000.0 / 10.0);chirpCfg.txEnable        = a8;/* Get the profile handle to which the chirp is to be added: */if (MMWave_getProfileHandle (gMmwMCB.ctrlHandle, chirpCfg.profileId,&profileHandle, &errCode) < 0){/* Error: Unable to get the profile handle. Return the error code */return;}/* Add the chirp to the profile */if (MMWave_addChirp (profileHandle, &chirpCfg, &errCode) == NULL){/* Error: Unable to add the chirp. Return the error code. */return;}return;
}
void CLI_Remix_frameCfg(int a1,int a2,int a3,int a4,float a5,int a6,float a7)
{rlFrameCfg_t    frameCfg;/* Sanity Check: Frame configuration is valid only for the Frame orAdvanced Frame Mode: */if (gMmwMCB.cfg.ctrlCfg.dfeDataOutputMode != MMWave_DFEDataOutputMode_FRAME){//CLI_write ("Error: Configuration is valid only if the DFE Output Mode is Chirp\n");return;}/* Initialize the frame configuration: */memset ((void *)&frameCfg, 0, sizeof(rlFrameCfg_t));/* Populate the frame configuration: */frameCfg.chirpStartIdx      = a1;frameCfg.chirpEndIdx        = a2;frameCfg.numLoops           = a3;frameCfg.numFrames          = a4;frameCfg.framePeriodicity   = (uint32_t)((float)a5 * 1000000 / 5);frameCfg.triggerSelect      = a6;frameCfg.frameTriggerDelay  = (uint32_t)((float)a7 * 1000000 / 5);/* Save Configuration to use later */memcpy((void *)&gMmwMCB.cfg.ctrlCfg.u.frameCfg.frameCfg, (void *)&frameCfg, sizeof(rlFrameCfg_t));return;
}

配置完成后 调用MmwDemo_CLISensorStart即可 但是这个函数会将CLI内部结构体gCLI的值读到用户结构体中 如果没有用CLI来配置的话 内部结构体时空的 所以得重构MmwDemo_CLISensorStart

MmwDemo_CLISensorStart函数重构

在此函数中 由于我们先前已经将所有的配置覆写了 并且赋值到用户结构体中 所以我们只需要将CLI_getMMWaveExtensionConfigCLI_getMMWaveExtensionOpenConfig注释掉即可
这是由于 原本的内部函数会将参数写入内部结构体 而我们的函数改写以后不会写到内部结构体中
如果又采用以上两个函数来进行参数获取 则获取到的参数为未配置之前的参数
如:

int CLI_Remix_sensorStart(void)
{bool doReconfig = true;int32_t     retVal = 0;/************************************************************************************ Do sensor state management to influence the sensor actions***********************************************************************************//* Error checking initial state: no partial config is alloweduntil the first sucessful sensor start state */if ((gMmwMCB.sensorState == MmwDemo_SensorState_INIT) ||(gMmwMCB.sensorState == MmwDemo_SensorState_OPENED)){MMWave_CtrlCfg ctrlCfg;/* need to get number of sub-frames so that next function to check* pending state can work *///CLI_getMMWaveExtensionConfig (&ctrlCfg);memcpy((void*)&ctrlCfg,(void*)&gMmwMCB.cfg.ctrlCfg,sizeof(MMWave_CtrlCfg));gMmwMCB.dataPathObj.objDetCommonCfg.preStartCommonCfg.numSubFrames =MmwDemo_RFParser_getNumSubFrames(&ctrlCfg);if (MmwDemo_isAllCfgInPendingState() == 0){System_printf ("Error: Full configuration must be provided before sensor can be started ""the first time\n");/* Although not strictly needed, bring back to the initial value since we* are rejecting this first time configuration, prevents misleading debug. */gMmwMCB.dataPathObj.objDetCommonCfg.preStartCommonCfg.numSubFrames = 0;return -1;}}if (gMmwMCB.sensorState == MmwDemo_SensorState_STARTED){System_printf ("Ignored: Sensor is already started\n");return 0;}if (doReconfig == false){/* User intends to issue sensor start without config, check if noconfig was issued after stop and generate error if this is the case. */if (! MmwDemo_isAllCfgInNonPendingState()){/* Message user differently if all config was issued or partial config wasissued. */if (MmwDemo_isAllCfgInPendingState()){System_printf ("Error: You have provided complete new configuration, ""issue \"sensorStart\" (without argument) if you want it to ""take effect\n");}else{System_printf ("Error: You have provided partial configuration between stop and this ""command and partial configuration cannot be undone.""Issue the full configuration and do \"sensorStart\" \n");}return -1;}}else{/* User intends to issue sensor start with full config, check if all configwas issued after stop and generate error if  is the case. */MMWave_CtrlCfg ctrlCfg;/* need to get number of sub-frames so that next function to check* pending state can work *///CLI_getMMWaveExtensionConfig (&ctrlCfg);memcpy((void*)&ctrlCfg,(void*)&gMmwMCB.cfg.ctrlCfg,sizeof(MMWave_CtrlCfg));gMmwMCB.dataPathObj.objDetCommonCfg.preStartCommonCfg.numSubFrames =MmwDemo_RFParser_getNumSubFrames(&ctrlCfg);if (MmwDemo_isAllCfgInPendingState() == 0){/* Message user differently if no config was issued or partial config wasissued. */if (MmwDemo_isAllCfgInNonPendingState()){System_printf ("Error: You have provided no configuration, ""issue \"sensorStart 0\" OR provide ""full configuration and issue \"sensorStart\"\n");}else{System_printf ("Error: You have provided partial configuration between stop and this ""command and partial configuration cannot be undone.""Issue the full configuration and do \"sensorStart\" \n");}/* Although not strictly needed, bring back to the initial value since we* are rejecting this first time configuration, prevents misleading debug. */gMmwMCB.dataPathObj.objDetCommonCfg.preStartCommonCfg.numSubFrames = 0;return -1;}}/************************************************************************************ Retreive and check mmwave Open related config before calling openSensor***********************************************************************************//*  Fill demo's MCB mmWave openCfg structure from the CLI configs*/if (gMmwMCB.sensorState == MmwDemo_SensorState_INIT){/* Get the open configuration: *///CLI_getMMWaveExtensionOpenConfig (&gMmwMCB.cfg.openCfg);/* call sensor open */retVal = MmwDemo_openSensor(true);if(retVal != 0){return -1;}gMmwMCB.sensorState = MmwDemo_SensorState_OPENED;}else{/* openCfg related configurations like chCfg, lowPowerMode, adcCfg* are only used on the first sensor start. If they are different* on a subsequent sensor start, then generate a fatal error* so the user does not think that the new (changed) configuration* takes effect, the board needs to be reboot for the new* configuration to be applied.*/MMWave_OpenCfg openCfg;//CLI_getMMWaveExtensionOpenConfig (&openCfg);memcpy((void*)&openCfg,(void*)&gMmwMCB.cfg.openCfg,sizeof(MMWave_OpenCfg));/* Compare openCfg->chCfg*/if(memcmp((void *)&gMmwMCB.cfg.openCfg.chCfg, (void *)&openCfg.chCfg,sizeof(rlChanCfg_t)) != 0){MmwDemo_debugAssert(0);}/* Compare openCfg->lowPowerMode*/if(memcmp((void *)&gMmwMCB.cfg.openCfg.lowPowerMode, (void *)&openCfg.lowPowerMode,sizeof(rlLowPowerModeCfg_t)) != 0){MmwDemo_debugAssert(0);}/* Compare openCfg->adcOutCfg*/if(memcmp((void *)&gMmwMCB.cfg.openCfg.adcOutCfg, (void *)&openCfg.adcOutCfg,sizeof(rlAdcOutCfg_t)) != 0){MmwDemo_debugAssert(0);}}/************************************************************************************ Retrieve mmwave Control related config before calling startSensor***********************************************************************************//* Get the mmWave ctrlCfg from the CLI mmWave Extension */if(doReconfig){/* if MmwDemo_openSensor has non-first time related processing, call here again*//* call sensor config *///CLI_getMMWaveExtensionConfig (&gMmwMCB.cfg.ctrlCfg);retVal = MmwDemo_configSensor();if(retVal != 0){return -1;}}retVal = MmwDemo_startSensor();if(retVal != 0){return -1;}/************************************************************************************ Set the state***********************************************************************************/gMmwMCB.sensorState = MmwDemo_SensorState_STARTED;return 0;
}

附录:结构框架

雷达基本原理叙述

雷达工作原理是上电-发送chirps-帧结束-处理-上电循环
一个Frame,首先是信号发送,比如96个chirp就顺次发出去,然后接收回来,混频滤波,ADC采样,这些都是射频模块的东西。射频完成之后,FFT,CFAR,DOA这些就是信号处理的东西。然后输出给那个结构体,就是当前帧获得的点云了。
在这里插入图片描述
在射频发送阶段 一个frame发送若干个chirp 也就是上图左上角
第一个绿色点为frame start 第二个绿色点为frame end
其中发送若干chirps(小三角形)
chirps的个数称为numLoops(代码中 rlFrameCfg_t结构体)
在mmwave studio上位机中 则称为 no of chirp loops

frame end 到 周期结束的时间为计算时间 称为inter frame period
在这里插入图片描述
frame start到循环结束的时间称为framePeriodicity(代码中 rlFrameCfg_t结构体)
在mmwave studio上位机中 则称为 Periodicity

如下图frame配置部分
在这里插入图片描述
在inter frame Periodicity时间内(比如这里整个周期是55ms)
就是用于计算和处理的时间 一定比55ms要小
如果chirps很多的话 那么计算时间就会减小

如果是处理点云数据 则只需要每一帧计算一次点云即可
计算出当前帧的xyz坐标和速度 以及保存时间戳

雷达天线排列位置

在工业雷达包:

C:\ti\mmwave_industrial_toolbox_4_12_0\antennas\ant_rad_patterns

路径下 有各个EVM开发板的天线排列说明
同样的 EVM手册中也有
如IWR6843AOPEVM:
在这里插入图片描述
在这里插入图片描述
其天线的间距等等位于数据手册:
在这里插入图片描述

芯片框架

IWR6843AOP可以分成三个主要部分及多个外设
BSS:雷达前端部分
MSS:cortex-rf4内核 主要用于控制
DSS: DSP C674内核 主要用于信号处理
外设:UART GPIO DPM HWA等

在这里插入图片描述
其中 大部分外设可以被MSS或DSS调用
另外 雷达前端BSS部分在SDK里由MMWave API调用

代码框架上 可以分成两个代码 MSS和DSS 两个代码同时运行 通过某些外设进行同步 协同运作

但也可以只跑一个内核 在仅MSS模式下 依旧可以调用某些用于信号处理的外设 demo代码就是如此

如下图为demo代码流程
在这里插入图片描述

Demo工程功能

IWR6843AOP的开箱工程是根据IWR6843AOPEVM开发板来的
该工程可以将IWR6843AOP的两个串口利用起来 实现的功能主要是两个方面:
通过115200波特率的串口配置参数 建立握手协议
通过115200*8的串口输出雷达数据
此工程需要匹配TI官方的上位机:mmWave_Demo_Visualizer_3.6.0来使用
该上位机可以在连接串口后自动化操作 并且对雷达数据可视化
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
关于雷达参数配置 则在SDK的mmw\profiles目录下
言简意赅 可以直接更改该目录下的文件参数来达到配置雷达参数的目的
在这里插入图片描述

但这种方法不利于直接更改 每次用上位机运行后的参数是固定的(上位机运行需要SDK环境) 所以也可以在代码中写死 本文探讨的就是这个方向

CCS工程导入

首先 在工业雷达包目录下找到该工程设置

C:\ti\mmwave_industrial_toolbox_4_12_0\labs\Out_Of_Box_Demo\src\xwr6843AOP

使用CCS的import project功能导入工程后 即可完成环境搭建
在这里插入图片描述
这里用到的SDK最新版为3.6版本

工程叙述

以下来自官方文档 可以直接跳过

Software Tasks

The demo consists of the following (SYSBIOS) tasks:

MmwDemo_initTask. This task is created/launched by main and is a one-time active task whose main functionality is to initialize drivers (<driver>_init), MMWave module (MMWave_init), DPM module (DPM_init), open UART and data path related drivers (EDMA, HWA), and create/launch the following tasks (the CLI_task is launched indirectly by calling CLI_open).
CLI_task. This command line interface task provides a simplified 'shell' interface which allows the configuration of the BSS via the mmWave interface (MMWave_config). It parses input CLI configuration commands like chirp profile and GUI configuration. When sensor start CLI command is parsed, all actions related to starting sensor and starting the processing the data path are taken. When sensor stop CLI command is parsed, all actions related to stopping the sensor and stopping the processing of the data path are taken
MmwDemo_mmWaveCtrlTask. This task is used to provide an execution context for the mmWave control, it calls in an endless loop the MMWave_execute API.
MmwDemo_DPC_ObjectDetection_dpmTask. This task is used to provide an execution context for DPM (Data Path Manager) execution, it calls in an endless loop the DPM_execute API. In this context, all of the registered object detection DPC (Data Path Chain) APIs like configuration, control and execute will take place. In this task. When the DPC's execute API produces the detected objects and other results, they are transmitted out of the UART port for display using the visualizer.

Data Path

在这里插入图片描述
Top Level Data Path Processing Chain
在这里插入图片描述
Top Level Data Path Timing

The data path processing consists of taking ADC samples as input and producing detected objects (point-cloud and other information) to be shipped out of UART port to the PC. The algorithm processing is realized using the DPM registered Object Detection DPC. The details of the processing in DPC can be seen from the following doxygen documentation:
ti/datapath/dpc/objectdetection/objdethwa/docs/doxygen/html/index.html

Output information sent to host

Output packets with the detection information are sent out every frame through the UART. Each packet consists of the header MmwDemo_output_message_header_t and the number of TLV items containing various data information with types enumerated in MmwDemo_output_message_type_e. The numerical values of the types can be found in mmw_output.h. Each TLV item consists of type, length (MmwDemo_output_message_tl_t) and payload information. The structure of the output packet is illustrated in the following figure. Since the length of the packet depends on the number of detected objects it can vary from frame to frame. The end of the packet is padded so that the total packet length is always multiple of 32 Bytes.

在这里插入图片描述
Output packet structure sent to UART
The following subsections describe the structure of each TLV.

List of detected objects
Type: (MMWDEMO_OUTPUT_MSG_DETECTED_POINTS)Length: (Number of detected objects) x (size of DPIF_PointCloudCartesian_t)Value: Array of detected objects. The information of each detected object is as per the structure DPIF_PointCloudCartesian_t. When the number of detected objects is zero, this TLV item is not sent. The maximum number of objects that can be detected in a sub-frame/frame is DPC_OBJDET_MAX_NUM_OBJECTS.The orientation of x,y and z axes relative to the sensor is as per the following figure. (Note: The antenna arrangement in the figure is shown for standard EVM (see gAntDef_default) as an example but the figure is applicable for any antenna arrangement.)

在这里插入图片描述
Coordinate Geometry
The whole detected objects TLV structure is illustrated in figure below.
在这里插入图片描述
Detected objects TLV

Range profile
Type: (MMWDEMO_OUTPUT_MSG_RANGE_PROFILE)Length: (Range FFT size) x (size of uint16_t)Value: Array of profile points at 0th Doppler (stationary objects). The points represent the sum of log2 magnitudes of received antennas expressed in Q9 format.Noise floor profile
Type: (MMWDEMO_OUTPUT_MSG_NOISE_PROFILE)Length: (Range FFT size) x (size of uint16_t)Value: This is the same format as range profile but the profile is at the maximum Doppler bin (maximum speed objects). In general for stationary scene, there would be no objects or clutter at maximum speed so the range profile at such speed represents the receiver noise floor.
Azimuth static heatmap
Type: (MMWDEMO_OUTPUT_MSG_AZIMUT_STATIC_HEAT_MAP)Length: (Range FFT size) x (Number of "azimuth" virtual antennas) (size of cmplx16ImRe_t_)Value: Array DPU_AoAProcHWA_HW_Resources::azimuthStaticHeatMap. The antenna data are complex symbols, with imaginary first and real second in the following order:
Imag(ant 0, range 0), Real(ant 0, range 0),...,Imag(ant N-1, range 0),Real(ant N-1, range 0)...Imag(ant 0, range R-1), Real(ant 0, range R-1),...,Imag(ant N-1, range R-1),Real(ant N-1, range R-1)

Note that the number of virtual antennas is equal to the number of “azimuth” virtual antennas. The antenna symbols are arranged in the order as they occur at the input to azimuth FFT. Based on this data the static azimuth heat map could be constructed by the GUI running on the host.

Azimuth/Elevation static heatmap
Type: (MMWDEMO_OUTPUT_MSG_AZIMUT_ELEVATION_STATIC_HEAT_MAP)Length: (Range FFT size) x (Number of all virtual antennas) (size of cmplx16ImRe_t_)Value: Array DPU_AoAProcHWA_HW_Resources::azimuthStaticHeatMap. The antenna data are complex symbols, with imaginary first and real second in the following order:
 Imag(ant 0, range 0), Real(ant 0, range 0),...,Imag(ant N-1, range 0),Real(ant N-1, range 0)...Imag(ant 0, range R-1), Real(ant 0, range R-1),...,Imag(ant N-1, range R-1),Real(ant N-1, range R-1)

Note that the number of virtual antennas is equal to the total number of active virtual antennas. The antenna symbols are arranged in the order as they occur in the radar cube matrix. This TLV is sent by AOP version of MMW demo, that uses AOA2D DPU. Based on this data the static azimuth or elevation heat map could be constructed by the GUI running on the host.

Range/Doppler heatmap
Type: (MMWDEMO_OUTPUT_MSG_RANGE_DOPPLER_HEAT_MAP)Length: (Range FFT size) x (Doppler FFT size) (size of uint16_t)Value: Detection matrix DPIF_DetMatrix::data. The order is :
 X(range bin 0, Doppler bin 0),...,X(range bin 0, Doppler bin D-1),...X(range bin R-1, Doppler bin 0),...,X(range bin R-1, Doppler bin D-1)
Stats information
Type: (MMWDEMO_OUTPUT_MSG_STATS )Length: (size of MmwDemo_output_message_stats_t)Value: Timing information as per MmwDemo_output_message_stats_t. See timing diagram below related to the stats.

在这里插入图片描述
Processing timing

Note:The MmwDemo_output_message_stats_t::interChirpProcessingMargin is not computed (it is always set to 0). This is because there is no CPU involvement in the 1D processing (only HWA and EDMA are involved), and it is not possible to know how much margin is there in chirp processing without CPU being notified at every chirp when processing begins (chirp event) and when the HWA-EDMA computation ends. The CPU is intentionally kept free during 1D processing because a real application may use this time for doing some post-processing algorithm execution.
While the MmwDemo_output_message_stats_t::interFrameProcessingTime reported will be of the current sub-frame/frame, the MmwDemo_output_message_stats_t::interFrameProcessingMargin and MmwDemo_output_message_stats_t::transmitOutputTime will be of the previous sub-frame (of the same MmwDemo_output_message_header_t::subFrameNumber as that of the current sub-frame) or of the previous frame.
The MmwDemo_output_message_stats_t::interFrameProcessingMargin excludes the UART transmission time (available as MmwDemo_output_message_stats_t::transmitOutputTime). This is done intentionally to inform the user of a genuine inter-frame processing margin without being influenced by a slow transport like UART, this transport time can be significantly longer for example when streaming out debug information like heat maps. Also, in a real product deployment, higher speed interfaces (e.g LVDS) are likely to be used instead of UART. User can calculate the margin that includes transport overhead (say to determine the max frame rate that a particular demo configuration will allow) using the stats because they also contain the UART transmission time.

The CLI command “guMonitor” specifies which TLV element will be sent out within the output packet. The arguments of the CLI command are stored in the structure MmwDemo_GuiMonSel_t.

Side information of detected objects
Type: (MMWDEMO_OUTPUT_MSG_DETECTED_POINTS_SIDE_INFO)Length: (Number of detected objects) x (size of DPIF_PointCloudSideInfo_t)Value: Array of detected objects side information. The side information of each detected object is as per the structure DPIF_PointCloudSideInfo_t). When the number of detected objects is zero, this TLV item is not sent.
Temperature Stats
Type: (MMWDEMO_OUTPUT_MSG_TEMPERATURE_STATS)Length: (size of MmwDemo_temperatureStats_t)Value: Structure of detailed temperature report as obtained from Radar front end. MmwDemo_temperatureStats_t::tempReportValid is set to return value of rlRfGetTemperatureReport. If MmwDemo_temperatureStats_t::tempReportValid is 0, values in MmwDemo_temperatureStats_t::temperatureReport are valid else they should be ignored. This TLV is sent along with Stats TLV described in Stats information
Range Bias and Rx Channel Gain/Phase Measurement and Compensation

Because of imperfections in antenna layouts on the board, RF delays in SOC, etc, there is need to calibrate the sensor to compensate for bias in the range estimation and receive channel gain and phase imperfections. The following figure illustrates the calibration procedure.

在这里插入图片描述
Calibration procedure ladder diagram

The calibration procedure includes the following steps:Set a strong target like corner reflector at the distance of X meter (X less than 50 cm is not recommended) at boresight.
Set the following command in the configuration profile in .../profiles/profile_calibration.cfg, to reflect the position X as follows: where D (in meters) is the distance of window around X where the peak will be searched. The purpose of the search window is to allow the test environment from not being overly constrained say because it may not be possible to clear it of all reflectors that may be stronger than the one used for calibration. The window size is recommended to be at least the distance equivalent of a few range bins. One range bin for the calibration profile (profile_calibration.cfg) is about 5 cm. The first argument "1" is to enable the measurement. The stated configuration profile (.cfg) must be used otherwise the calibration may not work as expected (this profile ensures all transmit and receive antennas are engaged among other things needed for calibration).measureRangeBiasAndRxChanPhase 1 X D
Start the sensor with the configuration file.
In the configuration file, the measurement is enabled because of which the DPC will be configured to perform the measurement and generate the measurement result (DPU_AoAProc_compRxChannelBiasCfg_t) in its result structure (DPC_ObjectDetection_ExecuteResult_t::compRxChanBiasMeasurement), the measurement results are written out on the CLI port (MmwDemo_measurementResultOutput) in the format below: For details of how DPC performs the measurement, see the DPC documentation.compRangeBiasAndRxChanPhase <rangeBias> <Re(0,0)> <Im(0,0)> <Re(0,1)> <Im(0,1)> ... <Re(0,R-1)> <Im(0,R-1)> <Re(1,0)> <Im(1,0)> ... <Re(T-1,R-1)> <Im(T-1,R-1)>
The command printed out on the CLI now can be copied and pasted in any configuration file for correction purposes. This configuration will be passed to the DPC for the purpose of applying compensation during angle computation, the details of this can be seen in the DPC documentation. If compensation is not desired, the following command should be given (depending on the EVM and antenna arrangement) Above sets the range bias to 0 and the phase coefficients to unity so that there is no correction. Note the two commands must always be given in any configuration file, typically the measure commmand will be disabled when the correction command is the desired one.For ISK EVM:compRangeBiasAndRxChanPhase 0.0   1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 For AOP EVMcompRangeBiasAndRxChanPhase 0.0   1 0 -1 0 1 0 -1 0 1 0 -1 0 1 0 -1 0 1 0 -1 0 1 0 -1 0 
Streaming data over LVDS
The LVDS streaming feature enables the streaming of HW data (a combination of ADC/CP/CQ data) and/or user specific SW data through LVDS interface. The streaming is done mostly by the CBUFF and EDMA peripherals with minimal CPU intervention. The streaming is configured through the MmwDemo_LvdsStreamCfg_t CLI command which allows control of HSI header, enable/disable of HW and SW data and data format choice for the HW data. The choices for data formats for HW data are:MMW_DEMO_LVDS_STREAM_CFG_DATAFMT_DISABLED
MMW_DEMO_LVDS_STREAM_CFG_DATAFMT_ADC
MMW_DEMO_LVDS_STREAM_CFG_DATAFMT_CP_ADC_CQ
In order to see the high-level data format details corresponding to the above data format configurations, refer to the corresponding slides in ti\drivers\cbuff\docs\CBUFF_Transfers.pptxWhen HW data LVDS streaming is enabled, the ADC/CP/CQ data is streamed per chirp on every chirp event. When SW data streaming is enabled, it is streamed during inter-frame period after the list of detected objects for that frame is computed. The SW data streamed every frame/sub-frame is composed of the following in time:HSI header (HSIHeader_t): refer to HSI module for details.
User data header: MmwDemo_LVDSUserDataHeader
User data payloads:
Point-cloud information as a list : DPIF_PointCloudCartesian_t x number of detected objects
Point-cloud side information as a list : DPIF_PointCloudSideInfo_t x number of detected objects

The format of the SW data streamed is shown in the following figure:
在这里插入图片描述
LVDS SW Data format

Note:Only single-chirp formats are allowed, multi-chirp is not supported.
When number of objects detected in frame/sub-frame is 0, there is no transmission beyond the user data header.
For HW data, the inter-chirp duration should be sufficient to stream out the desired amount of data. For example, if the HW data-format is ADC and HSI header is enabled, then the total amount of data generated per chirp is:
(numAdcSamples * numRxChannels * 4 (size of complex sample) + 52 [sizeof(HSIDataCardHeader_t) + sizeof(HSISDKHeader_t)] ) rounded up to multiples of 256 [=sizeof(HSIHeader_t)] bytes.
The chirp time Tc in us = idle time + ramp end time in the profile configuration. For n-lane LVDS with each lane at a maximum of B Mbps,
maximum number of bytes that can be send per chirp = Tc * n * B / 8 which should be greater than the total amount of data generated per chirp i.e
Tc * n * B / 8 >= round-up(numAdcSamples * numRxChannels * 4 + 52, 256).
E.g if n = 2, B = 600 Mbps, idle time = 7 us, ramp end time = 44 us, numAdcSamples = 512, numRxChannels = 4, then 7650 >= 8448 is violated so this configuration will not work. If the idle-time is doubled in the above example, then we have 8700 > 8448, so this configuration will work.
For SW data, the number of bytes to transmit each sub-frame/frame is:
52 [sizeof(HSIDataCardHeader_t) + sizeof(HSISDKHeader_t)] + sizeof(MmwDemo_LVDSUserDataHeader_t) [=8] +
number of detected objects (Nd) * { sizeof(DPIF_PointCloudCartesian_t) [=16] + sizeof(DPIF_PointCloudSideInfo_t) [=4] } rounded up to multiples of 256 [=sizeof(HSIHeader_t)] bytes.
or X = round-up(60 + Nd * 20, 256). So the time to transmit this data will be
X * 8 / (n*B) us. The maximum number of objects (Ndmax) that can be detected is defined in the DPC (DPC_OBJDET_MAX_NUM_OBJECTS). So if Ndmax = 500, then time to transmit SW data is 68 us. Because we parallelize this transmission with the much slower UART transmission, and because UART transmission is also sending at least the same amount of information as the LVDS, the LVDS transmission time will not add any burdens on the processing budget beyond the overhead of reconfiguring and activating the CBUFF session (this overhead is likely bigger than the time to transmit).
The total amount of data to be transmitted in a HW or SW packet must be greater than the minimum required by CBUFF, which is 64 bytes or 32 CBUFF Units (this is the definition CBUFF_MIN_TRANSFER_SIZE_CBUFF_UNITS in the CBUFF driver implementation). If this threshold condition is violated, the CBUFF driver will return an error during configuration and the demo will generate a fatal exception as a result. When HSI header is enabled, the total transfer size is ensured to be at least 256 bytes, which satisfies the minimum. If HSI header is disabled, for the HW session, this means that numAdcSamples * numRxChannels * 4 >= 64. Although mmwavelink allows minimum number of ADC samples to be 2, the demo is supported for numAdcSamples >= 64. So HSI header is not required to be enabled for HW only case. But if SW session is enabled, without the HSI header, the bytes in each packet will be 8 + Nd * 20. So for frames/sub-frames where Nd < 3, the demo will generate exception. Therefore HSI header must be enabled if SW is enabled, this is checked in the CLI command validation.
Implementation Notes
The LVDS implementation is mostly present in mmw_lvds_stream.h and mmw_lvds_stream.c with calls in mss_main.c. Additionally HSI clock initialization is done at first time sensor start using MmwDemo_mssSetHsiClk.
EDMA channel resources for CBUFF/LVDS are in the global resource file (mmw_res.h, see Hardware Resource Allocation) along with other EDMA resource allocation. The user data header and two user payloads are configured as three user buffers in the CBUFF driver. Hence SW allocation for EDMA provides for three sets of EDMA resources as seen in the SW part (swSessionEDMAChannelTable[.]) of MmwDemo_LVDSStream_EDMAInit. The maximum number of HW EDMA resources are needed for the data-format MMW_DEMO_LVDS_STREAM_CFG_DATAFMT_CP_ADC_CQ, which as seen in the corresponding slide in ti\drivers\cbuff\docs\CBUFF_Transfers.pptx is 12 channels (+ shadows) including the 1st special CBUFF EDMA event channel which CBUFF IP generates to the EDMA, hence the HW part (hwwSessionEDMAChannelTable[.]) of MmwDemo_LVDSStream_EDMAInit has 11 table entries.
Although the CBUFF driver is configured for two sessions (hw and sw), at any time only one can be active. So depending on the LVDS CLI configuration and whether advanced frame or not, there is logic to activate/deactivate HW and SW sessions as necessary.
The CBUFF session (HW/SW) configure-create and delete depends on whether or not re-configuration is required after the first time configuration.
For HW session, re-configuration is done during sub-frame switching to re-configure for the next sub-frame but when there is no advanced frame (number of sub-frames = 1), the HW configuration does not need to change so HW session does not need to be re-created.
For SW session, even though the user buffer start addresses and sizes of headers remains same, the number of detected objects which determines the sizes of some user buffers changes from one sub-frame/frame to another sub-frame/frame. Therefore SW session needs to be recreated every sub-frame/frame.
User may modify the application software to transmit different information than point-cloud in the SW data e.g radar cube data (output of range DPU). However the CBUFF also has a maximum link list entry size limit of 0x3FFF CBUFF units or 32766 bytes. This means it is the limit for each user buffer entry [there are maximum of 3 entries -1st used for user data header, 2nd for point-cloud and 3rd for point-cloud side information]. During session creation, if this limit is exceeded, the CBUFF will return an error (and demo will in turn generate an exception). A single physical buffer of say size 50000 bytes may be split across two user buffers by providing one user buffer with (address, size) = (start address, 25000) and 2nd user buffer with (address, size) = (start address + 25000, 25000), beyond this two (or three if user data header is also replaced) limit, the user will need to create and activate (and wait for completion) the SW session multiple times to accomplish the transmission.

The following figure shows a timing diagram for the LVDS streaming (the figure is not to scale as actual durations will vary based on configuration).
在这里插入图片描述

How to bypass CLI
Re-implement the file mmw_cli.c as follows:MmwDemo_CLIInit should just create a task with input taskPriority. Lets say the task is called "MmwDemo_sensorConfig_task".
All other functions are not needed
Implement the MmwDemo_sensorConfig_task as follows:
Fill gMmwMCB.cfg.openCfg
Fill gMmwMCB.cfg.ctrlCfg
Add profiles and chirps using MMWave_addProfile and MMWave_addChirp functions
Call MmwDemo_CfgUpdate for every offset in Offsets for storing CLI configuration (MMWDEMO_xxx_OFFSET in mmw.h)
Fill gMmwMCB.dataPathObj.objDetCommonCfg.preStartCommonCfg
Call MmwDemo_openSensor
Call MmwDemo_startSensor (One can use helper function MmwDemo_isAllCfgInPendingState to know if all dynamic config was provided)
Hardware Resource Allocation
The Object Detection DPC needs to configure the DPUs hardware resources (HWA, EDMA). Even though the hardware resources currently are only required to be allocated for this one and only DPC in the system, the resource partitioning is shown to be in the ownership of the demo. This is to illustrate the general case of resource allocation across more than one DPCs and/or demo's own processing that is post-DPC processing. This partitioning can be seen in the mmw_res.h file. This file is passed as a compiler command line define
"--define=APP_RESOURCE_FILE="<ti/demo/xwr64xx/mmw/mmw_res.h>" 

in mmw.mak when building the DPC sources as part of building the demo application and is referred in object detection DPC sources where needed as

#include APP_RESOURCE_FILE 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/660078.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

华为配置ARP安全综合功能实验

配置ARP安全综合功能示例 组网图形 图1 配置ARP安全功能组网图 ARP安全简介配置注意事项组网需求配置思路操作步骤配置文件 ARP安全简介 ARP&#xff08;Address Resolution Protocol&#xff09;安全是针对ARP攻击的一种安全特性&#xff0c;它通过一系列对ARP表项学习和A…

在深度学习中,epoch和learning rate的通常取值范围?

在深度学习中&#xff0c;epoch和学习率的取值确实会根据不同的任务、数据集和模型架构有所不同。然而&#xff0c;您提到的范围是一些常见的经验性取值&#xff0c;这些取值在很多情况下都能工作得相当好。 1. 对于epoch的取值范围&#xff1a; 在很多研究论文和实际应用中&…

单片机学习笔记--- 定时器/计数器(简述版!)

目录 定时器的介绍 定时计数器的定时原理 定时计数器的内部结构 两种控制寄存器 &#xff08;1&#xff09;工作方式寄存器TMOD &#xff08;2&#xff09;控制寄存器TCON 定时计数器的工作方式 方式0 方式1 方式2 方式3 定时器的配置步骤 第一步&#xff0c;对…

建立自己的交易法则,打造自己的交易系统

一、教程描述 本套教程由知名财经自媒体倾心打造&#xff0c;基金经理资深会计师游资操盘手团队&#xff0c;手把手教你打造自己的交易系统&#xff0c;1、海龟交易法则CANSLIM模型合二为一&#xff0c;建立自己的交易法则&#xff1b;2、严格执行交易系统&#xff0c;保护本金…

如何在微信搭建私域流量池?

A: ①给客户打标签 添加标签&#xff0c;多维度构建用户画像&#xff0c;精准发送消息。 ②群发信息 选择自定义时间&#xff0c;上传内容 (支持文字&#xff0c;图片) &#xff0c;一键群发 。 ③建立专属素材库 将常用的话术、图片与文件录入至素材库&#xff0c;员工可随…

永久删除 Elasticsearch 中的主节点

Elasticsearch 是一个开源分布式搜索和分析引擎&#xff0c;用于各种任务&#xff0c;例如全文搜索、日志分析和实时数据分析。 Elasticsearch 集群由一个或多个节点组成&#xff0c;每个节点可以具有多种角色&#xff0c;包括主节点&#xff08;master node&#xff09;、数据…

使用orangepi玩linux

最近看了这个大佬的文章&#xff0c;写了使用远程来挂载linux的方案&#xff0c;觉得还是很有意思的&#xff0c;瞬间感觉linux这块都还是相通的&#xff0c;就跑了一下&#xff0c;果然&#xff0c;牛逼&#xff01; 香橙派全志H3烧录Uboot&#xff0c;远程加载zImage&#xf…

vscode 插件 Tailwind CSS IntelliSense 解决 class 提示问题

问题描述&#xff1a; 如下写js字符串是没有class智能提示的&#xff1a; const clsName bg-[#123456] text-[#654321] return <div className{clsName}></div>解决方案&#xff1a; 安装 clsx 依赖 pnpm i clsx设置 vscode 的 settings.json {"tailwin…

Android 数据恢复电脑版免费下载使用方法 [2024 更新]

“我一直在寻找一款可以下载的适用于 PC 的优秀 Android 数据恢复软件。有很多&#xff0c;但大部分都需要我付费。你能推荐一个好的让我免费下载吗&#xff1f;” 奇客数据恢复安卓版是恢复已删除或丢失的 Android 数据的最安全的工具。免费下载下面的奇客数据恢复安卓版来尝试…

LPC804开发(9.DAC使用)

1.前言 这是最最简单的外设&#xff0c;应该没有之一&#xff0c;我大概看了10分钟就会用了&#xff0c;我这里快速说一说&#xff0c;争取今天再把ADC搞出来。 2.初始化 程序如下 /* Power on the DAC0.*/POWER_DisablePD(kPDRUNCFG_PD_DAC0);/* Configure the DAC. */DAC…

[word] word艺术字体如何设置? #知识分享#职场发展#媒体

word艺术字体如何设置&#xff1f; 在工作中有些技巧&#xff0c;可以快速提高工作效率&#xff0c;解决大部分工作&#xff0c;今天给大家分享word艺术字体如何设置的技巧&#xff0c;希望可以帮助到你。 1、设置艺术字 选中文字&#xff0c;然后点击菜单栏的【插入】按钮一一…

从零开始实现贪吃蛇(C语言版)

贪吃蛇 游戏介绍1.前置知识1.1 Win32API1.2 控制台程序1.3 坐标系统1.4 GetStdHandle(获取句柄)1.5 CONSOLE_CURSOR_INFO(控制台光标信息)1.6 GetConsoleCursorInfo(获取光标信息)1.7 SetConsoleCursorInfo(设置控制台光标信息)1.8 SetConsoleCursorPosition(设置光标当前位置)…

国外知名的农业机器人公司

从高科技温室到云播种&#xff0c;农业机器人如何帮助农民填补劳动力短缺以及超市货架的短缺。 概要 “高科技农业”并不矛盾。当代农业经营更像是硅谷&#xff0c;而不是美国哥特式&#xff0c;拥有控制灌溉的应用程序、驾驶拖拉机的 GPS 系统和监控牲畜的带有 RFID 芯片的耳…

Flutter 和 Android原生(Activity、Fragment)相互跳转、传参

前言 本文主要讲解 Flutter 和 Android原生之间&#xff0c;页面相互跳转、传参&#xff0c; 但其中用到了两端相互通信的知识&#xff0c;非常建议先看完这篇 讲解通信的文章&#xff1a; Flutter 与 Android原生 相互通信&#xff1a;BasicMessageChannel、MethodChannel、…

dnslog在sql盲注

首先必须保证sql是在windows下 因为需要使用到UNC路径 保证mysql中的secure_file_priv为空 secure_file_priv为null&#xff0c;load_file则不能加载文件。 secure_file_priv为路径&#xff0c;可以读取路径中的文件&#xff1b; secure_file_priv为空&#xff0c;可以读取磁盘…

千兆电口模块和万兆电口模块:网络速度的演变

随着信息技术的迅猛发展&#xff0c;网络通信技术也在不断进步。在过去的几十年中&#xff0c;以太网的速度发生了巨大的变化&#xff0c;从最初的百兆以太网&#xff0c;到如今的千兆以太网和万兆以太网甚至40G、100G以太网满足了大数据、云计算、人工智能等新兴应用的需求。在…

【蓝桥杯日记】复盘篇三——循环结构

前言 本篇内容是对循环结构进行复盘的&#xff0c;循环可谓是在基础阶段特别重要的东西&#xff0c;是三大结构&#xff08;顺序结构、选择结构、循环结构&#xff09;中最重要的结构之一。 目录 &#x1f351;1.找最小值 分析&#xff1a; 知识点&#xff1a; 代码如下 &…

数据库空间爆了怎么处理

作者&#xff1a; 马文斌 时间&#xff1a; 2024-1-29 标签&#xff1a; mysql 磁盘空间 爆满 binlog 背景 近期数据库空间一直告警&#xff0c;平时这套数据库集群是不会有磁盘空间告警的&#xff0c;难道是最近业务量猛增了吗&#xff1f;咱们来瞧瞧到底怎么回事&…

启动盘重装ubuntu22系统

win+R msinfo32查看 插入制作好的u盘电脑开机 进入BIOS界面的方法有多种,以下是一些常见的方法: 进入BIOS界面的最常见按键有: Del键:大多数台式机通过在启动时按下Del键来进入BIOS。Esc键:在AMI BIOS和某些品牌电脑中,进入BIOS系统需要按“Esc”键,一般在开机画面…

草图导入3d之后渲染模型发光怎么回事?---模大狮模型网

在草图大师中&#xff0c;当导入3D模型之后发现模型发光通常是由于模型的材质属性或灯光设置所导致的。以下是一些可能的原因和解决方法&#xff1a; 材质属性设置&#xff1a;某些3D模型文件可能包含了发光材质属性&#xff0c;导致模型在草图大师中显示为发光状态。您可以尝试…