TI的单芯片毫米波雷达传感器配置命令是如何传递到DSP和ARM核的?(串口程序代码走读)

本文编辑:调皮哥的小助理

TI毫米波雷达配置命令是如何传递到DSP和ARM核的?(程序代码走读)

TI毫米波雷达,上位机通过串口接收数据,雷达配置命令也是上位机通过串口下发到雷达芯片里,如下图所示。那么这是如何做到的呢?

在这里插入图片描述
(雷达配置参数(射频前端+信号处理+数据处理算法))

在这里插入图片描述
(上传数据格式(部分))

今天我以【呼吸心跳检测例程】为大家分享串口参数这个事儿。

其中两个串口都要介绍,一个控制串口,一个是数据串口。

〇、串口初始化位置

先来看代码,本文代码只截取一些关键部位,详细内容请回归例程详细阅读。

1.串口波特率设置和初始化

gMmwMssMCB.cfg.loggingBaudRate   = 921600;
gMmwMssMCB.cfg.commandBaudRate   = 115200;

/* Initialize the UART */
UART_init();

2.串口参数设置(两个串口都配置)

/* Setup the default UART Parameters */
UART_Params_init(&uartParams);
uartParams.clockFrequency  = gMmwMssMCB.cfg.sysClockFrequency;
uartParams.baudRate        = gMmwMssMCB.cfg.commandBaudRate;
uartParams.isPinMuxDone    = 1U;

/* 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;

3.打开串口

/* Open the Logging UART Instance: */
gMmwMssMCB.loggingUartHandle = UART_open(1, &uartParams);

一、数据串口

前面串口配置初始化完成之后,就是打开串口,然后就等待程序发送数据了。首先是数据串口,数据串口发送的数据比较多,数据协议今天不提,大家参照TI给提供的数据文档解析就完事儿了,很简单的。下面说一下数据串口在哪里发送数据的。

1.MmwDemo_mboxReadTask(读邮箱任务)

/* Create task to handle mailbox messges */
Task_Params_init(&taskParams);
taskParams.stackSize = 16*1024;
Task_create(MmwDemo_mboxReadTask, &taskParams, NULL);

进到这个任务中,可以看到这个语句:

retVal = Mailbox_read(gMmwMssMCB.peerMailbox, (uint8_t*)&message,
sizeof(MmwDemo_message));

这个就是把DSS那边传过来的信息给读取出来,放到message中。然后下面根据message信息往上位机进行传送。下面这段代码比较重要:

                totalPacketLen = sizeof(MmwDemo_output_message_header);
                UART_writePolling (gMmwMssMCB.loggingUartHandle,
                                   (uint8_t*)&message.body.detObj.header,
                                   sizeof(MmwDemo_output_message_header));

                /* Send TLVs */
                for (itemIdx = 0;  itemIdx < message.body.detObj.header.numTLVs; itemIdx++)
                {
                    UART_writePolling (gMmwMssMCB.loggingUartHandle,
                                       (uint8_t*)&message.body.detObj.tlv[itemIdx],
                                       sizeof(MmwDemo_output_message_tl));
                    UART_writePolling (gMmwMssMCB.loggingUartHandle,
                                       (uint8_t*)SOC_translateAddress(message.body.detObj.tlv[itemIdx].address,
                                                                      SOC_TranslateAddr_Dir_FROM_OTHER_CPU,NULL),
                                       message.body.detObj.tlv[itemIdx].length);
                    totalPacketLen += sizeof(MmwDemo_output_message_tl) + message.body.detObj.tlv[itemIdx].length;
                }

                /* Send padding to make total packet length multiple of MMWDEMO_OUTPUT_MSG_SEGMENT_LEN */
                numPaddingBytes = MMWDEMO_OUTPUT_MSG_SEGMENT_LEN - (totalPacketLen & (MMWDEMO_OUTPUT_MSG_SEGMENT_LEN-1));
                if (numPaddingBytes<MMWDEMO_OUTPUT_MSG_SEGMENT_LEN)
                {
                    uint8_t padding[MMWDEMO_OUTPUT_MSG_SEGMENT_LEN];
                    /*DEBUG:*/ memset(&padding, 0xf, MMWDEMO_OUTPUT_MSG_SEGMENT_LEN);
                    UART_writePolling (gMmwMssMCB.loggingUartHandle,
                                        padding,
                                        numPaddingBytes);
                }

MSS用函数UART_writePolling()即可把数据传送到上位机,那么具体这些数据内部是什么,下面继续分解。

上面的程序用了四个UART_writePolling()函数:

(1)帧头header

(2)TLV

(3)address

(4)padding

关于这些信息的具体含义,大家参照【呼吸心跳检测例程】PDF文档看就知道了,这里不做过多的阐述。其中这里最关键的信息是(3)address。这里传送的是一个地址,但是其实是传递这个地址下面的数据,具体地址下面是什么数据,接着解析。

现在我们去寻找数据的来源,即前往DSP核去查看。

依次往下寻找这些函数:

2.static void MmwDemo_dssDataPathTask(UArg arg0, UArg arg1)

if(event & MMWDEMO_FRAMESTART_EVT)
{
if(gMmwDssMCB.state == MmwDemo_DSS_STATE_STARTED)
{
if ((retVal = MmwDemo_dssDataPathProcessEvents(MMWDEMO_FRAMESTART_EVT)) < 0 )
{
System_printf (“Error: MMWDemoDSS Data Path process frame start event failed with Error[%d]\n”,
retVal);
}
}
}

3.static int32_t MmwDemo_dssDataPathProcessEvents(UInt event)

            /* Sending detected objects to logging buffer */
            MmwDemo_dssDataPathOutputLogging (dataPathObj); 
            dataPathObj->frameProcDoneTimeStamp = Cycleprofiler_getTimeStamp();

4. void MmwDemo_dssDataPathOutputLogging(MmwDemo_DSS_DataPathObj * dataPathObj)
/* Save output in logging buffer - HSRAM memory and a message is sent to MSS to notify
logging buffer is ready /
if (MmwDemo_dssSendProcessOutputToMSS(dataPathObj) < 0)
{
/
Increment logging error */
gMmwDssMCB.stats.detObjLoggingErr++;
}

5. int32_t MmwDemo_dssSendProcessOutputToMSS(uint8_t *ptrHsmBuffer,uint32_t outputBufSize, MmwDemo_DSS_DataPathObj *obj)

这个函数下是关键信息,包含帧头、字节长度、类型、地址等等:

在这里插入图片描述
在这里插入图片描述

下面疑惑的就是address映射的内容是什么了。

(1)首先看赋值的指针:

message.body.detObj.tlv[tlvIdx].address = (uint32_t) ptrCurrBuffer;;

(2)内存复制

 memcpy(ptrCurrBuffer, (void *)&vitalSignsStats, itemPayloadLen);

(3)vitalSignsStats结构体

  VitalSignsDemo_OutputStats vitalSignsStats;

(4)进入VitalSignsDemo_OutputStats查看

在这里插入图片描述

这些就是数据协议里传输的数据,都在这里面了,经过前面的一顿操作,现在终于搞清楚了,不得不说TI搞得很牛,封装得很全!

数据上传的部分说完了,现在讲数据下发,这个也不难!

请做好准备,这是今天的关键部分!

二、控制串口

回到MSS工程,去找到 Task_create(MmwDemo_mssInitTask, &taskParams, NULL)任务,然后进去寻找 MmwDemo_CLIInit()函数。

 * At this point, MSS and DSS are both up and synced. Configuration is ready to be sent.
 * Start CLI to get configuration from user
 *****************************************************************************/
MmwDemo_CLIInit();

进入MmwDemo_CLIInit()函数,可以发现这个函数是雷达配置命令的格式说明,如。

在这里插入图片描述

所有的配置参数都被cliCfg所定义。

最后这个函数是关键的地方:

/* 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");

CLI_open (&cliCfg)函数,这是用于初始化和设置 CLI 的函数。具体的函数定义,需要在SDK中去寻找。
在这里插入图片描述

找到CLI_open (CLI_Cfg* ptrCLICfg)函数的具体定义如下:

int32_t CLI_open (CLI_Cfg* ptrCLICfg)
{
Task_Params taskParams;
uint32_t index;
/* Sanity Check: Validate the arguments /
if (ptrCLICfg == NULL)
return -1;
/
Initialize the CLI MCB: /
memset ((void
)&gCLI, 0, sizeof(CLI_MCB));
/* Copy over the configuration: */
memcpy ((void *)&gCLI.cfg, (void )ptrCLICfg, sizeof(CLI_Cfg));
/
Cycle through and determine the number of supported CLI commands: /
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:/>”;
/
The CLI provides a help command by default:
* - Since we are adding this at the end of the table; a user of this module can also
* override this to provide its own implementation. /
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;
gCLI.cliTaskHandle = Task_create(CLI_task, &taskParams, NULL);
return 0;
}

在这个程序中有一个任务:

gCLI.cliTaskHandle = Task_create(CLI_task, &taskParams, NULL);

点进去看任务,看到有一个串口读的程序段。

    /* Read the command message from the UART: */
    UART_read (gCLI.cfg.cliUartHandle, &cmdString[0], (sizeof(cmdString) - 1));

其中有这么一段程序,这个就是我们之前下发命令时,上位机收到下位机的echo命令,用于确保命令下发正确(匹配):

在这里插入图片描述
在这里插入图片描述

看到现在真不容易,但是下面的真的很关键,我都差点看晕过去。

串口读到的数据存在cmdString[0]中,然后给了:

ptrCLICommand = (char*)&cmdString[0];

给了 ptrCLICommand, ptrCLICommand拆分又给了 tokenizedArgs[argIndex]。

   tokenizedArgs[argIndex] = strtok(ptrCLICommand, delimitter);

继续进入CLI_MMWaveExtensionHandler()函数

   cliStatus = CLI_MMWaveExtensionHandler (argIndex, tokenizedArgs);

在这里插入图片描述

该函数中定义最关键的部分是:

/* Get the pointer to the mmWave extension table */
ptrCLICommandEntry = &gCLIMMWaveExtensionTable[0];

&gCLIMMWaveExtensionTable[0]下就是串口数据赋值给雷达。

在这里插入图片描述

举个例子如,就是下面程序中进行赋值的:

在这里插入图片描述
在这里插入图片描述

至此,我们知道了整个TI毫米波雷达串口数据上传、下发的所有过程,可谓历经千辛万苦,人都快吐了。

还有很多地方解释的不详细,具体内容大家可以细细研究,如有写错还请告知。

创作不宜,谢谢你的赞!

  • 4
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
当阅读Spring Boot代码时,可以按照以下步骤进行: 1. 了解项目结构:Spring Boot项目通常遵循标准的MVC(Model-View-Controller)结构,其中包含控制器、服务、数据访问层等模块。首先,了解项目的整体结构有助于理解代码的组织方式。 2. 阅读启动类:Spring Boot应用程序的入口点是一个带有`@SpringBootApplication`注解的启动类。该类通常包含了主方法,用于启动应用程序。可以阅读该类来了解应用程序的配置和初始化过程。 3. 阅读配置文件:Spring Boot使用`application.properties`或`application.yml`等配置文件来配置应用程序。这些文件中包含了一些常用的配置项,如数据库连接、日志配置等。阅读配置文件可以了解应用程序的基本配置信息。 4. 阅读控制器:控制器负责处理HTTP请求,并将请求分派给相应的服务进行处理。通过阅读控制器代码,可以了解应用程序的请求处理逻辑。 5. 阅读服务:服务层是应用程序的心业务逻辑部分,负责处理业务逻辑、调用数据访问层等。阅读服务层代码可以了解应用程序的心功能和业务逻辑。 6. 阅读数据访问层:数据访问层负责与数据库进行交互,执行CRUD(创建、读取、更新、删除)操作。阅读数据访问层代码可以了解应用程序与数据库交互的方式和逻辑。 7. 阅读模型:模型类用于定义数据结构,通常与数据库中的表结构相对应。通过阅读模型类的代码,可以了解应用程序的数据结构和字段定义。 8. 阅读测试代码:Spring Boot鼓励进行单元测试和集成测试,测试代码通常位于与源代码相同的目录中。阅读测试代码可以了解应用程序的测试覆盖范围和测试用例。 在阅读代码时,可以结合官方文档、注释和命名规范等辅助信息来理解代码的含义和作用。还可以使用调试工具来跟踪代码的执行过程,以更深入地理解代码的运行流程。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

调皮连续波(rsp_tiaopige)

鼓励调皮哥继续在雷达领域创作!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值