AD9026芯片开发实录6-example code

        官方发布的软件包中,带了一份example code,用于向客户展示API的调用方法以及基于官方的验证版ADRV902X最简单的bring up的流程。

        该 example 位于软件包的路径下:“\Adi.Adrv9025.Api\src\c_src\app\example\”。

        代码组成:

        

  1. initdata.c / initdata.h 定义了一组默认的初始化配置参数和多片同步后初始化(PostMCS)的配置。这两个文件可以通过官方提供的GUI生成得到。在example code的工程中,initdata.c 源文件定义的 `adrv9025InitInst` 初始化配置结构体,并不会被用到,在后续的章节中会进行说明。

  2. main.c 文件给出了example 工程的具体实现,包括单板的初始化,FPGA/时钟芯片的初始化,以及ADRV902X的bringup,这些流程都是通过调用官方提供的API来实现的。

  3. makefile文件给出了构建example工程的方法,在Linux的环境中makefile较为通用,同时该makefile文件也给出了API的构建集成方式。

        下面的章节会重点介绍这几个文件中的代码实现以及如何在官方提供的验证板上构建并运行example code

        main函数的开头,就是单板的一些初始化准备工作:

        

int main(){    uint32_t rxChannelMaskGet = 0x00;    uint32_t txChannelMaskGet = 0x00;    uint32_t rxChannelMaskSet = 0x0F;    uint32_t txChannelMaskSet = 0x0F;    int inputSelection = 0x00;    recoveryAct = discoverPlatform();    if (recoveryAct != ADI_COMMON_ACT_NO_ACTION)    {        printf("\nERROR: : %s:%u has failed.\n", __func__, __LINE__);    }

       官方给的函数名称也比较有实际意义,`discoverPlatform`的字面意思是发现平台,也就是说在正式开始各种初始化工作前,需要先确定单板信息以及做一些软件层面的准备工作。

        ADRV902X官方指定的验证板是ADS9-V2EBZ,但由于该数字板的价格偏高,且单板的bringup时间较长,所以一般会选用价格较为便宜的ADS8作为其数字验证板使用,但是官方的example code例程并不支持ADS8 验证板。话题回到软件层面,`discoverPlatform`函数就是用来识别当前使用的验证板平台。

       在软件层面,ADI把数字板抽象为母板(motherboard),而ADRV902X 射频验证板抽象为子板(daughterboard),motherboard和daughterboard各有一个抽象出来的结构体,分别是 `adi_motherboard_trx_t`  和 `adi_daughterboard_trx_t`,这两个结构体采用了面向对象的思想,其中包含了单板的相关属性和操作方法。motherboard结构体中包含了daughterboard的结构体,这个也比较好理解,对比到硬件上,ADRV902X的验证平台,是由数字母版和扣在母版上的子板一并构成的。

函数`discoverPlatform`的实现如下:

{    printf("\n*** Begin Platform Discover *** ");    /********************************************************************************************/    /**************** Discover motherboard ******************************************************/    /********************************************************************************************/    /* This API creates a generic structure to hold all the necessary motherboard information ***/    recoveryAct = adi_motherboard_Discover(&motherboard);    if ((recoveryAct != ADI_COMMON_HAL_OK) || (motherboard == NULL))    {        printf("ERROR: adi_Motherboard_Discover has failed.\n");        return ADI_COMMON_ACT_ERR_RESET_FULL;    }    /**************** END: Discover motherboard *************************************************/    /********************************************************************************************/    /**************** Discover daughterboard ****************************************************/    /********************************************************************************************/    /* This API creates a generic structure to hold all the necessary daughterboard information */    recoveryAct = adi_daughterboard_Discover(motherboard);    if ((recoveryAct != ADI_COMMON_HAL_OK) || (motherboard == NULL))    {        printf("ERROR: ERPC-SERVER: %s:%u has failed.\n", __func__, __LINE__);        return failureReturn;    }    ...}    

        可以看到这个函数的主要作用是完成母版和子板的识别以及完成相关的硬件初始化的预备工作,比如配置结构体的初始化,hal层接口的挂接,硬件设备的资源配置等。

adi_motherboard_Discover

该函数的主要功能包括:

  1. 实例化子板结构体 `adi_daughterboard_trx_t`,并初始化其成为0;

  2. 实例化母板的设备层抽象,包括LOG和TIMER这两个模块;

  3. 识别母版类型;

  4. 完成platform 的hal层函数钩子注册挂接;

  5. 调用hal层设备打开接口,打开log模块;

注意这里很重要的一步是第4步,也是实际开发人员在集成的时候需要注意的步骤。

adi_daughterboard_Discover

在完成motherboard 的发现之旅后,便开始启动子板的发现之旅。该函数的主要功能包括:

1. 实例化子版的设备抽象,包括I2C/LOG/TIMER 这三个模块;

2. 挂接daughterboard对象中的方法(钩子函数们);

3. 通过daughterBoard->DeviceCreate,完成Clock/FPGA/TrxBoard 的Dispatch方法注册,用于后续的Clock/FPGA/TrxBoard的硬件初始化和配置操作,然后实例化Clock/FPGA/ADRV902X设备,在代码中对应结构体`adi_ad9528_Device_t`/`adi_adrv9025_Device_t`/`adi_fpga9010_Device_t`;

4. 通过daughterBoard->DeviceInit,实例化Clock/FPGA/TrxBoard的设备层抽象,这其中包含各个设备的SPI/I2C 总线接口,LOG 和 TIMER 模块,并调用 `adi_hal_HwOpen` 完成设备的打开。

        完成上述所有工作后,会将子板中实例化的Clock/FPGA/TrxBoard设备保存到三个全局对象中,分别为 `ad9528Device`/`adrv9025Device`和`fpga9025Device`中,方便后续的代码使用。

        总而言之,在真正program ADRV902X之前,官方示例代码通过子母板的抽象,完成了底层钩子函数的挂接、设备软件资源的分配、设备对应的控制总线(SPI/I2C)以及LOG 的基本配置和打开,为后续ADRV902X的初始化和Program做准备。

        这部分内容对用户做代码集成的时候有一定的指导作用。

ADRV902X 初始化及API使用方法

        回到示例main函数的主流程中,完成子母板以及子母板上设备的实例化和HAL抽象层初始化后,正式开始对ADRV902X 芯片进行初始化和配置。

        配置加载

        首先需要从UseCase的profile文件中加载配置,在实际的应用项目上,这一步可以跳过,如前文所说,可以使用GUI生成的initdata.h/initdata.c 文件,initdata.c 中保存了GUI根据实际修改配置所生成的所有关于ADRV902X的配置。在示例代码中使用了 `adi_adrv9025_ConfigFileLoad` 这个API来完成的这个任务,这也是在示例工程中第一个显式地调用ADRV902X API的例子:​​​​

static void configFileLoad(adi_adrv9025_Device_t *adrv9025_Device,                           adi_adrv9025_Init_t   *adrv9025_Init){    recoveryAct = ADI_COMMON_ACT_ERR_RESET_FULL;    /* Load ADRV9010 Init structure */    /* adiProfileFilePath is defined as const global at top of this file */    recoveryAct = adi_adrv9025_ConfigFileLoad(adrv9025_Device, adiProfileFilePath, adrv9025_Init);    if (recoveryAct != ADI_COMMON_ACT_NO_ACTION)    {        printf("ERROR: : %s:%u has failed.\n", __func__, __LINE__);        exit(EXIT_FAILURE);    }}

        这个例子也很好地说明了如何调用官方提供的API,ADI提供的API命名格式均为 `adi_adrv9025_functionName`,至少有一个入参 `adi_adrv9025_Device_t *adrv9025_Device`,返回值为 init32_t 类型的运行结果;所以调用时一般会先申明一个返回值变量,用来保存API的执行结果。API的第一个参数即为上一章节中提到的实例化的设备结构指针 adrv9025Device 。

        函数 `configFileLoad` 执行成功后会将加载的配置保存在全局变量 `adrv9025InitInst`中,也即initdata.c 中的配置结构体变量,这也是前面提到的,example code中initdata.c 的配置不会被用到的原因。关于ADRV902X的配置结构,以后有时间会更新专门的文章进行描述。

        在加载配置完成后,会通过usecase中的device clock/vcxo/reference clock 的值生成时钟的配置参数并保存。

        随后的操作是单板的PreProgram,其中会检查设备结构体是否实例化,并再次加载配置,感觉有点多余。

        最后的一部分是FPGA和clock的硬件初始化与配置,主要包括FPGA的AXI总线配置,MMCM配置,JESD配置等。至此完成了配置文件的加载和FPGA以及时钟的配置信息,历程运行到这里,可以看到ADRV902X子板上的时钟指示灯处于锁定状态。

        ADRV902X初始化

在完成上述的基本配置加载后,正式开始ADRV902X的初始化配置,配置的主要流程如下:

1. HWReset:ADRV902X芯片要求在上电配置之前,需要对芯片做一次硬件复位,API `adi_adrv9025_HwReset`即完成这个任务,但这个API同时也会检查hal层钩子函数的挂接状态以及硬件SPI的校验。

2. PreMcsInit:这一步是ADRV902X的具体初始化的第一步,通过调用API `adi_adrv9025_PreMcsInit_v2`来完成,这一步会初始化ADRV902X相关外设,加载ADRV902X的相关资源,比如固件版本、stream 二进制文件,增益补偿表等,然后尝试启动ADRV902X的arm芯片。

这里注意,API `adi_adrv9025_PreMcsInit_v2`需要提供初始化配置结构体,固件版本在BBIC侧单板操作系统中的路径,stream 二进制文件在BBIC侧单板操作系统中的路径,RX和TX的增益表。

3. NonBroadCast: 这一步主要是在上一步的基础上,等待ADRV902X 中的arm启动成功,并对TX和RX的通道参数进行配置,生成JESD的参数,通过调用API `adi_adrv9025_PreMcsInit_NonBroadCast` 实现。

4. MCS:这一步是完成多片ADRV902X的同步,需要时钟芯片的参与,MCS的控制是通过API `adi_adrv9025_MultichipSyncSet` 来实现,具体代码实现可参考example code。

5. PostMcsInit: 在完成多片同步后,还有一些初始化工作,比如TRX通道的使能,TXORX mapping,ADRV902X的InitialCal 的使能,这些工作都是在PostMcs阶段完成,通过调用API `adi_adrv9025_PostMcsInit` 实现。

6. JESD Link setup: 截止到上一步,芯片相关的基本配置和初始化已经完成,此时需要进行JESD建链操作,这个步骤稍微复杂一些,因为涉及到FPGA,clock和ADRV902X三个芯片的配合和设置,在example code中可以查看 `jesdBringup`这个函数。

7. Pa protection init: 在建链完成后,为了保护后继的PA,需要打开ADRV902X的PA 保护功能,通过调用 API `adi_adrv9025_TxRampDownInit` 来实现。

8. GP Int init: 这一步是打开GP INT的状态监控,这样我们就可以通过ADRV902X的两个GPIO管脚来监控芯片内部的事件,通过API `adi_adrv9025_GpIntInit` 来实现。

        上述的所有流程在main.c 中都被封装到了接口`programMadura`中,具体实现可以参考main.c 中该函数的源码。

        截止到这里,整个ADRV902X的初始化和板级的初始化已经结束,后续可以调用ADRV902X相关的功能API对其进行测试和控制,比如打开芯片的tracking calibration,TRX通道开关控制,ATT设置等。

        上述的流程涵盖了最基本的ADRV902X 设备的初始化流程,用户或开发者可以按照该流程将ADRV902X的初始化集成到自己的软件工程中。

 代码编译与环境部署

        ADI官方提供的构建工具为make,在example code的目录下可以看到Makefile,通过该makefile,可以直接在交叉编译环境,或者是官方的EVB板(ADS9/8) 上对代码进行编译构建。

        先说一下官方软件包中的makefile结构,除了device文件夹外,其他项目的次顶层文件夹下均有一个makefile,device文件夹下除了share_utils外的文件夹下,也均有makefile,这些makefile的构建目标,均为静态编译库,也就是说,这些文件夹内的文件相对独立,只会以接口形式调用其他文件夹下的函数。

        这些库的构建,均可以通过./c_src/boards下的makefile触发。这些库都会被example code工程构建所使用。对于example code 的makefile,通过调用上述./c_src/boards 下的makefile触发所有的静态库的编译,并链接到最终的输出应用的方式,构建完成整个example code工程:

        需要注意的一点是,官方提供的makefile中,是不包含debug编译选项的,如果所以如果是移植makefile并包含调试符号表时,可以增加debug编译选项为g1。作为编译的演示,使用指令 `make all -j4`即可启动编译,其中生成的'main'即为example code工程的应用程序:

        在构建完成后,我们需要在构建平台的文件系统上上传ADRV902X初始化需要的资源,如 固件版本,增益表,usecase profile等,存放的位置可以参考example code中的这两个变量:

const char adiProfileFilePath[] = "/home/analog/adrv9025_c_example/resources/adrv9025/profiles/public/ADRV9025Init_StdUseCase13_nonLinkSharing.profile";static adi_adrv9025_PlatformFiles_t platformFiles = { { "/home/analog/adrv9025_server/resources/ADRV9025_FW.bin;/home/analog/adrv9025_server/resources/ADRV9025_DPDCORE_FW.bin" },                                                      { "/home/analog/adrv9025_c_example/resources/adrv9025/arm_firmware/stream_image.bin" },                                                      { { { "/home/analog/adrv9025_c_example/resources/adrv9025/gain_tables/RxGainTable.csv" }, 0xFF } },                                                      1,                                                      { { { "/home/analog/adrv9025_c_example/resources/adrv9025/gain_tables/TxAttenTable.csv" }, 0x0F } },                                                      1 };

运行结果

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/39279.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

JavaScript 实用技巧

1. 使用 const 和 let 替代 var 在 ES6 之前,我们通常使用 var 声明变量。但如今,推荐使用 const 和 let,因为它们具有块级作用域,可以避免很多潜在的问题。 const PI 3.14; // 常量,无法重新赋值 let age 25; // …

边界框在目标检测中的作用与应用

目标检测是计算机视觉领域的核心任务之一,旨在从图像或视频中识别和定位感兴趣的目标。边界框(Bounding Box)是目标检测中常用的一种表示方法,用于确定目标在图像中的确切位置。本文将详细探讨边界框的概念、它在目标检测中的角色…

使用ElementUI组件库

引入ElementUI组件库 1.安装插件 npm i element-ui -S 2.引入组件库 import ElementUI from element-ui; 3.引入全部样式 import element-ui/lib/theme-chalk/index.css; 4.使用 Vue.use(ElementUI); 5.在官网寻找所需样式 饿了么组件官网 我这里以button为例 6.在组件中使用…

Redis中设置验证码

限制一分钟内最多发送5次,且每次有效时间是5分钟! String 发送验证码(phoneNumber) {key "shortMsg:limit:" phoneNumber;// 设置过期时间为 1 分钟(60 秒)// 使⽤ NX,只在不存在 key 时才能设置成功bool…

【QT】常用控件|widget|QPushButton|RadioButton|核心属性

目录 ​编辑 概念 信号与槽机制 控件的多样性和定制性 核心属性 enabled geometry ​编辑 windowTiltle windowIcon toolTip styleSheet PushButton RadioButton 概念 QT 控件是构成图形用户界面(GUI)的基础组件,它们是实现与…

tensorflow和numpy的版本

查看cuda版本 dpkg -l | grep cuda i libcudart11.0:amd64 11.5.117~11.5.1-1ubuntu1 amd64 NVIDIA CUDA Runtime Library ii nvidia-cuda-dev:amd64 11.5.1-1ubuntu1 …

搜维尔科技:数据手套为什么要选择SenseGlove

了解 SenseGlove SenseGlove 是一支由电子工程师、触觉研究人员和计算机视觉专家、XR 开发人员、UX 设计师和产品创新者组成的科幻爱好者团队,他们拥有丰富人类能力和赋予 Metaverse 意义的技能和热情。 推进触觉技术是我们实现这一目标的方式。 公司及产品背景 S…

【C++知识点总结全系列 (02)】:C++中的语句、运算符和表达式详细总结

文章目录 1、语句(1)简单语句A.空语句B.复合语句 (2)条件语句(3)迭代语句A.常规for循环B.范围for循环C.while和do...while (4)跳转语句A.break语句B.continue语句C.goto语句 (5)异常处理语句A.标准异常B.throw抛出异常 (6)try语句 2、运算符(1)算术运算符(2)关系运算符(3)逻辑运…

Cybervadis认证是什么?

Cybervadis认证是一种全面且深入的网络安全评估和认证服务,旨在帮助组织提高其网络安全实践的成熟度,并有效应对不断变化的网络威胁和攻击。以下是关于Cybervadis认证的一些关键信息: 认证目的: 评估和验证组织在网络安全方面的能…

Andrej Karpathy提出未来计算机2.0构想: 完全由神经网络驱动!网友炸锅了

昨天凌晨,知名人工智能专家、OpenAI的联合创始人Andrej Karpathy提出了一个革命性的未来计算机的构想:完全由神经网络驱动的计算机,不再依赖传统的软件代码。 嗯,这是什么意思?全部原生LLM硬件设备的意思吗&#xff1f…

HarmonyOS开发实战:UDP通讯示例规范

1. UDP简介 UDP协议是传输层协议的一种,它不需要建立连接,是不可靠、无序的,相对于TCP协议报文更简单,在特定场景下有更高的数据传输效率,在现代的网络通讯中有广泛的应用,以最新的HTTP/3为例,…

ESP32-Web-Server编程-建立多个 web server

ESP32-Web-Server编程-建立多个 web server 概述 当一个 web server 处理的请求过多、或者有长时间占用此 web server 的使用场景时,一个 web server 就不够用了。 这种情况下,我们可以在一个设备上建立两个或多个 web server 来满足更复杂的需求。 单个设备上建立多个 w…

Redis如何实现主从复制

Redis主从复制包括全量复制和增量复制。主是主服务器,从是从服务器,主服务器(master )的数据如果更新了也会同步到从服务器(slave),一个主服务器可以搭配很多个从服务器,主服务器负责写入,从服务器只能读取…

vmware虚拟机安装openEuler

一、openEuler简介 openEuler是一款开源操作系统。当前openEuler内核源于Linux,支持鲲鹏及其它多种处理器,能够充分释放计算芯片的潜能,是由全球开源贡献者构建的高效、稳定、安全的开源操作系统,适用于数据库、大数据、云计算、…

EEPROM内部原理

A2, A1, A0是EEPROM的地址引脚,用于设置设备地址。它们的作用如下: 设备寻址: 这三个引脚允许在I2C总线上唯一地标识EEPROM芯片。通过不同的连接方式(接高、接低或悬空),可以为同一类型的EEPROM芯片设置不同…

1uH电感SK6615电流1.5A频率2MHz输入5.5V同步降压转换器

SK6615C 1.5A 2MHz 5.5V同步降压转换器 SK6615 SOT23-5封装和丝印LA 描述 该SK6615C是一款高效、DC-DC降压型开关稳压器,能够提供高达1.5A的输出电流。该器件的工作输入电压范围为 2.6V 至 5.5V,输出电压范围为 0.6V 至 VIN。工作频率为2MHz&#xff0c…

02.C1W1.Sentiment Analysis with Logistic Regression

目录 Supervised ML and Sentiment AnalysisSupervised ML (training)Sentiment analysis Vocabulary and Feature ExtractionVocabularyFeature extractionSparse representations and some of their issues Negative and Positive FrequenciesFeature extraction with freque…

玩具租赁系统(安装+讲解+源码)

技术栈: 后端: SpringBoot Mysql MybatisPlus 前端: Vue Element 分为 管理员端 用户端 功能: 用户端 管理员端 观看地址: B站搜: 【毕设者】玩具租赁系统(安装讲解源码)

Java高级重点知识点-13-数据结构、List集合、List集合的子类

文章目录 数据结构List集合List的子类(ArrayList集、LinkedList集) 数据结构 栈 stack,又称堆栈,它是运算受限的线性表,其限制是仅允许在标的一端进行插入和删除操作,不允许在其他任何位置进行添加、查找、删除等操作…

cesium 添加 Echarts图层(人口迁徒图)

cesium 添加 Echarts 人口迁徒图(下面附有源码) 1、实现思路 1、在scene上面新增一个canvas画布 2、通坐标转换,将经纬度坐标转为屏幕坐标来实现 3、将ecarts 中每个series数组中元素都加 coordinateSystem: ‘cesiumEcharts’ 2、示例代码 <!DOCTYPE html> <ht…