APP下载

ZYNQ 主芯片结合TLV320AIC23 语音芯片实现语音采放

2022-10-20张来洪吴道远卢继川

电子技术应用 2022年9期
关键词:声卡调用时钟

张来洪,吴道远,卢继川

(武汉中原电子集团有限公司 研发中心,湖北 武汉 430000)

0 引言

ZYNQ7000 系列芯片是Xilinx 提供的全可编程片上系统(System on Chip,SoC)芯片,完美地将ARM 与FPGA融合在一起,ARM 称为处理系统(Processing System,PS)侧,FPGA 称为编程逻辑(Programmable Logic,PL)侧,既发挥了ARM 基于操作系统开发应用程序的优点,又发挥了FPGA 进行实时信号处理和实现高速接口的优点,PS侧自带了通用异步收发传输器(Universal Asynchronous Reveiver Transmitter,UART)、集成电路总线(Inter Integrated Circuit,IIC)等控制器,PL 侧还能通过FPGA 的逻辑资源实例化知识产权核(Intellectual Property Core,IP 核)额外扩展集成电路内置音频总线(Inter IC Sound,IIS)等控制器,PS 侧与PL 侧通过高级扩展接口(Advanced Extensible Interface,AXI)总线接口实现信息的交互,这些优点使得ZYNQ 芯片作为电台数字板的主芯片时充分发挥了优势。语音功能作为电台的基本功能,在数字板上实现语音的采放是进行语音远距离传输的前提。TLV320AIC23 是一款高性能低功耗立体声音频编解码器,可以在8 000 Hz~96 000 Hz 采样率下提供16、24、32 等不同位数的采样数据,非常灵活好用。本文详细阐述ZYNQ 主芯片结合TLV320AIC23 语音芯片在Linux 系统下基于高级Linux 声音架构(Advanced Linux Sound Architecture,ALSA)进行脉冲编码调制(Pulse Code Modulation,PCM)编程实现语音采放的技术原理,展示了测试效果,此方案可以移植到电台项目中,作为电台的语音采集和播放方案,具有实际工程意义。

1 硬件设计

本文所述ZYNQ 型号为xc7z030fbg676-2,ZYNQ7000系列芯片的PS 侧是一致的,都是双核CortexA9,仅PL侧资源不一样,芯片封装不一样。ZYNQ 与TLV320AIC23 的主要连接关系如图1 所示,此处只画出两芯片之间的连接关系,芯片自身所接的外围电路不画出。

图1 ZYNQ 与TLV320AIC23 连接关系

ZYNQ 作为主芯片,向TLV320AIC23 提供12.288 MHz的主时钟信号MCLK,TLV320AIC23 基于此主时钟运行;ZYNQ 向TLV320AIC23 提供片选功能CS;ZYNQ 通过IIC协议对TLV320AIC23 进行配置,例如音量、采样率、量化位数等。ZYNQ 通过IIS 协议与TLV320AIC23 进行语音样点的传输。IIS 主要有LR_CLK 左右声道选择时钟信号线、B_CLK 比特时钟信号线、DATA 串行数据线,工程中可进一步将DATA 细分为DATA_O 数据输出信号线和DATA_I 数据输入信号线。LR_CLK 和B_CLK 由ZYNQ 提供,LR_CLK 用于区分此时的语音所属的左右声道,在LR_CLK 变化后的B_CLK 的第二个及之后的上升沿交互数据,BCLK 的一个上升沿传输一位数据,先传输高位再传输低位,这样允许收发采用不一样的数据位数,在工程中,收发的数据位数应尽量设计为相同。

2 VIVADO 工程设计

根据硬件设计,基于VIVADO18.3 搭建工程,对ZYNQ的PS 进行配置,例如时钟、复位、调试UART 控制器等,确保PS 部分能正常工作,添加一系列IP 核用于实现语音功能。连接模块间的搭建完成的工程如图2 所示。

图2 VIVADO 工程的模块连接图

ZYNQ7 Processing System 描述了PS 侧的配置,例如内存、调试串口控制器、网口控制器等的配置、DMA 的配置、PS-PL 时钟的配置等。AXI Interconnect 是PS 侧与PL侧的AXI 接口模块,axi_i2s_adi 是进行串并转换实现IIS时序的IP 核,且具备先入先出(Fisrt In First Out,FIFO)功能用于缓存语音样点。Clocking Wizard 是时钟分频模块,将PS 向PL 提供的100 MHz 时钟分频为12.288 MHz,此12.288 MHz 的时钟是TLV320AIC23 的主时钟,也是axi_i2s_adi 模块的数据收发的时钟。AXI IIC 是利用PL 资源生成的IIC 控制器,ZYNQ 通过此IP 核产生IIC 时序。Constan 是常量信号产生模块,用于产生片选信号。concat是信号合并模块,用于将多个中断信号源合并后接到PS模块,此处合并AXI IIC 产生的中断信号。

PS 侧使能了两路DMA 资源,axi_i2s_adi模块的DMA_REQ_TX信号接PS的DMA1_REQ信号,axi_i2s_adi模块的DMA_REQ_RX信号接PS的DMA2_REQ。

axi_i2s_adi 模块对外提供连接有BCLK_O、LR_CLK_O、LR_CLK_I、SDATA_O、SDATA_I 等信号,连同时钟分频模块提供的MCLK_O 信号一起组成IIS 总线,实现IIS 时序,这些信号从ZYNQ 出来后最终连接到TLV320AIC23 的管脚,用于ZYNQ 和TLV320AIC23 之间的语音样点的传输。

搭建完VIVADO 工程,为axi_i2s_adi 模块和AXI IIC模块分别设置AXI 地址,axi_i2s_adi 地址为0x60000000,AXI IIC 地址为0x41600000,然后结合硬件原理图为外部信号做管脚约束,最后生成bit 流文件。

3 系统启动及驱动程序

将VIVADO 生成的bit 流文件和hardware 信息导出到SDK,SDK 下生成FSBL 作为一级引导程序,在Ubuntu虚拟机下使用XILINX 厂家提供的arm-xilinx-linuxgnueabi-gcc 交叉编译器配置并编译2016.07 版的uboot作为二级引导程序,将FSBL、bit、uboot 合成BOOT.BIN烧写进板子,启动进入uboot 阶段。

配置4.6.0 版的Linux 内核,在配置选项中添加AXI IIC 的驱动、TLV320 系列编解码器的驱动、ALSA for Soc audio 组件的支持等,交叉编译生成Linux_uImage 内核镜像文件。

修改Linux 源码目录子目录下的dts 文件,除了描述PS 侧资源外,额外添加声卡功能的描述片段,然后编译生成devicetree.dtb 设备树文件。设备树中描述声卡功能的片段结构如下:

此处只展示片段结构,省略冗长的细节字段。一级节点fpga-axi 包含整个与声卡有关的描述,二级节点audio_clock 描述的是12.288 MHz 的时钟,二级节点i2c0描述的是AXI IIC 控制器,AXI IIC 控制器下挂的三级节点sound0-codec 描述的是TLV320AIC23,二级节点axii2s0 描述的是axi_i2s_adi 模块,以上节点描述了VIVADO工程中的具体配置;接下来的二级节点sound0 描述了构造出来的具体声卡功能,即一个简易模式的声卡节点,包含了两路信息流,一路连到axi_i2s_adi 模块,一路连到sound0-codec。

与设备树中声卡节点匹配的内核源码主要有DMA的驱动程序源码pl330.c、语音芯片的驱动程序的源码tlv320aic23.c、axi_i2s_adi的驱动程序的源码axi-i2s.c。这些驱动程序源码在XILINX 厂家提供的内核代码里已经存在,设备树中的片段将这些代码有机地结合起来,形成特定的功能。可以结合工程实际对这些源码进行修改,例如修改tlv320aic23.c 文件里的tlv320aic23_codec_probe函数,使得在Linux 系统启动阶段加载声卡节点驱动时即可对TLV320AIC23 进行初步设置。

交叉编译1.20.1 版本的busybox,制作成uramdisk.image.gz 根文件系统,在根文件系统中添加脚本语句用于生成声卡的文件节点。

在uboot 阶段分别将Linux_uImage 内核镜像、devicetree.dtb 设备树、uramdisk.image.gz 根文件系统三组件加载到内存指定地址,然后启动Linux 操作系统。

在正常启动Linux 系统的基础上,可以看到系统启动过程中的打印信息,

这说明Linux 系统已经识别了声卡设备,证明VIVADO工程、Linux 操作系统、驱动功能都是正常的。但若需声卡正常工作,还需要库文件的支持,以及应用程序的运行。

配置并交叉编1.1.3 版本的ALSA 库源码,交叉编译最终得到整个ALSA 库的生成文件夹,内含Linux 系统下与ALSA 声卡功能有关的动态库、静态库、头文件等。将ALSA 库的生成文件夹下的内容拷贝到数字板的根文件系统下的相应目录下,通过aplay -l 命令证明ALSA正常工作。

4 应用程序

为了使用应用程序验证声卡是否正常工作,可以用ALSA 库的生成文件夹提供的若干应用程序,也可以自行编写实用性更强更灵活的程序,基于ALSA 的PCM 编程有相对固定的操作步骤,关键函数如下。

调用snd_pcm_open 函数分别打开两个句柄,一个用于采音,一个用于放音。调用snd_pcm_hw_params_set_access函数为句柄设置语音样点的模式,此处设置为SND_PCM_ACCESS_RW_INTERLEAVED 即读写交替模式。调用snd_pcm_hw_params_set_channels 函数为句柄设置语音声道,设置为1 即单声道。调用snd_pcm_hw_params_set_format 函数为句柄设置语音样点的格式,此处设置为SND_PCM_FORMAT_S16_LE,即每个语音样点用16 bit 表示。调用snd_pcm_hw_params_set_rate_near 函数为句柄设置采样率,此处设置为8 000,即每秒采集或播放8 000 个样点。调用snd_pcm_prepare 使句柄准备工作。

调用以上配置函数时,应用程序进一步调用ALSA库里的函数,然后调用操作系统内核里的函数,通过层层调用,最终达到驱动层,一方面通过AXI IIC 的驱动程序来配置TLV320AIC23 语音芯片,一方面更新了axi_i2s_adi模块的工作状态,将以上各函数整个封装后成为初始化函数。也可以通过应用程序访问AXI IIC 的驱动程序,将TLV320AIC23 的各寄存器的值配置为项目所需的值。TLV320AIC23 寄存器的配置如表1 所示。

表1 TLV320AIC23 各寄存器的配置

调用snd_pcm_writei 函数向放音句柄传递语音信息的变量,即可达到放音的效果。

调用snd_pcm_readi 函数向采音句柄传递语音信息的变量的指针,即可达到采音的效果。

结合snd_pcm_writei 和snd_pcm_readi 即可实现对外语音回环的效果。

调用snd_pcm_writei 函数时,应用程序进一步调用ALSA 库里的函数,然后调用操作系统内核里的函数,通过层层调用,最终达到驱动层。通过使用DMA 通道,将内存中的信息搬移给axi_i2s_adi 模块的发FIFO,然后由axi_i2s_adi 产生IIS 时序,将发FIFO 里的语音样点传输给TLV320AIC23,然后由TLV320AIC23 将数字量转化为模拟量,这是放音方向。对于采音方向,TLV320AIC23 将模拟量转化为数字量,然后将语言样点传输给axi_i2s_adi 模块的收FIFO,等到应用程序调用snd_pcm_readi 函数时,应用程序进一步调用ALSA 库里的函数,然后调用操作系统内核里的函数,通过层层调用,最终达到驱动层,通过使用DMA 通道,将axi_i2s_adi 模块的收FIFO 里的信息搬移到内存中的,最终到达应用层。

5 测试

先测试放音功能,运行初始化函数后,通过传递表示不同频率的正弦波样点的数组变量给snd_pcm_writei函数,来播放不同频率的正弦波单音,例如每8 个样点形成一个正弦周期,则对应1 000 Hz 的单音,通过示波器观测数字板上TLV320AIC23 的PHONE 脚,可以看到示波器观测的波形与代码变量的理论值一致,说明声卡放音功能正常。

再测试采音功能,运行初始化函数后,在while 循环中成对地依次调用snd_pcm_readi 和snd_pcm_writei,实现对外语音回环的效果,用信号源接到TLV320AIC23 的MIC脚,通过示波器观测TLV320AIC23 的PHONE 脚,信号源分别输出不同频率的正弦波,可以看到示波器观测的波形与信号源的设置值一致,说明声卡采音功能正常。

验证了放音功能和采音功能后,可以进一步通过人声来实测喊话自回环功能,给数字板接上话柄扬声器,对着话柄喊话,能在扬声器听到自己所喊声音,说明喊话自回环功能正常。

各项测试结果如图3 所示,测试结果与理论一致。

图3 语音采放功能测试

6 结论

本文详细阐述了ZYNQ 结合TLV320AIC23 实现语音采放功能的原理,对于实际电台的数字板的VIVADO 工程,只需添加与波形有关的其他模块即可,即对于语音功能,本文所述的技术方案是可以直接移植使用的,在应用程序里采集到的语音,递交给波形模块进行传输,在接收方收到后,再在应用程序里进行放音,即实现了电台里的话音功能,若需优化用户体验,还可以再加提示音等辅助功能。

猜你喜欢

声卡调用时钟
这个时钟一根针
基于Android Broadcast的短信安全监听系统的设计和实现
有趣的时钟
时钟会开“花”
利用RFC技术实现SAP系统接口通信
提升笔记本电脑音质
聊天室背景放音乐 为啥我的本本就不行?
风雨二十五载PC声卡春秋录
影音娱乐轻松搞定
C++语言中函数参数传递方式剖析