infineon BGTR13C target code

infineon
radar
Author

dd21

Published

December 8, 2022

Abstract

infineon 下位机代码处理流程概览, 以 MCU7 为案例

Referance

Infineon-Infineon-XENSIVTM_KIT_CSK_BGT60TR13C-UserGuide-UserManual-v01_00-EN.pdf

目录结构

Radar Development Kit\3.3.1.202211181510\assets\software\firmware-rbb7\Firmware\sources\targets\atmel> tree .
├─subprojects
  └─RadarBaseboardMCU7
      └─bsp
          ├─atr22
          ├─avian
          └─ltr11
└─target_platform
    ├─contrib
      ├─ASF
      │  ├─common
      │  │  ├─boards
      │  │  │  └─user_board
      │  │  ├─services
      │  │  │  ├─clock
      │  │  │  │  └─sams70
      │  │  │  ├─ioport
      │  │  │  │  └─sam
      │  │  │  ├─serial
      │  │  │  │  └─sam_uart
      │  │  │  ├─sleepmgr
      │  │  │  │  └─sam
      │  │  │  └─usb
      │  │  │      ├─class
      │  │  │      │  └─cdc
      │  │  │      │      └─device
      │  │  │      └─udc
      │  │  └─utils
      │  │      ├─interrupt
      │  │      └─stdio
      │  │          └─stdio_serial
      │  ├─sam
      │  │  ├─drivers
      │  │  │  ├─afec
      │  │  │  ├─efc
      │  │  │  ├─matrix
      │  │  │  ├─pio
      │  │  │  ├─pmc
      │  │  │  ├─pwm
      │  │  │  ├─qspi
      │  │  │  ├─rstc
      │  │  │  │  └─example1
      │  │  │  ├─spi
      │  │  │  ├─tc
      │  │  │  ├─twihs
      │  │  │  ├─uart
      │  │  │  ├─usart
      │  │  │  ├─usbhs
      │  │  │  └─xdmac
      │  │  ├─services
      │  │  │  └─flash_efc
      │  │  └─utils
      │  │      ├─cmsis
      │  │      │  └─sams70
      │  │      │      ├─include
      │  │      │      │  ├─component
      │  │      │      │  ├─instance
      │  │      │      │  └─pio
      │  │      │      └─source
      │  │      │          └─templates
      │  │      │              └─gcc
      │  │      ├─fpu
      │  │      ├─header_files
      │  │      ├─linker_scripts
      │  │      │  └─sams70
      │  │      │      └─sams70q21
      │  │      │          └─gcc
      │  │      ├─make
      │  │      ├─preprocessor
      │  │      └─syscalls
      │  │          └─gcc
      │  └─thirdparty
      │      └─CMSIS
      │          ├─Include
      │          └─Lib
      │              └─GCC
      ├─config
      └─debug_scripts
          └─gcc
    └─impl
        ├─custom
        ├─ids
        ├─peripherals
        └─serial

进入到 RadarBaseboardMCU7

这里一共对应三款雷达板

  1. atr22
  2. avian
  3. ltr11
RadarBaseboardMCU7
└─bsp
    ├─atr22
    ├─avian
    └─ltr11

RadarBaseboardMCU7:: main.c

标题格式 dir::file.cor(file.h) :: function :: interfunction….

进入到 main 函数中, main 函数中结构很简单

int main(void)
{
    // Board构造函数, 只调用这里只调用一次
    Board_Constructor();

    /* Loop forever */
    while (1)
    {
        Board_run();
    }
}

RadarBaseboardMCU7:: main.c :: Board_Constructor

该函数是 board 构造(init), 在该函数的Platform_Constructor()初始化平台, 创建低级接口

void Platform_Constructor(void)
{
    System_init();
    System_disableWatchdog();

    SysTimer_init();

    System_startUSB();

    PlatformInterfaces_Constructor();

    Timer_Constructor();
}

接下来是对底板(atmel)的判断, 判断地板的类型, 这些参数配置在BoardDefinition.h中, 后续如果添加版本, 只需要修改这里的定义即可.

// 如果不是Rev. A, 将原本BOARD_NAME_BASE的位置截断.
if (!Sams70RevisionA())
    {
        // If this is not Rev. A, trim the suffix from the board name
        boardInfo.name[sizeof(BOARD_NAME_BASE) - 1] = '\0';
    }

BoardDefinition.h

对板子信息进行描述, 方便后期移植工作.

// BOARD_NAME will be trimmed to BOARD_NAME_BASE in Board.c depending on silicon revision
#define BOARD_NAME_BASE "RadarBaseboardMCU7"
#define BOARD_NAME      BOARD_NAME_BASE " (Rev. A)"
#define BOARD_VID       0x058B
#define BOARD_PID       0x0251

//#define BOARD_EEPROM_ADDRESS_24CW128X 0x50

#define COMMUNICATION_SERIAL


#include "../../../version.h"

后边是对gpio, spi,i2c 的构造, 这里的代码写的很巧妙, 分别在上层创建对应各个外设的类(结构体), 但是实际上该类掉用的是bsp的接口, 这么做将 bsp 和上层接口进行分离, 使得 bsp 做出修改后, 只要接口不做调整, 上层应用也无需做出调整. IGpio前面的 I应该是Interface的意思.

    IGpio *gpio = &PlatformGpio;
    ISpi *spi   = &PlatformSpi;
    II2c *i2c   = &PlatformI2c;

紧接着是对雷达接口的创建, 和上面的操作类似.

 IRadar *radar = NULL;

下面是对, 板子的类型做出检测:HatvanPlus 或 HatvanLegacy(MCU7)

是对板子的一个类型的判断, 判断有几个 connecter, MCU7 上, 有两个链接器, 但是只能初始化一个.

/* 检测板类型:HatvanPlus 或 HatvanLegacy。
     *
     * 用于检测的引脚:
     * 在标记为 BoardID 并连接到下拉的 HatvanPlus 上;
     * 在标记为S2_SPI_DIR并连接到引体向上的 HatvanLegacy 上,
     * 作为第二电平转换器电路的一部分。
     *
     * 解决方法:需要使能 LDO2 以提供 3.3v
     * 用于上拉偏置,实现精确检测。
*/

  // detect board type
    const bool isHatvanLegacy = Board_isHatvanLegacy();
    if (isHatvanLegacy)
    {
        ShieldConnectorDefinition = &ShieldConnectorDefinitionHatvanLegacy[0];
        BoardSpiDefinition        = &BoardSpiDefinitionHatvanLegacy[0];
        BoardRadarPinsConfigAvian = &BoardRadarPinsConfigAvianHatvanLegacy[0];
        m_shieldConnectorCount    = ARRAY_SIZE(ShieldConnectorDefinitionHatvanLegacy);
    }
    else
    {
        // HatvanPlus has two different kinds of connectors and just one is initialized
        if (Board_isHatvanPlusV9Connected())
        {
            ShieldConnectorDefinition = &ShieldConnectorDefinitionHatvanPlus[1];
            BoardSpiDefinition        = &BoardSpiDefinitionHatvanPlus[1];
            BoardRadarPinsConfigAvian = &BoardRadarPinsConfigAvianHatvanPlus[1];
        }
        else
        {
            ShieldConnectorDefinition = &ShieldConnectorDefinitionHatvanPlus[0];
            BoardSpiDefinition        = &BoardSpiDefinitionHatvanPlus[0];
            BoardRadarPinsConfigAvian = &BoardRadarPinsConfigAvianHatvanPlus[0];
        }
        m_shieldConnectorCount = 1;
    }

因为上面对板子类型进行判断, 所以才得到 spi的一个具体配置信息, 才能后进行初始化工作, 代码如下.

PlatformSpi_initialize(BoardSpiDefinition, m_shieldConnectorCount);

spi配置完成后对 led 进行配置, 配置 led 的一个状态表, 以及当前状态的设置.

LedSequence_Constructor();
    LedSequence_setStatus(LED_STATUS_OPERATING);

检查核心板(radar 部分(shield))连接器是否存在配置错误 只有当扩展板具有 I2C 上拉时,才能检测到镜像连接 , OC 引脚上的其他意外电平被解释为错误的配置

 if (Board_detectShields() == E_SUCCESS)
    {
        /*
                使用 SPI 和 I2C 检查已知设备是否存在,

                尝试读取芯片 ID 并按以下顺序实例化相应的驱动程序
                (每个实例化只有一个设备)

                - Avian (SPI)  mcu 7 版本调用这个!!!!!
                - LTR11 (SPI)
                - ATR22 (I2C)
        */

        radar = Board_detectRadar(gpio, spi, i2c, &m_data);
    }

通信协议等外设, 继续正常初始化,这样即使没有检测到设备,I2C、SPI、GPIO 等也可以使用. 是能通信接口.

// Enable communication interface
    RequestHandler_Constructor(gpio, spi, m_data, i2c);
    ProtocolHandler_Constructor();
    CommandHandlerRadar_Constructor();

判断 radar 所有外设是否配置完成, 如果配置完成, 设置数据回调函数, 让回调函数来处理数据, 回调了函数Board_dataCallback, 其中封装了一帧的数据, 并发送给上层的操作.

 if (radar != NULL)
    {
        Commands_IRadar_register(radar);

        // register callback function to handle arriving data
        m_data->registerCallback(Board_dataCallback, NULL);
    }

到此整块板子(雷达主控) 的各部分件构造全部完成

RadarBaseboardMCU7:: main.c :: Board_run()

该部分, 是雷达各部分初始化工作,以及使能完成后, 对各中操作的监听, 以及响应的中断处理函数.

/* Loop forever */
    while (1)
    {
        Board_run();
    }

进入到Board_run函数中, Platform_run函数中没有任何操作, 预留给用户进行编写运行过程中的相关状态操作(猜测).

// needs to be called for state machines, etc.
Platform_run();

接下来的三个函数是针对三款不同的 60G mmwave(Avian, ltr11, atr22)进行执行响应的操作, 但是如果没有创建对应的实力的话, 函数会直接返回, 不会执行任何操作.

// these run functions can just be called unconditionally, since they will immediately return by default if they are not initialized
    DataAvian_run();
    DataLtr11_run();
    DataAtr22_run();

这里的案例是avian系列的, 所以进入到该函数中其他两个函数在该平台下, 直接返回, 无任何操作.

DataAvian_run 函数中, 先判断是够构建该实力, 判断该变量是否被实例化, 如果没有实例化, 没有实例化的默认值为NULL, 所以该函数直接反回, DataLtr11_runDataAtr22_run 中的该部分操作也类似.

if (!m_callback)
    {
        return;
    }

接下来是将雷达数据区遍历, 这里最大支持一个数据.

for (unsigned int index = 0; index < DATA_AVIAN_MAX_COUNT; index++)

检查雷达运行状态

if (!self->running)
        {
            continue;
        }

检查数据队列中的数据, 是否有数据

 /* Check if new data packets have been fetched into the queue */
        Queue_t *queue          = &self->queue;
        const uint32_t written = queue->written;
        const uint32_t read    = queue->read;
        if (read == written)
        {
            // queue is empty
            continue;
        }

往上层发送数据, 上位机.

 /* Transmit enqueued data packets to upper layers */
        const uint32_t idx_read             = queue->idx_read;
        const uint32_t max_packets          = queue->max_packets;
        const uint32_t packet_size          = queue->packet_size;
        const uint32_t payload_size         = queue->payload_size;
        uint8_t *payload                    = &queue->buffer[idx_read * packet_size];
        const queue_packet_header_t *header = &queue->packetHeaders[idx_read];
        const uint64_t timestamp            = chrono_ticks_to_microseconds(header->ticks);

检查是否溢出, 数据可能来自不同的 frame, 如果来自不同 frame, 判断会不会导致 FIFO 溢出.

/* Check if FIFO overflow or underflow condition occurred */
        bool errors = false;
        if (self->frameSlices > 1)
        {
            // In case a frame is being aggregated, check all slices in the queue
            uint32_t idx_write = queue->idx_write;
            for (uint32_t i = idx_read; i < idx_write; i++)
            {
                const queue_packet_header_t *sliceHeader = &queue->packetHeaders[i];

                errors = fifo_overflow(sliceHeader->gsr0);
                if (errors)
                {
                    break;
                }
            }
        }
        else
        {
            // If no aggregation, just check the next slice in the queue
            errors = fifo_overflow(header->gsr0);
        }

如果存在错误, 将雷达停止, 回调溢出错误函数, 记录当前时间错, 和 FIFO 索引.然后继续往下运行

if (errors)
        {
            DataAvian_stop(self->index);
            errorCallback(ERR_FIFO_OVERFLOW, self->index, timestamp);
            continue;
        }

检查队列中是否有完整的数据帧, 如果没有回调函数还不能被调用.

const uint32_t slicesAvailable = written - read;
        if (slicesAvailable < self->frameSlices)
        {
            // complete frame is not yet available
            这里的如果错误的逻辑还没有写, 就是错误与否都往上发送
            continue;
        }

将队列中的数据进行发送

m_callback(m_arg, payload, payload_size * self->frameSlices, self->index, timestamp);

更新读取的索引, 和已读数量, 并且释放上一帧已经发送的数据

queue->idx_read = (idx_read + self->frameSlices) % max_packets;
        queue->read     = read + self->frameSlices;

如果数据队列已满, 数据获取请求可能会被挂起, 没有被挂起则每次回调后更新指针.

if (self->pending)
        {
            DataAvian_fetchCallback(self, false);
            self->pending--;
        }