Pynq-Z2 开发指南与实例(Linux系统方式)

前言

本教程分三个部分

  1. 介绍使用官方镜像文件,使用Python进行开发的一个简单小例子,并且简单了解底层是如何运作的。
  2. 记录使用自制镜像文件,使用C/C++开发基于Linux的Pynq-Z2。完成一个将3.5毫米耳机输入口的音频采集,并输出到一个USB音频设备的任务。
  3. 自行编译Pynq-Z2镜像文件的步骤(高级)

一、使用Python开发Pynq的简单介绍

概述

本节使用了Pynq官方镜像v2.5,基于Ubuntu 18.04,Linux 4.19.0。将简单介绍安装流程,Python程序样例简介与简单认识底层实现原理。

前期准备

一张 microSD卡(推荐16GB以上)
一个 microSD卡读卡器
一根 网线
一个 路由器
一根 3.5mm公对公音频线(内录线)(如果需要体验实验结果)
下载 Pynq-Z2 磁盘镜像(本节基于v2.5)
安装 Win32DiskImager
安装 DiskGenius
安装 WinSCP(如果需要访问完整文件系统)

下载完成后请安装下载的软件

安装配置

将SD卡插入电脑,打开Win32DiskImager,选择下载的镜像文件,点击写入

在这里插入图片描述
待完成后,不要按系统提示进行格式化,打开DiskGenius。
在这里插入图片描述
在左侧找到SD卡磁盘,选择较大的分区(大概5GB那个),右键,扩容分区。
在这里插入图片描述
点击开始,等待约5分钟即可完成。
在这里插入图片描述
在这里插入图片描述
剩余时间是假的,不必理会。
完成后,将SD卡从电脑上取下,插入Pynq-Z2的卡槽里(背部)。
在这里插入图片描述
将启动方式跳线帽选择SD。
在这里插入图片描述
使用microUSB线连接到电脑,开启电源。
等待4个绿色LED,2个蓝色LED高亮闪烁后,代表启动完成。
在这里插入图片描述
使用网线连接Pynq-Z2到电脑的局域网中,将自动获取IP地址。
以小米路由器为例,可以看到开发板的IP地址为192.168.31.69
在这里插入图片描述
浏览器访问该IP,将自动跳转到Jupyter Notebook
需要输入密码,该linux系统的账号为xilinx,密码为xilinx
在这里插入图片描述
点击登录
在这里插入图片描述

文件系统

可以通过文件管理器访问\\<你的Pynq-Z2 IP地址>\xilinx,来访问其文件系统(无法访问根目录)。
在这里插入图片描述
在这里插入图片描述
如果需要访问完整文件系统,请按以下步骤进行,如不需要请跳过。
下载安装 WinSCP
按如下方法配置
在这里插入图片描述
点击保存(保存密码),即可以后在左侧选择。
在这里插入图片描述
点击登录,即可访问完整目录。
在这里插入图片描述

程序分析

base文件夹中包含了很多python的例子,可以自行参考学习。
本文以base/audio/audio_playback.ipynb为研究对象。
在这里插入图片描述
该例程使用python控制板载的ADAU1761芯片,采集从耳机接口输入的音频。
在这里插入图片描述
LINE_IN代表双声道输入接口,HP MIC代表耳麦(传统4段式3.5毫米耳机接口,2声道输出,1声道输入)
首先来看其第一个功能
在这里插入图片描述
具体实现了选择LINE_IN作为输入,直接输出到HP MIC的输出,不储存。
你需要一根"内录线",即3.5mm公对公音频线,一端插入LINE_IN,一端插入一个输出源(如手机耳机口),再插入一个耳机到HP MIC中,即可听见声音。
可以自己点击上方的运行查看效果,你将听到从LINE_IN输入的声音。
在这里插入图片描述
下面我们来分析他具体做了什么
访问文件系统\\192.168.31.69\xilinx\pynq\lib,将IP替换为你自己的。
在这里插入图片描述
这里就是其具体调用的python文件。
在这里插入图片描述
这两部是加载Pynq开发者为Pynq-Z2写的底层PL文件base.bit,和加载libaudio.so类库。下文删除了注释,请自己打开文件查看。

class AudioADAU1761(DefaultIP):
	def __init__(self, description): 
        super().__init__(description)

        self._ffi = cffi.FFI()
        self._libaudio = self._ffi.dlopen(LIB_SEARCH_PATH + "/libaudio.so")
        self._ffi.cdef("""void config_audio_pll(int iic_index);""")
        self._ffi.cdef("""void config_audio_codec(int iic_index);""")
        self._ffi.cdef("""void select_line_in(int iic_index);""")
        self._ffi.cdef("""void select_mic(int iic_index);""")
        self._ffi.cdef("""void deselect(int iic_index);""")
        self._ffi.cdef("""void bypass(unsigned int audio_mmap_size,
                          unsigned int nsamples, 
                          int uio_index, int iic_index) ;""")
        self._ffi.cdef("""void record(unsigned int audio_mmap_size,
                          unsigned int * BufAddr, unsigned int nsamples,
                          int uio_index, int iic_index);""")
        self._ffi.cdef("""void play(unsigned int audio_mmap_size,
                          unsigned int * BufAddr, unsigned int nsamples,
                          int uio_index, int iic_index);""")

        self.buffer = numpy.zeros(0).astype(numpy.int32)
        self.sample_rate = None
        self.sample_len = len(self.buffer)
        self.iic_index = None
        self.uio_index = None
        self.configure()

这里是将native层(原生、C/C++层)的函数暴露给python层使用,根据函数定义去解析libaudio.so的符号,查找地址,并建立调用封送约定。

def configure(self, sample_rate=48000,
                  iic_index=1, uio_name="audio-codec-ctrl"): 
        self.sample_rate = sample_rate
        self.iic_index = iic_index
        self.uio_index = get_uio_index(uio_name)
        if self.uio_index is None:
            raise ValueError("Cannot find UIO device {}".format(uio_name))

        self._libaudio.config_audio_pll(self.iic_index)
        self._libaudio.config_audio_codec(self.iic_index)

这里是设置采样率,配置时钟,让底层去查找在linux系统中注册的IO口。

    def select_line_in(self): 
        self._libaudio.select_line_in(self.iic_index)
	def bypass(self, seconds): 
        if not 0 < seconds <= 60:
            raise ValueError("Bypassing time has to be in (0,60].")

        self.sample_len = math.ceil(seconds * self.sample_rate)
        self._libaudio.bypass(self.mmio.length,
                              self.sample_len, self.uio_index, self.iic_index)

其余函数都是对native层的封装调用,可以说,做的并不好,逻辑全在native层里,python也没封装的咋样。
为此需要进一步查看libaudio.so中是如何实现的,可以查看源码
访问目录\\192.168.31.69\xilinx\pynq\lib\_pynq\_audio,即为libaudio.so的源码。由于我们是Pynq-Z2,所以查看audio_adau1761.cpp即可。

首先查看两个配置函数

        self._libaudio.config_audio_pll(self.iic_index)
        self._libaudio.config_audio_codec(self.iic_index)

由于过长,全文请自行查看文件。

extern "C" void config_audio_pll(int iic_index) {
   
    ...
    // Poll PLL Lock bit
    u8TxData[0] = 0x40;
    u8TxData[1] = 0x02;
    do {
   
        if (writeI2C_asFile(iic_fd, u8TxData, 2) < 0){
   
            printf("Unable to write I2C %d.\n", iic_index);
        }
        if (readI2C_asFile(iic_fd, u8RxData, 6) < 0){
   
            printf("Unable to read I2C %d.\n", iic_index)
  • 10
    点赞
  • 70
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值