ZYNQ MPSOC 软件无线电开发[软件部分(3)] - 生成Petalinux SDK并在主机进行交叉编译、ADDA demo测试

ZYNQ MPSOC 软件无线电开发[软件部分(3)] - 生成Petalinux SDK并在主机进行交叉编译、ADDA测试

ZYNQ MPSOC 软件无线电开发[软件部分(2)] - 在Petalinux工程中添加驱动程序与自启动脚本
ZYNQ MPSOC 软件无线电开发[软件部分(1)] - 导出Vivado硬件设计并构建基本的Petalinux工程

生成Petalinux SDK是为了在本地编译能在ZYNQ的arm核上运行的程序,同时一些对Petalinux的改动可以不必进行petalinux-build而使用交叉编译链手动编译,可以大大节省时间。

1. 生成PetaLinux SDK

PetaLinux可以生成特定于平台的sdk,只需要在工程目录执行

petalinux-build --sdk

然后等待即可。生成的sdk在

~/<PROJECT_DIR>/petalinux/images/linux/sdk.sh

执行安装,安装的默认路径就在你的petalinux安装路径下。我将其安装到了工程目录下。

PetaLinux SDK installer version 2020.1
======================================
Enter target directory for SDK (default: /opt/petalinux/2020.1): ~/peta_prj/adda_probtest/petalinux/            
You are about to install the SDK to "/home/xlnxdev-2020-1/peta_prj/adda_probtest/petalinux". Proceed [Y/n]? 
Extracting SDK....................................................done
Setting it up...done
SDK has been successfully set up and is ready to be used.
Each time you wish to use the SDK in a new shell session, you need to source the environment setup script e.g.
 $ . /home/xlnxdev-2020-1/peta_prj/adda_probtest/petalinux/environment-setup-aarch64-xilinx-linux

现在将sdk加载到终端环境,上面安装时的log最后一行已经告诉我们该执行什么:

source /home/xlnxdev-2020-1/peta_prj/adda_probtest/petalinux/environment-setup-aarch64-xilinx-linux 

如果出现权限不够的提示,将脚本增加可执行权限:

chmod +x /home/xlnxdev-2020-1/peta_prj/adda_probtest/petalinux/environment-setup-aarch64-xilinx-linux

现在,检查编译链:

which $CC
/home/xlnxdev-2020-1/peta_prj/adda_probtest/petalinux/sysroots/x86_64-petalinux-linux/usr/bin/aarch64-xilinx-linux/aarch64-xilinx-linux-gcc

可以看出sdk提供的环境已经加载到当前终端。

2. 编写ADC、DAC测试程序

内容不过多赘述,该部分内容是c、cpp、linux设备使用上的知识。在工程目录建立applications文件夹,在此编译程序。我使用的编辑器是vscode。

两个工程的目录如下图:

下面给出源码。参考了ALINX教程文档的源码并加以修改。

2.0 axidma.c axidma.h

axidma.h

#ifndef AXIDMA_H
#define AXIDMA_H

#define AXI_DMA_IOCTL_BASE 'W'
#define AXI_SET_SAMPLE_NUM _IO(AXI_DMA_IOCTL_BASE, 0)
#define AXI_SET_DMA_LEN_BYTES _IO(AXI_DMA_IOCTL_BASE, 1)
#define AXI_DMA_INIT _IO(AXI_DMA_IOCTL_BASE, 2)
#define AXI_DMA_START _IO(AXI_DMA_IOCTL_BASE, 3)
#define AXI_DMA_DEINIT _IO(AXI_DMA_IOCTL_BASE, 4)
#define AXI_DMA_CYCLIC_SEND _IO(AXI_DMA_IOCTL_BASE, 5)
#define AXI_DMA_CYCLIC_STOP _IO(AXI_DMA_IOCTL_BASE, 6)

int axidma_init(int *, char *, unsigned int, int, int);
int axidma_read(int, int, unsigned char *);
int axidma_write(int, int, unsigned char *);
int axidma_close(int);
int axidma_cyclic_write(int, int, unsigned char *);
int axidma_cyclic_stop(int);
int axidma_cyclic_close(int);

#endif

axidma.c

#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>

#include "axidma.h"

/* Thread capture AXI samples and put it to Circular buffer */
int axidma_init(int *fd, char *axidma_dev, unsigned int mode, int sample_num, int len_bytes)
{
	// Open axi dev node
	*fd = open(axidma_dev, mode);

	if (ioctl(*fd, AXI_SET_SAMPLE_NUM, sample_num))
	{
		printf("AXI_SET_SAMPLE_NUM failed: %s\n", strerror(errno));
		return -2;
	}
	if (ioctl(*fd, AXI_SET_DMA_LEN_BYTES, len_bytes))
	{
		printf("AXI_SET_DMA_LEN_BYTES failed: %s\n", strerror(errno));
		return -2;
	}
	if (ioctl(*fd, AXI_DMA_INIT))
	{
		printf("AXI_DMA_INIT failed: %s\n", strerror(errno));
		return -2;
	}
	if (*fd < 0)
	{
		return -2;
	}

	return 0;
}

int axidma_read(int fd, int sample_num, unsigned char *buf)
{
	if (ioctl(fd, AXI_DMA_START) == 0)
	{
		read(fd, buf, sample_num);
	}
	else
	{
		printf("AXI_DMA_START failed: %s\n", strerror(errno));
		return -1;
	}
	return 0;
}

int axidma_write(int fd, int sample_num, unsigned char *buf)
{
	if (ioctl(fd, AXI_DMA_START) == 0)
	{
		write(fd, buf, sample_num);
	}
	else
	{
		printf("AXI_DMA_START failed: %s\n", strerror(errno));
		return -1;
	}
	return 0;
}

int axidma_close(int fd)
{
	if (ioctl(fd, AXI_DMA_DEINIT) == 0)
	{
		close(fd);
	}
	else
	{
		printf("AXI_DMA_DEINIT failed: %s\n", strerror(errno));
		return -1;
	}
	return 0;
}

int axidma_cyclic_write(int fd, int sample_num, unsigned char *buf)
{
	write(fd, buf, sample_num);
	if (ioctl(fd, AXI_DMA_CYCLIC_SEND))
	{
		printf("AXI_DMA_CYCLIC_SEND failed: %s\n", strerror(errno));
		return -1;
	}
	return 0;
}

int axidma_cyclic_stop(int fd)
{
	if (ioctl(fd, AXI_DMA_CYCLIC_STOP))
	{
		printf("AXI_DMA_CYCLIC_STOP failed: %s\n", strerror(errno));
		return -1;
	}
	return 0;
}

int axidma_cyclic_close(int fd)
{
    int ans;
	ans = axidma_cyclic_stop(fd);
    if(ans)
    {
        return ans;
    }
	ans = axidma_close(fd);
    if(ans)
    {
        return ans;
    }
    return 0;
}

2.1 ad9238的 main.c 和 Makefile

main.c

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <limits.h>

#include "axidma.h"

#define ADC_CAPTURELEN 255 /* ADC capture buffer */

#define ADC_DEVPATH0 "/dev/adc0"
#define ADC_DEVPATH1 "/dev/adc1"

void varargproc(int argc, char *argv[], int it, int *it2)
{
    if (argc == 2)
    {
        *it2 = atoi(argv[1]);
    }
    else if (argc == 1)
    {
        ;
    }
    else
    {
        printf("Unsupported options:");
        for (it = 1; it < argc; it++)
        {
            printf(" %s", argv[it]);
        }
        putchar('\n');
        printf("Usage: %s [round]\n", argv[0]);
        printf("  default round is INT_MAX.\n\n");
        exit(2);
    }
}

int main(int argc, char *argv[])
{
    int it, it2 = INT_MAX;
    varargproc(argc, argv, it, &it2);

    int fd0, fd1;
    short CH0DmaRxBuffer[ADC_CAPTURELEN];
    short CH1DmaRxBuffer[ADC_CAPTURELEN];

    axidma_init(&fd0, ADC_DEVPATH0, O_RDONLY, ADC_CAPTURELEN, ADC_CAPTURELEN * sizeof(short));
    axidma_init(&fd1, ADC_DEVPATH1, O_RDONLY, ADC_CAPTURELEN, ADC_CAPTURELEN * sizeof(short));

    while (it2--)
    {
        if (axidma_read(fd0, ADC_CAPTURELEN * sizeof(short), (unsigned char *)CH0DmaRxBuffer))
        {
            exit(1);
        }

        printf(ADC_DEVPATH0);
        putchar('\n');
        for (it = 0; it < ADC_CAPTURELEN; it++)
        {
            printf("%hd\t", CH0DmaRxBuffer[it]);
        }
        printf("\n\n");

        if (axidma_read(fd1, ADC_CAPTURELEN * sizeof(short), (unsigned char *)CH1DmaRxBuffer))
        {
            exit(1);
        }

        printf(ADC_DEVPATH1);
        putchar('\n');
        for (it = 0; it < ADC_CAPTURELEN; it++)
        {
            printf("%hd\t", CH1DmaRxBuffer[it]);
        }
        printf("\n\n");

        // usleep(100 * 1000); // wait 100us
    }

    axidma_close(fd0);
    axidma_close(fd1);

    return 0;
}

Makefile

OUTPUT_DIR = ./build/
OUTPUT_BIN = adc_test

$(OUTPUT_BIN):axidma.o main.o
	$(CC) $(OUTPUT_DIR)axidma.o $(OUTPUT_DIR)main.o -o $(OUTPUT_DIR)$(OUTPUT_BIN)

axidma.o:axidma.c
	$(CC) -c axidma.c -o $(OUTPUT_DIR)axidma.o

main.o:main.c
	$(CC) -c main.c -o $(OUTPUT_DIR)main.o
	
.PHONY:clean
clean:
	-rm $(OUTPUT_DIR)*.o
	-rm $(OUTPUT_DIR)$(OUTPUT_BIN)

2.2 ad9767的 main.c 和 Makefile

main.c

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <math.h>

#include "axidma.h"

#define DAC_CAPTURELEN 1024 /* Buffer length must >= 1024 */

#define DAC_DEVPATH0 "/dev/dac0"
#define DAC_DEVPATH1 "/dev/dac1"


// make a sin wave
#define MAX_AMP_VAL (16384) /* 2^14, do not change */
#define AMP_VAL (16384)     /* must be less than 2^14 */
unsigned short wave_data[DAC_CAPTURELEN];
void sinwave(int point, int max_amp, int amp_val, unsigned short *sin_tab)
{
    int i;
    double radian, x;
    double PI = 3.1415926;
    radian = 2 * PI / point;
    for (i = 0; i < point; i++)
    {
        x = radian * i;
        sin_tab[i] = (unsigned short)((amp_val / 2) * sin(x) + max_amp / 2);
    }
}

int main()
{
    int fd0, fd1;

    sinwave(DAC_CAPTURELEN, MAX_AMP_VAL, AMP_VAL, wave_data);

    axidma_init(&fd0, DAC_DEVPATH0, O_RDWR, DAC_CAPTURELEN, DAC_CAPTURELEN * sizeof(short));
    axidma_init(&fd1, DAC_DEVPATH1, O_RDWR, DAC_CAPTURELEN, DAC_CAPTURELEN * sizeof(short));

    axidma_cyclic_write(fd0, DAC_CAPTURELEN * sizeof(short), (unsigned char *)wave_data);
    axidma_cyclic_write(fd1, DAC_CAPTURELEN * sizeof(short), (unsigned char *)wave_data);

    while (1)
    {
        sleep(1);
    }

    axidma_cyclic_close(fd0);
    axidma_cyclic_close(fd1);

    return 0;
}

Makefile

OUTPUT_DIR = ./build/
OUTPUT_BIN = dac_test

$(OUTPUT_BIN):axidma.o main.o
	$(CC) $(OUTPUT_DIR)axidma.o $(OUTPUT_DIR)main.o -lm -o $(OUTPUT_DIR)$(OUTPUT_BIN)

axidma.o:axidma.c
	$(CC) -c axidma.c -o $(OUTPUT_DIR)axidma.o

main.o:main.c
	$(CC) -c main.c -o $(OUTPUT_DIR)main.o
	
.PHONY:clean
clean:
	-rm $(OUTPUT_DIR)*.o
	-rm $(OUTPUT_DIR)$(OUTPUT_BIN)

在终端source一下sdk env,对这两个工程cd到其目录内,make就可以生成可执行文件了。

source /home/xlnxdev-2020-1/peta_prj/adda_probtest/petalinux/environment-setup-aarch64-xilinx-linux 
cd ad9238
mkdir build
make
cd ../ad9767
mkdir build
make
aarch64-xilinx-linux-gcc  -march=armv8-a+crc -mtune=cortex-a72.cortex-a53 --sysroot=/home/xlnxdev-2020-1/peta_prj/adda_probtest/petalinux/sysroots/aarch64-xilinx-linux -c axidma.c -o ./build/axidma.o
aarch64-xilinx-linux-gcc  -march=armv8-a+crc -mtune=cortex-a72.cortex-a53 --sysroot=/home/xlnxdev-2020-1/peta_prj/adda_probtest/petalinux/sysroots/aarch64-xilinx-linux -c main.c -o ./build/main.o
aarch64-xilinx-linux-gcc  -march=armv8-a+crc -mtune=cortex-a72.cortex-a53 --sysroot=/home/xlnxdev-2020-1/peta_prj/adda_probtest/petalinux/sysroots/aarch64-xilinx-linux ./build/axidma.o ./build/main.o -o ./build/adc_test
aarch64-xilinx-linux-gcc  -march=armv8-a+crc -mtune=cortex-a72.cortex-a53 --sysroot=/home/xlnxdev-2020-1/peta_prj/adda_probtest/petalinux/sysroots/aarch64-xilinx-linux -c axidma.c -o ./build/axidma.o
aarch64-xilinx-linux-gcc  -march=armv8-a+crc -mtune=cortex-a72.cortex-a53 --sysroot=/home/xlnxdev-2020-1/peta_prj/adda_probtest/petalinux/sysroots/aarch64-xilinx-linux -c main.c -o ./build/main.o
aarch64-xilinx-linux-gcc  -march=armv8-a+crc -mtune=cortex-a72.cortex-a53 --sysroot=/home/xlnxdev-2020-1/peta_prj/adda_probtest/petalinux/sysroots/aarch64-xilinx-linux ./build/axidma.o ./build/main.o -lm -o ./build/dac_test


这两个文件就是是生成的测试程序。现在安装ad、da模块安装到开发板,将ad的输入和da的输出连接起来,并将程序拷贝到开发板上测试。

我已经将两个程序拷到sd卡的/home/root,登录并执行下面的命令

ls 
./dac_test& # 后台运行
./adc_test # 采集一次数据


可以看到已经从ADC的channel1读出数据了。


其实上一章的驱动程序也可以交叉编译,然后在板子上手动insmod加载驱动程序。

  • 17
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
使用Simulink在Zynq开发软件无线电是一种高效的方式。Simulink是一种图形化编程环境,可以方便地进行软件无线电系统的建模、仿真和实现。 使用Simulink,开发者可以通过简单地拖拽和连接各种预定义的模块、功能模块和信号处理模块来设计无线电通信系统。这些模块可以是数字滤波器、混频器、调制器、解调器等等。同时,Simulink也支持自定义模块,可以根据具体需求进行开发Zynq是一款强大的可编程逻辑器件,集成了FPGA和ARM处理器。在Simulink中,可以通过适配器模块将软件定义无线电系统与Zynq的硬件接口进行连接。这样,可以将无线电系统设计的模型直接部署到Zynq上。通过部署到FPGA上,可以实现高性能的信号处理和并行计算。 使用Simulink在Zynq开发软件无线电具有许多优势。首先,Simulink提供了一个直观的可视化编程界面,不需要繁琐的代码编写,降低了入门门槛。其次,Simulink具有强大的信号处理和仿真功能,可以进行全面的系统验证和性能优化。此外,由于Simulink可以与Zynq硬件进行无缝集成,可以充分发挥Zynq的高性能特点,提高系统的实时性和处理能力。 综上所述,使用Simulink在Zynq开发软件无线电是一种高效、灵活和可靠的方法。它可以提高开发效率,提供全面的系统验证和优化,同时充分发挥Zynq的硬件优势。这对于软件无线电开发者来说,是一种非常有吸引力的解决方案。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值