SDR-B1软件无线电平台开发环境搭建

1. 概述

SDR-B1是正旗通信推出的软件无线电硬件平台,采用Xilinx Zynq XC7Z045 FPGA及ADI AD9363无线收发芯片,其尺寸仅为59*88mm,适用于无人机组网、宽带数据传输等应用场景。本文档给出SDR-B1开发环境的搭建过程,适合于具备一定技术基础的工程师。

SDR-B1的硬件架构如下图所示。

开发环境的搭建过程大致分为三个部分:根据SDR-B1的硬件设计搭建Vivado工程并得到Bitstream及HDF文件,搭建Petalinux工程,使用ADI官方软件进行测试。

2. 涉及到的软件

注意,ADI hdl 2019_R2必须使用Vivado 2019.1。

3. 创建Vivado工程

(1) 安装cygwin,安装过程中,选择devel分类下面的make与git,会自动选择依赖包。

(2) 将cygwin及Vivado所在的目录添加至系统环境变量,如下图所示。

(3) 下载并解压hdl_2019_r2,放在合适的目录下,运行Cygwin64 Terminal,切换到hdl-hdl_2019_r2\projects\adrv9361z7035目录下,make,等待编译完成,得到Vivado工程文件。

(4) 使用Vivado打开ccbob_lvds下面的工程文件,然后将工程另存为另一个工程,File-->Project-->Save as,Project name一栏填写sdr-b1,Project location一栏选择E:/Projects目录,如下图所示。

(5) 双击工程文件中的system.bd,右侧窗口出现框图,如下图所示。

(6) 双击ZYNQ,根据SDR-B1的实际情况重新配置,主要就是MIO、RAM及BANK0/1的工作电压,对于SDR-B1,具体设置汇总如下:

MIO设置

MIO Pin Peripheral Signal IO Type
MIO 0 NAND Flash cs LVCMOS 3.3V
MIO 1 GPIO gpio[1] LVCMOS 3.3V
MIO 2 NAND Flash ale LVCMOS 3.3V
MIO 3 NAND Flash we_b LVCMOS 3.3V
MIO 4 NAND Flash data[2] LVCMOS 3.3V
MIO 5 NAND Flash data[0] LVCMOS 3.3V
MIO 6 NAND Flash data[1] LVCMOS 3.3V
MIO 7 NAND Flash cle LVCMOS 3.3V
MIO 8 NAND Flash re_b LVCMOS 3.3V
MIO 9 NAND Flash data[4] LVCMOS 3.3V
MIO 10 NAND Flash data[5] LVCMOS 3.3V
MIO 11 NAND Flash data[6] LVCMOS 3.3V
MIO 12 NAND Flash data[7] LVCMOS 3.3V
MIO 13 NAND Flash data[3] LVCMOS 3.3V
MIO 14 NAND Flash busy LVCMOS 3.3V
MIO 15 GPIO gpio[15] LVCMOS 3.3V
MIO 16 Enet 0 tx_clk LVCMOS 1.8V
MIO 17 Enet 0 txd[0] LVCMOS 1.8V
MIO 18 Enet 0 txd[1] LVCMOS 1.8V
MIO 19 Enet 0 txd[2] LVCMOS 1.8V
MIO 20 Enet 0 txd[3] LVCMOS 1.8V
MIO 21 Enet 0 tx_ctl LVCMOS 1.8V
MIO 22 Enet 0 rx_clk LVCMOS 1.8V
MIO 23 Enet 0 rxd[0] LVCMOS 1.8V
MIO 24 Enet 0 rxd[1] LVCMOS 1.8V
MIO 25 Enet 0 rxd[2] LVCMOS 1.8V
MIO 26 Enet 0 rxd[3] LVCMOS 1.8V
MIO 27 Enet 0 rx_ctl LVCMOS 1.8V
MIO 28 Enet 1 tx_clk LVCMOS 1.8V
MIO 29 Enet 1 txd[0] LVCMOS 1.8V
MIO 30 Enet 1 txd[1] LVCMOS 1.8V
MIO 31 Enet 1 txd[2] LVCMOS 1.8V
MIO 32 Enet 1 txd[3] LVCMOS 1.8V
MIO 33 Enet 1 tx_ctl LVCMOS 1.8V
MIO 34 Enet 1 rx_clk LVCMOS 1.8V
MIO 35 Enet 1 rxd[0] LVCMOS 1.8V
MIO 36 Enet 1 rxd[1] LVCMOS 1.8V
MIO 37 Enet 1 rxd[2] LVCMOS 1.8V
MIO 38 Enet 1 rxd[3] LVCMOS 1.8V
MIO 39 Enet 1 rx_ctl LVCMOS 1.8V
MIO 40 SD 0 clk LVCMOS 1.8V
MIO 41 SD 0 cmd LVCMOS 1.8V
MIO 42 SD 0 data[0] LVCMOS 1.8V
MIO 43 SD 0 data[1] LVCMOS 1.8V
MIO 44 SD 0 data[2] LVCMOS 1.8V
MIO 45 SD 0 data[3] LVCMOS 1.8V
MIO 46 UART 0 rx LVCMOS 1.8V
MIO 47 UART 0 tx LVCMOS 1.8V
MIO 48 UART 1 tx LVCMOS 1.8V
MIO 49 UART 1 rx LVCMOS 1.8V
MIO 50 SD 0 cd LVCMOS 1.8V
MIO 51 ENET Reset reset LVCMOS 1.8V
MIO 52 Enet 0 mdc LVCMOS 1.8V
MIO 53 Enet 0 mdio LVCMOS 1.8V

DDR 设置

Parameter name Value
Enable DDR 1
Memory Part MT41K128M16 JT-125
DRAM bus width 32 Bit
ECC Disabled
BURST Length (lppdr only) 8
Internal Vref 0
Operating Frequency (MHz) 533.333333
HIGH temperature Normal (0-85)
DRAM IC bus width 16 Bits
DRAM Device Capacity 2048 MBits
Speed Bin DDR3_1066F
BANK Address Count 3
ROW Address Count 14
COLUMN Address Count 10
CAS Latency 7
CAS Write Latency 6
RAS to CAS Delay 7
RECHARGE Time 7
tRC (ns ) 48.75
tRASmin ( ns ) 35
tFAW 40
ADDITIVE Latency 0
Write levelling 1
Read gate 1
Read gate 1
DQS to Clock delay [0] (ns) -0.053
DQS to Clock delay [1] (ns) -0.059
DQS to Clock delay [2] (ns) 0.065
DQS to Clock delay [3] (ns) 0.066
Board delay [0] (ns) 0.264
Board delay [1] (ns) 0.265
Board delay [2] (ns) 0.33
Board delay [3] (ns) 0.33

(7) 由于SDR-B1没有用到串行收发器,所以删除框图中axi_pz_xcvrlb及相关的连接线;将axi_gpreg连接至axi_cpu_interconnet的M05_AXI端口;双击axi_cpu_interconnet,将Number of Master Interfaces改为6,如下图。

然后validate design,保证无错。

(8) 点击Project Manager下面的Settings,修改芯片型号为XC7Z045FFG900-2。

(9) 修改system_top.v及约束文件,并且注释掉system_wrapper中的gt_ref_clk,gt_rx_n,gt_rx_p,gt_tx_n,gt_tx_p,然后Generate Bitsteam,如果因为缺少文件报错,则把原hdl目录下的文件复制过去,修改过后的system_top.v如下。


`timescale 1ns/100ps

module system_top (

  inout   [14:0]  ddr_addr,
  inout   [ 2:0]  ddr_ba,
  inout           ddr_cas_n,
  inout           ddr_ck_n,
  inout           ddr_ck_p,
  inout           ddr_cke,
  inout           ddr_cs_n,
  inout   [ 3:0]  ddr_dm,
  inout   [31:0]  ddr_dq,
  inout   [ 3:0]  ddr_dqs_n,
  inout   [ 3:0]  ddr_dqs_p,
  inout           ddr_odt,
  inout           ddr_ras_n,
  inout           ddr_reset_n,
  inout           ddr_we_n,

  inout           fixed_io_ddr_vrn,
  inout           fixed_io_ddr_vrp,
  inout   [53:0]  fixed_io_mio,
  inout           fixed_io_ps_clk,
  inout           fixed_io_ps_porb,
  inout           fixed_io_ps_srstb,

  inout           iic_scl,
  inout           iic_sda,

//  inout   [19:0]  gpio_bd,

  input           rx_clk_in_p,
  input           rx_clk_in_n,
  input           rx_frame_in_p,
  input           rx_frame_in_n,
  input   [ 5:0]  rx_data_in_p,
  input   [ 5:0]  rx_data_in_n,
  output          tx_clk_out_p,
  output          tx_clk_out_n,
  output          tx_frame_out_p,
  output          tx_frame_out_n,
  output  [ 5:0]  tx_data_out_p,
  output  [ 5:0]  tx_data_out_n,

  output          enable,
  output          txnrx,
//  input           clkout_in,
//  output          clkout_out,

  inout           gpio_clksel,
  inout           gpio_resetb,
  inout           gpio_sync,
  inout           gpio_en_agc,
  inout   [ 3:0]  gpio_ctl,
  inout   [ 7:0]  gpio_status,

  output          spi_csn,
  output          spi_clk,
  output          spi_mosi,
  input           spi_miso,
  
  input           clk_pl,
  input           rst_in,
  
  output          led1,
  output          led2,
  output          led3,
  output          led4

//  output  [85:0]  gp_out,
//  input   [85:0]  gp_in

//  input           gt_ref_clk_p,
//  input           gt_ref_clk_n,
//  output  [ 3:0]  gt_tx_p,
//  output  [ 3:0]  gt_tx_n,
//  input   [ 3:0]  gt_rx_p,
//  input   [ 3:0]  gt_rx_n
  );
  
    reg [26:0] clk_ref=27'd0;
  
  	always@(posedge clk_pl)
	begin
		if(~rst_in)
			clk_ref <= 0;
		else 
			clk_ref <=clk_ref + 1'b1;
	end
	
	assign led1=clk_ref[26];
	assign led2=clk_ref[26];
	assign led3=clk_ref[26];
	assign led4=clk_ref[26];

  // internal signals

//  wire            gt_ref_clk;
//  wire    [95:0]  gp_out_s;
//  wire    [95:0]  gp_in_s;
  wire    [63:0]  gpio_i;
  wire    [63:0]  gpio_o;
  wire    [63:0]  gpio_t;

  // assignments

//  assign clkout_out = clkout_in;
//  assign gp_out[85:0] = gp_out_s[85:0];
//  assign gp_in_s[95:86] = gp_out_s[95:86];
//  assign gp_in_s[85: 0] = gp_in[85:0];

  // instantiations

//  IBUFDS_GTE2 i_ibufds_gt_ref_clk (
//    .CEB (1'd0),
//    .I (gt_ref_clk_p),
//    .IB (gt_ref_clk_n),
//    .O (gt_ref_clk),
//    .ODIV2 ());

  // board gpio - 31-0

  assign gpio_i[31:20] = gpio_o[31:20];
  assign gpio_i[19:0] = gpio_o[19:0];

//  ad_iobuf #(.DATA_WIDTH(20)) i_iobuf_bd (
//    .dio_t (gpio_t[19:0]),
//    .dio_i (gpio_o[19:0]),
//    .dio_o (gpio_i[19:0]),
//    .dio_p (gpio_bd));

  // ad9361 gpio - 63-32

  assign gpio_i[63:52] = gpio_o[63:52];
  assign gpio_i[50:47] = gpio_o[50:47];

  ad_iobuf #(.DATA_WIDTH(16)) i_iobuf (
    .dio_t ({gpio_t[51], gpio_t[46:32]}),
    .dio_i ({gpio_o[51], gpio_o[46:32]}),
    .dio_o ({gpio_i[51], gpio_i[46:32]}),
    .dio_p ({ gpio_clksel,        // 51:51
              gpio_resetb,        // 46:46
              gpio_sync,          // 45:45
              gpio_en_agc,        // 44:44
              gpio_ctl,           // 43:40
              gpio_status}));     // 39:32

  // instantiations

  system_wrapper i_system_wrapper (
    .ddr_addr (ddr_addr),
    .ddr_ba (ddr_ba),
    .ddr_cas_n (ddr_cas_n),
    .ddr_ck_n (ddr_ck_n),
    .ddr_ck_p (ddr_ck_p),
    .ddr_cke (ddr_cke),
    .ddr_cs_n (ddr_cs_n),
    .ddr_dm (ddr_dm),
    .ddr_dq (ddr_dq),
    .ddr_dqs_n (ddr_dqs_n),
    .ddr_dqs_p (ddr_dqs_p),
    .ddr_odt (ddr_odt),
    .ddr_ras_n (ddr_ras_n),
    .ddr_reset_n (ddr_reset_n),
    .ddr_we_n (ddr_we_n),
    .enable (enable),
    .fixed_io_ddr_vrn (fixed_io_ddr_vrn),
    .fixed_io_ddr_vrp (fixed_io_ddr_vrp),
    .fixed_io_mio (fixed_io_mio),
    .fixed_io_ps_clk (fixed_io_ps_clk),
    .fixed_io_ps_porb (fixed_io_ps_porb),
    .fixed_io_ps_srstb (fixed_io_ps_srstb),
    .gp_in_0 (32'd0),       //not used
    .gp_in_1 (32'd0),       //not used
    .gp_in_2 (32'd0),       //not used
    .gp_in_3 (32'd0),       //not used
    .gp_out_0 (),           //not used
    .gp_out_1 (),           //not used
    .gp_out_2 (),           //not used
    .gp_out_3 (),           //not used
    .gpio_i (gpio_i),
    .gpio_o (gpio_o),
    .gpio_t (gpio_t),
    .gps_pps (1'b0),
//    .gt_ref_clk (1'b0),         //not used
//    .gt_rx_n (),            //not used
//    .gt_rx_p (),            //not used
//    .gt_tx_n (),            //not used
//    .gt_tx_p (),            //not used
    .iic_main_scl_io (iic_scl),    //not used
    .iic_main_sda_io (iic_sda),    //not used
    .otg_vbusoc (1'b0),
    .rx_clk_in_n (rx_clk_in_n),
    .rx_clk_in_p (rx_clk_in_p),
    .rx_data_in_n (rx_data_in_n),
    .rx_data_in_p (rx_data_in_p),
    .rx_frame_in_n (rx_frame_in_n),
    .rx_frame_in_p (rx_frame_in_p),
    .spi0_clk_i (1'b0),
    .spi0_clk_o (spi_clk),
    .spi0_csn_0_o (spi_csn),
    .spi0_csn_1_o (),
    .spi0_csn_2_o (),
    .spi0_csn_i (1'b1),
    .spi0_sdi_i (spi_miso),
    .spi0_sdo_i (1'b0),
    .spi0_sdo_o (spi_mosi),
    .spi1_clk_i (1'b0),
    .spi1_clk_o (),
    .spi1_csn_0_o (),
    .spi1_csn_1_o (),
    .spi1_csn_2_o (),
    .spi1_csn_i (1'b1),
    .spi1_sdi_i (1'b0),
    .spi1_sdo_i (1'b0),
    .spi1_sdo_o (),
    .tdd_sync_i (1'b0),
    .tdd_sync_o (),
    .tdd_sync_t (),
    .tx_clk_out_n (tx_clk_out_n),
    .tx_clk_out_p (tx_clk_out_p),
    .tx_data_out_n (tx_data_out_n),
    .tx_data_out_p (tx_data_out_p),
    .tx_frame_out_n (tx_frame_out_n),
    .tx_frame_out_p (tx_frame_out_p),
    .txnrx (txnrx),
    .up_enable (gpio_o[47]),
    .up_txnrx (gpio_o[48]));

endmodule

(10) Export Hardware,将system_top.hdf及system_top.bit复制出来,准备用于Petalinux的编译。

4. 搭建Petalinux工程

我们推荐使用Ubuntu 18.04.6 LTS搭建Petalinux工程,另外在本文档中,代码存放在/home/lics/data/code目录下。

(1) 登录Ubuntu,切换至/home/lics/data/code目录,输入以下命令

mkdir petalinux
cp petalinux-v2019.1-final-installer.run .
cd data/code/petalinux/
./petalinux-v2019.1-final-installer.run
source /home/lics/data/code/petalinux/settings.sh
petalinux-create --type project --template zynq --name sdr_b1

(2) 获取meta-adi代码,依次输入以下命令

git clone https://github.com/analogdevicesinc/meta-adi.git
cd meta-adi
git checkout 2019_R2

修改meta-adi-xilinx/recipes-bsp/device-tree/files/pl-delete-nodes-zynq-adrv9361-z7035-bob.dtsi文件,去掉其中的/delete-node/ &axi_pz_xcvrlb;一行,修改完成后的pl-delete-nodes-zynq-adrv9361-z7035-bob.dtsi如下所示

/delete-node/ &axi_ad9361;
/delete-node/ &misc_clk_0;
/delete-node/ &axi_ad9361_adc_dma;
/delete-node/ &axi_ad9361_dac_dma;
/delete-node/ &axi_gpreg;
/delete-node/ &axi_iic_main;
/delete-node/ &axi_sysid_0;

(3) 配置sdr_b1工程,依次输入以下命令(/home/lics/data/share/sdr_b1/目录存放的是system_top.hdf及system_top.bit文件)

cd sdr_b1
cp -a /home/lics/data/share/sdr_b1/* .
petalinux-config --get-hw-description=/home/lics/data/code/petalinux/sdr_b1

在出现的配置界面上选择Yocto Settings,敲击回车,然后在下一个配置界面上选择User Layers,敲击回车,在user layer 0中填入meta-adi-core的路径,即/home/lics/data/code/petalinux/meta-adi/meta-adi-core,在user layer 1中填入meta-adi-xilinx的路径即/home/lics/data/code/petalinux/meta-adi/meta-adi-xilinx,如下图。

然后退出并保存。

修改project-spec/meta-user/conf/petalinuxbsp.conf,添加一行

KERNEL_DTB = "zynq-adrv9361-z7035-bob"

(4) 编译Petalinux,输入以下命令

petalinux-build
cd images/linux/
petalinux-package --boot --format BIN --fsbl zynq_fsbl.elf --fpga system.bit --u-boot --force
cd ..
rm -rf /home/lics/data/share/linux
cp -a linux /home/lics/data/share/

至此,就可以在/home/lics/data/share/linux目录中看到编译得到的二进制文件了。

5. 固件验证

(1) 将第4步中得到的BOOT.bin及image.ub复制到TF卡中,请注意TF卡需要格式化为FAT32格式,而不是FAT格式,否则会出现Unable to read image.ub错误。

(2) 将TF卡插入SDR-B1的TF卡槽中,妥善连接SDR-B1的网口、串口及电源,并将上位机电脑的串口连接至SDR-B1的UART1上。

(3) 运行串口软件,如putty,将波特率设置为115200,为SDR-B1加电,即可看到SDR-B1的启动信息,如下图。

(4) 待系统启动完成后,输入用户名root,并输入密码analog,进入Linux系统,输入以下命令,为eth0配置IP地址,请确保上位机电脑与SDR-B1具有相同网段的IP地址。

ifconfig eth0 192.168.2.77

(5) 运行ADI IIO Oscilloscope 软件,在弹出的界面中点击Manual处,并在地址栏中填写ip:192.168.2.77,请务必完整填写,否则无法正常使用。

(6) 点击刷新,即可看到SDR-B1的相关信息,如下图。

(7) 点击连接,即可与SDR-B1建立联系,并可正常获取相关波形,如下图。