完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
1)实验平台:正点原子开拓者FPGA 开发板
2)摘自《开拓者FPGA开发指南》关注官方微信号公众号,获取更多资料:正点原子 3)全套实验源码+手册+视频下载地址:http://www.openedv.com/thread-13912-1-1.html 第四十八章 基于以太网的板对板音频互传实验 在音频环回实验中,我们成功地在开发板上实现音频的采集与播放功能;在以太网通信实 验中,我们通过网口调试助手成功地和开发板完成了以太网通信的功能。本章我们将使用以太 网接口实现两块FPGA开发板之间的音频互传与播放功能。 本章包括以下几个部分: 48.1 板对板音频互传简介 48.2 实验任务 48.3 硬件设计 48.4 程序设计 48.5 下载验证 板对板音频互传简介 音频板对板互传实验是基于以太网来传输音频数据的,我们在“以太网通信实验”章节中 对以太网的协议、MII时序等内容作了详细的介绍,如果大家对这部分内容不是很熟悉的话, 请参考“以太网通信实验”中的以太网简介部分。 从“音频环回实验”章节中可以知道,WM8978音频芯片的采样率最大为48Khz,在数据位 宽 为 32 位 数 据 格 式 下 , 每 秒 钟 传 输 的 数 据 量 为 48000*32*2 ( 左 右 两 个 声 道 ) = 3072000bit≈2.930Mbit。我们FPGA开发板上的PHY芯片类型为百兆以太网,理论上最大传输速 率为 100Mbit/s,即使加上帧头、CRC校验以及帧间隙带来的额外开销,对于实时传输音频数 据来说也是毫无压力的。我们知道,以太网通信是以数据包为单位进行数据传输,单包数据除 以太网帧头与CRC校验之外,以太网数据至少为46个有效字节,对于不足46个字节的数据要在 数据的后面补充任意值。如果我们使用以太网通信单包只传输一个32位的音频数据,那么会极 大的浪费以太网的高速传输能力,因此我们先将收到的音频数据使用fifo缓存下来,待数据量 达到预设值之后,再通过以太网发送出去。 实验任务 本节实验任务是使用以太网接口实现两块FPGA开发板之间的音频互传与播放功能。首先开 发板A对WM8978芯片进行音频数据采集,并将采集的数据通过以太网接口发送给开发板B,开发 板B将收到的数据通过WM8978芯片进行播放;开发板B同样对WM8978芯片进行音频数据采集,并 将采集的数据通过以太网接口发送给开发板A,开发板A将收到的数据通过WM8978芯片进行播放, 从而实现两块FPGA开发板之间的音频互传与播放功能。 硬件设计 WM8978音频芯片及音频接口原理图与“音频环回实验”完全相同,请参考“音频环回实验” 的硬件设计部分。以太网接口部分的硬件设计请参考“以太网通信实验”中的硬件设计部分。 由于以太网接口和WM8978音频引脚数目较多且在前面相应的章节中已经给出它们的管脚 列表,这里不再列出管脚分配。 程序设计 图 48.4.1是根据本章实验任务画出的系统框图。PLL时钟模块为WM8978音频芯片提供主时 钟,而UDP模块的驱动时钟是由开发板上的PHY芯片提供;WM8978配置模块用于初始化WM8978音 频芯片,使其能够在预设的工作模式下工作;音频接收模块用于接收来自WM8978的音频数据,将WM8978串行输入的1位数据转换成32位的并行数据;音频缓存发送控制模块用于缓存32位的 音频数据,当缓存的数据量达到预设值之后,控制以太网发送模块开始发送音频数据。以太网 接收模块负责接收另一块开发板传输的音频数据,并将接收到的数据写入音频缓存接收控制模 块,音频缓存接收控制模块负责缓存以太网接收到的音频数据,将数据存入fifo模块等待被音 频发送模块读取,音频发送模块发送音频数据,将并行输入的32位数据转成1位串行数据发送 出去。 板对板音频互传实验系统框图如下图所示: 图 48.4.1 基于以太网的板对板音频互传系统框图 顶层模块的原理图如下图所示: 图 48.4.2 顶层模块原理图 由上图可知,FPGA顶层模块(eth_audio_transmit)例化了以下五个模块:PLL时钟模块 (pll_clk)、WM8978控制模块(wm8978_ctrl)、音频缓存发送控制模块(audio_cache_tx_ctrl)、 UDP模块(udp)和音频缓存接收控制模块(audio_cache_rx_ctrl)。 PLL时钟模块(pll_clk):PLL时钟模块通过调用锁相环(PLL)IP核来实现,输出1个频 率为12Mhz的时钟,作为WM8978的主时钟MCLK。 WM8978控制模块(wm8978_config):WM8978控制模块完成了WM8978的初始化配置、音频 数据采集和音频数据发送的功能,该模块例化了WM8978配置模块(wm8978_config)、音频接 收模块(audio_receive)、音频发送模块(audio_send),其中WM8978配置模块例化了IIC配 置模块(i2c_reg_cfg)和IIC驱动模块(i2c_dri)。有关该模块的详细介绍请大家参考“音 频环回实验”章节。 音频缓存发送控制(audio_cache_tx_ctrl):音频缓存发送控制模块用于缓存32位的音 频数据,当缓存的数据量达到预设值之后,控制以太网发送模块开始发送音频数据。 UDP模块(udp):UDP模块实现以太网通信的收发功能,该模块内部例化了以太网接收模 块(ip_receive)、以太网发送模块(ip_send)和CRC32校验模块(crc32_d4)。有关该模块 的详细介绍请大家参考“以太网通信实验”章节。 音频缓存接收控制(audio_cache_rx_ctrl):音频缓存接收控制模块负责缓存以太网接 收到的音频数据,将数据存入fifo模块等待被WM8978控制模块读取。 顶层模块代码如下: 1 module eth_audio_transmit( 2 input sys_clk , //系统时钟 3 input sys_rst_n , //系统复位信号,低电平有效 4 //以太网接口 5 input eth_rx_clk , //MII接收数据时钟 6 input eth_rxdv , //MII输入数据有效信号 7 input eth_tx_clk , //MII发送数据时钟 8 input [3:0] eth_rx_data , //MII输入数据 9 output eth_tx_en , //MII输出数据有效信号 10 output [3:0] eth_tx_data , //MII输出数据 11 output eth_rst_n , //以太网芯片复位信号,低电平有效 12 //wm8978 interface 13 //audio interface(master mode) 14 input aud_bclk , // WM8978位时钟 15 input aud_lrc , // 对齐信号 16 input aud_adcdat , // 音频输入 17 output aud_mclk , // WM8978的主时钟(最大为12.288MHz) 18 output aud_dacdat , // 音频输出 19 //control interface 20 output aud_scl , // WM8978的SCL信号 21 inout aud_sda // WM8978的SDA信号 22 ); 23 24 //parameter define 25 //这里DES_IP=BOARD_IP,这样两块开发板可以用同一个程序实现互传音频播放 26 //开发板MAC地址 00-11-22-33-44-55 27 parameter BOARD_MAC = 48'h00_11_22_33_44_55; 28 //开发板IP地址 192.168.1.123 29 parameter BOARD_IP = {8'd192,8'd168,8'd1,8'd123}; 30 //目的MAC地址 ff_ff_ff_ff_ff_ff 31 parameter DES_MAC = 48'hff_ff_ff_ff_ff_ff; 32 //目的IP地址 192.168.1.102 33 parameter DES_IP = {8'd192,8'd168,8'd1,8'd123}; 34 //wire define 35 wire rst_n ; 36 wire locked ; 37 38 wire aud_rx_done ; //音频数据接收完成信号 39 wire [31:0] adc_data ; //接收到的音频数据 40 wire udp_tx_start_en ; //以太网开始发送信号 41 wire [15:0] udp_tx_byte_num ; //以太网发送的有效字节数 42 wire [31:0] udp_tx_data ; //以太网发送的数据 43 wire udp_rec_pkt_done; //以太网单包数据接收完成信号 44 wire udp_rec_en ; //以太网接收使能信号 45 wire [31:0] udp_rec_data ; //以太网接收到的数据 46 wire udp_tx_req ; //以太网发送请求数据信号 47 wire udp_tx_done ; //以太网发送完成信号 48 wire aud_tx_done ; //音频发送完成信号 49 wire [31:0] dac_data ; //音频dac数据 50 51 //***************************************************** 52 //** main code 53 //***************************************************** 54 55 assign rst_n = sys_rst_n & locked; 56 57 //锁相环 58 pll_clk u_pll_clk( 59 .inclk0 (sys_clk), 60 .areset (~sys_rst_n), 61 .c0 (aud_mclk), 62 .locked (locked) 63 ); 64 65 //WM89878模块 66 wm8978_ctrl 67 #( 68 .WL (6'd32 ) //word length音频字长定义 69 ) 70 u_wm8978_ctrl( 71 //system clock 72 .clk (sys_clk ), 73 .rst_n (rst_n ), 74 //wm8978 interface 75 //audio interface(master mode) 76 .aud_bclk (aud_bclk ), 77 .aud_lrc (aud_lrc ), 78 .aud_adcdat (aud_adcdat ), 79 .aud_dacdat (aud_dacdat ), 80 //control interface 81 .aud_scl (aud_scl ), 82 .aud_sda (aud_sda ), 83 //user interface 84 .dac_data (dac_data ), 85 .adc_data (adc_data ), 86 .rx_done (aud_rx_done), 87 .tx_done (aud_tx_done) 88 ); 89 90 //音频缓存发送控制 91 audio_cache_tx_ctrl u_audio_cache_tx_ctrl( 92 .aud_bclk (aud_bclk), 93 .rst_n (rst_n), 94 .aud_rx_done (aud_rx_done), 95 .aud_adc_data (adc_data), 96 .eth_tx_clk (eth_tx_clk), 97 .udp_tx_req (udp_tx_req), 98 .udp_tx_done (udp_tx_done), 99 .udp_tx_start_en (udp_tx_start_en), 100 .udp_tx_byte_num (udp_tx_byte_num), 101 .udp_tx_data (udp_tx_data) 102 ); 103 104 //UDP模块 105 udp 106 #( 107 .BOARD_MAC (BOARD_MAC), //参数例化 108 .BOARD_IP (BOARD_IP ), 109 .DES_MAC (DES_MAC ), 110 .DES_IP (DES_IP ) 111 ) 112 u_udp( 113 .eth_rx_clk (eth_rx_clk ), 114 .rst_n (rst_n ), 115 .eth_rxdv (eth_rxdv ), 116 .eth_rx_data (eth_rx_data), 117 .eth_tx_clk (eth_tx_clk ), 118 .tx_start_en (udp_tx_start_en), 119 .tx_data (udp_tx_data), 120 .tx_byte_num (udp_tx_byte_num), 121 .tx_done (udp_tx_done), 122 .tx_req (udp_tx_req ), 123 .rec_pkt_done (udp_rec_pkt_done), 124 .rec_en (udp_rec_en), 125 .rec_data (udp_rec_data), 126 .rec_byte_num (), 127 .eth_tx_en (eth_tx_en ), 128 .eth_tx_data (eth_tx_data), 129 .eth_rst_n (eth_rst_n ) 130 ); 131 132 //音频缓存接收控制 133 audio_cache_rx_ctrl u_audio_cache_rx_ctrl( 134 .eth_rx_clk (eth_rx_clk), 135 .rst_n (rst_n), 136 .udp_rec_pkt_done (udp_rec_pkt_done), 137 .udp_rec_en (udp_rec_en), 138 .udp_rec_data (udp_rec_data), 139 .aud_bclk (aud_bclk), 140 .aud_dac_req (aud_tx_done), 141 .dac_data (dac_data) 142 ); 143 144 endmodule 在代码的第25至第33行定义了四个参量:开发板MAC地址BOARD_MAC、开发板IP地址 BOARD_IP、目的MAC地址DES_MAC和目的IP地址DES_IP。需要注意的是,如果目的IP地址和开发 板IP地址不一致或者目的MAC(公共MAC地址除外)地址和开发板MAC地址不一致的话,以太网 接收模块会直接丢掉数据,导致接收音频数据失败。因此目的MAC地址这里写的是公共MAC地址 (48'hff_ff_ff_ff_ff_ff),目的IP地址写的是和开发板IP地址相同的值,目的是为了让同 一程序可以下载在两个开发板中。 在代码的第85至第86行代码中,aud_rx_done(音频数据接收完成信号)和adc_data(接 收到的音频数据)写入音频缓存发送控制模块,该模块输出的udp_tx_start_en(以太网开始 发送信号)用于控制以太网发送模块开始传输音频数据。UDP模块输出的udp_rec_en(以太网 接收数据有效信号)和udp_rec_data(以太网接收到的数据)写入音频缓存接收控制模块。 WM8978控制模块输出的aud_tx_done(音频数据发送完成)信号作为音频缓存接收控制模块的 读请求信号,并将读取后的数据dac_data通过引脚aud_dacdat引脚发送出去。 音频缓存发送控制模块用于缓存32位的音频数据,当缓存的数据量达到预设值之后,控制 以太网发送模块开始发送音频数据。该模块代码如下所示: 1 module audio_cache_tx_ctrl( 2 input aud_bclk , //WM8978位时钟 3 input rst_n , //复位信号,低电平有效 4 input aud_rx_done , //音频数据接收完成信号 5 input [31:0] aud_adc_data , //32位音频数据 6 7 input eth_tx_clk , //以太网发送时钟 8 input udp_tx_req , //以太网发送请求数据信号 9 input udp_tx_done , //以太网发送完成信号 10 output reg udp_tx_start_en, //以太网开始发送信号 11 output [15:0] udp_tx_byte_num, //以太网发送的字节数 12 output [31:0] udp_tx_data //以太网发送的数据 13 ); 14 15 //parameter define 16 //fifo缓存的数量大于等于此值时控制udp开始发送数据 17 parameter AUDIO_TX_NUM = 9'd256; 18 19 //reg define 20 reg udp_tx_flag ; //udp正在发送数据的标志 21 22 //wire define 23 wire [8:0] data_cnt; //fifo中缓存的个数 24 25 //***************************************************** 26 //** main code 27 //***************************************************** 28 29 //以太网发送的字节数(1个32位音频数据 = 4个字节),即udp_tx_byte_num = AUDIO_TX_NUM * 4 30 assign udp_tx_byte_num = {AUDIO_TX_NUM,2'd0}; 31 32 //判断fifo中缓存的个数,超过预设值控制udp开始发送数据 33 always @(posedge eth_tx_clk or negedge rst_n) begin 34 if(rst_n == 1'b0) begin 35 udp_tx_flag <= 1'b0; 36 udp_tx_start_en <= 1'b0; 37 end 38 else begin 39 udp_tx_start_en <= 1'b0; 40 //只有当udp没有发送数据时才判断fifo大小是否满足发送条件 41 if(udp_tx_flag == 1'b0) begin 42 if(data_cnt >= AUDIO_TX_NUM) begin 43 udp_tx_flag <= 1'b1; 44 udp_tx_start_en <= 1'b1; //udp开始发送信号 45 end 46 end 47 else if(udp_tx_done) //udp发送完成后,将udp发送标志清零 48 udp_tx_flag <= 1'b0; 49 end 50 end 51 52 //异步fifo 53 async_fifo_512x32b u_async_fifo( 54 .aclr (~rst_n), 55 .data (aud_adc_data), 56 .rdclk (eth_tx_clk), 57 .rdreq (udp_tx_req), 58 .wrclk (aud_bclk), 59 .wrreq (aud_rx_done), 60 .q (udp_tx_data), 61 .rdempty (), 62 //注意rdusedw为读时钟下的计数,如果需要在写时钟下读取数据时,在建立fifo时选择wrusedw 63 .rdusedw (data_cnt), //fifo缓存的个数 64 .wrfull () 65 ); 66 67 endmodule 在代码的第17行定义了参数AUDIO_TX_NUM(单包发送音频数据个数),当以太网没有在发 送数据时,判断data_cnt(fifo中缓存的个数)的值是否大于等于AUDIO_TX_NUM值,当大于等 于此值时,开始通知以太网发送数据,发送的字节数为AUDIO_TX_NUM的4倍(32bit=4个字节)。 AUDIO_TX_NUM的值在这里设置为256,设置成其它值也是可以的。需要注意的是不建议单 包发送的音频数据个数太小或者太大,单包发送音频数据量太小传输效率低,太大会造成音频 传输的延时。需要注意的是,如果单包发送的数据量增加,fifo的深度也要根据缓存量相应增 加,否则fifo写满溢出,导致音频数据丢失。 图 48.4.3为音频缓存发送模块SignalTap抓取的波形图,当rdusedw(fifo中缓存的个数, 同data_cnt)计数达到256之后,udp_tx_start_en(以太网开始发送信号)开始输出一个脉冲 信号,发送的有效字节个数为1024(256*4)个字节。 图 48.4.3 音频缓存发送模块SignalTap波形图 音频缓存接收控制模块负责缓存以太网接收到的音频数据,将数据存入fifo模块等待被音 频发送模块读取。该模块代码如下所示: 1 module audio_cache_rx_ctrl( 2 input eth_rx_clk , //以太网接收时钟 3 input rst_n , //复位信号,低电平有效 4 input udp_rec_pkt_done, //以太网单包数据接收完成信号 5 input udp_rec_en , //以太网接收数据使能信号 6 input [31:0] udp_rec_data , //以太网接收到的数据 7 8 input aud_bclk , //WM8978位时钟 9 input aud_dac_req , //dac数据请求信号 10 output [31:0] dac_data //dac值 11 ); 12 13 //reg define 14 reg rec_done_flag ; //单包数据接收完成后给出标志 15 reg rec_done_flag_d0; //异步信号打拍处理 16 reg rec_done_flag_d1; //异步信号打拍处理 17 18 wire fifo_rd_req ; //fifo读请求信号 19 20 //***************************************************** 21 //** main code 22 //***************************************************** 23 24 //接收完单包数据后再开始读fifo,防止fifo为空时被读取 25 assign fifo_rd_req = aud_dac_req & rec_done_flag_d1; 26 27 //接收完单包数据后给出标志 28 always @(posedge eth_rx_clk or negedge rst_n) begin 29 if(rst_n == 1'b0) 30 rec_done_flag <= 1'b0; 31 else if(udp_rec_pkt_done) 32 rec_done_flag <= 1'b1; 33 end 34 35 //异步信号打拍处理 36 always @(posedge aud_bclk or negedge rst_n) begin 37 if(rst_n == 1'b0) begin 38 rec_done_flag_d0 <= 1'b0; 39 rec_done_flag_d1 <= 1'b0; 40 end 41 else begin 42 rec_done_flag_d0 <= rec_done_flag; 43 rec_done_flag_d1 <= rec_done_flag_d0; 44 end 45 end 46 47 //异步fifo 48 async_fifo_512x32b u_async_fifo( 49 .aclr (~rst_n), 50 .data (udp_rec_data), 51 .rdclk (aud_bclk), 52 .rdreq (fifo_rd_req), 53 .wrclk (eth_rx_clk), 54 .wrreq (udp_rec_en), 55 .q (dac_data), 56 .rdempty (), 57 .rdusedw (), 58 .wrfull () 59 ); 60 61 endmodule 在代码的第27行开始的always语句块中,当接收完单包数据之后,rec_done_flag(单包 数据接收完成后给出的标志)信号拉高;由于rec_done_flag信号对于aud_bclk时钟来说是异 步信号,因此该信号通过延时打拍的方式同步到aud_bclk时钟下。在代码的第25行,fifo必须 在rec_done_flag_d1为高电平之后,即接收完单包数据之后才开始读取数据,防止在fifo为空 时进行读操作。 下载验证 首先我们打开基于以太网的板对板音频互传实验工程,在工程所在的路径下打开 eth_audio_transmit/par文件夹,在里面找到“eth_audio_transmit.qpf”并双击打开。注意 工程所在的路径名只能由字母、数字以及下划线组成,不能出现中文、空格以及特殊字符等。 工程打开后如图 48.5.1所示: 图 48.5.1 基于以太网的板对板音频互传实验工程 然后将下载器一端连电脑,另一端与开发板上对应端口连接;将音频连接线的一端连接至电脑或手机的音频输出端口,另一端连接至其中一块开发板的WM8978的LINE_IN接口,并将耳 机连接至另一开发板的PHONE接口;网线的两端分别接在两个开发板上的以太网接口,最后连 接电源线并打开电源开关。 接下来我们下载程序,验证音频互传与播放的功能。工程打开后通过点击工具栏中的 “Programmer” 图 标 打 开 下 载 界 面 , 通 过 “Add File” 按钮选择 eth_audio_transmit/par/output_files目录下的“eth_audio_transmit.sof”文件。开发板 电源打开后,在程序下载界面点击“Hardware Setup”,在弹出的对话框中选择当前的硬件连 接为“USB-Blaster[USB-0]”。然后点击“Start”将工程编译完成后得到的sof文件下载到开 发板中,如图 48.5.所示: 图 48.5.2 程序下载完成界面 程序下载完成后并且硬件连接无误的话,我们可以看到两块开发板上以太网接口的灯会不 停地闪烁,说明此时两块开发板正在互传音频。如果音频连接线的另一端已经连接至电脑或手 机的音频输出端口,此时打开音乐,就可以听到另一块开发板上喇叭播放的音乐。戴上耳机, 也能听到耳机播放的音乐,说明音频互传实验验证成功。 |
|
相关推荐
|
|
飞凌嵌入式ElfBoard ELF 1板卡-CAN编程示例之开发板测试
769 浏览 0 评论
该问题是用APP给芯海科技的CST92F25芯片发指令是出现的
2583 浏览 1 评论
849 浏览 0 评论
1641 浏览 1 评论
2551 浏览 1 评论
浏览过的版块 |
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-26 04:02 , Processed in 0.580963 second(s), Total 64, Slave 46 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号