简单音调生成
该模块通过使用一个计数器生成一个1 kHz的信号,该计数器在CLK的每个刻度上都递增。 当计数器达到32,000时,将切换输出BUZZER,并将计数器重置为0。
音频输出
使用一个1-kΩ电阻器和一小段实心线将GPIO引脚P97和GND连接到与有源扬声器相连的音频引线。 导线和电阻器引线仅缠绕在音频插孔的接地和插孔插头的尖端部分周围。
您可能想使用一些排针和一个3.5mm直插式插座来做一些实质性的事情。
通用音/频率发生器
我们制作一个通用的音调发生器模块,该模块将针对您的电路板的时钟频率进行参数设置,并且还允许您指定要产生的音调作为其输入之一。
该模块的测试程序不会通过音频插孔播放生成的频率,而是会在FPGA板的三个不同引脚上生成三个不同的频率。 如果您的示波器或万用表具有频率设置,那么您将能够验证所产生的信号。 如果您不这样做,则按照“警报”项目,将其中一个“音调” NET的位置(LOC)更改为音频插孔,并通过放大器收听音调,尽管您可能很难听到12.5- kHz音调。
音调模块具有系统时钟(CLK)的输入以及要生成的音调周期(以微秒为单位)和tone_out的单个输出。 参数CLK_F用于配置模块的预分频器以适合您电路板的时钟频率。 使用周期而不是频率的原因是将频率转换为要在Verilog中计数的多个时钟周期将需要除法。 在不使用除法模块的情况下,无法在Verilog中除2的幂(1、2、4、8、16等)以外的任何东西,否则将需要除以一个时钟周期来执行。
时钟的频率是每秒的完整周期数(从0到1再回到0)。 时钟周期是一个周期所花费的时间。 因此,对于非常慢的1 Hz时钟(每秒1个周期),周期为1秒。 对于1 MHz时钟,周期为1 / 1,000,000秒或1微秒。
对于特定频率f,周期为1 / f。下表中列出的周期代表您可能希望与音频模块一起使用的一些值得注意的频率。
使用两个计数器。 预分频器计数器将时钟频率降低到2 MHz,并且计数器用于计数预分频的时钟。 预分频器生成2MHz时钟而不是1MHz时钟,因为每次到达正确的周期时,输出将被切换(0至1或1至0),从而有效地将频率减半。 这种切换可确保生成的信号具有50%的占空比。 即,方波的大小相等且高低。
tone_tester模块会创建音频模块的三个实例,每个实例都在不同的引脚上,并且以不同的频率。 实际上,period_12khz实例将产生12.5 kHz而不是12 kHz的频率。
FPGA微型板端口示意图
播放音频文件
该项目使用FPGA通过放大器播放录制的音频数据。 它介绍了一些有用的新技术,包括使用随机存取存储器(RAM)以及如何在合成期间将其与一组数据一起加载。
音频文件
音频文件的类型很多,大多数使用聪明的压缩算法来尽可能地减小文件的大小,而质量的损失则尽可能小。 简单来说,一个音频文件将只包含一系列数字,每个数字代表一个瞬间的振幅(思考电压)。 这种格式称为原始格式,因为没有花哨的数字。 下图显示了一个我说“一”字的样本数据。“一个”音频样本的波形。
每个采样点的数值都保存在一个字节(8位)中,范围为0到255之间的数字。声音是以8 kHz采样的,因此大约3,800个采样代表不到半秒的音频。
诸如Audacity(www.audacityteam.org/)之类的软件工具将使您可以录制自己的音频文件或以几乎任何格式导入音频文件,然后将结果保存为原始数据。 稍后,在“准备自己的声音”部分中,您将学习如何使用Audacity和一个小的Python脚本将原始声音文件转换为适合导入FPGA的格式。
RAM
要播放的声音将保存在FPGA的内存(RAM)中。 三个示例板上使用的所有FPGA(实际上,大多数FPGA)都有专用于RAM的FPGA芯片区域。 当ISE在您的Verilog中发现看起来像内存的reg声明时,它将使用此专用块而不是通用单元。
RAM将具有许多输入地址线和输出数据线。 您在地址行上以二进制形式设置一个数字,以指定要访问的存储字节。 然后,您可以读取或写入当前选定的字节。 更改地址,即可访问其他字节的数据。 尽管RAM的全部目的是您可以对其进行读取和写入,但在此项目中,RAM在合成期间会用文件中的初始内容填充,然后保持不变。
wav_player模块
要播放声音文件,可使用一个计数器依次遍历每个地址。 然后使用PWM输出每个位置的值。 该模块具有CLK和switch_play的输入,用于在按下开关时触发要播放的声音文件:
接下来,有一个本地参数来保存音频文件中包含的数据字节数。 用于指定内存的格式类似于常规的reg声明,除了在指定名称之后还要指定数据的每个元素的大小(7:0)之外,还指定此类内存位置的数量(MEM_SIZE-1:0) 内存(memory)的:
为了控制声音文件的播放,使用了注册播放。 这充当一个触发器,用于打开和关闭到地址计数器的脉冲。 预分频器计数器用于降低电路板的时钟频率以匹配电路板的采样率。 8位计数器用作PWM计数器,而值则用于当前由address引用的存储器的内容。
下图展示了所有这些东西如何相互联系。 它还提供了有关Verilog可能合成的线索。声音文件播放器的示意图。
always块仅在播放为1时才递增预分频器计数器。如果您跳到Always块的末尾,您将看到按下“开始”按钮时发生。 假定已按下按钮,预分频器将时钟频率从50 MHz输入时钟分频到2 MHz。 然后计数器增加,并且来自当前存储位置的数据被锁存到value中。 然后将当前存储位置的值与适当设置的counter和audio_out进行比较。
这将导致PWM输出的脉冲在高振幅时较长,而在低振幅时较短。 当地址的值达到MEMORY_SIZE时,播放会被重置以停止预分频器的计时并阻止进一步的音频播放,直到再次按下该按钮:
测试
准备您的声音
准备自己的声音文件非常简单。 主要问题是使其足够短以适合RAM。 首先安装并运行Audacity。 Audacity适用于Windows,Mac和Linux,并且是免费的。 开始一个新项目,并确保将“ Project Rate”设置为8 kHz,并将录音设置为“ mono”(下图)。 单击红色的圆形“记录”按钮进行简短记录。
录制完成后,按“停止”按钮(黄色正方形),您将看到录制的波形。 如果波形有点平坦,您可以再次记录它,但可以大声讲话,或者通过选择菜单上的Effect Ampilfy…选项以数字方式放大信号。 您可能还希望从记录的开始和结束处消除任何静音,方法是选择要删除的波形部分,然后按DELETE键。
现在,您需要以非常特殊的格式导出声音文件,因此选择菜单选项“文件导出音频”。…您需要选择“其他未压缩”文件类型,然后在标题字段中选择“ RAW”(无标题),然后 在编码字段中,选择“无符号8位PCM”。 然后点击“保存”以创建文件(下图)。
您刚刚创建的文件是二进制文件,并将其放入适合$readmemh文件的格式,需要将其转换为带有两位十六进制字符串的文本文件,每行一个,如以下示例所示:
要进行此转换,您可以使用为此目的创建的Python脚本(本文源码中包含脚本)。 在运行此脚本之前,您需要安装Python。安装细节请参考Python官网,在此不赘述。
将导出的声音文件与脚本放置在同一文件夹(“实用程序/音频”),然后使用以下命令从命令行运行该程序:
第一个参数(在本例中为01_05.aiff)是要转换的声音文件的名称,第二个参数(01_05.txt)是输出文本文件。 该实用程序可以帮助您告知所生成数据的大小,以便在构建项目之前可以使用它在wav_player中设置MEM_SIZE。
源码
详情参阅 - 亚图跨际