首页
关于我
友链
小程序
小黑屋
Search
1
windows11系统自带VPN连接不上群辉VPN服务器问题
595 阅读
2
使用ESP8266完成校园网WEB认证
540 阅读
3
数字振镜XY2-100协议
540 阅读
4
将校园卡复制到小米手环
519 阅读
5
frp+softether_vpn实现外网访问校园网
411 阅读
技术
生活
登录
Search
标签搜索
qt
mqtt
FreeRTOS
stm32
iar
VPN
光猫破解
esp8266
群晖
VideoStation
exti
c++
eclipse
bootloader
pixhawk
遥控器
失控保护
ARM
NAS
ENPASS
AMENG
累计撰写
79
篇文章
累计收到
15
条评论
首页
栏目
技术
生活
页面
关于我
友链
推荐
小黑屋
搜索到
72
篇与
的结果
2024-03-29
C与C++相互调用的问题
案例描述首先简单描述一下同事的案例场景: 同事的项目工程依赖其他两个部门A和B提供的动态库libA.so,libB.so。它们之间的关系是:libB.so 依赖 libA.so 生成。之后他再依赖libB.so库生成abupvdiapp可执行程序。在最终生成可执行程序时,会提示部分符号未定义。而这些符号是在libA.so。依赖关系如下图:排查思路: 1、首先确认编译生成可执行程序abupvdiapp时,是否链接了libA.so。打开cmake 中的VERBOSE参数,发现的确有-lA -lB链接信息。 2、查看libB.so是否依赖libA.so。通过ldd libB.so查看,发现libB.so 并不依赖libA.so。这是我第一个疑惑点。 3、查看未定义符号adm_vdi_init是否在libA.so定义。结果是存在。 4、查看未定义符号adm_vdi_init是否被libB.so引用。结果是有被引用,但是符号不匹配。 其实到这里我已经知道什么原因了。后续在A.h的头文件中增加extern "C"即可。有兴趣的朋友可以按照下面的示例演示一遍,加深影响。<br/>//A.cinclude <stdio.h>int adm_vdi_init(){ printf("i'm adm_vdi_init\n");}//A.hextern int adm_vdi_init();//B.cppinclude<A.h>include<stdio.h>int adm_host_init(){ adm_vdi_init(); printf("i'm adm_host_init\n"); return 0;}//B.hextern int adm_host_init();//main.cppinclude<B.h>int main(){ adm_host_init(); return 0;}<br/>编译流程如下:修改后://A.hifdef __cplusplusextern "C" {endifextern int adm_vdi_init();ifdef __cplusplus}endif 我相信有经验的朋友肯定已经知道问题的原因了,但是对于未接触相关案例的同学,估计还是一头雾水,特别是一直从事C语言开发的工程师,估计还不清楚发生了什么。如果你有同样的疑问,请继续往下阅读,一定不会让你失望。原理 我们知道模块之间的函数或全局变量的引用,其实就是对符号的引用。在链接过程中就是通过这个符号寻找对应的代码,实现上下文的跳转。 在历史的长河中,先辈们发现随着项目工程的扩大,很容易出现不同模块定义了相同的全局变量或对外函数,导致符号相同的情况。这样就导致链接时,不知道应该链接到哪一个代码段。但是上述的现象是一个趋势,很难去避免。因此,出现了符号修饰的概念。符号修饰即根据一定的规则,对源码中的符号进行修饰,进行区分。 在较新的GCC编译工具中,并不会对C 符号进行修饰。如上面的A.c文件中,定义了adm_vdi_init函数,编译之后的符号表中,依旧是adm_vdi_init。 C++因为支持类,继承,重载,名称空间等这些特定,因此GCC编译工具,会对C++进行符号修饰。C++符号的修饰规则可参考该GNU C++的符号改编机制介绍_gnu c++的符号装饰机制-CSDN博客如图:B.cpp文件中adm_host_init函数经过修饰,变为了_Z13adm_host_initv。分析: 1、_Z:属于标识 2、13:adm_host_init字符串长度 3、adm_host_init :函数名 4、v:参数void 了解以上原理后,我们就明白为什么在A.h的头文件中增加extern "C",就编译通过了。libA.so是C语言,因此不会进行符号修饰。B.cpp 是C++,会进行符号修饰,编译器并不知道adm_vdi_init是否进行了符号修饰,所以它默认进行了修饰。所以libB.so引用的符号与libA.so的符号并不匹配。而extern "C"就是明确告诉编译器,adm_vdi_init是C编译的,并没有进行符号修饰。C++调用 C 同事的案例,其实就是C++(B.cpp)调用C(A.c)导致的问题。在这里我再简单总结一下: C 并不会进行符号修饰,而C++默认会对符号进行修饰,因此会导致C++ 认知中A.h 的符号与 A.o的实际符号不匹配,虽然动态库libB.so 已经能生成,但是在链接阶段,符号重定位时,就会出现undefined reference to错误。<br/> 因此,C 代码以SDK的方式提供给外部使用时,应该在头文件中用extern "C"修饰。如:<br/>#ifdef __cplusplusextern "C" {endif .....ifdef __cplusplus}endifC调用C++ C++ 调用C 的方式大家可能比较常见,因为C++更适合用于开发偏上层应用,C更适合底层开发。天然的存在依赖关系,所以在工作中也比较常见。 而C 调用C++ 的场景就比较少了,一般是因为公司内部原因了。还是用上面的示例,将 main.cpp 改为main.c。 该现象与我们预期相符,因为libB.so是C++ 编译的库,所以会对符号进行修饰。但是main.c 是C,gcc 并不会进行符号修饰。 但是我们如何解决符号的问题呢?很难受,并没有extern "C++"的参数。在这里我提供三种思路:最简单的方式 最简单的方式就是将main.c 改为main.cpp 。要求GCC 以C++的方式去编译,自然会进行符号修饰。但是这样容易出现其他问题,因为C依赖的很多头文件,C++可能并不支持。为了做到兼容,可能会修改更多的代码。封装一层C接口如我们增加一个libC.so,代码如下:// C.hifdef __cplusplusextern "C" {endifextern int adm_C_init();ifdef __cplusplus}endif//C.cppinclude<C.h>include<B.h>int adm_C_init(){ adm_host_init(); return 0;}// main.cinclude<C.h>int main(){ adm_C_init(); return 0;}注意:其中C.cpp中显示声明了extern "C"修饰adm_C_init,因此libC.so中则不会对adm_C_init进行符号修饰。<br/><br/>直接引用被修饰的符号 封装C接口的方式比较麻烦,还有一种就是比较简单,不易理解的方式。就是main.c 直接引用 libB.so中修饰过后的符号。比如,我们通过nm libB.so | grep adm_host_init查看修饰后的符号为_Z13adm_host_initv。我们可以这样修改main.c。//main.cextern int _Z13adm_host_initv();int main(){ _Z13adm_host_initv(); return 0;}<br/>总结 综上所述,相信大家应该理解C 与 C++ 之间相互调用为什么存在一些困难的原因。工作中我们也应该注意一些事项。比如:C语言编译的SDK,对外提供头文件时,为了兼容c++,应该用extern "C"修饰<br/>
2024年03月29日
135 阅读
0 评论
0 点赞
2023-08-29
Verilog基础语法
1、基础知识逻辑0:低电平,也就是电路中的GND 逻辑1:高电平,也就是电路中的VCC逻辑X:未知状态,逻辑Z:高阻态,外部没有激励信号,是一个悬空状态 2、数字进制格式、标示符b:表示二进制 o:表示八进制 d:表示十进制 h:表示十六进制 numA=8'b10101010; //8'表示numA这个变量占8位,numA的值是二进制的10101010 numB=4'd2;//numB的值是十进制的2 numC=4'ha;//numC的值是十六进制的A numD=10;//numD占32bit,是十进制的10说明:不指定位宽则默认是32位,不指定进制则默认是十进制 标示符:可用于模块名、端口号、信号名等(类似C的变量名)3、数据类型 寄存器数据类型 (reg)线网数据类型(wire)参数数据类型(parameter)3.1寄存器数据类型关键则:reg 初始值为:不定制X(逻辑X)module test(L); output LED; input num; reg[7:0] LED; //寄存器数据类型 reg num; //寄存器数据类型 always begin LED=8'b10101010; end endmodule3.2 线网数据类型关键字:wire 表示结构实体之间的物理连线线网类型的变量不能村初值,他是由驱动她都元件决定的没有驱动元件连接的线网类型变量是:高阻值(逻辑Z)wire key_flag;3.3 参数类型关键字:parameter 他类似C中的 #define,宏定义4、运算符Verilog中的 算数运算符、关系运算符、逻辑运算符、条件运算符、位运算符、移位运算符包括其 运算符优先级 也与C语言相同。 Verilog特有的拼接运算符:{}C={a,b[3:0]} //将变量a与变量b的低四位拼接起来,赋值给变量C5、模块Verilog的基本设计单元是“模块”(类似C语言中的函数)一个模块由两部分组成描述接口描述逻辑接口一个模块的示例: module test(LED,a,b,c,d,e); //模块开始的关键字是:module 括号里的都是:端口定义output LED,c,d; //输出信号 input output 都是:IO说明 input a,b; //输入信号reg[7:0] LED; //寄存器数据类型 reg e; //寄存器数据类型 wire f; //线网数据类型 f:内部信号 //变量声明结束后,都是:功能定义 assign c=a|b; assign d=a&b; //assign :产生wire信号语句的关键字 描述组合逻辑 always begin //always:产生reg信号语句的关键字 描述组合、时序逻辑 LED=8'b10101010;end endmodule //模块要用“endmodule”结束 与C语言不同的是,Verilog中多个<always>块都是“并行”的 ,也就是说,两个<always>块可以同时被执行。单个<always>块是中的代码是顺序执行的。 assign相当于连线,一般是将一个变量的值不间断地赋值给另一个变量,就像把这两个变量连在一起,所以习惯性的当做连线用,比如把一个模块的输出给另一个模块当输入。 assign的功能属于组合逻辑的范畴,应用范围可概括为以下三点:持续赋值; 连线; 对wire型变量赋值,wire是线网,相当于实际的连接线,如果要用assign直接连接,就用wire型变量。wire型变量的值随时变化。其实以上三点是相通的。 要更好的把握assign的使用,Verilog中有几个要点需要深入理解和掌握:在Verilog module中的所有过程块(如initial块和always块)、连续赋值语句(如assign语句)和实例引用都是并行的。在同一module中这三者出现的先后顺序没有关系。只有连续赋值语句assign和实例引用语句可以独立于过程块而存在于module的功能定义部分。连续赋值assign语句独立于过程块,所以不能在always过程块中使用assign语句。 module LED_Blink( //可以在端口定义时 指定IOinput sys_clk,//系统时钟inputsys_rst_n, //系统复位output reg[3:0] led;//4bit 代表四颗灯);reg [23:0] count; //计数 (这是一个内部信号声明)//计数器对系统时钟计数,0.2s/*赋值“=”用于阻塞式赋值(执行到该行时,等待赋值完成再执行下一条语句),仿真是initial中用=;“<=”用于非阻塞式赋值中(执行到改行时,不等待赋值完成,直接执行下一条语句),always中用<=*/always @(posedge sys_clk or negedge sys_rst_n)begin//posedge:上升沿触发 negedge:下降沿触发if(!sys_rst_n)count<=24'd0; //对Count1赋23位十进制的0else if(count<24'd1000_0000)count<=count+1'b1;elsecount<=24'b0;end endmodule赋值“=” 用于阻塞式赋值(执行到该行时,等待赋值完成再执行下一条语句),仿真是initial中用=;赋值“<=”用于非阻塞式赋值中(执行到改行时,不等待赋值完成,直接执行下一条语句),always中用<= 6、模块的调用在模块调用时,信号通过模块端口在模块之间传递。module seg_led_static_top( //上层模块input sys_clk,//系统时钟inputsys_rst_n, //系统复位output [5:0] sel; output [7:0] sel_led;);parameter TIME_SHOW=25'd25000_000; //宏定义wireadd_flag;//数码管变化通知 //# 是延迟的意思,井号后面数字是延迟的数量 //#1 a=1;#表延迟,延迟一个时间单位后执行a=1 time_count #( //这里的#表示:用来将parameter变量传给调用实例。.MAX_NUM(TIME_SHOW) //上层模块传输给底层模块)u_time_count(.clk (sys_clk) // .表示:连接 将上层模块的sys_clk与下层模块clk连接在一起.rst_n(sys_rst_n).flag(add_flag)) endmodule module time_count( // 底层模块input clk,//系统时钟inputrst_n, //系统复位output reg flag; );parameter MAX_NUM=25'd50000_000; //宏定义reg [24:0] cnt; endmodule# 是延迟的意思,井号后面数字是延迟的数量 例如代码 : #1 a=1; //延迟一个时间单位后执行a=1#():这里的#表示:用来将parameter变量传给调用实例。.是连接的意思:将上层模块的变量与下层模块变量连接在一起7、结构语言7.1 always 和 initialinitial 语句只执行一次always 语句是一直不断重复的//initial 语句只执行一次//always 语句是一直不断重复的initial beginsys_clk=10;b=11;c=12;#20d=13;end//赋值“=”用于阻塞式赋值(执行到该行时,等待赋值完成再执行下一条语句),仿真是initial中用=; always #10 sys_clk<=~sys_clk; //chans 50Mhz的时钟,周期为20ns//“<=”用于非阻塞式赋值中(执行到改行时,不等待赋值完成,直接执行下一条语句)always中用<= always的时间就控制可以是沿触发,也可以是电平触发。 沿触发的always块常用于表示时序逻辑行为always @(posedge sys_clk or negedge sys_rst_n)begin//posedge:上升沿触发 negedge:下降沿触发if(!sys_rst_n)count<=24'd0; //对Count1赋23位十进制的0else if(count<24'd1000_0000)count<=count+1'b1;elsecount<=24'b0;end or 连接的多个时间或者信号组成的列表称为:敏感列表 只有敏感列表里的条件满足时,才会执行此always模块电平触发的always模块表示组合逻辑行为always @(*)begin out1=a?(b+c):(d+e);end//@(*):模块中所有使用的输入变量都是敏感的 @(*):模块中所有使用的输入变量都是敏感的组合逻辑:输出只取决于输入时序逻辑:输出取决于输入和原电路状态7.2 阻塞赋值和非阻塞赋值 阻塞赋值:只有一个步骤的操作,即执行到该行赋值语句时,要等待赋值完成再执行下一条语句,是一个顺序执行的串行方式。(这点与C语言一致) 假设 a=1,b=2,C=3 执行 a=0;b=a;c=b; 后 a b c的值都为0非阻塞赋值:多个步骤同时的操作,即执行到改行时,不等待赋值完成,直接执行下一条语句,是一个顺序执行的并行方式。 假设 a=0,b=2,C=3 执行 a<=0;b<=a;c<=b; 后 a =0 b=1 c=2 描述组合逻辑的always语句用“阻塞赋值=” 描述时序逻辑的always语句用“非阻塞赋值<=”注意:1.在同一个always模块中不同时使用 非阻塞赋值 和 阻塞赋值 2. 不允许在多个always块中一个变量进行赋值 ,因为Verilog是并行执行的 阻塞赋值和非阻塞赋值产生的实际电路区别: 当存在多条赋值语句时,阻塞赋值会产生多个级联的触发器.7.3 条件语句 if....else if .........else if.......... 用法和C语言相同。 if语句中的条件,为1则表示真,若为0 X Z都按假处理 if else 后面可以用begin 和end包含多个语句,类似与C语言中 if后面的大括号if......esle..........是带有优先级的,实际产生的电路如下: case语句 分支表达式的值互不相同 所有表达式的位宽必须相等(必须定位宽) caseZ不适用于高阻值Z (casez) casex 下列代码 语句1 和语句2 都不执行 case是没有优先级的 实际电路如下: 7.4 循环7.4.1:forever:连续循环执行 一般只用于仿真测试 7.4.2:repeat 执行固定次数循环7.4.3 while循环 while循环与C语言相同,但是Verilog中只用于仿真调试 7.4.4 for循环 与C语言相同,实际产生的是一个多层级的物理电路,for循环在Verilog中比较常用。 7.5 函数 函数通常为一系列组合逻辑,有返回值 函数关键字:function函数定义://下面相当于函数声明function [15:0]mult;//函数名 input[7:0] a,b; reg [15:0] r; integer i; //整数(integer),integer类型的变量为有符号数//下面相当于函数主体 begin if(a[0]==1) r=b; else r=0; for (i =1 ;i<=7 ;i=i+1 ) begin if(a[i]==1) r=r+b<<1; end mult=r; //返回值就是函数名 end endfunction函数调用: module mult_acc( input[7:0] ina,inb; ) wire[15:0]mult_out; assign mult_out=mult(ina,inb);//函数调用endmodule 7.6 任务任务关键字:taskmodule module_name task add_num; //任务定义 input a,b; output c; begin c=a+b; endendtask reg num;add_num(1,2,num) //任务调用 endmodule函数 与任务的区别 function task在时间0开始执行 执行过程中不能暂停不能包含延时、时间、或者其他 时间控制操作可在非0仿真时间执行可包含延时、时间或其他时间控制操作必须包含至少一个输入 可以没有输入、输出不能使用输出/双向参数 (类似C的形参带出返回值),只能返回1个值,返回变量与函数名相同使用输出参数、可以返回多个值函数可以调用另一个函数,但是不能调用任务任务可以调用另外的函数或者任务。 8、状态机(FSM) 状态机:在有限个状态之间按一定规律转换的时序电路 mealy状态机 : 输出与当前状态和输入有关 (时序逻辑的类似) moore状态机: 输出只与输入有关(组合逻辑类似)状态机模型中由 两个组合逻辑 和 一个时序逻辑 组成8.1设计状态机 以下的设计步骤:状态空间定义状态跳转下个状态判断各个状态的动作 8.1.1状态空间定义是一个定义的过程 宏定义出状态的名称 和数值定义当前状态和下一个状态的存储变量(变量要与上面定义的数值位数相同) 推荐每一个状态只有寄存器的一个位置,这样编译逻辑简单,编译后的硬件电路简单 8.1.2状态跳转状态跳转是一个时序逻辑 再次强调:时序逻辑中使用 非阻塞赋值 8.1.3下一个状态的判断根据输入状态判断输出状态,是一个组合逻辑 再次强调:组合逻辑中使用 阻塞赋值 latch:是一个锁存器,程序设计中要避免latch的产生,他会使我们电路输出的信号产生毛刺(if else 没有配对 case中没有default 就会产生latch) 8.1.4下一个状态的动作根据当前状态完成当前动作,是一个组合逻辑下面是产生组合逻辑的两种方式: always:可以表示时序逻辑 和 组合逻辑 mealy状态机 后面又加了一级寄存器来实现时序逻辑的输出,这么做的好处是:可以在有效的滤去组合逻辑输出的毛刺可以有效的进行时序计算和约束对于总线型的输出信号来说,容易使总线对齐,从而减小总线数据见的便宜,减小接收端数据采样的出错频率转自:https://blog.csdn.net/qq_34301282/article/details/120763063
2023年08月29日
150 阅读
1 评论
0 点赞
2023-08-06
ZYNQ lwip 自适应网络速率
默认的网络自动识别接入速率有bug,需做如下修改。找到lwip库文件,libsrc->lwip202->src->contrib->ports->xulinx->netif,打开文件xemacpsif_physpeed.c找到static u32_t get_Realtek_phy_speed(XEmacPs *xemacpsp, u32_t phy_addr),将此函数删除或者注释掉,加入如下函数static u32_t get_Realtek_phy_speed(XEmacPs *xemacpsp, u32_t phy_addr) { u16_t temp; u16_t control; u16_t status; u16_t status_speed; u32_t timeout_counter = 0; xil_printf("Start PHY autonegotiation \r\n"); XEmacPs_PhyWrite(xemacpsp,phy_addr, IEEE_PAGE_ADDRESS_REGISTER, 2); XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_MAC, &control); control |= IEEE_RGMII_TXRX_CLOCK_DELAYED_MASK; XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_CONTROL_REG_MAC, control); XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_PAGE_ADDRESS_REGISTER, 0); XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, &control); control |= IEEE_ASYMMETRIC_PAUSE_MASK; control |= IEEE_PAUSE_MASK; control |= ADVERTISE_100; control |= ADVERTISE_10; XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, control); XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_1000_ADVERTISE_REG_OFFSET, &control); control |= ADVERTISE_1000; XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_1000_ADVERTISE_REG_OFFSET, control); XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_PAGE_ADDRESS_REGISTER, 0); XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_COPPER_SPECIFIC_CONTROL_REG, &control); control |= (7 << 12); /* max number of gigabit attempts */ control |= (1 << 11); /* enable downshift */ XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_COPPER_SPECIFIC_CONTROL_REG, control); XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, &control); control |= IEEE_CTRL_AUTONEGOTIATE_ENABLE; control |= IEEE_STAT_AUTONEGOTIATE_RESTART; XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, control); XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, &control); control |= IEEE_CTRL_RESET_MASK; XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, control); while (1) { XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, &control); if (control & IEEE_CTRL_RESET_MASK) continue; else break; } XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_STATUS_REG_OFFSET, &status); xil_printf("Waiting for PHY to complete autonegotiation.\r\n"); while ( !(status & IEEE_STAT_AUTONEGOTIATE_COMPLETE) ) { sleep(1); XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_COPPER_SPECIFIC_STATUS_REG_2, &temp); timeout_counter++; if (timeout_counter == 30) { xil_printf("Auto negotiation error \r\n"); return 0; } XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_STATUS_REG_OFFSET, &status); } xil_printf("autonegotiation complete \r\n"); XEmacPs_PhyRead(xemacpsp, phy_addr,0x1A, &status_speed); if ( (status_speed & 0x30) == 0x20)/* 1000Mbps */ return 1000; else if ( (status_speed & 0x30) == 0x10)/* 100Mbps */ return 100; else if ( (status_speed & 0x30) == 0x00)/* 10Mbps */ return 10; return XST_FAILURE; }
2023年08月06日
150 阅读
0 评论
0 点赞
2023-07-22
加快Vivado的编译速度
一. 设置当前Vivado软件使用的线程数,重启软件后失效在Tcl Console中输入命令,如下图。set_param general.maxThreads 32表示设置最大线程数为32。线程数的有效值为1~32。另一个命令:get_param general.maxThreads表示返回当前软件使用的线程数,可用来验证设置线程数是否成功。此方法只在当前Vivado进程中有效,重启软件需要再次设置。二. 设置Vivado默认线程数,重启软件依然生效在Vivado安装路径的scripts文件夹中新建Vivado_init.tcl,名称不能错,Vivado启动时会自动加载此tcl,可以将需要启动执行的命令都写到此tcl文件中。这里在tcl中写入:set_param general.maxThreads 32重启Vivado验证一下,如下图,可见设置默认线程数为32成功。
2023年07月22日
263 阅读
0 评论
0 点赞
2023-07-19
zynq调试网口所遇到的问题记录
1、显示连接正常,出了IP和端口,但tcp client连不上。-----lwIP TCP echo server ------ TCP packets sent to port 6001 will be echoed back link speed for phy address 0: 1000 DHCP Timeout Configuring default IP of 192.168.1.10 Board IP: 192.168.1.10 Netmask : 255.255.255.0 Gateway : 192.168.1.1 TCP echo server started @ port 7解决方法:bank电压设置不对,电压要设置为1.8V2、网络速率协商失败。Start PHY autonegotiation Waiting for PHY to complete autonegotiation. autonegotiation complete Phy setup error Assert due to phy setup failure解决方法:手动设置速率3、网络一直循环连接和断开Link speed for phy address 0: 1000 Ethernet Link up Ethernet Link down Link speed for phy address 0: 1000 Ethernet Link up Ethernet Link down解决方法:此为自带demo的bug,屏蔽掉platform_zynq.c以下代码。/* For detecting Ethernet phy link status periodically */ //if (DetectEthLinkStatus == ETH_LINK_DETECT_INTERVAL) { //eth_link_detect(echo_netif); //DetectEthLinkStatus = 0; //}
2023年07月19日
394 阅读
0 评论
0 点赞
2023-07-14
Verilog中为inout类型赋值
inout类型的作用inout 类型常出现于芯片外部引脚,为的是减少管腿个数,一个端口同时做输入和输出。inout类型的用法那么,如何判断这个数据段代表输入还是输出呢?一般我们还需要另一个读写控制信号we,根据这个决定inout类型的数据段按读还是写解析。因为inout类型既是input又是output类型,所以必须同时遵守输入输出的描述规定。这个规定也很好理解。因为硬件描述语言的=不是C语言的“覆盖”,而是用一根线将电路中的两个点链接起来。如果这个=表示的电线链接了两个寄存器类型,那么当其中一个reg改变时,另一个无法改变,则会产生冲突。所以用语法规定,盛装某电路模块输出信息的必须是wire类型。那么,在向inout类型传入数据时(tb模块),必须遵守output的规定,使用线网型。(inout接口的另一端必须是wire)
2023年07月14日
182 阅读
0 评论
0 点赞
2023-07-06
数字振镜XY2-100协议
一、协议格式该协议时钟(SENDCK)为2MHz ,SYNC为同步信号,CHANNELX/Y 是数据信号,它有20位组成,其中C2、C1、C0是振镜运动方向值,参考值为001,D15—D0是数据位,它是16位的二进制数,用来控制振镜转过的角度大小(取值为0~65535,即将振镜轴的转动角度范围映射到0~65535);最后一位是偶校验位,当发送的数 据中有偶数个“1”时,对应的校验位为“0”。当发送的数据中有奇数个“1”时对应的校验位为“1”。二、FPGA(Verilog)代码实现module xy2_100( //端口列表 rst_n, clk50m, send_en, x_data, y_data, sendck, sync, chl_x, chl_y, TxDone, xy2_state ); //端口定义 input rst_n; input clk50m; input send_en; input [15:0]x_data; input [15:0]y_data; output reg sendck; output reg sync; output reg chl_x; output reg chl_y; output reg TxDone; output reg xy2_state; reg [4:0]div_cnt;//分频计数器 reg [4:0]bps_cnt;//波特率时钟计数器 reg [15:0]r_data_x; reg [15:0]r_data_y; localparam bps_DR = 5'd24; //分频计数最大值 localparam CTRL_WD = 3'b001; //控制字 localparam MAX_BIT = 5'd20; //发送状态信号 always@(posedge clk50m or negedge rst_n) if(!rst_n) xy2_state <= 1'b0; else if(send_en) xy2_state <= 1'b1; else if(bps_cnt == MAX_BIT) xy2_state <= 1'b0; else xy2_state <= xy2_state; //发送数据锁存 always@(posedge clk50m or negedge rst_n) if(!rst_n) r_data_x <= 15'd0; else if(send_en) r_data_x <= x_data; else r_data_x <= r_data_x; always@(posedge clk50m or negedge rst_n) if(!rst_n) r_data_y <= 15'd0; else if(send_en) r_data_y <= y_data; else r_data_y <= r_data_y; //分频计数器 always@(posedge clk50m or negedge rst_n) if(!rst_n) div_cnt <= 5'd0; else if(xy2_state||send_en) begin if(div_cnt == bps_DR) div_cnt <= 5'd0; else div_cnt <= div_cnt+1'b1; end else div_cnt <= 5'd0; // bps counter always@(posedge clk50m or negedge rst_n) if(!rst_n) bps_cnt <= 5'd0; else if(bps_cnt==MAX_BIT) bps_cnt <= 5'd0; else if(div_cnt==bps_DR) bps_cnt <= bps_cnt + 1'b1; else bps_cnt <= bps_cnt; // 发送完成信号 always@(posedge clk50m or negedge rst_n) if(!rst_n) TxDone <= 1'b0; else if(bps_cnt == MAX_BIT) TxDone <= 1'b1; else TxDone <= 1'b0; // x按位发送数据 always@(posedge clk50m or negedge rst_n) if(!rst_n) chl_x <= 1'b0; else if(div_cnt==5'd0) begin case (bps_cnt) 0:chl_x <= 1'b0; //c2 1:chl_x <= 1'b0; //c1 2:chl_x <= 1'b1; //c0 3:chl_x <= r_data_x[15]; 4:chl_x <= r_data_x[14]; 5:chl_x <= r_data_x[13]; 6:chl_x <= r_data_x[12]; 7:chl_x <= r_data_x[11]; 8:chl_x <= r_data_x[10]; 9:chl_x <= r_data_x[9]; 10:chl_x <= r_data_x[8]; 11:chl_x <= r_data_x[7]; 12:chl_x <= r_data_x[6]; 13:chl_x <= r_data_x[5]; 14:chl_x <= r_data_x[4]; 15:chl_x <= r_data_x[3]; 16:chl_x <= r_data_x[2]; 17:chl_x <= r_data_x[1]; 18:chl_x <= r_data_x[0]; 19:chl_x <= ^{CTRL_WD,r_data_x}; //偶校验 default:chl_x <= 1'b0; endcase end // y按位发送数据 always@(posedge clk50m or negedge rst_n) if(!rst_n) chl_y <= 1'b0; else if(div_cnt==5'd0) begin case (bps_cnt) 0:chl_y <= 1'b0; //c2 1:chl_y <= 1'b0; //c1 2:chl_y <= 1'b1; //c0 3:chl_y <= r_data_y[15]; 4:chl_y <= r_data_y[14]; 5:chl_y <= r_data_y[13]; 6:chl_y <= r_data_y[12]; 7:chl_y <= r_data_y[11]; 8:chl_y <= r_data_y[10]; 9:chl_y <= r_data_y[9]; 10:chl_y <= r_data_y[8]; 11:chl_y <= r_data_y[7]; 12:chl_y <= r_data_y[6]; 13:chl_y <= r_data_y[5]; 14:chl_y <= r_data_y[4]; 15:chl_y <= r_data_y[3]; 16:chl_y <= r_data_y[2]; 17:chl_y <= r_data_y[1]; 18:chl_y <= r_data_y[0]; 19:chl_y <= ^{CTRL_WD,r_data_y}; //偶校验 default:chl_y <= 1'b0; endcase end //同步信号 always@(posedge clk50m or negedge rst_n) if(!rst_n) sync <= 1'b0; else if(send_en) sync <= 1'b1; else if(bps_cnt==(MAX_BIT-1)) //&&(div_cnt==5'd0)) sync <= 1'b0; else sync <= sync; //发送时钟信号 always@(posedge clk50m or negedge rst_n) if(!rst_n) sendck <= 1'b0; else if((xy2_state||send_en)&&(bps_cnt<MAX_BIT)) begin if(div_cnt<=bps_DR/2) sendck <= 1'b1; else sendck <= 1'b0; end else sendck <= 1'b0; endmodule
2023年07月06日
540 阅读
0 评论
0 点赞
2023-06-27
zynq 程序固化过程中不切换启动模式,强制烧写
问题:在利用vivado sdk烧录QSPI flash过程中,提示要切换至jtag模式,由于模式切换电阻不知位于何处,于是寻找一种软件调整来达到强制烧写的母的。最终办法: 也就是说通过在“指定的fsbl”中的main.c中如下位置添加如下语句,防止FSBL在编程运行时从Flash设备加载任何现有分区。/* * Read bootmode register */ BootModeRegister = Xil_In32(BOOT_MODE_REG); BootModeRegister &= BOOT_MODES_MASK; //add this line to trick boot mode to JTAG BootModeRegister = JTAG_MODE;
2023年06月27日
155 阅读
0 评论
0 点赞
2023-06-08
常见激光器控制协议
Fiber激光器转接板输出接口说明如下表,通过EXIO_DIR设置好IO方向后,便可通过右侧的IO编号控制激光器。D0和D7一共8位组合设置激光器的功率,激光出光口为OUT8,激光出光前先设置好激光器的功率并打开激光使能开关OUT47,红光的开关为OUT48。→EXIO扩展IO配置说明:采用EXIO接口扩展后, 均需要使用EXIO_DIR指令对扩展IO进行方向配置才可正常使用。按上节接线完成后,配置好EXIO扩展IO接口的IO方向之后才能控制激光器,扩展IO功能设置EXIO_DIR(0, $8FFFF)。指令语法:EXIO_DIR(isel, dirbit)Isel:0(指定激光器类型)dirbit: 按位设置是否输出, 0- 输入, 1-输出 (自定义配置转接口对应的信号类型)控制器与激光器的接线参考图如下:3.激光控制说明例如某激光器的控制端口针脚说明如下表,对比上表可知,Fiber-DB25头转接板输出接口采用与该激光器匹配的标准端口,针脚定义一致,可直接与该激光器相连,再通过OUT引脚控制激光器。主要控制端子说明:功率信号定义:设置针 1~8 的 TTL 信号,通过 TTL 信号的组合来设置泵浦激光二极管的电流,从而控制激光器的输出功率。通过 1~8 针可以设置 0~255 范围内的编码,对应于 0~100%的功率输出。电源:针17和GND组成激光器控制端口的供电回路,采用5V直流供电。4.打标应用例程编程界面如下图,采用Basic和HMI混合编程,Basic完成控制过程,HMI编写界面。初始化定义相关变量,初始化轴参数,配置好FIBER转接板的方向为输出,后续的激光加工控制由HMI界面的按钮触发。D0和D7一共8位组合设置激光器的功率,通过AOUT3配置激光功率;激光出光口为OUT8,激光出光前先设置好激光器的功率并打开激光使能开关OUT47,红光的开关为OUT48。(1)Basic程序如下'**********************************************************HMI初始化Global Sub Sub_HmiInit()Sub_VarDefine() '定义变量Sub_AxisInit() '初始轴参数Sub_SetExioFiber 'Fiber转化板参数设置End Sub'**********************************************************HMI刷新扫描Global Sub Sub_HmiScan()End Sub'**********************************************************变量定义初始化Global Sub Sub_VarDefine()Global Const Gc_AxisX = 4Global Const Gc_AxisY = 5Global Const Gc_Out_Laser = 8 '出光OUT口Global Const Gc_Out_LaserEnable = 47 '激光使能Global Const Gc_Out_Red = 48 '红灯Global Const Gc_Aout_Laser = 3 '激光能量模拟量输出口Global Gv_StartDelay '开光延时usGv_StartDelay = 1000Global Gv_LastDelay '关光延时usGv_LastDelay = 1000Global Gv_CorDelay '拐角延时usGv_CorDelay = 1000Global Gv_JumpDelay '跳转延时usGv_JumpDelay = 1000Global Gv_LaserPower '激光功率0-2^8Gv_LaserPower = 128Global Gv_EmpSp '空移速度Gv_EmpSp = 10000Global Gv_WorkSp '加工速度Gv_WorkSp = 5000Global Gv_WorkMode '加工模式 0-红光 1-激光Gv_WorkMode = 0Global Gv_MarkSize '标刻大小Gv_MarkSize = 80End Sub'**********************************************************轴参数初始化Global Sub Sub_AxisInit()base(Gc_AxisX,Gc_AxisY)Atype = 21,21 '轴类型 振镜轴Units = 500,500 '脉冲当量speed = 100,100 '运动速度Accel = 10000,10000 '加速度AXIS_ZSET = 3,3 '开启精准输出End Sub'**********************************************************切换红光Global Sub Sub_Btn_Red()if op(Gc_Out_Red) THENop(Gc_Out_Red,OFF)ELSEop(Gc_Out_Red,ON)endifEnd Sub'**********************************************************切换出光Global Sub Sub_Btn_Laser()if op(Gc_Out_Laser) THENAout(Gc_Aout_Laser) = 0op(Gc_Out_Laser,OFF)DELAY(100)op(Gc_Out_LaserEnable,OFF)ELSEAout(Gc_Aout_Laser) = Gv_LaserPower '设置能量op(Gc_Out_LaserEnable,ON) '打开激光使能DELAY(100)op(Gc_Out_Laser,ON) '出光endifEnd Sub'**********************************************************fiber转换板处理GLOBAL SUB Sub_SetExioFiber()'修改扩展接口方向为输出EXIO_DIR(0, $FFFFF)END SUB'**********************************************************空移到起点Global Sub Sub_MoveEmp(StartX,StartY)base(Gc_AxisX,Gc_AxisY)FORCE_SPEED = Gv_EmpSpMOVESCANABS(StartX,StartY) '空移到起点MOVE_DELAY(Gv_JumpDelay/1000) '跳转延时if Gv_WorkMode =1 thenMOVE_OP(Gc_Out_Laser, ON)ELSEMOVE_OP(Gc_Out_Red, ON)endifMOVE_DELAY(Gv_StartDelay/1000) '开光延时End Sub'**********************************************************直线运动'XPos 运行结束点X坐标'YPos 运行结束点Y坐标'If_End 是否最后的结束点,是启动关光参数Global Sub Sub_MoveLine(XPos,YPos,If_End)FORCE_SPEED = Gv_WorkSpMOVESCANABS(XPos,YPos) '运动到加工点if(If_End) thenMOVE_DELAY(Gv_LastDelay/1000) '关光延时if Gv_WorkMode =1 thenMOVE_OP(Gc_Out_Laser, OFF)ELSEMOVE_OP(Gc_Out_Red, OFF)endifendifEnd Sub'**********************************************************画矩形运动'XPos 运行结束点X坐标'YPos 运行结束点Y坐标'If_End 是否最后的结束点,是启动关光参数Global Sub Sub_MoveRect(StartX, StartY, EndX,EndY,If_End)FORCE_SPEED = Gv_WorkSpMOVESCANABS(StartX,EndY)MOVE_DELAY(Gv_CorDelay/1000)MOVESCANABS(EndX, EndY)MOVE_DELAY(Gv_CorDelay/1000)MOVESCANABS(EndX, StartX)MOVE_DELAY(Gv_CorDelay/1000)MOVESCANABS(StartX, StartY)if(If_End) thenMOVE_DELAY(Gv_LastDelay/1000) '关光延时if Gv_WorkMode =1 thenMOVE_OP(Gc_Out_Laser, OFF)ELSEMOVE_OP(Gc_Out_Red, OFF)endifendifEnd Sub'**********************************************************Global Sub Sub_Move9Point()Local dScanSizedScanSize = Gv_MarkSizeMOVE_Aout(Gc_Aout_Laser,Gv_LaserPower) '设置能量MOVE_op(Gc_Out_LaserEnable,ON) '打开激光使能MOVE_DELAY(10)TRIGGER'绘制横线Sub_MoveEmp((-dScanSize/2 - dScanSize/10), 0)Sub_MoveLine((dScanSize/2 + dScanSize/10), 0,TRUE)'绘制竖线Sub_MoveEmp(0, (-dScanSize/2 - dScanSize/10))Sub_MoveLine(0,(dScanSize/2 + dScanSize/10),TRUE)'矩形Sub_MoveEmp(-dScanSize/2, -dScanSize/2)Sub_MoveRect(-dScanSize/2, -dScanSize/2, dScanSize/2, dScanSize/2,TRUE)'绘制XSub_MoveEmp((dScanSize/2-0.06*dScanSize), -0.02*dScanSize)Sub_MoveLine((dScanSize/2-0.02*dScanSize), -0.08*dScanSize,TRUE)Sub_MoveEmp((dScanSize/2-0.02*dScanSize), -0.02*dScanSize)Sub_MoveLine((dScanSize/2-0.06*dScanSize), -0.08*dScanSize,TRUE)'绘制YSub_MoveEmp(0.02*dScanSize, (dScanSize/2-0.02*dScanSize))Sub_MoveLine(0.04*dScanSize, (dScanSize/2-0.05*dScanSize),TRUE)Sub_MoveEmp(0.06*dScanSize, (dScanSize/2-0.02*dScanSize))Sub_MoveLine(0.04*dScanSize, (dScanSize/2-0.05*dScanSize),FALSE)Sub_MoveLine(0.04*dScanSize, (dScanSize/2-0.08*dScanSize),TRUE)'回原点FORCE_SPEED = Gv_EmpSpMOVESCANABS(0,0) '空移到原点MOVE_Aout(Gc_Aout_Laser,0) '关闭能量MOVE_op(Gc_Out_LaserEnable,OFF) '关闭激光使能End Sub'**********************************************************Global Sub Sub_Bnt_TaskRun() '九点标定按钮STOPTASK 1RUNTASK 1,Sub_Move9PointEnd Sub'**********************************************************Global Sub Sub_Btn_TaskStop() '停止按钮STOPTASK 1base(Gc_AxisX,Gc_AxisY)Cancel(2)End Sub
2023年06月08日
135 阅读
0 评论
0 点赞
2023-06-07
MDK和各种pack软件包镜像下载
MDK软件:mdk454.exe (491.23MB)mdk474.exe (576.82MB)MDK527.EXE (802.01MB)MDK529.EXE (835.12MB)MDK 530.EXE (875.73MB)MDK531.EXE (875.96MB)MDK532.EXE (892.75MB)MDK533.EXE (923.68MB)MDK534.EXE (942.70MB)MDK535.EXE (890.96MB)MDK536.EXE (891.11MB)MDK537.EXE (855.73MB)最后一个AC5编译器,从MDK5.37开始,不再默认安装,需要独立安装ARMCompiler_506_Windows_x86_b960.zip (80.94MB)MDK兼容包:(MDK4升级到MDK5的兼容包,截止到MDK5.25已经没有再更新了)可用于Arm7, Arm9,Cortex-RMDK79525.EXE (127.34MB)可用于Cortex-MMDKCM 525.EXE (359.98MB)TensorFlow和神经网络内核Ethos-U:ARM.ethos-u-core-driver.0.4.0.pack (80.06KB)tensorflow.gemmlowp.0.4.0.pack (881.69KB)tensorflow.tensorflow-lite-micro.0.4.0.pack (597.45KB)tensorflow.kissfft.0.4.0.pack (65.07KB)tensorflow.ruy.0.4.0.pack (351.56KB)Cyclone TCP:Oryx-Embedded.Middleware.1.9.8.pack (13.67MB)Oryx-Embedded.Middleware.2.0.0.pack (13.86MB)Oryx-Embedded.Middleware.2.0.2.pack (14.40MB)Oryx-Embedded.Middleware.2.0.4.pack (15.61MB)Oryx-Embedded.Middleware.2.1.2.pack (16.32MB)wolfSSL和wolfCrypt加密库I-CUBE-WOLFSSL-WOLFSSL.pack (11.85 MB)wolfSSL.wolfSSL.4.6.0.pack (15.79MB)CMSIS:ARM.CMSIS.5.6.0.pack (100.66MB)ARM.CMSIS.5.7.0.pack (110.86MB)ARM.CMSIS.5.8.0.pack (34.49MB)ARM.CMSIS.5.9.0.pack (32.55MB)ARM.CMSIS-Driver_Validation.2.0.0.pack (8.32MB)ARM.CMSIS-RTOS_Validation.1.1.0.pack (511.87KB)ARM.CMSIS-Driver.2.6.1.pack (576.73KB)ARM.CMSIS-Driver.2.7.0.pack (592.16KB)MDK中间件(2022-04-28):Keil.MDK-Middleware.7.10.0.pack (123.50MB)Keil.MDK-Middleware.7.11.0.pack (108.24MB)Keil.MDK-Middleware.7.11.1.pack (108.25MB)Keil.MDK-Middleware.7.12.0.pack (108.30MB)Keil.MDK-Middleware.7.13.0.pack (174.86MB)Keil.MDK-Middleware.7.14.0.pack (28.94MB)Keil.MDK-Middleware.7.15.0.pack (30.10MB)LwIP(2020-07-16):lwIP.lwIP.2.1.2.pack (5.12MB)MbedTLS(2022-02-17)ARM.mbedTLS.1.6.1.pack (4.92MB)ARM.mbedTLS.1.7.0.pack (16.24MB)ARM.mbedTLS.1.8.0.pack (20.08MB)Mbed Crypto(2020-06-07)ARM.mbedCrypto.3.0.1.pack (3.19MB)ARM Compiler扩展包:Keil.ARM_Compiler.1.6.3.pack (3.88MB)Keil.ARM_Compiler.1.7.0.pack (3.88MB)安全固件TF-M:ARM.TFM.2.1.0.pack (61.82MB)ARM.TFM-Test.1.0.0.pack (197.90KB)Keil.LPC55S6x_TFM-PF.1.0.0.pack (2.97MB)Keil.STM32L5xx_TFM-PF.1.0.0.pack (2.22MB)ST所有产品线:Keil.STBlueNRG-1_DFP.1.2.0.pack (1.45MB)Keil.STBlueNRG-2_DFP.1.0.1.pack (3.95MB)Keil.STM32F0xx_DFP.2.1.0.pack (65.20MB)Keil.STM32F1xx_DFP.2.3.0.pack (47.84MB)Keil.STM32F2xx_DFP.2.9.0.pack (66.39MB)Keil.STM32F2xx_DFP.2.10.0.pack (49.96MB)Keil.STM32F3xx_DFP.2.2.0.pack (90.31MB)Keil.STM32F4xx_DFP.2.15.0.pack (248.76MB)Keil.STM32F4xx_DFP.2.16.0.pack (152.53MB)Keil.STM32F7xx_DFP.2.14.0.pack (218.25MB)Keil.STM32H7xx_DFP.2.6.0.pack (339.13MB)Keil.STM32H7xx_DFP.2.7.0.pack (337.51MB)Keil.STM32H7xx_DFP.2.8.0.pack (278.49MB)Keil.STM32H7xx_DFP.3.0.0.pack (278.73MB)Keil.STM32L0xx_DFP.2.1.0.pack (56.13MB)Keil.STM32L0xx_DFP.2.2.0.pack (59.42MB)Keil.STM32L1xx_DFP.1.3.0.pack (39.86MB)Keil.STM32L4xx_DFP.2.6.1.pack (241.56MB)Keil.STM32L5xx_DFP.1.3.0.pack (40.92MB)Keil.STM32L5xx_DFP.1.4.0.pack (44.88MB)Keil.STM32W1xx_DFP.1.0.0.pack (4.09MB)Keil.STM32WBxx_DFP.1.1.0.pack (31.11MB)Keil.STM32WLxx_DFP.1.1.0.pack (28.96MB)Keil.STM32G0xx_DFP.1.3.0.pack (47.37MB)Keil.STM32G4xx_DFP.1.4.0.pack (93.96MB)Keil.STM32MP1xx_DFP.1.3.0.pack (35.02MB)Keil.STM32L562E-DK_BSP.1.0.0.pack (44.69MB)Keil.NUCLEO-L552ZE-Q_BSP.1.0.0.pack (21.38MB)Keil.STM32NUCLEO_BSP.1.7.0.pack (10.22MB)Keil.STM32U5xx_DFP.1.1.0.pack (89.80MB)MDK物联网(2020-05-21):MDK-Packs.AWS_IoT_Device.2.0.0-beta.pack (1.43MB)MDK-Packs.Azure_IoT.1.0.2.pack (3.60MB)MDK-Packs.cJSON.1.0.0.pack (435.31KB)MDK-Packs.Google_IoT_Device.1.0.2.pack (91.03KB)MDK-Packs.HTTP_Parser.1.0.0.pack (113.62KB)MDK-Packs.Jsmn.1.1.0.pack (16.64KB)MDK-Packs.Paho_MQTT.1.0.2.pack (966.52KB)MDK-Packs.QCA400x_Host_Driver_SDK.1.1.0.pack (458.59KB)MDK-Packs.QCA400x_WiFi_Driver.1.1.0.pack (21.92KB)MDK-Packs.TinyCBOR.1.0.0.pack (113.91KB)2020-07-16MDK-Packs.IoT_Socket.1.2.1.pack (180.35KB)MDK-Packs.Watson_IoT_Device.1.0.2.pack (208.74KB)RT-Thread:RealThread.RT-Thread.3.1.3.pack (2.06MB)FreeRTOS软件包ARM.CMSIS-FreeRTOS.10.3.1.pack (53.10MB)LVGLLVGL.lvgl.1.0.1-alpha3.pack (4.62MB)emWin6.xKeil.MDK-Middleware_Graphics.1.0.0.pack (197.83MB)对应emWin6.24:Keil.MDK-Middleware_Graphics.1.1.0.pack (122.92MB)TouchGFXSTMicroelectronics.X-CUBE-TOUCHGFX.4.18.1.pack (487.12MB)
2023年06月07日
214 阅读
0 评论
0 点赞
1
2
...
8