ZYNQ学习笔记(三):PL与PS数据交互—— UART串口+AXI GPIO控制DDS IP核输出实验

本文主要是介绍ZYNQ学习笔记(三):PL与PS数据交互—— UART串口+AXI GPIO控制DDS IP核输出实验,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

前言

实验环境:

一、设计需求

二、硬件设计

2.1 系统框图

2.2 模块配置

三、软件设计

四、实验现象

总结



前言

一个月没有继续更新是因为入手了一块新的板子——redpitaya。
自上一个实验完成后,在罗德频谱仪上观测信号,发现信号质量不够好,毕竟黑金开发板配套的AN108模块,它的ADDA芯片都是8位的,使我们输出DDS信号的SDRF最多是48,所以信号观测起来体验感很差,而火龙果板拥有支持最高125Mhz,14位的ADDA芯片,能很大程度上提供更精确和稳定的模拟信号输出,所以以后的实验就在这块板子上进行~


实验环境:

火龙果(redpitaya)开发板(SOC型号zynq7010),2018.3 Vivado,2018.3 SDK, 示波器。

一、设计需求

1.学会利用redpitaya板输出波形
2.学会利用PS端串口来控制AXI GPIO核的输出
3.最终实现能够通过串口输入来控制AXI GPIO核的输出,进而控制DDS IP核输出不同频率信号。

二、硬件设计

2.1 系统框图

根据实验任务我大致画出本次实验的系统框图 ~  如图所示:

PS 端的 M_AXI_GP0 作为主端口,与 PL 端的 AXI GPIO IP 核以 AXI4-Lite 总线相连接。
其中,AXI Interconnect 用于连接 AXI 存储器映射( memory-mapped )的主器件和从器件。

2.2 模块配置

创建VIVADO工程之前我们要看一下火龙果板的原理图:要注意它内部各器件的型号~

首先ZYNQ7 Processing System 模块配置:
点击PS-PL Configuration配置 PS-PL 接口,包括 AXI 接口, 在右侧展开 General 下的 Enable Clock Resets ,勾选其中的 FCLK_RESET0_N 。 另外在当前界面中展开 AXI Non Secure Enablement 下的 GP Master AXI Interface,勾选其中的 MAXI GP0 interface。

点击Peripheral IO Pins , 这里我们只需要配置UART0与GPIO MIO。

 其余配置如下:

 添加AXI-GPIO模块:

我们也可以通过勾选图中的“ All Inputs ”或者“ All Outputs ”将 GPIO 指定为输入或者输出接口。这两个选项默认是没有勾选的,这样我们可以在程序中将其动态地配置成输入或者输出接口, 注意如果在这里设置了All Input/Output,那么在PS程序中就无需再设置GPIO方向,设置了也无效 ,建议不要在这里设置,通过PS程序去设置,保持灵活性),可设置输出默认值与三态默认值。

GPIO 接口的位宽“GPIO Width”, 最大可以支持 32 位。这里我们需要控制8种不同频率,因此将其设置为 4。

参数“ Default Tri State Value ”,它配置 GPIO 默认情况下的输入输出模式,当其为 0xFFFFFFFF时,表明GPIO所有的位默认为输入模式。参数“Default Output value ”:指的是默认的输出值,意味着当该GPIO核被初始化或复位时,它会将输出端口设置为指定的默认值。

 “Enable Dual Channel”可以使能 GPIO 通道 2GPIO 2 的配置与 GPIO 完全相同。该选项默认没有勾选,即该IP工作在单通道模式下。

AXI GPIO内核的顶层框图如图所示:

S_AXI中S代表slave是从端口,处理器作为Master可以控制AXI GPIO这个从器件。

AXI4-Lite作为轻量级的接口可以实现简单寄存器的配置和少量的数据传输,READ_REG是读寄存器,Interrupt Registers是中断寄存器,AXI4-Lite可以实现对这两个寄存器的配置。三态缓冲器不包含在AXI GPIO里,是工具在顶层文件里自动添加的。

GPIO内核包含寄存器(输入输出和中断)和多路复用器(选择两个GPIO的通道),GPIO_DATA是数据寄存器(Data Register),读数据和写数据都是通过这个寄存器。GPIO_TRI是三态控制寄存器,控制GPIO引脚作为输入还是输出,GPIO_T是三态的使能信号。GPIO_T=1配置为输入(in),GPIO_T=0配置为输出(out)。GPIO_WIDTH是用户指定的位宽,可以配置在1位到32位之间。

此外输入数据一方面进入READ_REG,一方面进入中断检测模块Interrupt Detection。只要输入端口数据发生改变就可以生成中断,中断检测实现该功能并通过ip2intc_irpt输出一个中断。

添加配置完这两个IP核后,点击Diagram 窗口的1、2:

连接完成后如图:

接下来我们配置PL端DDS与ADDA部分~

DDS ip核:

自定义ADDA ip核


module red_ADDA_shell (input             [0:0]    fclk          , //[0]-125MHzinput             [0:0]    frstn         ,// ADCinput   [16-1:0] adc_dat_0_i     , // ADC datainput   [16-1:0] adc_dat_1_i     , // ADC datainput   [ 2-1:0] adc_clk_i     , // ADC clock {p,n}output  [ 2-1:0] adc_clk_o     , // optional ADC clock source (unused)output           adc_cdcs_o    , // ADC clock duty cycle stabilizeroutput  [16-1:0] rtl_adc_0_o   , // rtl side adc 0 outputoutput  [16-1:0] rtl_adc_1_o   , // rtl side adc 1 outputoutput           rtl_adc_clk_o , // rtl side adc clk output// DACoutput  [14-1:0] dac_dat_o  ,  // DAC combined dataoutput           dac_wrt_o  ,  // DAC writeoutput           dac_sel_o  ,  // DAC channel selectoutput           dac_clk_o  ,  // DAC clockoutput           dac_rst_o  ,  // DAC resetinput   [14-1:0] rtl_dac_0_i,input   [14-1:0] rtl_dac_1_i,output           rtl_dac_clk );red_pitaya_ADDA U_adda(.fclk          (fclk          ), //[0]-125MHz.frstn         (frstn         ),.adc_dat_0_i   (adc_dat_0_i   ), // ADC data.adc_dat_1_i   (adc_dat_1_i   ), // ADC data.adc_clk_i     (adc_clk_i     ), // ADC clock {p,n}.adc_clk_o     (adc_clk_o     ), // optional ADC clock source (unused).adc_cdcs_o    (adc_cdcs_o    ), // ADC clock duty cycle stabilizer.rtl_adc_0_o   (rtl_adc_0_o   ), // rtl side adc 0 output.rtl_adc_1_o   (rtl_adc_1_o   ), // rtl side adc 1 output.rtl_adc_clk_o (rtl_adc_clk_o ), // rtl side adc clk output.dac_dat_o     (dac_dat_o     ),  // DAC combined data.dac_wrt_o     (dac_wrt_o     ),  // DAC write.dac_sel_o     (dac_sel_o     ),  // DAC channel select.dac_clk_o     (dac_clk_o     ),  // DAC clock.dac_rst_o     (dac_rst_o     ),  // DAC reset.rtl_dac_0_i   (rtl_dac_0_i   ),.rtl_dac_1_i   (rtl_dac_1_i   ),.rtl_dac_clk   (rtl_dac_clk   ));endmodule
module red_pitaya_ADDA (input  logic           [0:0]    fclk          , //[0]-125MHzinput  logic           [0:0]    frstn         ,// ADCinput  logic           [16-1:0] adc_dat_0_i     , // ADC datainput  logic           [16-1:0] adc_dat_1_i     , // ADC datainput  logic           [ 2-1:0] adc_clk_i     , // ADC clock {p,n}output logic           [ 2-1:0] adc_clk_o     , // optional ADC clock source (unused)output logic                    adc_cdcs_o    , // ADC clock duty cycle stabilizeroutput logic           [16-1:0] rtl_adc_0_o   , // rtl side adc 0 outputoutput logic           [16-1:0] rtl_adc_1_o   , // rtl side adc 1 outputoutput logic                    rtl_adc_clk_o , // rtl side adc clk output// DACoutput logic [14-1:0] dac_dat_o  ,  // DAC combined dataoutput logic          dac_wrt_o  ,  // DAC writeoutput logic          dac_sel_o  ,  // DAC channel selectoutput logic          dac_clk_o  ,  // DAC clockoutput logic          dac_rst_o  ,  // DAC resetinput  logic [14-1:0] rtl_dac_0_i,input  logic [14-1:0] rtl_dac_1_i,output logic          rtl_dac_clk);// PLL signals
logic                 adc_clk_in;
logic                 pll_adc_clk;
logic                 pll_dac_clk_1x;
logic                 pll_dac_clk_2x;
logic                 pll_dac_clk_2p;
logic                 pll_ser_clk;
logic                 pll_pwm_clk;
logic                 pll_locked;// ADC clock/reset
logic                 adc_clk;
logic                 adc_rstn;// stream bus type
localparam type SBA_T = logic signed [14-1:0];  // acquire
localparam type SBG_T = logic signed [14-1:0];  // generateSBA_T [  2-1:0]          adc_dat;// DAC signals
logic                    dac_clk_1x;
logic                    dac_clk_2x;
logic                    dac_clk_2p;
logic                    dac_rst;logic        [14-1:0] dac_dat_a, dac_dat_b;
logic        [14-1:0] dac_a    , dac_b    ;
logic signed [15-1:0] dac_a_sum, dac_b_sum;// ASG
SBG_T [2-1:0]            asg_dat;// PID
SBA_T [2-1:0]            pid_dat;// configuration
// logic                    digital_loop;// PLL (clock and reset)// diferential clock input
IBUFDS i_clk (.I (adc_clk_i[1]), .IB (adc_clk_i[0]), .O (adc_clk_in));  // differential clock inputred_pitaya_pll pll (// inputs.clk         (adc_clk_in),  // clock.rstn        (frstn[0]  ),  // reset - active low// output clocks.clk_adc     (pll_adc_clk   ),  // ADC clock.clk_dac_1x  (pll_dac_clk_1x),  // DAC clock 125MHz.clk_dac_2x  (pll_dac_clk_2x),  // DAC clock 250MHz.clk_dac_2p  (pll_dac_clk_2p),  // DAC clock 250MHz -45DGR.clk_ser     (pll_ser_clk   ),  // fast serial clock.clk_pdm     (pll_pwm_clk   ),  // PWM clock// status outputs.pll_locked  (pll_locked)
);logic                 pwm_clk ;
logic                 pwm_rstn;
logic                 ser_clk ;BUFG bufg_adc_clk    (.O (adc_clk   ), .I (pll_adc_clk   ));
BUFG bufg_dac_clk_1x (.O (dac_clk_1x), .I (pll_dac_clk_1x));
BUFG bufg_dac_clk_2x (.O (dac_clk_2x), .I (pll_dac_clk_2x));
BUFG bufg_dac_clk_2p (.O (dac_clk_2p), .I (pll_dac_clk_2p));
BUFG bufg_ser_clk    (.O (ser_clk   ), .I (pll_ser_clk   ));
BUFG bufg_pwm_clk    (.O (pwm_clk   ), .I (pll_pwm_clk   ));// ADC reset (active low)
always @(posedge adc_clk)
adc_rstn <=  frstn[0] &  pll_locked;// DAC reset (active high)
always @(posedge dac_clk_1x)
dac_rst  <= ~frstn[0] | ~pll_locked;// Analog mixed signals (PDM analog outputs)logic [ 4-1:0] [8-1:0] pdm_cfg;
logic [ 4-1:0] dac_pwm_o  ;  // 1-bit PWM DACred_pitaya_pdm pdm (// system signals.clk   (adc_clk ),.rstn  (adc_rstn),// configuration.cfg   (pdm_cfg),.ena      (1'b1),.rng      (8'd255),// PWM outputs.pdm (dac_pwm_o));// ADC IO// generating ADC clock is disabled
assign adc_clk_o = 2'b10;
.R(1'b0), .S(1'b0));
.R(1'b0), .S(1'b0));// ADC clock duty cycle stabilizer is enabled
assign adc_cdcs_o = 1'b1 ;logic [2-1:0] [14-1:0] adc_dat_raw;// IO block registers should be used here
// lowest 2 bits reserved for 16bit ADC
always @(posedge adc_clk)
beginadc_dat_raw[0] <= adc_dat_0_i[16-1:2];adc_dat_raw[1] <= adc_dat_0_i[16-1:2];
endalways @(posedge adc_clk)
beginrtl_adc_0_o <= adc_dat_0_i;rtl_adc_1_o <= adc_dat_1_i;
end
assign rtl_adc_clk_o = adc_clk;// transform into 2's complement (negative slope)
assign adc_dat[0] = {adc_dat_raw[0][14-1], ~adc_dat_raw[0][14-2:0]};
assign adc_dat[1] = {adc_dat_raw[1][14-1], ~adc_dat_raw[1][14-2:0]};// DAC IO// Sumation of ASG and PID signal perform saturation before sending to DAC 
assign dac_a_sum = asg_dat[0] + pid_dat[0];
assign dac_b_sum = asg_dat[1] + pid_dat[1];// saturation
assign dac_a = (^dac_a_sum[15-1:15-2]) ? {dac_a_sum[15-1], {13{~dac_a_sum[15-1]}}} : dac_a_sum[14-1:0];
assign dac_b = (^dac_b_sum[15-1:15-2]) ? {dac_b_sum[15-1], {13{~dac_b_sum[15-1]}}} : dac_b_sum[14-1:0];assign rtl_dac_clk = dac_clk_1x;
always @(posedge dac_clk_1x)
begindac_dat_a <=  rtl_dac_0_i;dac_dat_b <=  rtl_dac_1_i;
end// DDR outputs
ODDR oddr_dac_clk          (.Q(dac_clk_o), .D1(1'b0     ), .D2(1'b1     ), .C(dac_clk_2p), .CE(1'b1), .R(1'b0   ), .S(1'b0));
ODDR oddr_dac_wrt          (.Q(dac_wrt_o), .D1(1'b0     ), .D2(1'b1     ), .C(dac_clk_2x), .CE(1'b1), .R(1'b0   ), .S(1'b0));
ODDR oddr_dac_sel          (.Q(dac_sel_o), .D1(1'b1     ), .D2(1'b0     ), .C(dac_clk_1x), .CE(1'b1), .R(dac_rst), .S(1'b0));
ODDR oddr_dac_rst          (.Q(dac_rst_o), .D1(dac_rst  ), .D2(dac_rst  ), .C(dac_clk_1x), .CE(1'b1), .R(1'b0   ), .S(1'b0));
ODDR oddr_dac_dat [14-1:0] (.Q(dac_dat_o), .D1(dac_dat_b), .D2(dac_dat_a), .C(dac_clk_1x), .CE(1'b1), .R(dac_rst), .S(1'b0));endmodule:red_pitaya_ADDAmodule red_pitaya_pll (// inputsinput  logic clk       ,  // clockinput  logic rstn      ,  // reset - active low// output clocksoutput logic clk_adc   ,  // ADC clockoutput logic clk_dac_1x,  // DAC clockoutput logic clk_dac_2x,  // DAC clockoutput logic clk_dac_2p,  // DAC clockoutput logic clk_ser   ,  // fast serial clockoutput logic clk_pdm   ,  // PDM clock// status outputsoutput logic pll_locked
);logic clk_fb;PLLE2_ADV #(.BANDWIDTH            ("OPTIMIZED"),.COMPENSATION         ("ZHOLD"    ),.DIVCLK_DIVIDE        ( 1         ),.CLKFBOUT_MULT        ( 8         ),.CLKFBOUT_PHASE       ( 0.000     ),.CLKOUT0_DIVIDE       ( 8         ),.CLKOUT0_PHASE        ( 0.000     ),.CLKOUT0_DUTY_CYCLE   ( 0.5       ),.CLKOUT1_DIVIDE       ( 8         ),.CLKOUT1_PHASE        ( 0.000     ),.CLKOUT1_DUTY_CYCLE   ( 0.5       ),.CLKOUT2_DIVIDE       ( 4         ),.CLKOUT2_PHASE        ( 0.000     ),.CLKOUT2_DUTY_CYCLE   ( 0.5       ),.CLKOUT3_DIVIDE       ( 4         ),.CLKOUT3_PHASE        (-45.000    ),.CLKOUT3_DUTY_CYCLE   ( 0.5       ),.CLKOUT4_DIVIDE       ( 4         ),  // 4->250MHz, 2->500MHz.CLKOUT4_PHASE        ( 0.000     ),.CLKOUT4_DUTY_CYCLE   ( 0.5       ),.CLKOUT5_DIVIDE       ( 4         ),.CLKOUT5_PHASE        ( 0.000     ),.CLKOUT5_DUTY_CYCLE   ( 0.5       ),.CLKIN1_PERIOD        ( 8.000     ),.REF_JITTER1          ( 0.010     )
) pll (// Output clocks.CLKFBOUT     (clk_fb    ),.CLKOUT0      (clk_adc   ),.CLKOUT1      (clk_dac_1x),.CLKOUT2      (clk_dac_2x),.CLKOUT3      (clk_dac_2p),.CLKOUT4      (clk_ser   ),.CLKOUT5      (clk_pdm   ),// Input clock control.CLKFBIN      (clk_fb    ),.CLKIN1       (clk       ),.CLKIN2       (1'b0      ),// Tied to always select the primary input clock.CLKINSEL     (1'b1 ),// Ports for dynamic reconfiguration.DADDR        (7'h0 ),.DCLK         (1'b0 ),.DEN          (1'b0 ),.DI           (16'h0),.DO           (     ),.DRDY         (     ),.DWE          (1'b0 ),// Other control and status signals.LOCKED       (pll_locked),.PWRDWN       (1'b0      ),.RST          (!rstn     )
);endmodule: red_pitaya_pllmodule red_pitaya_pdm #(int unsigned DWC = 8,  // counter width (resolution)int unsigned CHN = 4   // output  width
)(// system signalsinput  logic                      clk ,  // clockinput  logic                      rstn,  // reset// configurationinput  logic [CHN-1:0] [DWC-1:0]  cfg ,  // input  logic                      ena ,input  logic           [DWC-1:0]  rng ,// PWM outputsoutput logic [CHN-1:0]            pdm    // PWM output - driving RC
);
generate
for (genvar i=0; i<CHN; i++) begin: for_chnlogic [DWC-1:0] dat;// input data copy
always_ff @(posedge clk)
if (~rstn)            dat <= '0;
else beginif (ena)  dat <= cfg[i];
endlogic [DWC-1:0] acu;  // accumulator
logic [DWC  :0] sum;  // summation
logic [DWC  :0] sub;  // subtraction// accumulator
always_ff @(posedge clk)
if (~rstn)  acu <= '0;
else beginif (ena)  acu <= ~sub[DWC] ? sub[DWC-1:0] : sum[DWC-1:0];else      acu <= '0;
end// summation
assign sum = acu + dat;// subtraction
assign sub = sum - rng;// PDM output
always_ff @(posedge clk)
if (~rstn)  pdm[i] <= 1'b0;
else        pdm[i] <= ena & (~sub[DWC] | ~|sub[DWC-1:0]);end: for_chn
endgenerate
endmodule: red_pitaya_pdm

解释一下red_pitaya_ADDA 模块的代码逻辑。

red_pitaya_pll 模块:这是一个锁相环模块,用于生成各种时钟信号,包括 ADC 时钟、DAC 时钟和其他内部时钟信号。它的输入是外部信号 clk 和 rstn,输出包括各种时钟信号如 clk_adc、clk_dac_1x、clk_dac_2x、clk_dac_2p、clk_ser 和 clk_pdm。它通过 PLL 控制时钟的频率和相位,并提供了锁定状态的输出信号 pll_locked。

ADC 逻辑部分:ADC 通过时钟信号 adc_clk 对输入的模拟数据进行采样。采样后的数据经过一定的处理后输出到 rtl_adc_0_o 和 rtl_adc_1_o 输出端口。这部分代码包括了时钟同步和数据处理逻辑。例如,adc_dat_raw 数组用于存储采样后的原始数据。

DAC 逻辑部分:DAC 的逻辑包括了一些处理步骤。ASG 和 PID 信号的加和后进行饱和处理,最终的输出数据存储在 dac_dat_a 和 dac_dat_b 中。这些数据最终通过 rtl_dac_0_i 和 rtl_dac_1_i 输出到外部的 DAC 接口。

red_pitaya_pdm 模块:这个模块似乎用于控制 PWM 输出信号。它包含一个循环,用于处理 PWM 输出的逻辑。其中包括了数据累加、数据比较和输出控制等逻辑,最终控制 pdm 的输出。

时钟控制和同步逻辑:在整个模块中,存在一些时序逻辑,用于控制时钟的频率和相位,以及确保数据在正确的时钟边沿进行传输和处理。这些逻辑包括了时钟分频、时钟同步和时钟延迟等方面的处理。

自定义dds_contral ip核

module dds_contral(input           clk,input           rst_n,input [3 : 0]   key_PINC,output reg [23 : 0] Fword);
always@(*)
begincase(key_PINC)4'b0001:  Fword <= 'h20c4;      4'b0010:  Fword <= 'h624c;    4'b0011:  Fword <= 'ha3d4;     4'b0100:  Fword <= 'h147a8;4'b0101:  Fword <= 'h1EB85;4'b0110:  Fword <= 'h28f5c;4'b0111:  Fword <= 'h33333;4'b1000:  Fword <= 'h3d70a; default: Fword <= 'h1EB85;endcaseend
endmodule

频率字的计算参考第一篇文章~不再细说。

自定义signed_to_unsigned模块:目的是为了在示波器上显示

module signed_to_unsigned(
DIN  ,
DOUT );parameter DWL  = 16;input [DWL-1:0] DIN;
output[DWL-1:0] DOUT;
assign DOUT[DWL-1]   = ~DIN[DWL-1];
assign DOUT[DWL-2:0] =  DIN[DWL-2:0];endmodule

其余的模块参考文章开头的Block Design~

三、软件设计

导出硬件后,Launch SDK~ 在 SDK 软件中新建一个 BSP 工程和一个空的应用工程,应用工程名为“redptiaya ”。然后为应用工程新建一个源文件“main.c ”,我们在新建的 main.c 文件中输入本次实验的代码。

 

代码的主体部分如下所示:
这段代码的功能是读取用户输入的数字,并根据数字控制 GPIO 输出信号的状态。然后从 GPIO 读取输出状态并通过 UART 发送回去,以检测GPIO输出是否符合自己预期。
#include <stdio.h>
#include <string.h>
#include "xparameters.h"
#include "xgpio.h"
#include "xuartps.h"#define GPIO_DEVICE_ID XPAR_AXI_GPIO_0_DEVICE_ID
#define UART_DEVICE_ID XPAR_XUARTPS_0_DEVICE_ID
#define CHANNEL 1XGpio Gpio;
XUartPs Uart_Ps;int main() {XUartPs_Config *Config;Config = XUartPs_LookupConfig(UART_DEVICE_ID);if (Config == NULL) {printf("无法找到UART配置。\n");return 1;}XUartPs *Uart_PsPtr = &Uart_Ps;XUartPs_CfgInitialize(Uart_PsPtr, Config, Config->BaseAddress);XUartPs_SetBaudRate(Uart_PsPtr, 115200);if (XGpio_Initialize(&Gpio, GPIO_DEVICE_ID) != XST_SUCCESS) {printf("GPIO初始化失败。\n");return 1;}XGpio_SetDataDirection(&Gpio, CHANNEL, 0x0);int input;int output;int gpio_output;int in_num; // 用整数存储输入while (1) {printf("输入一个数字频率模式:\n ");scanf("%d", &in_num); // 直接读取整数if (in_num >= 1 && in_num <= 8) {input = in_num;// 将输入转换为4位二进制数output = input & 0xF;// 将4位二进制数输出到GPIOXGpio_DiscreteWrite(&Gpio, CHANNEL, output);// 从GPIO读取值gpio_output = XGpio_DiscreteRead(&Gpio, CHANNEL);// 将从GPIO读取的值发送到串口char buffer[15];sprintf(buffer, "频率%d", gpio_output);XUartPs_Send(Uart_PsPtr, (u8 *)buffer, strlen(buffer)); // 发送整个字符串XUartPs_Send(Uart_PsPtr, (u8 *)"\n", 1); // 发送换行符} else {printf("输入错误。请确保输入一个1到8之间的数字。\n");}}return 0;
}

代码通过 XUartPs_LookupConfig 函数查找 UART 的配置信息,如果找不到,则打印一条错误消息。然后通过 XUartPs_CfgInitialize 函数进行初始化,并设置波特率为 115200。然后,通过 XGpio_Initialize 函数初始化 GPIO 设备,并设置通道的数据方向为输出。接下来进入一个无限循环,循环中首先提示用户输入一个数字频率模式。

输入一个整数作为频率模式,如果用户输入的数字在 1 到 8 之间,代码将读取输入的数字并将其转换为一个 4 位的二进制数,接着,代码将这个 4 位二进制数写入到 GPIO 设备中,然后再从 GPIO 读取值。接着将从 GPIO 读取的值发送到 UART,以便通过串口发送出去。这部分代码使用了 sprintf 函数将读取的 GPIO 值转换为字符串,然后通过 XUartPs_Send 函数将字符串发送到串口。

CLTA+S保存代码并编译~

电脑与开发板用USB、JATG线相连,连接上示波器

选择自己电脑的串口号连接串口。

下载程序与硬件到板子里~

四、实验现象

程序下载完成后,目光移至SDK Terminal

发送数字后,观察示波器

由此可以看出,比较符合自己一开始的预期~


总结

总体来说,整体工程的完成自己断断续续大概用了20天,虽然实现的功能不复杂,但真正做起来,对于自己这个初学者还是非常费时费力的~回顾这个过程自己走了很多弯路,但也学会了很多,比如自己还没记录下来的IP核如何封装,如何移植,不用ILA IP核怎么用另一种方式去添加观测信号等等。这个工程实现过程中也发现了一些问题,比如说DDS IP核,当整体设计中存在锁相环倍频时,选择硬件模式就是无法正常输出波形,选择系统模式功能才正常,更详细的原因我还是没有查到,可能等以后自己对zynq知识学习的更系统更完善时,这个问题可能就有了答案~路阻且长,还在路上~加油

这篇关于ZYNQ学习笔记(三):PL与PS数据交互—— UART串口+AXI GPIO控制DDS IP核输出实验的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/301022

相关文章

Unity新手入门学习殿堂级知识详细讲解(图文)

《Unity新手入门学习殿堂级知识详细讲解(图文)》Unity是一款跨平台游戏引擎,支持2D/3D及VR/AR开发,核心功能模块包括图形、音频、物理等,通过可视化编辑器与脚本扩展实现开发,项目结构含A... 目录入门概述什么是 UnityUnity引擎基础认知编辑器核心操作Unity 编辑器项目模式分类工程

Java整合Protocol Buffers实现高效数据序列化实践

《Java整合ProtocolBuffers实现高效数据序列化实践》ProtocolBuffers是Google开发的一种语言中立、平台中立、可扩展的结构化数据序列化机制,类似于XML但更小、更快... 目录一、Protocol Buffers简介1.1 什么是Protocol Buffers1.2 Pro

Linux查询服务器 IP 地址的命令详解

《Linux查询服务器IP地址的命令详解》在服务器管理和网络运维中,快速准确地获取服务器的IP地址是一项基本但至关重要的技能,下面我们来看看Linux中查询服务器IP的相关命令使用吧... 目录一、hostname 命令:简单高效的 IP 查询工具命令详解实际应用技巧注意事项二、ip 命令:新一代网络配置全

java -jar example.jar 产生的日志输出到指定文件的方法

《java-jarexample.jar产生的日志输出到指定文件的方法》这篇文章给大家介绍java-jarexample.jar产生的日志输出到指定文件的方法,本文给大家介绍的非常详细,对大家的... 目录怎么让 Java -jar example.jar 产生的日志输出到指定文件一、方法1:使用重定向1、

Python学习笔记之getattr和hasattr用法示例详解

《Python学习笔记之getattr和hasattr用法示例详解》在Python中,hasattr()、getattr()和setattr()是一组内置函数,用于对对象的属性进行操作和查询,这篇文章... 目录1.getattr用法详解1.1 基本作用1.2 示例1.3 原理2.hasattr用法详解2.

Python实现数据可视化图表生成(适合新手入门)

《Python实现数据可视化图表生成(适合新手入门)》在数据科学和数据分析的新时代,高效、直观的数据可视化工具显得尤为重要,下面:本文主要介绍Python实现数据可视化图表生成的相关资料,文中通过... 目录前言为什么需要数据可视化准备工作基本图表绘制折线图柱状图散点图使用Seaborn创建高级图表箱线图热

MySQL数据脱敏的实现方法

《MySQL数据脱敏的实现方法》本文主要介绍了MySQL数据脱敏的实现方法,包括字符替换、加密等方法,通过工具类和数据库服务整合,确保敏感信息在查询结果中被掩码处理,感兴趣的可以了解一下... 目录一. 数据脱敏的方法二. 字符替换脱敏1. 创建数据脱敏工具类三. 整合到数据库操作1. 创建服务类进行数据库

MySQL中处理数据的并发一致性的实现示例

《MySQL中处理数据的并发一致性的实现示例》在MySQL中处理数据的并发一致性是确保多个用户或应用程序同时访问和修改数据库时,不会导致数据冲突、数据丢失或数据不一致,MySQL通过事务和锁机制来管理... 目录一、事务(Transactions)1. 事务控制语句二、锁(Locks)1. 锁类型2. 锁粒

Qt中实现多线程导出数据功能的四种方式小结

《Qt中实现多线程导出数据功能的四种方式小结》在以往的项目开发中,在很多地方用到了多线程,本文将记录下在Qt开发中用到的多线程技术实现方法,以导出指定范围的数字到txt文件为例,展示多线程不同的实现方... 目录前言导出文件的示例工具类QThreadQObject的moveToThread方法实现多线程QC

SpringBoot集成EasyExcel实现百万级别的数据导入导出实践指南

《SpringBoot集成EasyExcel实现百万级别的数据导入导出实践指南》本文将基于开源项目springboot-easyexcel-batch进行解析与扩展,手把手教大家如何在SpringBo... 目录项目结构概览核心依赖百万级导出实战场景核心代码效果百万级导入实战场景监听器和Service(核心