2022暑期在家一起练——基于小脚丫FPGA制作的电子琴
2022暑期在家一起练 FPGA 电子琴 PWM 正弦波 apio仿真 音乐播放
标签
FPGA
测试
DDS
aramy
更新2022-09-06
1232

任务介绍
很早就想去接触一下FPGA了。感觉它很神秘,像是单片机,又和单片机有很大区别。趁着“电子森林推出的2022暑期在家一起练(3) - 基于FPGA的电子琴设计”的机会,开始了学习FPGA的路程。这次活动使用的是STEP小脚丫FPGA STEP-MXO2-C。

  • 核心器件:Lattice LCMXO2-4000HC-4MG132
    • 132脚BGA封装,引脚间距0.5mm,芯片尺寸8mm x 8mm;
    • 上电瞬时启动,启动时间<1ms;
    • 4320个LUT资源, 96Kbit 用户闪存,92Kbit RAM;
    • 2+2路PLL+DLL;
    • 嵌入式功能块(硬核):一路SPI、一路定时器、2路I2C
    • 支持DDR/DDR2/LPDDR存储器;
    • 104个可热插拔I/O;
    • 内核电压2.5-3.3V;
  • 板载资源:
    • 两位7段数码管;
    • 两个RGB三色LED;
    • 8路用户LED;
    • 4路拨码开关;
    • 4路按键;
  • 36个用户可扩展I/O(其中包括一路SPI硬核接口和一路I2C硬核接口)
  • 支持的开发工具Lattice Diamond
  • 支持MICO32/8软核处理器
  • 板上集成FPGA编程器
  • 一路Micro USB接口
  • 板卡尺寸52mm x 18mm

任务内容:

  1. 基于我们提供的套件和工具,自己组装电子琴
  2. 自己编程基于FPGA实现:
    1. 存储一段音乐,并可以进行音乐播放,
    2. 可以自己通过板上的按键进行弹奏,支持两个按键同时按下(和弦)并且声音不能失真,板上的按键只有13个,可以通过有上方的“上“、”下”两个按键对音程进行扩展
    3. 使用扬声器进行播放时,输出的音调信号除了对应于该音调的单频正弦波外,还必须包含至少一个谐波分量
    4. 音乐的播放支持两种方式,这两种方式可以通过开关进行切换: 
      1. 当开关切换到蜂鸣器端,可以通过蜂鸣器来进行音乐播放
      2. 当开关切换到扬声器端,可以通过模拟扬声器来进行音乐播放,每个音符都必须包含基频 + 至少一个谐波分量

任务实现:

入门第一次接触FPGA,各种不适应。从硬禾学堂的《小脚丫FPGA在数字电路设计中的应用》开始学起,才明白FPGA和自己掌握的软件知识完全不一样。FPGA更加偏向于硬件,编程也更加底层。开发工具使用了“Diamond”和小脚丫的在线编程,在群里老师的帮助下,学会了使用apio来做模拟。最后在老师的直播课《2022暑假练FPGA电子琴直播 - 项目需求及参考资源》指导下开始了自己的项目。

FksbQ7jFfuon50fJYRCZaN7CZPFw

 

输入:电子琴有13个琴键;右上角还有两个按键,底部还有一个拨动开关。分配一下各个按键的功能。底部拨动开关作为扬声器、蜂鸣器的选择开关。右边两个按键上边的按键作为音调切换按键,下边的用来控制是否自动播放音乐。自己音乐知识匮乏,就知道个简谱。安排13个琴键为低音mi到高音do,当音调切换后就变换为 从do到高音la。一共19个音调。使用小脚丫板子上的三个LED灯,用了指示当前状态。

音名 对应简谱 频率   传入参数
低音 1 261.63   366
低音 2 293.67   411
低音 3 329.63   461
低音 4 349.23   488
低音 5 391.99   548
低音 6 440   615
低音 7 493.88   690
中音 1 532.25   744
中音 2 587.33   821
中音 3 659.25   922
中音 4 698.46   977
中音 5 783.99   1096
中音 6 880   1230
中音 7 987.76   1381
高音 1 1046.5   1463
高音 2 1174.66   1642
高音 3 1318.51   1843
高音 4 1396.92   1953
高音 5 1567.98   2192
高音 6 1760   2461

消抖:小脚丫FPGA电子琴使用的是机械开关,这就会导致琴键(按键)按下后大概率会有多次电平的高低跳变。这里直接使用了一个消抖模块进行消抖处理。

// Module Function:按键消抖 
module debounce (clk,rst,key,key_out,key_pulse); 
	parameter       N  =  1;         //要消除抖动的按键的数量 
	input             clk;
	input             rst;
	input 	[N-1:0]   key;           //输入的按键	
	output  [N-1:0]   key_out;
	output  [N-1:0]   key_pulse;     //按键动作产生的脉冲一个时钟周期高电平	
 
	reg     [N-1:0]   key_rst_pre;   //定义一个寄存器型变量存储上一个触发时的按键值
	reg     [N-1:0]   key_rst;       //定义一个寄存器变量储存储当前时刻触发的按键值
 
	wire    [N-1:0]   key_edge;      //检测到按键由高到低变化时产生一个高脉冲
 
	//利用非阻塞赋值特点,将两个时钟触发时按键状态存储在两个寄存器变量中
	always @(posedge clk  or  negedge rst)
		begin
			if (!rst) begin
				key_rst <= {N{1'b1}};       //初始化时给key_rst赋值全为1,{}中表示N个1
				key_rst_pre <= {N{1'b1}};
				end
			else begin
				key_rst <= key;             //第一个时钟上升沿触发之后key的值赋给key_rst,同时key_rst的值赋给key_rst_pre
				key_rst_pre <= key_rst;     //非阻塞赋值。相当于经过两个时钟触发,key_rst存储的是当前时刻key的值,key_rst_pre存储的是前一个时钟的key的值
				end    
		end
 
	//脉冲边沿检测。当key检测到下降沿时,key_edge产生一个时钟周期的高电平
	assign  key_edge = key_rst_pre & (~key_rst);
	
	reg	[17:0]	  cnt;                       //产生延时所用的计数器,系统时钟12MHz,要延时20ms左右时间,至少需要18位计数器     
 
	//产生20ms延时,当检测到key_edge有效是计数器清零开始计数
	always @(posedge clk or negedge rst)
		begin
			if(!rst)
				cnt <= 18'h0;
			else if(key_edge)
				cnt <= 18'h0;
			else
				cnt <= cnt + 1'h1;
			end  
 
	reg     [N-1:0]   key_sec_pre;                //延时后检测电平寄存器变量
	reg     [N-1:0]   key_sec;                    
 
 
	//延时后检测key,如果按键状态变低产生一个时钟的高脉冲。如果按键状态是高的话说明按键无效
	always @(posedge clk  or  negedge rst)
		begin
			if (!rst) 
				key_sec <= {N{1'b1}};                
			else if (cnt==18'h3ffff)
				key_sec <= key;  
		end
	always @(posedge clk  or  negedge rst)
		begin
			if (!rst)
				key_sec_pre <= {N{1'b1}};
			else                   
				key_sec_pre <= key_sec;             
			end      
	assign  key_pulse = key_sec_pre & (~key_sec);   
	assign	key_out = key_sec;
 
endmodule

自动播放音乐:自动播放的曲子选了《梁祝》,曲子是1/4节拍的,相当于每秒按下4次按键。程序只需要将对应的按键信息记录下来,然后依次自动按下就可以实现自动播放。于是就使用晶振产生4Hz的时钟,然后将保存在136位的数组里的曲子信息,依次弹奏出来,就实现了自动播放音乐。

module clk_quarter(
	input wire clk_in,rst_in,
	output reg clk_out
);
	localparam counter_max = 32'd3000000;   // 
	reg [31:0]counter;
	
	always@(posedge clk_in or negedge rst_in)begin
		if(!rst_in)begin
			counter <= 0;
			clk_out <= 1'b0;
		end
		else begin
			if(counter >= counter_max)begin
				counter <= 0;
				clk_out <= 1'b1;
			end
			else begin
				counter <= counter + 1'b1;
				clk_out <= 1'b0;
			end
		end
	end
	
endmodule

形成正弦波信号:需要将输入的信息转换为对应的正弦波信息。反复观看直播课老师的视频,学习老师思路和方法,通过查询波表的方式形成对应的正弦波。

module sin_table(
		input  [5:0] address,	     //64个点来生成1/4个周期的波形,完整的一个周期为256个点
		output reg  [8:0] sin         //实际波形表为9位分辨率(1/4周期)
		); 
always @(address)
	begin
                  case(address)	
                      6'h0: sin=9'h0;
                      6'h1: sin=9'hC;
                      6'h2: sin=9'h19;
                      6'h3: sin=9'h25;
                      6'h4: sin=9'h32;
                      6'h5: sin=9'h3E;
                      6'h6: sin=9'h4B;
                      6'h7: sin=9'h57;
                      6'h8: sin=9'h63;
                      6'h9: sin=9'h70;
                      6'ha: sin=9'h7C;
                      6'hb: sin=9'h88;
                      6'hc: sin=9'h94;
                      6'hd: sin=9'hA0;
                      6'he: sin=9'hAC;
                      6'hf: sin=9'hB8;
                      6'h10: sin=9'hC3;
                      6'h11: sin=9'hCF;
                      6'h12: sin=9'hDA;
                      6'h13: sin=9'hE6;
                      6'h14: sin=9'hF1;
                      6'h15: sin=9'hFC;
                      6'h16: sin=9'h107;
                      6'h17: sin=9'h111;
                      6'h18: sin=9'h11C;
                      6'h19: sin=9'h126;
                      6'h1a: sin=9'h130;
                      6'h1b: sin=9'h13A;
                      6'h1c: sin=9'h144;
                      6'h1d: sin=9'h14E;
                      6'h1e: sin=9'h157;
                      6'h1f: sin=9'h161;
                      6'h20: sin=9'h16A;
                      6'h21: sin=9'h172;
                      6'h22: sin=9'h17B;
                      6'h23: sin=9'h183;
                      6'h24: sin=9'h18B;
                      6'h25: sin=9'h193;
                      6'h26: sin=9'h19B;
                      6'h27: sin=9'h1A2;
                      6'h28: sin=9'h1A9;
                      6'h29: sin=9'h1B0;
                      6'h2a: sin=9'h1B7;
                      6'h2b: sin=9'h1BD;
                      6'h2c: sin=9'h1C3;
                      6'h2d: sin=9'h1C9;
                      6'h2e: sin=9'h1CE;
                      6'h2f: sin=9'h1D4;
                      6'h30: sin=9'h1D9;
                      6'h31: sin=9'h1DD;
                      6'h32: sin=9'h1E2;
                      6'h33: sin=9'h1E6;
                      6'h34: sin=9'h1E9;
                      6'h35: sin=9'h1ED;
                      6'h36: sin=9'h1F0;
                      6'h37: sin=9'h1F3;
                      6'h38: sin=9'h1F6;
                      6'h39: sin=9'h1F8;
                      6'h3a: sin=9'h1FA;
                      6'h3b: sin=9'h1FC;
                      6'h3c: sin=9'h1FD;
                      6'h3d: sin=9'h1FE;
                      6'h3e: sin=9'h1FF;
                      6'h3f: sin=9'h1FF;
                   endcase
              end
endmodule
//查找正弦值
module look_table(
			input  	[7:0] 	phase,
			output 	[9:0] 	sin_out
			);

reg	[5:0] 	address;
wire   	[1:0] 	sel;
wire   	[8:0] 	sine_table_out;
reg    [9:0]   sine_onecycle_amp;

assign sin_out = sine_onecycle_amp[9:0];
 
assign sel = phase[7:6];
 
sin_table u_sin_table(
				.address(address),
				.sin(sine_table_out)
				);
 
always @(sel or sine_table_out or phase)
begin
	case(sel)
	2'b00: 	begin
			sine_onecycle_amp =  9'h1ff+sine_table_out[8:0];
			address = phase[5:0];
	     	end
  	2'b01: 	begin 
			sine_onecycle_amp =  9'h1ff+sine_table_out[8:0];
			address = ~phase[5:0];
	     	end
  	2'b10: 	begin
			sine_onecycle_amp =  9'h1ff- sine_table_out[8:0];
			address = phase[5:0];
     		end
  	2'b11: 	begin
			sine_onecycle_amp =  9'h1ff- sine_table_out[8:0];
			address = ~ phase[5:0];
     		end
	endcase
end
 
endmodule

这里sintable记录了正弦波的1/4波型的离散值,共64个点。当一个指定频率的波需要查询当前时间点的值时,在looktable使用8位地址(其中高两位来判断在播的那个位置)来找出波的值。

module wave(
	input clk,
	input rst,
	input enable,
	output reg  [9:0] waveout
);
	
	parameter FREQ = 24'd366;   //C1 261.63Hz 时钟12MHz =(261.63*2**24)/12000000
	reg [23:0] phase_acc;
	wire  [9:0] sinout;

	always @(posedge clk or negedge rst)  
		if(!rst)
			phase_acc <= 0;
		else
			phase_acc <= phase_acc + FREQ;

		
	always@(posedge clk or negedge rst)
		if(!rst)
			waveout <=0;
		else if(!enable)
			waveout <= sinout;
		else
			waveout <= 0;
	
	look_table u0_table(
			.phase(phase_acc[23:16]), 
			.sin_out(sinout)
			);

endmodule		

核心部分wave这个模块,用来获得一个具体的正弦波。波的频率由参FREQ决定。频率计算公式:输入值=(波的频率值*2^24)/12000000 。
这里用apio做模拟,获得532.25Hz(do,输入值744)的波形。正弦波还是挺漂亮的!(这里需要留意,因为apio模拟程序的限制,clk无法输入小于1的值,导致波的周期时间不对)Fstwfq4eLZCms4Ozxf3pqQQyVVzw

有了正玄波,仅仅是能够表达正确的频率。我们能够准确地分辨各种乐器的演奏,是因为除了制定频率的波之外还有个谐波。谐波的频率是基波的整数倍。在本项目中,我使用2倍频率作为谐波,并且做了适当的弱化(*0.6)。仿真图如下。

Fo3qWFQcL8E6Ya7yieU0CqKrCGc0

按题目要求,当多按键按下时,必须同时产生多个按键对应频率的波。所以这里还需要处理多个波的信号的叠加。模块synthesizer就是将多个波形进行叠加输出。这里是叠加了 532.25Hz,659.25Hz,783.995Hz(do,mi,so)三条波形。
Fq4XCz5LlYaF8k8yzLUQBNSXW0aR

输出:信号最终是要由扬声器(蜂鸣器)做展示。但是小脚丫的输出管脚输出的只能是0、1的数字信号,这里就需要使用PWM通过对占空比的控制来获得到一个直流分量。PWM波自身有一个频率,通过占空比的改变来形成正弦波的输出。质量就要求PWM的频率远大于输入的正弦波的频率。
FhYUWFr4GhXV-cxAHKR2tgYodZGS

这里的输出本质上依然是高低电平。高低电平作用于蜂鸣器和扬声器还是有区别的。观察电路图可以发现,蜂鸣器是小脚丫的输出管脚使用一个三极管S8050直接驱动;而扬声器还经历了一个R-2R DAC的转换然后在由放大器8002B来驱动扬声器的。R-2R DAC将数字信号转换为模拟信号,但是R-2R电路我没看太懂。这块我的基本理解就是扬声器使用了变化的电压作为输入信号,蜂鸣器使用的是1/0持续的时间来模拟电压的信号量。这里导致的结果就是,扬声器听上去声音比较好,失真小。而蜂鸣器就声音非常小,几乎到了听不见的程度。

FhKLOvkaH_dXHC960xlRpICVTsdV

module pwm
(
    input					clk,
    input					rst,
    input		[10:0]		duty,	
    output					pwm_out
);

    reg [11:0] PWM_accumulator0;
    always @(posedge clk or negedge rst)
    	if(!rst)
    		PWM_accumulator0 <= 0;
    	else
    		PWM_accumulator0 <= PWM_accumulator0[10:0] + duty;
    assign pwm_out = PWM_accumulator0[11];
endmodule

PWM转换这里使用的是1阶的sigma-delta调制。在保证占空比的前提下尽可能采用更高的脉冲频率,尽可能地提高了DAC的转换频率,减少了对合成频率的频段内的混叠。但是任何输出的PWM波中,总是包含着两个频率的信息,只是一个频率较高,无法听见而已。

最后top模块将各个模块进行整合,分配管脚。通过两个状态变量,来记录功能键的信息。将当前状态信息通过LED灯展示出来。13个琴键,按高低音切换状态信息,来决定左补6位还是右补6位。然后按输出状态开关来决定是送到蜂鸣器还是扬声器。(项目地址:https://www.stepfpga.com/project/3329/)

Fk6oo-URs9pr3tqb8B9DR5vBe77OFgtlrBFRXEvXdPPhUK13psTcSM8h

run.log
--- Lattice Diamond Version 3.7.0.96.1
--- Copyright (C) 1992-2016 Lattice Semiconductor Corporation.
--- All Rights Reserved.
--- Lattice Diamond install path: 3.7_x64
--- Start Time: Sat Aug 20 09:37:29 2022
WARNING - Create a new implementation in an existing sub-directory 'implement'.

synthesis -f "PRJ_3329_implement_lattice.synproj"
synthesis: version Diamond (64-bit) 3.7.0.96.1

Copyright (c) 1991-1994 by NeoCAD Inc. All rights reserved.
Copyright (c) 1995 AT&T Corp. All rights reserved.
Copyright (c) 1995-2001 Lucent Technologies Inc. All rights reserved.
Copyright (c) 2001 Agere Systems All rights reserved.
Copyright (c) 2002-2016 Lattice Semiconductor Corporation, All rights reserved.
Sat Aug 20 09:37:30 2022


Command Line: synthesis -f PRJ_3329_implement_lattice.synproj

INFO - synthesis: Lattice Synthesis Engine Launched.
Synthesis options:
The -a option is MachXO2.
The -s option is 5.
The -t option is CSBGA132.
The -d option is LCMXO2-4000HC.
Using package CSBGA132.
Using performance grade 5.


##########################################################

### Lattice Family : MachXO2

### Device : LCMXO2-4000HC

### Package : CSBGA132

### Speed : 5

##########################################################



Optimization goal = Balanced
The -top option is not used.
Target frequency = 1.000000 MHz.
Maximum fanout = 1000.
Timing path count = 3
BRAM utilization = 100.000000 %
DSP usage = true
DSP utilization = 100.000000 %
fsm_encoding_style = auto
resolve_mixed_drivers = 0
fix_gated_clocks = 1

Mux style = Auto
Use Carry Chain = true
carry_chain_length = 0
Loop Limit = 1950.
Use IO Insertion = TRUE
Use IO Reg = AUTO

Resource Sharing = TRUE
Propagate Constants = TRUE
Remove Duplicate Registers = TRUE
force_gsr = auto
ROM style = auto
RAM style = auto
The -comp option is FALSE.
The -syn option is FALSE.
-p 3329 (searchpath added)
-p data (searchpath added)
-p implement (searchpath added)
-p 3329 (searchpath added)
Verilog design file = clk_quarter.v
Verilog design file = debounce.v
Verilog design file = looktable.v
Verilog design file = pwm.v
Verilog design file = sintable.v
Verilog design file = synthesizer.v
Verilog design file = top.v
Verilog design file = wave.v
NGD file = PRJ_3329_implement.ngd
-sdc option: SDC file input not used.
-lpf option: Output file option is ON.
Hardtimer checking is enabled (default). The -dt option is not used.
The -r option is OFF. [ Remove LOC Properties is OFF. ]
WARNING - synthesis: Setting top as the top-level module. To specify the top-level module explicitly, use the -top option.
Technology check ok...

Analyzing Verilog file machxo2.v. VERI-1482
Compile design.
Compile Design Begin
Analyzing Verilog file clk_quarter.v. VERI-1482
Analyzing Verilog file debounce.v. VERI-1482
Analyzing Verilog file looktable.v. VERI-1482
Analyzing Verilog file pwm.v. VERI-1482
Analyzing Verilog file sintable.v. VERI-1482
Analyzing Verilog file synthesizer.v. VERI-1482
Analyzing Verilog file top.v. VERI-1482
Analyzing Verilog file wave.v. VERI-1482
Analyzing Verilog file machxo2.v. VERI-1482
Top module name (Verilog): top
INFO - synthesis: top.v(1): compiling module top. VERI-1018
INFO - synthesis: clk_quarter.v(18): compiling module clk_quarter. VERI-1018
INFO - synthesis: debounce.v(18): compiling module debounce(N=13). VERI-1018
INFO - synthesis: debounce.v(18): compiling module debounce. VERI-1018
INFO - synthesis: pwm.v(18): compiling module pwm. VERI-1018
INFO - synthesis: synthesizer.v(1): compiling module synthesizer. VERI-1018
INFO - synthesis: wave.v(1): compiling module wave(FREQ=461). VERI-1018
WARNING - synthesis: wave.v(16): expression size 32 truncated to fit in target size 24. VERI-1209
INFO - synthesis: looktable.v(2): compiling module look_table. VERI-1018
INFO - synthesis: sintable.v(1): compiling module sin_table. VERI-1018
INFO - synthesis: wave.v(1): compiling module wave(FREQ=488). VERI-1018
WARNING - synthesis: wave.v(16): expression size 32 truncated to fit in target size 24. VERI-1209
INFO - synthesis: wave.v(1): compiling module wave(FREQ=548). VERI-1018
WARNING - synthesis: wave.v(16): expression size 32 truncated to fit in target size 24. VERI-1209
INFO - synthesis: wave.v(1): compiling module wave(FREQ=615). VERI-1018
WARNING - synthesis: wave.v(16): expression size 32 truncated to fit in target size 24. VERI-1209
INFO - synthesis: wave.v(1): compiling module wave(FREQ=690). VERI-1018
WARNING - synthesis: wave.v(16): expression size 32 truncated to fit in target size 24. VERI-1209
INFO - synthesis: wave.v(1): compiling module wave(FREQ=744). VERI-1018
WARNING - synthesis: wave.v(16): expression size 32 truncated to fit in target size 24. VERI-1209
INFO - synthesis: wave.v(1): compiling module wave(FREQ=821). VERI-1018
WARNING - synthesis: wave.v(16): expression size 32 truncated to fit in target size 24. VERI-1209
INFO - synthesis: wave.v(1): compiling module wave(FREQ=922). VERI-1018
WARNING - synthesis: wave.v(16): expression size 32 truncated to fit in target size 24. VERI-1209
INFO - synthesis: wave.v(1): compiling module wave(FREQ=977). VERI-1018
WARNING - synthesis: wave.v(16): expression size 32 truncated to fit in target size 24. VERI-1209
INFO - synthesis: wave.v(1): compiling module wave(FREQ=1096). VERI-1018
WARNING - synthesis: wave.v(16): expression size 32 truncated to fit in target size 24. VERI-1209
INFO - synthesis: wave.v(1): compiling module wave(FREQ=1230). VERI-1018
WARNING - synthesis: wave.v(16): expression size 32 truncated to fit in target size 24. VERI-1209
INFO - synthesis: wave.v(1): compiling module wave(FREQ=1381). VERI-1018
WARNING - synthesis: wave.v(16): expression size 32 truncated to fit in target size 24. VERI-1209
INFO - synthesis: wave.v(1): compiling module wave(FREQ=1463). VERI-1018
WARNING - synthesis: wave.v(16): expression size 32 truncated to fit in target size 24. VERI-1209
INFO - synthesis: wave.v(1): compiling module wave(FREQ=1642). VERI-1018
WARNING - synthesis: wave.v(16): expression size 32 truncated to fit in target size 24. VERI-1209
INFO - synthesis: wave.v(1): compiling module wave(FREQ=1843). VERI-1018
WARNING - synthesis: wave.v(16): expression size 32 truncated to fit in target size 24. VERI-1209
INFO - synthesis: wave.v(1): compiling module wave(FREQ=1953). VERI-1018
WARNING - synthesis: wave.v(16): expression size 32 truncated to fit in target size 24. VERI-1209
INFO - synthesis: wave.v(1): compiling module wave(FREQ=2192). VERI-1018
WARNING - synthesis: wave.v(16): expression size 32 truncated to fit in target size 24. VERI-1209
INFO - synthesis: wave.v(1): compiling module wave(FREQ=2641). VERI-1018
WARNING - synthesis: wave.v(16): expression size 32 truncated to fit in target size 24. VERI-1209
INFO - synthesis: wave.v(1): compiling module wave(FREQ=2762). VERI-1018
WARNING - synthesis: wave.v(16): expression size 32 truncated to fit in target size 24. VERI-1209
INFO - synthesis: wave.v(1): compiling module wave(FREQ=1488). VERI-1018
WARNING - synthesis: wave.v(16): expression size 32 truncated to fit in target size 24. VERI-1209
INFO - synthesis: wave.v(1): compiling module wave(FREQ=2461). VERI-1018
WARNING - synthesis: wave.v(16): expression size 32 truncated to fit in target size 24. VERI-1209
INFO - synthesis: wave.v(1): compiling module wave(FREQ=2926). VERI-1018
WARNING - synthesis: wave.v(16): expression size 32 truncated to fit in target size 24. VERI-1209
INFO - synthesis: wave.v(1): compiling module wave(FREQ=3285). VERI-1018
WARNING - synthesis: wave.v(16): expression size 32 truncated to fit in target size 24. VERI-1209
INFO - synthesis: wave.v(1): compiling module wave(FREQ=3687). VERI-1018
WARNING - synthesis: wave.v(16): expression size 32 truncated to fit in target size 24. VERI-1209
INFO - synthesis: wave.v(1): compiling module wave(FREQ=3906). VERI-1018
WARNING - synthesis: wave.v(16): expression size 32 truncated to fit in target size 24. VERI-1209
INFO - synthesis: wave.v(1): compiling module wave(FREQ=3384). VERI-1018
WARNING - synthesis: wave.v(16): expression size 32 truncated to fit in target size 24. VERI-1209
INFO - synthesis: wave.v(1): compiling module wave(FREQ=4921). VERI-1018
WARNING - synthesis: wave.v(16): expression size 32 truncated to fit in target size 24. VERI-1209
INFO - synthesis: wave.v(1): compiling module wave(FREQ=5524). VERI-1018
WARNING - synthesis: wave.v(16): expression size 32 truncated to fit in target size 24. VERI-1209
ERROR - synthesis: synthesizer.v(82): illegal operation with real number. VERI-1044

资源使用情况:还不太会看这个列表,待学习。

Design Summary:
   Number of registers:   1221 out of  4635 (26%)
      PFU registers:         1221 out of  4320 (28%)
      PIO registers:            0 out of   315 (0%)
   Number of SLICEs:      2021 out of  2160 (94%)
      SLICEs as Logic/ROM:   2021 out of  2160 (94%)
      SLICEs as RAM:            0 out of  1620 (0%)
      SLICEs as Carry:       1000 out of  2160 (46%)
   Number of LUT4s:        4036 out of  4320 (93%)
      Number used as logic LUTs:        2036
      Number used as distributed RAM:     0
      Number used as ripple logic:      2000
      Number used as shift registers:     0
   Number of PIO sites used: 23 + 4(JTAG) out of 105 (26%)
   Number of block RAMs:  0 out of 10 (0%)
   Number of GSRs:        1 out of 1 (100%)
   EFB used :        No
   JTAG used :       No
   Readback used :   No
   Oscillator used : No
   Startup used :    No
   POR :             On
   Bandgap :         On
   Number of Power Controller:  0 out of 1 (0%)
   Number of Dynamic Bank Controller (BCINRD):  0 out of 6 (0%)
   Number of Dynamic Bank Controller (BCLVDSO):  0 out of 1 (0%)
   Number of DCCA:  0 out of 8 (0%)
   Number of DCMA:  0 out of 2 (0%)
   Number of PLLs:  0 out of 2 (0%)
   Number of DQSDLLs:  0 out of 2 (0%)
   Number of CLKDIVC:  0 out of 4 (0%)
   Number of ECLKSYNCA:  0 out of 4 (0%)
   Number of ECLKBRIDGECS:  0 out of 2 (0%)
   Notes:-
      1. Total number of LUT4s = (Number of logic LUT4s) + 2*(Number of distributed RAMs) + 2*(Number of ripple logic)
      2. Number of logic LUT4s does not include count of distributed RAM and ripple logic.
   Number of clocks:  2
     Net clk_c: 674 loads, 674 rising, 0 falling (Driver: PIO clk )
     Net clk_4Hz: 5 loads, 5 rising, 0 falling (Driver: clk_inst/clk_out_12 )
   Number of Clock Enables:  2
     Net debounce_k13/clk_c_enable_1: 1 loads, 1 LSLICEs
     Net debounce_k14/clk_c_enable_2: 1 loads, 1 LSLICEs
   Number of LSRs:  21
     Net pos_7__N_64: 5 loads, 5 LSLICEs
     Net wave_in_4: 12 loads, 12 LSLICEs
     Net wave_in_6: 12 loads, 12 LSLICEs
     Net wave_in_7: 12 loads, 12 LSLICEs
     Net wave_in_1: 12 loads, 12 LSLICEs
     Net wave_in_8: 12 loads, 12 LSLICEs
     Net wave_in_10: 12 loads, 12 LSLICEs
     Net wave_in_0: 12 loads, 12 LSLICEs
     Net debounce_k13/key_edge_0: 10 loads, 10 LSLICEs
     Net clk_inst/counter_31__N_131: 17 loads, 17 LSLICEs
     Net wave_in_2: 12 loads, 12 LSLICEs
     Net wave_in_9: 12 loads, 12 LSLICEs
     Net wave_in_11: 12 loads, 12 LSLICEs
     Net wave_in_3: 12 loads, 12 LSLICEs
     Net wave_in_16: 12 loads, 12 LSLICEs
     Net wave_in_18: 12 loads, 12 LSLICEs
     Net wave_in_13: 12 loads, 12 LSLICEs
     Net wave_in_14: 12 loads, 12 LSLICEs
     Net wave_in_17: 12 loads, 12 LSLICEs
     Net wave_in_15: 12 loads, 12 LSLICEs
     Net debounce_k14/key_edge_0: 10 loads, 10 LSLICEs
   Number of nets driven by tri-state buffers:  0
   Top 10 highest fanout non-clock nets:
     Net synthesizer_u0/n11086: 61 loads
     Net synthesizer_u0/n11071: 60 loads
     Net synthesizer_u0/n11073: 58 loads
     Net synthesizer_u0/n19351: 58 loads
     Net synthesizer_u0/n11079: 56 loads
     Net synthesizer_u0/n19358: 56 loads
     Net synthesizer_u0/n11078: 54 loads
     Net synthesizer_u0/n19367: 54 loads
     Net synthesizer_u0/n11077: 52 loads
     Net synthesizer_u0/n19375: 52 loads
 

   Number of warnings:  0
   Number of errors:    0



Total CPU Time: 1 secs  
Total REAL Time: 2 secs  
Peak Memory Usage: 74 MB

Flq7vZ0i4kmt9lLibIampb0O0u1T

遇到的问题及解决方法

FPGA编程真难。Diamond软件真的很不友好,错误提示完全不明就里。Verilog中的并行概念非常有意思,自己的先入为主,按着经验推测代码都是顺序执行的,结果让自己卡了很久,在各位老师的解释下才明白,FPGA中的并行执行。自动播放音乐部分想用模块实现,可要么报错,要么无法实现功能,无奈下只能放在top模块中了。感觉入门FPGA还是挺艰辛 的,感谢硬禾学堂的课程和电子森林的教程,自己的学习道路才刚刚开始。在群里讨论中,还有几个思路还没有去尝试:谐波使用波表来解决,就是在查表时就将谐波信息写入,但添加了谐波的正弦波对称性就破坏了,使用四分之一波表应该是不行了,感觉要使用二分之一波表才够用。IP核编程,群里老师介绍,可以将模块功能放置在ip核中,还没太明白怎么做,后续需要继续尝试一下。

附件下载
archive.zip
implement.jed
团队介绍
折腾小能手
团队成员
aramy
单片机业余爱好者,瞎捣鼓小能手。
评论
0 / 100
查看更多
目录
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2023 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号