TI 毫米波雷达开发 —— 免配置程序上电自启动
mmWave 常规启动流程
TI 官方的例程上电启动流程为:
上电 – 等待配置 – 串口配置 – 配置完成后运行
现介绍一种上电之后不需要使用配置文件配置的方法,直接在ARM核上写固定程序。
mmWave 免配置启动流程
上电 – 配置完成后直接运行
主要思路
对于TI所有的需要配置参数的Demo而言,背后的处理流程都是一样的。
- PC通过UART发送命令。
- ARM内核接收,通过串口中断服务函数接收配置命令和配置数据。实现这一步需要初始化串口和CLI函数。
// 串口初始化函数
/* Setup the default UART Parameters */
UART_Params_init(&uartParams);
uartParams.writeDataMode = UART_DATA_BINARY;
uartParams.readDataMode = UART_DATA_BINARY;
uartParams.clockFrequency = gMmwMssMCB.cfg.sysClockFrequency;
uartParams.baudRate = gMmwMssMCB.cfg.loggingBaudRate;
uartParams.isPinMuxDone = 1U;
/* Open the Logging UART Instance: */
gMmwMssMCB.loggingUartHandle = UART_open(1, &uartParams);
if (gMmwMssMCB.loggingUartHandle == NULL)
{
System_printf("Error: MMWDemoMSS Unable to open the Logging UART Instance\n");
return;
}
/*忽略中间代码*/
MmwDemo_CLIInit(); //CLI 初始化函数用于注册当前Demo中所需的命令解析回调函数。
// 接下俩看看MmwDemo_CLIInit()的函数体
void MmwDemo_CLIInit(void)
{
CLI_Cfg cliCfg;
char demoBanner[256];
/* CLI 初始化命令 */
sprintf(&demoBanner[0],
"******************************************\n"
"xWR68xx High Acc Demo. SDK: %02d.%02d.%02d.%02d\n"
"******************************************\n",
MMWAVE_SDK_VERSION_MAJOR,
MMWAVE_SDK_VERSION_MINOR,
MMWAVE_SDK_VERSION_BUGFIX,
MMWAVE_SDK_VERSION_BUILD);
/* 初始化CLI 配置 */
memset((void *)&cliCfg, 0, sizeof(CLI_Cfg));
cliCfg.cliPrompt = "mmwDemo:/>";
cliCfg.cliBanner = demoBanner;
cliCfg.cliUartHandle = gMmwMssMCB.commandUartHandle;
cliCfg.taskPriority = 3;
cliCfg.socHandle = gMmwMssMCB.socHandle;
cliCfg.mmWaveHandle = gMmwMssMCB.ctrlHandle;
cliCfg.enableMMWaveExtension = 1U;
cliCfg.usePolledMode = true;
cliCfg.tableEntry[0].cmd = "sensorStart";
cliCfg.tableEntry[0].helpString = "No arguments";
cliCfg.tableEntry[0].cmdHandlerFxn = MmwDemo_CLISensorStart;
cliCfg.tableEntry[1].cmd = "sensorStop";
cliCfg.tableEntry[1].helpString = "No arguments";
cliCfg.tableEntry[1].cmdHandlerFxn = MmwDemo_CLISensorStop;
cliCfg.tableEntry[2].cmd = "frameStart";
cliCfg.tableEntry[2].helpString = "No arguments";
cliCfg.tableEntry[2].cmdHandlerFxn = MmwDemo_CLIFrameStart;
cliCfg.tableEntry[3].cmd = "guiMonitor";
cliCfg.tableEntry[3].helpString = "<detectedObjects> <logMagRange> <rangeAzimuthHeatMap> <rangeDopplerHeatMap>";
cliCfg.tableEntry[3].cmdHandlerFxn = MmwDemo_CLIGuiMonSel;
cliCfg.tableEntry[4].cmd = "highAccCfg";
cliCfg.tableEntry[4].helpString = "<numRangeBinZoomIn> <skipLeft> <skipRight> <enablePhaseEst> <enableLinearFit> <enableFilter>";
cliCfg.tableEntry[4].cmdHandlerFxn = MmwDemo_CLIHighAccuCfg;
cliCfg.tableEntry[5].cmd = "dataLogger";
cliCfg.tableEntry[5].helpString = "<mssLogger | dssLogger>";
cliCfg.tableEntry[5].cmdHandlerFxn = MmwDemo_CLISetDataLogger;
cliCfg.tableEntry[6].cmd = "adcbufCfg";
cliCfg.tableEntry[6].helpString = "<adcOutputFmt> <SampleSwap> <ChanInterleave> <ChirpThreshold>";
cliCfg.tableEntry[6].cmdHandlerFxn = MmwDemo_CLIADCBufCfg;
cliCfg.tableEntry[7].cmd = "RangeLimitCfg";
cliCfg.tableEntry[7].helpString = "<numRangeBinZoomIn> <enabled> <min_range> <max_range> "; //"<numRangeBinZoomIn> <enabled> <min_range> <max_range> ";
cliCfg.tableEntry[7].cmdHandlerFxn = MmwDemo_CLIRangeLimitCfg;
if (CLI_open(&cliCfg) < 0) // 记住CLI_open 函数会创建一个task , 用于接收并解析命令,后面会提到。
{
System_printf("Error: Unable to open the CLI\n");
return;
}
System_printf("Debug: CLI is operational\n");
return;
}
- 接收到的数据提交到命令解析回调函数。
// CLI_open 会进行相关内容的初始化并且创建新的CLI task
int32_t CLI_open (CLI_Cfg* ptrCLICfg)
{
Task_Params taskParams;
uint32_t index;
/* 空指针检查 */
if (ptrCLICfg == NULL)
return -1;
/* 初始化 CLI 管理控制块 */
memset ((void*)&gCLI, 0, sizeof(CLI_MCB));
/* 数据复制,用于安全控制*/
memcpy ((void *)&gCLI.cfg, (void *)ptrCLICfg, sizeof(CLI_Cfg));
/* 循环查看支持的命令 */
for (index = 0; index < CLI_MAX_CMD; index++)
{
/* Do we have a valid entry? */
if (gCLI.cfg.tableEntry[index].cmd == NULL)
{
/* NO: This is the last entry */
break;
}
else
{
/* YES: Increment the number of CLI commands */
gCLI.numCLICommands = gCLI.numCLICommands + 1;
}
}
/* Is the mmWave Extension enabled? */
if (gCLI.cfg.enableMMWaveExtension == 1U)
{
/* YES: Initialize the CLI Extension: */
if (CLI_MMWaveExtensionInit (ptrCLICfg) < 0)
return -1;
}
/* Do we have a CLI Prompt specified? */
if (gCLI.cfg.cliPrompt == NULL)
gCLI.cfg.cliPrompt = "CLI:/>";
gCLI.cfg.tableEntry[gCLI.numCLICommands].cmd = "help";
gCLI.cfg.tableEntry[gCLI.numCLICommands].helpString = NULL;
gCLI.cfg.tableEntry[gCLI.numCLICommands].cmdHandlerFxn = CLI_help;
/* Increment the number of CLI commands: */
gCLI.numCLICommands++;
/* Initialize the task parameters and launch the CLI Task: */
Task_Params_init(&taskParams);
taskParams.priority = gCLI.cfg.taskPriority;
taskParams.stackSize = 4*1024;
// 创建CLI任务
gCLI.cliTaskHandle = Task_create(CLI_task, &taskParams, NULL);
return 0;
}
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]);
}
}
}
}
- 命令解析函数对各配置命令进行处理。
// 以MmwDemo_CLIHighAccuCfg为例
static int32_t MmwDemo_CLIHighAccuCfg(int32_t argc, char *argv[])
{
radarModuleHighAccuConfig highAccuConfig;
MmwDemo_message message;
/* Sanity Check: Minimum argument check */
if (argc != 7)
{
CLI_write("Error: Invalid usage of the CLI command\n");
return -1;
}
/* Initialize the ADC Output configuration: */
memset((void *)&highAccuConfig, 0, sizeof(radarModuleHighAccuConfig));
// System_printf("highAccuConfig config\n");
// cliCfg.tableEntry[4].helpString = "<numRangeBinZoomIn> <skipLeft> <skipRight> <enablePhaseEst> <enableLinearFit> <enableFilter>";
/* Populate configuration: */
highAccuConfig.numRangeBinZoomIn = (uint16_t)atoi(argv[1]);
highAccuConfig.skipLeft = (uint16_t)atoi(argv[2]);
highAccuConfig.skipRight = (uint16_t)atoi(argv[3]);
highAccuConfig.enablePhaseEst = (uint16_t)atoi(argv[4]);
highAccuConfig.enableLinearFit = (uint16_t)atoi(argv[5]);
highAccuConfig.enableFilter = (uint16_t)atoi(argv[6]);
/* Save Configuration to use later */
memcpy((void *)&gMmwMssMCB.cfg.highAccuRangeCfg, (void *)&highAccuConfig, sizeof(radarModuleHighAccuConfig));
/* Send configuration to DSS */
memset((void *)&message, 0, sizeof(MmwDemo_message));
message.type = MMWDEMO_MSS2DSS_HIGHACCURANGE_CFG;
memcpy((void *)&message.body.highAccuRangeCfg, (void *)&highAccuConfig, sizeof(radarModuleHighAccuConfig));
if (MmwDemo_mboxWrite(&message) == 0)
return 0;
else
return -1;
}
所以如果期望实现免配置自启动,只需要给第3步提供合适的入口参数。
实现方式
cli.c中定义配置命令
#define USE_HARD_CODED_CONFIG
#ifdef USE_HARD_CODED_CONFIG
int32_t hardCodedConfigIndex;
char *hardCodedConfigCommands[] = {
"sensorStop",
"flushCfg",
"dfeDataOutputMode 1",
"channelCfg 15 7 0",
"adcCfg 2 1",
"adcbufCfg -1 0 1 1 1",
"lowPower 0 0",
"profileCfg 0 60 7 3 24 0 0 166 1 256 12500 0 0 158",
"chirpCfg 0 0 0 0 0 0 0 1",
"chirpCfg 1 1 0 0 0 0 0 4",
"chirpCfg 2 2 0 0 0 0 0 2",
"frameCfg 0 2 32 0 100 1 0",
"guiMonitor -1 1 1 1 0 0 1",
"cfarCfg -1 0 2 8 4 3 0 15.0 0",
"cfarCfg -1 1 0 4 2 3 1 15.0 0",
"multiObjBeamForming -1 1 0.5",
"calibDcRangeSig -1 0 -5 8 256",
"clutterRemoval -1 0",
"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",
"measureRangeBiasAndRxChanPhase 0 1. 0.2",
"aoaFovCfg -1 -90 90 -90 90",
"cfarFovCfg -1 0 0.25 9.0",
"cfarFovCfg -1 1 -20.16 20.16",
"extendedMaxVelocity -1 0",
"CQRxSatMonitor 0 3 4 63 0",
"CQSigImgMonitor 0 127 4",
"analogMonitor 0 0",
"lvdsStreamCfg -1 0 0 0",
"bpmCfg -1 0 0 0",
"calibData 0 0 0",
"sensorStart",
"!!!END_OF_HARD_CODED_COMMANDS"
};
#endif
CLI_task 函数增加处理代码
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);
}
#ifdef USE_HARD_CODED_CONFIG
hardCodedConfigIndex = 0;
CLI_write("Wait some time for system to initialize...\n");
Task_sleep(100);
CLI_write("Performing hard-coded config\n");
#endif
/* Loop around forever: */
while (1)
{
/* Demo Prompt: */
CLI_write(gCLI.cfg.cliPrompt);
/* Reset the command string: */
memset((void *)&cmdString[0], 0, sizeof(cmdString));
#ifdef USE_HARD_CODED_CONFIG
//新增上电自启动处理代码
if (hardCodedConfigCommands[hardCodedConfigIndex][0] != '!')
{ // CLI_write (hardCodedConfigCommands[hardCodedConfigIndex]);
CLI_write("Command\n");
memcpy((void *)&cmdString[0], (void *)hardCodedConfigCommands[hardCodedConfigIndex],
strlen(hardCodedConfigCommands[hardCodedConfigIndex]));
hardCodedConfigIndex++;
}
else
{
UART_read(gCLI.cfg.cliUartHandle, &cmdString[0], (sizeof(cmdString) - 1));
}
#else //保留原来的串口处理方式
/* Read the command message from the UART: */
UART_read(gCLI.cfg.cliUartHandle, &cmdString[0], (sizeof(cmdString) - 1));
#endif
/* 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]);
}
}
}
}
工程中添加宏定义使能
在 工程中添加宏定义配置 USE_HARD_CODED_CONFIG 后生效 。