fpga项目:i2s dac自己仿写(驱动PCM5102A) - minichao9901/TangNano-20k-Zynq-7020 GitHub Wiki
草稿画时序图
开始写代码
- 时钟:例化pll产生6MHz,进一步手写4分频产生1.5MHz。理论时钟需求是48kHz*32=1.536MHz,差不多就行了。
- sin_rom模块:用256深度的case语句产生。用excel表产生。注意负数的补码转换公式为:-x+65536。例如-701的补码为-701+65536=64835
- i2s_drv模块:按时序图手写,很简单。注意时序对齐,注意i2s_ws信号要提前i2s_din一拍,这是i2s标准协议要求
- i2s_top模块,将这几个模块连起来。
rom模块生成excel表
代码
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 2023/12/17 20:12:20
// Design Name:
// Module Name: i2s_drv
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module i2s_drv(
input clk_1p5m,
input rst_n,
input [15:0] idata,
output reg req,
output i2s_din,
output reg i2s_ws
);
reg [4:0] cnt;
reg [15:0] idata_r;
reg req_r;
//cnt
always @(posedge clk_1p5m or negedge rst_n)
if(rst_n==0)
cnt<=0;
else
cnt<=cnt+1;
//req
always @(posedge clk_1p5m or negedge rst_n)
if(rst_n==0)
req<=0;
else if(cnt==0 || cnt==16)
req<=1;
else
req<=0;
//req_r
always @(posedge clk_1p5m or negedge rst_n)
if(rst_n==0)
req_r<=0;
else
req_r<=req;
//idata_r
always @(posedge clk_1p5m or negedge rst_n)
if(rst_n==0)
idata_r<=0;
else if(req_r==1)
idata_r<=idata; //reload data
else
idata_r<=idata_r<<1; //begin to shift
//i2s_din
assign i2s_din=idata_r[15];
//i2s_ws
always @(*)
if(cnt>=2 && cnt<18)
i2s_ws=0;
else
i2s_ws=1;
endmodule
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 2023/12/17 20:13:28
// Design Name:
// Module Name: rom_sine
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module rom_sine(
input clk,
input rst_n,
input [7:0] addr,
output reg [15:0] data
);
always @(posedge clk or negedge rst_n)
if(rst_n==0)
data<=0;
else
case(addr)
0 : data<= 16'd0;
1 : data<= 16'd764;
2 : data<= 16'd1527;
3 : data<= 16'd2290;
4 : data<= 16'd3051;
5 : data<= 16'd3811;
6 : data<= 16'd4568;
7 : data<= 16'd5322;
8 : data<= 16'd6073;
9 : data<= 16'd6821;
10 : data<= 16'd7564;
11 : data<= 16'd8303;
12 : data<= 16'd9036;
13 : data<= 16'd9765;
14 : data<= 16'd10487;
15 : data<= 16'd11203;
16 : data<= 16'd11913;
17 : data<= 16'd12615;
18 : data<= 16'd13310;
19 : data<= 16'd13996;
20 : data<= 16'd14674;
21 : data<= 16'd15344;
22 : data<= 16'd16004;
23 : data<= 16'd16654;
24 : data<= 16'd17295;
25 : data<= 16'd17925;
26 : data<= 16'd18544;
27 : data<= 16'd19152;
28 : data<= 16'd19748;
29 : data<= 16'd20333;
30 : data<= 16'd20905;
31 : data<= 16'd21465;
32 : data<= 16'd22012;
33 : data<= 16'd22546;
34 : data<= 16'd23066;
35 : data<= 16'd23572;
36 : data<= 16'd24064;
37 : data<= 16'd24541;
38 : data<= 16'd25004;
39 : data<= 16'd25451;
40 : data<= 16'd25883;
41 : data<= 16'd26300;
42 : data<= 16'd26701;
43 : data<= 16'd27085;
44 : data<= 16'd27454;
45 : data<= 16'd27806;
46 : data<= 16'd28141;
47 : data<= 16'd28459;
48 : data<= 16'd28760;
49 : data<= 16'd29044;
50 : data<= 16'd29310;
51 : data<= 16'd29558;
52 : data<= 16'd29789;
53 : data<= 16'd30002;
54 : data<= 16'd30197;
55 : data<= 16'd30373;
56 : data<= 16'd30531;
57 : data<= 16'd30671;
58 : data<= 16'd30793;
59 : data<= 16'd30895;
60 : data<= 16'd30980;
61 : data<= 16'd31045;
62 : data<= 16'd31092;
63 : data<= 16'd31120;
64 : data<= 16'd31130;
65 : data<= 16'd31120;
66 : data<= 16'd31092;
67 : data<= 16'd31045;
68 : data<= 16'd30980;
69 : data<= 16'd30895;
70 : data<= 16'd30793;
71 : data<= 16'd30671;
72 : data<= 16'd30531;
73 : data<= 16'd30373;
74 : data<= 16'd30197;
75 : data<= 16'd30002;
76 : data<= 16'd29789;
77 : data<= 16'd29558;
78 : data<= 16'd29310;
79 : data<= 16'd29044;
80 : data<= 16'd28760;
81 : data<= 16'd28459;
82 : data<= 16'd28141;
83 : data<= 16'd27806;
84 : data<= 16'd27454;
85 : data<= 16'd27085;
86 : data<= 16'd26701;
87 : data<= 16'd26300;
88 : data<= 16'd25883;
89 : data<= 16'd25451;
90 : data<= 16'd25004;
91 : data<= 16'd24541;
92 : data<= 16'd24064;
93 : data<= 16'd23572;
94 : data<= 16'd23066;
95 : data<= 16'd22546;
96 : data<= 16'd22012;
97 : data<= 16'd21465;
98 : data<= 16'd20905;
99 : data<= 16'd20333;
100 : data<= 16'd19748;
101 : data<= 16'd19152;
102 : data<= 16'd18544;
103 : data<= 16'd17925;
104 : data<= 16'd17295;
105 : data<= 16'd16654;
106 : data<= 16'd16004;
107 : data<= 16'd15344;
108 : data<= 16'd14674;
109 : data<= 16'd13996;
110 : data<= 16'd13310;
111 : data<= 16'd12615;
112 : data<= 16'd11913;
113 : data<= 16'd11203;
114 : data<= 16'd10487;
115 : data<= 16'd9765;
116 : data<= 16'd9036;
117 : data<= 16'd8303;
118 : data<= 16'd7564;
119 : data<= 16'd6821;
120 : data<= 16'd6073;
121 : data<= 16'd5322;
122 : data<= 16'd4568;
123 : data<= 16'd3811;
124 : data<= 16'd3051;
125 : data<= 16'd2290;
126 : data<= 16'd1527;
127 : data<= 16'd764;
128 : data<= 16'd0;
129 : data<= 16'd64772;
130 : data<= 16'd64009;
131 : data<= 16'd63246;
132 : data<= 16'd62485;
133 : data<= 16'd61725;
134 : data<= 16'd60968;
135 : data<= 16'd60214;
136 : data<= 16'd59463;
137 : data<= 16'd58715;
138 : data<= 16'd57972;
139 : data<= 16'd57233;
140 : data<= 16'd56500;
141 : data<= 16'd55771;
142 : data<= 16'd55049;
143 : data<= 16'd54333;
144 : data<= 16'd53623;
145 : data<= 16'd52921;
146 : data<= 16'd52226;
147 : data<= 16'd51540;
148 : data<= 16'd50862;
149 : data<= 16'd50192;
150 : data<= 16'd49532;
151 : data<= 16'd48882;
152 : data<= 16'd48241;
153 : data<= 16'd47611;
154 : data<= 16'd46992;
155 : data<= 16'd46384;
156 : data<= 16'd45788;
157 : data<= 16'd45203;
158 : data<= 16'd44631;
159 : data<= 16'd44071;
160 : data<= 16'd43524;
161 : data<= 16'd42990;
162 : data<= 16'd42470;
163 : data<= 16'd41964;
164 : data<= 16'd41472;
165 : data<= 16'd40995;
166 : data<= 16'd40532;
167 : data<= 16'd40085;
168 : data<= 16'd39653;
169 : data<= 16'd39236;
170 : data<= 16'd38835;
171 : data<= 16'd38451;
172 : data<= 16'd38082;
173 : data<= 16'd37730;
174 : data<= 16'd37395;
175 : data<= 16'd37077;
176 : data<= 16'd36776;
177 : data<= 16'd36492;
178 : data<= 16'd36226;
179 : data<= 16'd35978;
180 : data<= 16'd35747;
181 : data<= 16'd35534;
182 : data<= 16'd35339;
183 : data<= 16'd35163;
184 : data<= 16'd35005;
185 : data<= 16'd34865;
186 : data<= 16'd34743;
187 : data<= 16'd34641;
188 : data<= 16'd34556;
189 : data<= 16'd34491;
190 : data<= 16'd34444;
191 : data<= 16'd34416;
192 : data<= 16'd34406;
193 : data<= 16'd34416;
194 : data<= 16'd34444;
195 : data<= 16'd34491;
196 : data<= 16'd34556;
197 : data<= 16'd34641;
198 : data<= 16'd34743;
199 : data<= 16'd34865;
200 : data<= 16'd35005;
201 : data<= 16'd35163;
202 : data<= 16'd35339;
203 : data<= 16'd35534;
204 : data<= 16'd35747;
205 : data<= 16'd35978;
206 : data<= 16'd36226;
207 : data<= 16'd36492;
208 : data<= 16'd36776;
209 : data<= 16'd37077;
210 : data<= 16'd37395;
211 : data<= 16'd37730;
212 : data<= 16'd38082;
213 : data<= 16'd38451;
214 : data<= 16'd38835;
215 : data<= 16'd39236;
216 : data<= 16'd39653;
217 : data<= 16'd40085;
218 : data<= 16'd40532;
219 : data<= 16'd40995;
220 : data<= 16'd41472;
221 : data<= 16'd41964;
222 : data<= 16'd42470;
223 : data<= 16'd42990;
224 : data<= 16'd43524;
225 : data<= 16'd44071;
226 : data<= 16'd44631;
227 : data<= 16'd45203;
228 : data<= 16'd45788;
229 : data<= 16'd46384;
230 : data<= 16'd46992;
231 : data<= 16'd47611;
232 : data<= 16'd48241;
233 : data<= 16'd48882;
234 : data<= 16'd49532;
235 : data<= 16'd50192;
236 : data<= 16'd50862;
237 : data<= 16'd51540;
238 : data<= 16'd52226;
239 : data<= 16'd52921;
240 : data<= 16'd53623;
241 : data<= 16'd54333;
242 : data<= 16'd55049;
243 : data<= 16'd55771;
244 : data<= 16'd56500;
245 : data<= 16'd57233;
246 : data<= 16'd57972;
247 : data<= 16'd58715;
248 : data<= 16'd59463;
249 : data<= 16'd60214;
250 : data<= 16'd60968;
251 : data<= 16'd61725;
252 : data<= 16'd62485;
253 : data<= 16'd63246;
254 : data<= 16'd64009;
255 : data<= 16'd64772;
endcase
endmodule
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 2023/12/17 20:47:04
// Design Name:
// Module Name: i2s_top
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module i2s_top(
input clk,
input rst_n,
output i2s_clk,
output i2s_din,
output i2s_ws
);
wire clk_6m;
reg [1:0] cnt;
wire clk_1p5m;
wire [15:0] sine_data;
reg [7:0] addr;
wire req_r;
assign i2s_clk=clk_1p5m;
clk_wiz_0 instance_name
(
.clk_out1(clk_6m), // output clk_out1
.reset(~rst_n), // input reset
.clk_in1(clk)); // input clk_in1
//clk_1p5m
always @(posedge clk_6m or negedge rst_n)
if(rst_n==0)
cnt<=0;
else
cnt<=cnt+1;
assign clk_1p5m=(cnt<=1)? 1:0;
i2s_drv u_i2s_dev(
.clk_1p5m(clk_1p5m),
.rst_n(rst_n),
.idata(sine_data),
.req(req_r),
.i2s_din(i2s_din),
.i2s_ws(i2s_ws)
);
//addr
always @(posedge clk_1p5m or negedge rst_n)
if(rst_n==0)
addr<=0;
else if(req_r)
addr<=addr+1;
else
addr<=addr;
rom_sine u_rom_sine(
.clk(clk),
.rst_n(rst_n),
.addr(addr),
.data(sine_data)
);
endmodule
`timescale 1ns/1ns
module test;
reg clk;
reg rst_n;
initial begin
rst_n=0;
#1000;
rst_n=1;
end
initial begin
clk=0;
forever #10 clk=~clk;
end
i2s_top u_i2s_top(
.clk(clk),
.rst_n(rst_n)
);
endmodule
z7-nano管脚约束
create_clock -period 20.000 [get_ports clk]
set_property -dict {PACKAGE_PIN N18 IOSTANDARD LVCMOS33} [get_ports clk]
set_property -dict {PACKAGE_PIN P14 IOSTANDARD LVCMOS33} [get_ports rst_n]
set_property -dict {PACKAGE_PIN G15 IOSTANDARD LVCMOS33} [get_ports i2s_din]
set_property -dict {PACKAGE_PIN F17 IOSTANDARD LVCMOS33} [get_ports i2s_clk]
set_property -dict {PACKAGE_PIN D18 IOSTANDARD LVCMOS33} [get_ports i2s_ws]
测试效果