FPGA-音频模块开发(二)

audio_record_play_ctrl模块

该模块主要完成通过I2S完成与WM8731的通信(发送和接收数据),信号包括bclk、adclrc、daclrc、adcdat、dacdat。该系统还完成了播放和录制的功能,为此在该模块中添加了audio_key子模块,主要通过key的按下和释放发出record和play的命令,将WM8731输出的数字信号写到SDRAM中(达到录制的功能),而播放是读出相应地址的SDRAM中的数据。并且同frame_read_write模块进行信息交互(其中包括write_data、read_data、write_en、read_en、read_req_ack、write_req_ack、write_req、read_req)。

audio_record_play_ctrl.v(模块顶层文件)

 

该段代码是audio_record_play_ctrl模块的顶层文件,它主要描述该模块是由三个子模块

audio_key、audio_tx、_audio_rx逻辑组合的。

audio_tx.v

 

首先,对外部的输入信号sck_bclk、ws_lrc进行锁存,达到与系统时钟同步的目的,避免紊乱。 

 

 

与WM8731通信,我们需要遵从约定好的通信协议,即I2S。根据时序图可以知道WM8731发送一次数据或者接收一次数据(左右声道),即一个周期(1/fs),开始于lrc信号的上升沿。在lrc的上升沿,我们将frame_read_write模块中fifo里读出的64位数据赋给两个移位寄存器,left_data_shift以及right_data_shift(分别用来储存左声道以及右声道的数字信 号)。同样根据时序图,在bclk的下降沿,WM8731发送一位数据,那么FPGA也应该在下降沿发送数据,lrc==1时,发送的是左声道的数据,所以在每个bclk的下降沿,left_data_shift左移一位,lrc==0时,发送的是右声道的数据,所以在每个bclk的下降沿,right_data_shift左移一位。我们会在下面的always块里看到sdata<=left_data_shift[31],或者sdata<=right_data_shift[31]最初我比较困惑按照通信协议里规定的,要在BCLK的下降沿发送数据,这里同步的时钟是系统时钟,这样会不会破坏协议,oh,my god!bclk_d0/bclk_d1

每次发生改变都是在clk的上升沿!!!豁然开朗!!!

在这里我们仔细分析这个子模块的逻辑,当采集到lrc的跳变(上升沿)的下一个CLK的上升沿,left_data/right_data赋给left_data_shift/right_data_shift,而此时left_data/right_data的数据是上一个(1/fs)周期从fifo中读到的。为什么是这样呢?原因是在lrc跳变沿触发后(也就是lrc上升沿的下一个CLK时钟),read_data_en置1,才会给frame_read_write这个模块中的fifo提供读使能,q[63...0]({left_data,right,data})的输出滞后读使能一个CLK时钟。所以此时left_data/right_data为上一个(1/fs)周期从fifo中读到的数据。

在audio_record_play_ctrl这个模块中我们可以看到assign read_en = read_data_en & play;

read_en这个信号是连接到fifo中的读使能的,达到连续发送数据的目的。

这里延伸一下关于fifo的知识:

关于读使能与data的输出由两种模式可以选择:

第一种是Normal synchronous FIFO mode

该模式,数据输出滞后读使能一个时钟周期(The data becomes available after rdreq is asserted)。

第二种是Show-ahead synchronous FIFO mode(The data becomes available before rdreq is asserted)。

笔者在网络这个浩瀚的宇宙苦苦寻觅,终于找到了这组时序图,帮我解决了许久的困惑,在学习音频模块的时候,发现了一个问题,CHECK FIFO这个状态中,设计中通过判断rdusedw与BURST_SIZE之间的大小,即(可读数据长度是否大于一次突发写的数据长度)来决定是否进入下个状态。当时笔者在想,rdusedw和BURST_SIZE的单位是否一致?BURST_SIZE是指一次突发读写多少组数据,它的单位是16位的数据。最初我在想rdusedw和wrusedw的计数方式是一致的,会以同一位宽为基准,就是说如果fifo里输入端口的位宽是64,输出端口的位宽是16,在写使能有效的时候,写进一个64位的数据,wrusedw+1,那么在读使能有效的时候,读出4个16位的数据,rdusedw+1,那么黑金写的音频模块就是错误的。但是看了这个时序笔者恍然大悟,rdusedw/wrusedw的计数方式是根据自己输入输出数据端口进出数据计数的,如上图在wrreq有效时,在第一个时钟写入0xFF01,在第二个时钟的上升沿后wrusedw==01,在第二个时钟写入0x0002,在第三个时钟的上升沿后wrusedw==02,当rdreq为1,在下一个rdclk的上升沿有效,并输出第一个数据0x01,在之后的下一个时钟的上升沿输出第二个数据0xFF,同时rdusedw-1,从上面的逻辑我们可以知道wrusedw和rdusedw的计数原则。

 

audio_rx.v

 

接收模块和发送模块逻辑设计上大体一致,区别在于,接收模块中BCLK上升沿采集数据,发送模块中BCLK下降沿发送数据。还有需要注意的是,每次LRC的上升沿(完成一个周期的数据接收,左右声道),right_data_shift/left_data_shift赋给right_data,left_data,然后复位清0,并将data_valid置1,标志着完成了一次数据接收。在这里大家可能会有疑问,为什么会先赋值,再清0,FPGA不是并行的吗?怎么会有先后顺序呢?逻辑中不都是在判断语句中判断了LRC的上升沿吗?有这样的疑问说明了大家对时序逻辑没有深刻的认识,首先大家要根据逻辑关系在脑海里有一个大体的输入输出逻辑门关系,在该判断逻辑中left_data/right_data这两个寄存器的输入是left_data_shift/right_data_shift,而left_data_shift/right_data_shift的输入是0,而这四个寄存器的时钟输入都是CLK,那么在CLK的上升沿,left_data_shift/right_data_shift的值并没有改变,而是在CLK上升沿之后,left_data_shift/right_data_shift才被清0。在这里再延伸一下,关于数据采样的问题,我们发现在FPGA逻辑中,时钟的上升沿伴随着数据的更新,数据采样如果采用系统的时钟,那么会出现一个问题,没有办法在数据的中端位置采样,这样就无法保证数据的有效性。所以我们会常常用PLL分频出一个相位差180°的时钟,这样数据的中端位置恰巧在时钟的上升沿,方便数据的采样。言归正传,现在我们看data_valid这个信号,它和read_data_en一样都是与record/play组合输出并连接在fifo上的,data_valid标志着接收了一次数据(由WM8731发出的左右声道数据)。 

 audio_key.v

 

 

首先在程序底部,我们看到了一段例化描述,它主要是添加了按键去抖,因为我们需要捕捉按键的下降沿/上升沿用来完成record/play的功能。接下来我们来看这个子模块的状态机,S_IDLE、S_RECORD、S_PLAY,初始化/录制/播放。其他没什么特别的难点,唯一我们需要注意的是record_cnt和play_cnt,这两个寄存器的目的,是保证录制时间和播放时间的一致。 

 

 

 

  • 3
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
### 回答1: FPGA设计技巧与案例开发是一个非常专业、复杂性高的领域,需要深入掌握相关的知识和技术,才能够设计出高效稳定的FPGA电路。针对这一问题,以下为您详细介绍FPGA设计技巧与案例开发的相关内容。 首先,FPGA设计需要充分考虑电路的可维护性、可扩展性等诸多因素。具体来说,需要从以下几个方面进行考虑:电路可读性、可测试性、可维护性等。例如,在设计FPGA电路时,应尽量避免出现大量的状态机和多层嵌套的IF语句等复杂的结构,这些可能会导致设计失控、难以调试。 其次,FPGA设计的重要原则是要重视模块开发,尽可能将电路分解为多个模块,每个模块完成一个特定的功能,利用好设计软件对模块进行大规模的复用。当然,在模块开发的过程中,还应当充分考虑模块之间的接口设计及功能划分等问题。 最后,对于FPGA设计,我们要充分运用现代化的设计方法和技术,例如采用系统级设计(SLD)、硬件描述语言(HDL)等来进行开发,尤其是对于复杂电路的设计工作,采用高层次综合(HLS)工具来进行设计是非常必要的。这样能够有效简化设计过程、提高设计效率和可靠性,降低设计风险。 总的来说,FPGA设计技巧与案例开发需要综合考虑多方面的问题和因素,通过体系化的设计方法和技术,将电路分解为多个小模块,并通过复用模块来达到快速、高效的设计目的。 ### 回答2: FPGA(现场可编程门阵列)是一种集成电路芯片,它可以根据需要重新编程。因此,FPGA是一种非常灵活的技术,可以在数字电路设计、嵌入式系统设计等领域中得到广泛应用。 在FPGA设计中,设计者需要掌握一些技巧,以便有效地使用FPGA。首先,设计者需要了解FPGA的结构和工作原理。其次,设计者需要选择合适的FPGA软件开发工具,并熟练掌握FPGA编程语言和CAD工具。 在FPGA案例开发中,设计者需要遵循以下步骤。首先,设计者需要充分了解系统要求和应用场景,并确定FPGA的使用目标。其次,设计者需要进行FPGA系统的架构设计,并选择适当的FPGA器件和外设。然后,设计者需要进行FPGA硬件电路设计,包括时序分析、时钟驱动、I/O电路等。最后,设计者需要进行FPGA软件开发,包括程序编写、仿真测试、调试验证等。 在实际FPGA开发中,设计者还需要注意以下几点。首先,设计者需要考虑系统的可靠性和稳定性,并进行严格的测试验证。其次,设计者需要优化FPGA的性能和功耗,并控制FPGA的热管理。最后,设计者需要关注FPGA系统的安全性和保密性。 总之,FPGA设计技巧和案例开发需要设计者具备丰富的专业知识和实践经验,同时需要注重系统性能和可靠性、安全性和保密性等方面的控制。通过不断学习和实践,设计者可以不断提高FPGA设计能力,为实现更广泛的应用场景做出贡献。 ### 回答3: FPGA(Field-Programmable Gate Array)是一种灵活的硬件开发平台,可以实现定制化的芯片设计,因此在很多场合都有广泛的应用。FPGA开发的关键是熟练掌握设计技巧,避免在设计过程中出现问题,从而更好地满足设计需求。以下是几个常用技巧: 1.使用适当的FPGA资源:在设计过程中,应根据设计需求选取适当的FPGA资源,如LUT、RAM、DSP、IO等,并合理地分配资源使用。这样可以保证设计的运行效率和系统性能。 2.时序约束的设置:时序约束是指为了确保信号的有效响应和数据的正确稳定指定的时间要求。在FPGA设计中,需要合理设置时序约束,保证信号的稳定性和系统的正常工作。 3.参照现有资料:在FPGA开发过程中,可以参照官方文档和各种技术资料,掌握FPGA的相关知识和设计方法,节省时间和减少错误。 4.设计验证:在设计完成后,需要进行全面的设计验证和测试,以验证设计的正确性和有效性。 案例开发FPGA开发的重要一环,以下是一些常见的案例开发: 1.视频处理:视频处理是FPGA的常见应用,包括图像采集、图像处理和合成等。可以使用FPGA在不同的视频采集和处理方面实现高效的数据流处理。 2.数字信号处理:FPGA也经常用于数字信号处理,包括滤波、卷积、FFT、解码、编码等。可以使用FPGA在实时数据处理、高速数据转换以及音频和视频信号处理方面达到优异的性能。 3.嵌入式系统:FPGA也可以用于实现嵌入式系统,包括嵌入式处理器、外设控制等。可以使用FPGA来实现定制的芯片设计,以适应不同的应用场景和需求。 总之,掌握FPGA的设计技巧和运用案例开发的方法,可以为设计者提供创新性的解决方案,以满足不同的应用需求。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值