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 };

运行结果

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

.NET周刊【6月第5期 2024-06-30】

国内文章 呼吁改正《上海市卫生健康信息技术应用创新白皮书》 C# 被认定为A 组件 的 错误认知 https://www.cnblogs.com/shanyou/p/18264292 近日,《上海市卫生健康“信息技术应用创新”白皮书》发布,提到医疗信创核心应用适配方法及公立医院信息系统…

2024 年江西省研究生数学建模竞赛题目 A题交通信号灯管理---完整文章分享(仅供学习)

问题: 交通信号灯是指挥车辆通行的重要标志,由红灯、绿灯、黄灯组成。红灯停、绿灯行,而黄灯则起到警示作用。交通信号灯分为机动车信号灯、非机动车信号灯、人行横道信号 灯、方向指示灯等。一般情况下,十字路口有东西向和南北向…

二刷 动态规划

什么是动态规划 Dynamic Programming DP 如果某一问题有很多重叠子问题,使用动态规划时最有效的 动态规划中每一个状态是由上一个状态推导出来的。 动规五部曲 1.确定dp数组以及下标的含义 2.确定递归公式 3.dp数组如何初始化 4.确定遍历顺序 5.举例推导dp数…

分班查询系统,老师们应该如何制作?

新学期的开始,作为教师,我们面临的一项关键任务就是组织分班。传统分班方法往往需要处理大量的数据,这个过程不仅耗时,而且容易出错。为了简化这一流程,提高效率,我们可以利用现代技术,创建一个…

VSCode打开其它IDE项目注释显示乱码的解决方法

问题描述:VSCode打开Visual Studio(或其它IDE)工程,注释乱码,如下图所示: 解决方法:点击VSCode右下角的UTF-8,根据提示点击“通过编码重新打开”,再选择GB2312&#xff0…

【触想智能】工业平板电脑在新能源领域上的应用分析

工业平板电脑是一种具有高性能和稳定性的计算机设备,适用于在恶劣环境下进行数据采集、运营管理和现场操作。 随着新能源技术的快速发展,工业平板电脑不断地得到应用,并且已成为新能源领域中的重要工具之一。本文将从四个方面探讨工业平板电脑…

VMware Mac/Win 虚拟机软件介绍

VMware作为全球领先的虚拟化技术提供商,其Mac/Win虚拟机软件为用户带来了前所未有的跨平台操作体验。这款软件凭借其强大的功能和稳定的性能,成为了众多开发者、设计师、企业用户以及个人用户的首选工具。 强大的多操作系统支持 VMware Mac/Win 虚拟机…

c++习题06-ljc的储蓄计划

目录 一,问题 二,思路 1,思路1 2,思路2 三,代码 1,思路1代码 2,思路2代码 四,用例输入输出 一,问题 二,思路 1,思路1 定义变量&#x…

频繁调价不用愁,统一销售报价话术就用聊天宝

前言 在当今的数字化时代,企业面临着日益增长的客户服务需求,特别是在电商、销售等领域。客服团队的效率和响应速度直接影响到客户满意度和企业的专业形象。面对频繁变动的价格信息和销售策略,如何确保客服回复的及时性和准确性成为了一大挑…

uboot 编译时传递参数实现条件编译

KCFLAGS make ARCHarm KCFLAGS-DENV_DEBUG CROSS_COMPILEaarch64-linux-gnu-env/sf.c env_sf_save 加入调试信息 # saveenv Saving Environment to SPI Flash... env_sf_save (1) spi_flash_erase (2) spi_flash_write is40000 Erasing SPI flash...Writing to SPI flash.…

Git入门 本地仓库 远端仓库 多分支

Git入门 Git入门本地git初始化git仓库初始化 创建远端仓库githubgitee 指定远端仓库推送至远端多分支将feature分支合并至dev分支 其他开发者 Git入门 本地git初始化 git仓库初始化 mkdir myrepo # 创建仓库文件夹 cd myrepo/ # 进入目录 git init # 初始化git仓库 (创建.g…

YOLOv8改进 | 卷积模块 | 减少冗余计算和内存访问的PConv【CVPR2023】

秋招面试专栏推荐 :深度学习算法工程师面试问题总结【百面算法工程师】——点击即可跳转 💡💡💡本专栏所有程序均经过测试,可成功执行💡💡💡 专栏目录 :《YOLOv8改进有效…

某Dota/IM对战平台玩家助手、查看战绩下、胜率等

功能说明 WAR3游戏启动后,可以自动获取游戏双方的玩家列表,然后查询显示玩家的战绩及个人信息。附带查看玩家的战绩详情、最近游戏,查看对手及友方的战绩详情,据此推算出是否开黑、是否小号等信息 使用方法及运行效果 启动 查…

品牌推广怎么样?掌握正确做法,让品牌大放异彩!

品牌推广对于初创公司来说是一项至关重要的任务。在市场众多品牌中,如何脱颖而出,是每个品牌方都要考虑的问题。 作为一名手工酸奶品牌的创始人,目前全国复制了100多家门店,我来分享下,如何推广,可以让品牌…

前端基础--Vue3

Vue3基础 VUE3和VUE2的区别 2020年9月18日,Vue.js发布版3.0版本,代号:One Piece 于 2022 年 2 月 7 日星期一成为新的默认版本! Vue3性能更高,初次渲染快55%, 更新渲染快133% 。体积更小 Vue3.0 打包大小减少41%。 同时Vue3可以更好的支持T…

Python爬虫与数据可视化:构建完整的数据采集与分析流程

Python爬虫技术概述 Python爬虫是一种自动化的数据采集工具,它可以模拟浏览器行为,访问网页并提取所需信息。Python爬虫的实现通常涉及以下几个步骤: 发送网页请求:使用requests库向目标网站发送HTTP请求。获取网页内容&#xf…

多模态大模型面对误导性问题:看懂图片也会答错,一骗就中招

多模态大语言模型(MLLMs)因其在视觉理解和推理方面的突出表现,例如生成详细的图像描述和回答复杂的问题等,逐渐成为近期AI研究的热点。 然而,Bunny 团队的最新研究发现,尽管许多MLLMs对视觉内容能够正确理…

MM-LLM:使用Llava类构建图文多模态大模型实践

多模态大模型的结构如上,llava是用两层MLP作为连接器。该模式也是后续很多工作的基础。 本文主要参考了https://github.com/yuanzhoulvpi2017/zero_nlp/tree/main/train_llava的工作,最初是在b站看到的,讲解的很细致。 基础模型 大语言模型…

夏日编码狂欢:GitCode x DevUI挑战赛,点燃你的创造力

在这个创新驱动的时代,开源技术已成为推动全球软件开发进步的强大引擎,技术的边界正被全球开发者的集体智慧不断拓展。 在这个充满活力的夏日,开源社区迎来了一场全新的活动——由GitCode携手华为云DevUI精心打造的开源共创挑战赛。这不仅是…

【瑞吉外卖 | day01】项目介绍+后台登录退出功能

文章目录 瑞吉外卖 — day011. 所需知识2. 软件开发整体介绍2.1 软件开发流程2.2 角色分工2.3 软件环境 3. 瑞吉外卖项目介绍3.1 项目介绍3.2 产品原型展示3.3 技术选型3.4 功能架构3.5 角色 4. 开发环境搭建4.1 数据库环境搭建4.2 Maven项目构建 5. 后台系统登录功能5.1 创建需…