附件:02_radar_presence.zip存在检测是雷达传感器常见的一种应用,英飞凌的雷达芯片有相关的DSP支持库用于处理雷达芯片采集到的数据,用于检测区域内的存在检测。同时也有相关的示例程序说明如何使用相关的库函数。
【英飞凌 CY8CKIT-062S2-AI评测】-02雷达芯片初始化和测试
https://bbs.21ic.com/icview-3495993-1-1.html
(出处: 21ic电子技术开**坛)
上述帖子中介绍如何初始化雷达芯片和对其进行测试,本文介绍处理雷达数据用于存在检测。
1、添加FreeRTOS和Sensor-dsp驱动库
英飞凌的library-manager工具可以方便地管理工程中使用的软件组件,通过调用 make library-manager指令即可打开工程的库管理工具,或者使用IDE中对应的工具。VSCode的ModusToolbox扩展中也提供相应的按键用于调用library-manager工具。

使用library-manager添加FreeRTOS和sensor-dsp支持库。


更新工程后,可以查看当前工程中使用到的库包括用于串口重定向的retarget-io、freertos支持库、雷达传感器的sensor-xensiv-bgt60trxx库以及传感器信号处理相关的sensor-dsp。

2、FreeRTOS使用
ModusToolbox中添加的库组件以代码仓库的形式保存在的 mtb_share文件夹中,通过工程中xxx.code-workspace文件打开VSCode,可以在左侧的文件树视图中看到 mtb_share文件夹中的内容。

FreeRTOS组件中除了包含FreeRTOS相关的源码,在doc文件夹中有相关的使用说明。

在工程的Makefile文件中,在 COMPONENTS变量中添加FREERTOS
COMPONENTS += FREERTOS
从雷达存在检测示例程序中复制其中的 FreeRTOSConfig.h文件到工程的source文件夹中,使用已经配置好的环境,或者从FreeRTOS仓库的 Source/portable/COMPONENT_(CORE)*路径中复制和芯片内核对应的 FreeRTOSConfig.h文件,并对其进行修改。
在代码中添加FreeRTOS相关的头文件,即可创建FreeRTOS应用程序。
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
3、雷达信号处理
在英飞凌的存在检测示例程序中,可以看到其中有关雷达数据梳理的时序图如下。

雷达芯片FIFO中的数据就绪后产生中断,MCU接收到中断后读取FIFO中的数据到缓存区,缓存区中的数据达到算法需要的数据后,对对其进行数据处理,进行物体存在检测。
3.1 雷达FIFO数据获取
雷达芯片的数据就绪并产生中断通知MCU读取FIFO中的采样数据,sensor-xensiv-bgt60trxx库中提供相关的fifo处理函数,通过调用 xensiv_bgt60trxx_get_fifo_data读取雷达芯片fifo中的缓存数据。
/*******************************************************************************
* Function Name: read_radar_data
********************************************************************************
* Summary:
* This is the function for reading radar data using buffering
*
* Parameters:
* * data: pointer to radar data
* *num_samples: pointer to number of samples per frame
* samples_ub: maximum number of samples to be copied at a time from owner task/caller
*
* Return:
* int32_t: 0 if success
*
*******************************************************************************/
int32_t read_radar_data(uint16_t* data, uint32_t *num_samples, uint32_t samples_ub)
{
if (xensiv_bgt60trxx_get_fifo_data(&bgt60_obj.dev,
data,
NUM_SAMPLES_PER_FRAME) == XENSIV_BGT60TRXX_STATUS_OK)
{
*num_samples = NUM_SAMPLES_PER_FRAME *2; // in bytes
if (samples_ub < NUM_SAMPLES_PER_FRAME *2)
{
xensiv_bgt60trxx_soft_reset(&bgt60_obj.dev,XENSIV_BGT60TRXX_RESET_FIFO );
}
}
return 0;
}
3.2 数据采集和处理
定义两个FreeRTOS任务,main_task实现
processing_task的创建;
- 雷达外设的初始化;
- 雷达缓存数据的读取以及数据的预处理;
processing_task实现
- 初始化存在检测算法运行的环境;
- 接收预处理数据的通知,并执行存在检测算法,输出结果到串口终端;
/* RTOS tasks */
#define MAIN_TASK_NAME "main_task"
#define MAIN_TASK_STACK_SIZE (configMINIMAL_STACK_SIZE * 4)
#define MAIN_TASK_PRIORITY (configMAX_PRIORITIES - 2)
#define PROCESSING_TASK_NAME "processing_task"
#define PROCESSING_TASK_STACK_SIZE (configMINIMAL_STACK_SIZE * 4)
#define PROCESSING_TASK_PRIORITY (configMAX_PRIORITIES - 3)
static void main_task(void *pvParameters);
static void processing_task(void *pvParameters);
读取雷达FIFO中的数据并缓存,对接收的数据量进行判断,是否满足进行存在检测的数据量,示例程序中提供相关数据的缓存结构体 manager_state_s和操作函数接口 radar_data_manager_s。
manager_state_s用于管理数据缓存区和内存分配的接口函数,在使用FreeRTOS时,使用Notify功能实现雷达数据的订阅功能,可以供多个程序读取。
#ifdef FREERTOS_AWARE
/*
*\def typedef struct subscribed_task_lists_s
*
* Attributes pertaining to every subscriber task
*/
typedef struct {
bool data_read; /*<<indicate and mark if task has read the data*/
TaskHandle_t suscriber_task_handle; /*<<The FREERTOS Task handle representing subscriber task*/
}subscribers_task_lists_s;
#endif
/*
*\def typedef struct manager_state_s
*
* Attributes for managing radar data.
*/
typedef struct {
uint8_t *buffer; /*<< Pointer to heap for FIFO buffer allocation*/
uint32_t buff_size; /*<< Total size of buffer in bytes FIFO buffer */
uint32_t samples; /*<< Total number of bytes in FIFO */
uint32_t head,tail; /*<< front and back positions of the FIFO queue*/
uint32_t fill_level; /*<< FIFO water mark level in bytes*/
uint8_t subscribers; /*<< Number of subscribers (task/callers)*/
#ifdef FREERTOS_AWARE
subscribers_task_lists_s subscriptions[ACTIVE_SUBSCRIPTION_UB + 1]; /*<<list of all subscriber tasks of type \ref subscribers_task_lists_s*/
#else
cb_radar_data_event subscriptions[ACTIVE_SUBSCRIPTION_UB + 1]; /*<<list of all subscriber tasks of type \ref cb_radar_data_event*/
#endif
void* (*malloc_func)(size_t size); /*<<Hold reference to consumer supplied memory allocation*/
void (* free_func)(void* ptr); /*<Hold reference to consumer supplied definition for releasing allocated memory<*/
}manager_state_s;
操作函数接口 radar_data_manager_s提供数据操作接口,其中 in_read_radar_data有外部提供,用于雷达数据缓存到buffer中的数据输入部分,read_from_buffer用buffer中数据的输出。run用于对缓存区数据的管理以及通知订阅任务读取数据。具体的函数实现可以查看示例中的源码。
/*
* [url=/u/typedef]@typedef[/url] typedef void (*cb_radar_data_event)(void* data_ptr, uint32_t size)
* Data subscriber callback prototype. The subscriber's callback function must follow this prototype.
*/
typedef void (*cb_radar_data_event)(void* data_ptr, uint32_t size);
/*
* @typedef typedef struct radar_data_manager_s
* Radar Data Manager (RDM) interface .
*/
typedef struct {
int32_t (*in_read_radar_data) (uint16_t* data, uint32_t *num_samples, uint32_t samples_ub);
#ifdef FREERTOS_AWARE
int32_t (*subscribe)(TaskHandle_t subscriber_task);
int32_t (*read_from_buffer)(int32_t subscription_id, uint16_t **data_ptr, uint32_t *size);
void (*ack_data_read)(int32_t subscription_id);
void (*run)(bool run_from_isr);
#else
int32_t (*subscribe)(cb_radar_data_event call_back);
void (*run)(void);
#endif
void (*unsubscribe)(int32_t subscription_id);
int32_t (*set_fill_level)(int32_t fill_level);
int32_t (*get_fill_level)(void);
}radar_data_manager_s;
模块初始化时设置 in_read_radar_data的函数指针为从雷达FIFO中读取数据的函数 read_radar_date,并设置缓存区的大小以及数据可读的大小。
int main(void)
{
...
mgr.in_read_radar_data = read_radar_data;
radar_data_manager_init(&mgr, NUM_SAMPLES_PER_FRAME *6, NUM_SAMPLES_PER_FRAME *2);
radar_data_manager_set_malloc_free(pvPortMalloc,vPortFree);
...
}
在需要读取数据的任务中调用订阅的接口。这样在任务的循环部分,等待通知即可实现雷达数据的传递。
static __NO_RETURN void main_task(void *pvParameters)
{
mgr.subscribe(main_task_handler);
for(;;)
{
/* Wait for the GPIO interrupt to indicate that another slice is available */
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
mgr.read_from_buffer(1, &data_buff, &sz);
}
}
接收的雷达原始数据需要进行格式转换和归一化处理。输出预处理完成后,通知 processing_task对数据进行处理
static __NO_RETURN void main_task(void *pvParameters)
{
for(;;)
{
/* Data preprocessing */
uint16_t *bgt60_buffer_ptr = data_buff;
float32_t *frame_ptr = &frame[0];
for (int32_t sample = 0; sample < NUM_SAMPLES_PER_FRAME * 2; ++sample)
{
*frame_ptr++ = ((float32_t)(*bgt60_buffer_ptr++) / 4096.0F);
}
mgr.ack_data_read(1);
/* calculate the average of the chirps first */
arm_fill_f32(0, avg_chirp, NUM_SAMPLES_PER_CHIRP);
for (int chirp = 0; chirp < NUM_CHIRPS_PER_FRAME * 2; chirp++)
{
arm_add_f32(avg_chirp, &frame[NUM_SAMPLES_PER_CHIRP * chirp], avg_chirp, NUM_SAMPLES_PER_CHIRP);
}
arm_scale_f32(avg_chirp, 1.0f / NUM_CHIRPS_PER_FRAME, avg_chirp, NUM_SAMPLES_PER_CHIRP);
if(ce_app_state.last_reported_event.timestamp != last_timestamp)
{
last_timestamp = ce_app_state.last_reported_event.timestamp; // save latest timestamp
}
/* Tell processing task to take over */
xTaskNotifyGive(processing_task_handler);
}
}
雷达存在检测的算法在英飞凌官方示例中的 xensiv_radar_presence.c/h中提供相关的源码,将文件复制到工程中,并引用头文件即可使用。调用 xensiv_radar_presence_process_frame对预处理的雷达帧数据处理,可以得到存在检测的结果。
static __NO_RETURN void processing_task(void *pvParameters)
{
(void)pvParameters;
xensiv_radar_presence_handle_t handle;
//cy_rslt_t result;
xensiv_radar_presence_set_malloc_free(pvPortMalloc,
vPortFree);
if (xensiv_radar_presence_alloc(&handle, &default_config) != 0)
{
CY_ASSERT(0);
}
xensiv_radar_presence_set_callback(handle, presence_detection_cb, NULL);
for(;;)
{
/* Wait for frame data available to process */
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
xensiv_radar_presence_process_frame(handle, avg_chirp, xTaskGetTickCount() * portTICK_PERIOD_MS);
process_verbose_cmd(handle, xTaskGetTickCount() * portTICK_PERIOD_MS);
}
}
在存在检测的回调函数中,根据结果输出不同的信息,或者执行其他函数调用供程序的其余部分调用。
void presence_detection_cb(xensiv_radar_presence_handle_t handle,
const xensiv_radar_presence_event_t* event,
void *data)
{
(void)handle;
(void)data;
if (!ce_app_state.verbose)
{
switch (event->state)
{
case XENSIV_RADAR_PRESENCE_STATE_MACRO_PRESENCE:
cyhal_gpio_write(USER_LED1, true);
cyhal_gpio_write(USER_LED2, false);
printf("[INFO] macro presence %" PRIi32 " %" PRIi32 "\n",
event->range_bin,
event->timestamp);
break;
case XENSIV_RADAR_PRESENCE_STATE_ABSENCE:
printf("[INFO] absence %" PRIu32 "\n", event->timestamp);
cyhal_gpio_write(USER_LED1, false);
cyhal_gpio_write(USER_LED2, true);
break;
default:
printf("[MSG] ERROR: Unknown reported state in event handling\n");
break;
}
}
/* save the last reported event state */
ce_app_state.last_reported_event = *event;
}
程序编译并下载到开发板后的输出如下,存在检测的结果根据检测区域内的变化而产生输出。

4、总结
英飞凌雷达存在检测的示例代码结构清晰,而且都是公开的源码,对于学习使用英飞凌雷达存在检测开发是很好的学习材料。
附件:01_Radar_Test_Mode.zip