前言
在进行Out-of-box Demo的工作流程分析之前,各位应该已经可以熟练掌握源码的编译以及烧录方法,同时基本了解TI mmWave Demo Visualizer 的使用技巧,并可以结合1843等相关开发板进行可视化结果的展示。
本章节主要是简要介绍TI官方Demo的工作流程,结合“1843 Out-of-box 开箱教程”你会对整个工程的基本工作流程有一个清晰的了解,明白在“ mmWave Demo Visualizer”中各种“点点点操作”的具体意义。
整体框图概览:
如下图所示是1843 Out-of-box的软件执行框图,可以将其分为四个部分进行分析,分别是:①任务初始化部分;②参数配置部分;③算法解析,数据传输部分;④停止运行并再次配置解析部分;
任务初始化
首先,整个工程在启动瞬间,会先进行各种任务的初始化,以下是mss_main.c中的主函数(由于本专栏非完整的代码走读专栏,因此部分代码分析仅一提而过,仅和串口数据输出相关的部分会逐行进行分析解释)。对main.c函数分析可以发现,主函数中主要包含了三个操作:1是SOC相关配置及初始化;2是gMmwMssMCB初始化,其是整个Out-of-box Demo中一个重要的全局变量,各位可以点击查看该变量的数据类型(MmwDemo_MSS_MCB),点击后可以发现gMmwMssMCB是一个非常复杂的数据结构,其是用于追踪整个mmw Demo 中包含的大部分信息的全局变量;3是建立了一个名称是“MmwDemo_initTask”的任务,该任务各位进一步在CCS中打开函数定义进行分析,其内部主要包含了:各种串口初始化,GPIO初始化等一系列接口初始化程序以及一些任务的建立。
通过这些参数初始化及任务的建立(这里需要提及一个任务,CLI任务的建立,这个任务就是用于接收“ mmWave Demo Visualizer”下发的CFG指令并控制毫米波雷达“sensor start”和“sensor stop”的),毫米波雷达此时就会处于一个待机状态,在这个状态下毫米波雷达并没有进入工作状态且串口是没有数据输出的。
int main (void)
{
Task_Params taskParams;
int32_t errCode;
SOC_Handle socHandle;
SOC_Cfg socCfg;
/* Initialize the ESM: Dont clear errors as TI RTOS does it */
ESM_init(0U);
/* Initialize the SOC confiugration: */
memset ((void *)&socCfg, 0, sizeof(SOC_Cfg));
/* Populate the SOC configuration: */
socCfg.clockCfg = SOC_SysClock_INIT;
socCfg.mpuCfg = SOC_MPUCfg_CONFIG;
socCfg.dssCfg = SOC_DSSCfg_UNHALT;
/* Initialize the SOC Module: This is done as soon as the application is started
* to ensure that the MPU is correctly configured. */
socHandle = SOC_init (&socCfg, &errCode);
if (socHandle == NULL)
{
System_printf ("Error: SOC Module Initialization failed [Error code %d]\n", errCode);
MmwDemo_debugAssert (0);
return -1;
}
/* Wait for BSS powerup */
if (SOC_waitBSSPowerUp(socHandle, &errCode) < 0)
{
/* Debug Message: */
System_printf ("Debug: SOC_waitBSSPowerUp failed with Error [%d]\n", errCode);
return 0;
}
/* Check if the SOC is a secure device */
if (SOC_isSecureDevice(socHandle, &errCode))
{
/* Disable firewall for JTAG and LOGGER (UART) which is needed by all unit tests */
SOC_controlSecureFirewall(socHandle,
(uint32_t)(SOC_SECURE_FIREWALL_JTAG | SOC_SECURE_FIREWALL_LOGGER),
SOC_SECURE_FIREWALL_DISABLE,
&errCode);
}
/* Initialize and populate the demo MCB */
memset ((void*)&gMmwMssMCB, 0, sizeof(MmwDemo_MSS_MCB));
gMmwMssMCB.socHandle = socHandle;
/* Debug Message: */
System_printf ("**********************************************\n");
System_printf ("Debug: Launching the MMW Demo on MSS\n");
System_printf ("**********************************************\n");
/* Initialize the Task Parameters. */
Task_Params_init(&taskParams);
gMmwMssMCB.taskHandles.initTask = Task_create(MmwDemo_initTask, &taskParams, NULL);
/* Start BIOS */
BIOS_start();
return 0;
}
参数配置
在毫米波雷达进入待机状态后,其需要接收各种参数信息来配置并驱动雷达进行工作,这些参数包括:Chirp参数信息,天线配置信息,输出数据类型,输出数据间隔,传感器开始工作及停止工作指令以及其他参数。
这些参数就是“MmwDemo_initTask”进行下发的,具体流程是“ mmWave Demo Visualizer”根据你在“setup details”,“scene Selection”及“plot selection”中的所选择的信息生成一组CFG指令,这组指令在你点击“send config to mmwave device”就会通过串口发送到传感器端,至于生成的参数你可以在“console message”中查看到,当然也可以点击“save config to PC”保存下来再打开观看。
如下图所示是保存至 PC端的CFG指令,详细的参数解释请见下一章节的内容。
回顾任务初始化章节,里面提及了串口初始化,下面我们分析这个串口初始化的代码,首先是uartParams初始化及参数的赋值,随后根据赋值好的参数后打开串口,后面则按照相类似的流程再次开启了一个了串口。
/*****************************************************************************
* Open the mmWave SDK components:
*****************************************************************************/
/* Setup the default UART Parameters */
UART_Params_init(&uartParams);
uartParams.clockFrequency = gMmwMssMCB.cfg.platformCfg.sysClockFrequency;
uartParams.baudRate = gMmwMssMCB.cfg.platformCfg.commandBaudRate;
uartParams.isPinMuxDone = 1;
/* Open the UART Instance */
gMmwMssMCB.commandUartHandle = UART_open(0, &uartParams);
if (gMmwMssMCB.commandUartHandle == NULL)
{
//System_printf("Error: Unable to open the Command UART Instance\n");
MmwDemo_debugAssert (0);
return;
}
//System_printf("Debug: UART Instance %p has been opened successfully\n", gMmwMssMCB.commandUartHandle);
/* Setup the default UART Parameters */
UART_Params_init(&uartParams);
uartParams.writeDataMode = UART_DATA_BINARY;
uartParams.readDataMode = UART_DATA_BINARY;
uartParams.clockFrequency = gMmwMssMCB.cfg.platformCfg.sysClockFrequency;
uartParams.baudRate = gMmwMssMCB.cfg.platformCfg.loggingBaudRate;
uartParams.isPinMuxDone = 1U;
/* Open the Logging UART Instance: */
gMmwMssMCB.loggingUartHandle = UART_open(1, &uartParams);
if (gMmwMssMCB.loggingUartHandle == NULL)
{
System_printf("Error: Unable to open the Logging UART Instance\n");
MmwDemo_debugAssert (0);
return;
}
/* Create binary semaphores which is used to signal DPM_start/DPM_stop/DPM_ioctl is done
* to the sensor management task. The signalling (Semaphore_post) will be done
* from DPM registered report function (which will execute in the DPM execute task context). */
Semaphore_Params_init(&semParams);
semParams.mode = Semaphore_Mode_BINARY;
gMmwMssMCB.DPMstartSemHandle = Semaphore_create(0, &semParams, NULL);
gMmwMssMCB.DPMstopSemHandle = Semaphore_create(0, &semParams, NULL);
gMmwMssMCB.DPMioctlSemHandle = Semaphore_create(0, &semParams, NULL);
点击UART_Params_init进行查看可以发现uartParams的初始参数,而后续uartParams很明显被重新赋值进行修改了,一个是text模式,一个是binary模式;一个是的串口波特率是loggingBaudRate,一个是commandBaudRate。通过全局搜索关键词可以发现loggingBaudRate是921600,commandBaudRate是115200。
/*!
* @brief Function to initialize the UART_Params struct to its defaults
*
* @param params An pointer to UART_Params structure for
* initialization
*
* Defaults values are:
* readTimeout = UART_WAIT_FOREVER;
* writeTimeout = UART_WAIT_FOREVER;
* readReturnMode = UART_RETURN_NEWLINE;
* readDataMode = UART_DATA_TEXT;
* writeDataMode = UART_DATA_TEXT;
* readEcho = UART_ECHO_ON;
* baudRate = 115200;
* dataLength = UART_LEN_8;
* stopBits = UART_STOP_ONE;
* parityType = UART_PAR_NONE;
*
* \ingroup UART_DRIVER_EXTERNAL_FUNCTION
*/
extern void UART_Params_init(UART_Params *params);
此时回忆“ mmWave Demo Visualizer”中的options中的串口配置你就理解其中为什么是有两个串口,且一个串口的波特率是115200,一个是921600了。
算法解析、数据传输
当“ mmWave Demo Visualizer”通过串口将CFG指令发送到毫米波雷达后,雷达会按照CFG指令中的各项数据配置雷达并进行相应的工作,例如数据的发送。
MmwDemo_transmitProcessedOutput是该工程的数据输出函数,数据的输出格式输出类型均是由该函数进行定义的,后面我会详细地逐行分析改代码,此处就不再赘述。
static void MmwDemo_transmitProcessedOutput
(
UART_Handle uartHandle,
DPC_ObjectDetection_ExecuteResult *result,
MmwDemo_output_message_stats *timingInfo
)
{
MmwDemo_output_message_header header;
MmwDemo_GuiMonSel *pGuiMonSel;
MmwDemo_SubFrameCfg *subFrameCfg;
uint32_t tlvIdx = 0;
uint32_t index;
uint32_t numPaddingBytes;
uint32_t packetLen;
uint8_t padding[MMWDEMO_OUTPUT_MSG_SEGMENT_LEN];
MmwDemo_output_message_tl tl[MMWDEMO_OUTPUT_MSG_MAX];
int32_t errCode;
uint16_t *detMatrix = (uint16_t *)result->detMatrix.data;
DPIF_PointCloudCartesian *objOut;
cmplx16ImRe_t *azimuthStaticHeatMap;
DPIF_PointCloudSideInfo *objOutSideInfo;
DPC_ObjectDetection_Stats *stats;
/* Get subframe configuration */
subFrameCfg = &gMmwMssMCB.subFrameCfg[result->subFrameIdx];
/* Get Gui Monitor configuration */
pGuiMonSel = &subFrameCfg->guiMonSel;
/* Clear message header */
memset((void *)&header, 0, sizeof(MmwDemo_output_message_header));
/******************************************************************
Send out data that is enabled, Since processing results are from DSP,
address translation is needed for buffer pointers
*******************************************************************/
{
detMatrix = (uint16_t *) SOC_translateAddress((uint32_t)detMatrix,
SOC_TranslateAddr_Dir_FROM_OTHER_CPU,
&errCode);
DebugP_assert ((uint32_t)detMatrix!= SOC_TRANSLATEADDR_INVALID);
objOut = (DPIF_PointCloudCartesian *) SOC_translateAddress((uint32_t)result->objOut,
SOC_TranslateAddr_Dir_FROM_OTHER_CPU,
&errCode);
DebugP_assert ((uint32_t)objOut != SOC_TRANSLATEADDR_INVALID);
objOutSideInfo = (DPIF_PointCloudSideInfo *) SOC_translateAddress((uint32_t)result->objOutSideInfo,
SOC_TranslateAddr_Dir_FROM_OTHER_CPU,
&errCode);
DebugP_assert ((uint32_t)objOutSideInfo != SOC_TRANSLATEADDR_INVALID);
stats = (DPC_ObjectDetection_Stats *) SOC_translateAddress((uint32_t)result->stats,
SOC_TranslateAddr_Dir_FROM_OTHER_CPU,
&errCode);
DebugP_assert ((uint32_t)stats != SOC_TRANSLATEADDR_INVALID);
result->radarCube.data = (void *) SOC_translateAddress((uint32_t) result->radarCube.data,
SOC_TranslateAddr_Dir_FROM_OTHER_CPU,
&errCode);
DebugP_assert ((uint32_t) result->radarCube.data!= SOC_TRANSLATEADDR_INVALID);
}
/* Header: */
header.platform = 0xA1843;
header.magicWord[0] = 0x0102;
header.magicWord[1] = 0x0304;
header.magicWord[2] = 0x0506;
header.magicWord[3] = 0x0708;
header.numDetectedObj = result->numObjOut;
header.version = MMWAVE_SDK_VERSION_BUILD |
(MMWAVE_SDK_VERSION_BUGFIX << 8) |
(MMWAVE_SDK_VERSION_MINOR << 16) |
(MMWAVE_SDK_VERSION_MAJOR << 24);
packetLen = sizeof(MmwDemo_output_message_header);
if ((pGuiMonSel->detectedObjects == 1) || (pGuiMonSel->detectedObjects == 2) &&
(result->numObjOut > 0))
{
tl[tlvIdx].type = MMWDEMO_OUTPUT_MSG_DETECTED_POINTS;
tl[tlvIdx].length = sizeof(DPIF_PointCloudCartesian) * result->numObjOut;
packetLen += sizeof(MmwDemo_output_message_tl) + tl[tlvIdx].length;
tlvIdx++;
}
/* Side info */
if ((pGuiMonSel->detectedObjects == 1) && (result->numObjOut > 0))
{
tl[tlvIdx].type = MMWDEMO_OUTPUT_MSG_DETECTED_POINTS_SIDE_INFO;
tl[tlvIdx].length = sizeof(DPIF_PointCloudSideInfo) * result->numObjOut;
packetLen += sizeof(MmwDemo_output_message_tl) + tl[tlvIdx].length;
tlvIdx++;
}
if (pGuiMonSel->logMagRange)
{
tl[tlvIdx].type = MMWDEMO_OUTPUT_MSG_RANGE_PROFILE;
tl[tlvIdx].length = sizeof(uint16_t) * subFrameCfg->numRangeBins;
packetLen += sizeof(MmwDemo_output_message_tl) + tl[tlvIdx].length;
tlvIdx++;
}
if (pGuiMonSel->noiseProfile)
{
tl[tlvIdx].type = MMWDEMO_OUTPUT_MSG_NOISE_PROFILE;
tl[tlvIdx].length = sizeof(uint16_t) * subFrameCfg->numRangeBins;
packetLen += sizeof(MmwDemo_output_message_tl) + tl[tlvIdx].length;
tlvIdx++;
}
if (pGuiMonSel->rangeAzimuthHeatMap)
{
#if defined(USE_2D_AOA_DPU)
tl[tlvIdx].type = MMWDEMO_OUTPUT_MSG_AZIMUT_ELEVATION_STATIC_HEAT_MAP;
#else
tl[tlvIdx].type = MMWDEMO_OUTPUT_MSG_AZIMUT_STATIC_HEAT_MAP;
#endif
tl[tlvIdx].length = result->azimuthStaticHeatMapSize * sizeof(cmplx16ImRe_t);
packetLen += sizeof(MmwDemo_output_message_tl) + tl[tlvIdx].length;
tlvIdx++;
}
if (pGuiMonSel->rangeDopplerHeatMap)
{
tl[tlvIdx].type = MMWDEMO_OUTPUT_MSG_RANGE_DOPPLER_HEAT_MAP;
tl[tlvIdx].length = subFrameCfg->numRangeBins * subFrameCfg->numDopplerBins * sizeof(uint16_t);
packetLen += sizeof(MmwDemo_output_message_tl) + tl[tlvIdx].length;
tlvIdx++;
}
if (pGuiMonSel->statsInfo)
{
tl[tlvIdx].type = MMWDEMO_OUTPUT_MSG_STATS;
tl[tlvIdx].length = sizeof(MmwDemo_output_message_stats);
packetLen += sizeof(MmwDemo_output_message_tl) + tl[tlvIdx].length;
tlvIdx++;
MmwDemo_getTemperatureReport();
tl[tlvIdx].type = MMWDEMO_OUTPUT_MSG_TEMPERATURE_STATS;
tl[tlvIdx].length = sizeof(MmwDemo_temperatureStats);
packetLen += sizeof(MmwDemo_output_message_tl) + tl[tlvIdx].length;
tlvIdx++;
}
header.numTLVs = tlvIdx;
/* Round up packet length to multiple of MMWDEMO_OUTPUT_MSG_SEGMENT_LEN */
header.totalPacketLen = MMWDEMO_OUTPUT_MSG_SEGMENT_LEN *
((packetLen + (MMWDEMO_OUTPUT_MSG_SEGMENT_LEN-1))/MMWDEMO_OUTPUT_MSG_SEGMENT_LEN);
header.timeCpuCycles = Pmu_getCount(0);
header.frameNumber = stats->frameStartIntCounter;
header.subFrameNumber = result->subFrameIdx;
UART_writePolling (uartHandle,
(uint8_t*)&header,
sizeof(MmwDemo_output_message_header));
tlvIdx = 0;
/* Send detected Objects */
if ((pGuiMonSel->detectedObjects == 1) || (pGuiMonSel->detectedObjects == 2) &&
(result->numObjOut > 0))
{
UART_writePolling (uartHandle,
(uint8_t*)&tl[tlvIdx],
sizeof(MmwDemo_output_message_tl));
/*Send array of objects */
UART_writePolling (uartHandle, (uint8_t*)objOut,
sizeof(DPIF_PointCloudCartesian) * result->numObjOut);
tlvIdx++;
}
/* Send detected Objects Side Info */
if ((pGuiMonSel->detectedObjects == 1) && (result->numObjOut > 0))
{
UART_writePolling (uartHandle,
(uint8_t*)&tl[tlvIdx],
sizeof(MmwDemo_output_message_tl));
UART_writePolling (uartHandle, (uint8_t*)objOutSideInfo,
sizeof(DPIF_PointCloudSideInfo) * result->numObjOut);
tlvIdx++;
}
/* Send Range profile */
if (pGuiMonSel->logMagRange)
{
UART_writePolling (uartHandle,
(uint8_t*)&tl[tlvIdx],
sizeof(MmwDemo_output_message_tl));
for(index = 0; index < subFrameCfg->numRangeBins; index++)
{
UART_writePolling (uartHandle,
(uint8_t*)&detMatrix[index*subFrameCfg->numDopplerBins],
sizeof(uint16_t));
}
tlvIdx++;
}
/* Send noise profile */
if (pGuiMonSel->noiseProfile)
{
uint32_t maxDopIdx = subFrameCfg->numDopplerBins/2 -1;
UART_writePolling (uartHandle,
(uint8_t*)&tl[tlvIdx],
sizeof(MmwDemo_output_message_tl));
for(index = 0; index < subFrameCfg->numRangeBins; index++)
{
UART_writePolling (uartHandle,
(uint8_t*)&detMatrix[index*subFrameCfg->numDopplerBins + maxDopIdx],
sizeof(uint16_t));
}
tlvIdx++;
}
/* Send data for static azimuth heatmap */
if (pGuiMonSel->rangeAzimuthHeatMap)
{
azimuthStaticHeatMap = (cmplx16ImRe_t *) SOC_translateAddress((uint32_t)result->azimuthStaticHeatMap,
SOC_TranslateAddr_Dir_FROM_OTHER_CPU,
&errCode);
DebugP_assert ((uint32_t)azimuthStaticHeatMap!= SOC_TRANSLATEADDR_INVALID);
UART_writePolling (uartHandle,
(uint8_t*)&tl[tlvIdx],
sizeof(MmwDemo_output_message_tl));
UART_writePolling (uartHandle,
(uint8_t *)azimuthStaticHeatMap,
result->azimuthStaticHeatMapSize * sizeof(cmplx16ImRe_t));
tlvIdx++;
}
/* Send data for range/Doppler heatmap */
if (pGuiMonSel->rangeDopplerHeatMap == 1)
{
UART_writePolling (uartHandle,
(uint8_t*)&tl[tlvIdx],
sizeof(MmwDemo_output_message_tl));
UART_writePolling (uartHandle,
(uint8_t*)detMatrix,
tl[tlvIdx].length);
tlvIdx++;
}
/* Send stats information */
if (pGuiMonSel->statsInfo == 1)
{
UART_writePolling (uartHandle,
(uint8_t*)&tl[tlvIdx],
sizeof(MmwDemo_output_message_tl));
/* Address translation is done when buffer is received*/
UART_writePolling (uartHandle,
(uint8_t*)timingInfo,
tl[tlvIdx].length);
tlvIdx++;
UART_writePolling (uartHandle,
(uint8_t*)&tl[tlvIdx],
sizeof(MmwDemo_output_message_tl));
UART_writePolling (uartHandle,
(uint8_t*)&gMmwMssMCB.temperatureStats,
tl[tlvIdx].length);
tlvIdx++;
}
/* Send padding bytes */
numPaddingBytes = MMWDEMO_OUTPUT_MSG_SEGMENT_LEN - (packetLen & (MMWDEMO_OUTPUT_MSG_SEGMENT_LEN-1));
if (numPaddingBytes<MMWDEMO_OUTPUT_MSG_SEGMENT_LEN)
{
UART_writePolling (uartHandle,
(uint8_t*)padding,
numPaddingBytes);
}
}
在传感器正式工作后,mss_main.c中的MmwDemo_transmitProcessedOutput函数就会在每一帧运行结束后进行数据的传递,该函数的具体工作包括:获取共享内存中获取DSP核解析完成的数据,按照一定的方式进行数据的解析,设计一定的数据组合方式,最后将数据传递出去。上述过程在毫米波雷达的每一帧都会进行,不断重复,完成数据的连续发送。
停止运行、再次配置参数并运行
当毫米波雷达进入工作状态后,如何才能停止运行,或者更改相关参数后再次运行呢,这就是这一个环节的作用,和参数配置相类似,还是由“ mmWave Demo Visualizer”发送了相关指令,使毫米波雷达进入了上述提及的“停止运行”或者是“修改参数的”这两个状态。
后续则是不断的重复上述过程。
总结
通过上述的分析,我们可以理解Demo的基本工作流程是毫米波雷达在初始化完成后就会等待“ mmWave Demo Visualizer”发送CFG指令来配置相关参数并进行工作,随后串口就会按照一定的数据格式输出相应数据,“ mmWave Demo Visualizer”会通过串口再接收数据并解析数据,随后显示在Plot窗口中。
那么理解了这个流程,我们也就可以通过MATLAB来实现上述功能,即通过MATLAB发送相关的指令,在通过MATLAB接收毫米波雷达返回的数据,最后进行相应的算法解析就行,这一块的内容会在后续进行展示。