oe_data_in16(data_bank),//初始化系数的数据输入端
136 .wr_coe_addr(~wr_blk_addr[3:0]),//初始化系数的地址输入端
137 ////!!!特别注意这里,乘加时数据从大地址进入乘加操作,因此地址要求补码,将系数翻转过来。相当于:fliplr();!!!!!//
138 .wr_coe_clk(clk),//初始化系数写入时钟
139 .wr_coe_en(csh2),//系数配置的使能端,由初始化模块地址译码产生,方便不同系数blk的选通
140 .start(start),//输入的启动卷积和fir的控制端
141 .shft_out_dp_data(shft_data3[15:0]),
142 .s_latch(conv_res3[39:0])
143 );
144 CONV_SER16 i_conv_ser16_IV(//例化第4个16阶卷积/fir电路
145 .clk(clk),
146 .a(shft_data3[15:0]),//由级联的第一节移出的数据
147 .en(rdy_work),//系数配置完成后才能使能
148 .coe_data_in16(data_bank),//初始化系数的数据输入端
149 .wr_coe_addr(~wr_blk_addr[3:0]),//初始化系数的地址输入端
150 ////!!!特别注意这里,乘加时数据从大地址进入乘加操作,因此地址要求补码,将系数翻转过来。相当于:fliplr();!!!!!//
151 .wr_coe_clk(clk),//初始化系数写入时钟
152 .wr_coe_en(csh3),//系数配置的使能端,由初始化模块地址译码产生,方便不同系数blk的选通
153 .start(start),//输入的启动卷积和fir的控制端
154 .shft_out_dp_data(shft_data4[15:0]),
155 .s_latch(conv_res4[39:0])
156 );
157 PADD i_PADD (//为了方便DA输出将所有输出偏置为正数
158 .clock ( start ),
159 .data0x ( conv_res1[31:0] ),
160 .data1x ( conv_res2[31:0] ),
161 .data2x ( conv_res3[31:0] ),
162 .data3x ( conv_res4[31:0] ),
163 .result ( acc_sum[33:0] )
164 );
165
166 MCP4822 i_mcp4822(.clk100m(clk),
167 .rst_n(rdy_work),
168 .start(start),
169 .dac_data_a(data_cha),//通道a输出的数据
170 //.dac_data_b(dds_data12),//通道b连接DDS内容
171 //.dac_data_b(product12),//通道b连接乘法的高12位
172 //.dac_data_b(conv_data12),//通道b连接卷积的结果
173 .dac_data_b(data_chb),//通道b输出的数据
174 .cs(cs_da),
175 .mosi(mosi_da),
176 .sck(sck_da),
177 .ld(ld_da)
178 );
179 MCP3202 i_mcp3202(
180 .clk100m(clk),
181 .rst_n(rdy_work),
182 .start(start),
183 .adc_data_a(ad_data),
184 .cs(cs_ad),
185 .mosi(mosi_ad),
186 .miso(miso_ad),
187 .sck(sck_ad)
188 );
189
190 sub_offset i_sub_offset (//这个减法器用于从AD结果中去除直流偏置,结果是16位补码
191 .dataa ( {4'd0,acc_sum[26:15]} ),//卷积结果用于计算
192 //.dataa ( {4'd0,ad_data[11:0]} ),//AD结果是正整数,只要补零就可以得到16位补码
193 .datab ( 16'h0000 ),//直流偏置认为是1/2满幅度16'h0800,没有直流偏置则为16'h0000
194 .result ( ac_sig[15:0] )//去除直流偏置以后的结果,是16bit补码
195 );
196
197 pow_cal i_pow_cal (//平方运算计算信号能量
198 .dataa ( ac_sig[15:0] ),
199 .result ( pow_sig[31:0] )
200 );
201
202 shft_reg i_shft_reg (//例化移位寄存器
203 .clock ( start ),
204 .shiftin ( pow_sig[31:0] ),
205 .shiftout ( shiftout[31:0] ),
206 .taps ( )
207 );
208 sub_add sub_add_inst (//减法器,用送入累加结果的数减去要从累加结果中拿出的数,结果有可能是负数
209 //减完后再送入累加器,以实现累加器内容的维护:最近64个数的和
210 .dataa ( pow_sig[31:0] ),
211 .datab ( shiftout[31:0]),
212 .result ( acc_in[31:0] )
213 );
214 ////////计算最近64个数的和/////////
215 always @ (posedge start or negedge rst_n)
216 begin
217 if(!rst_n)
218 acc_out[39:0] <= 40'd0;
219 else begin
220 acc_out[39:0] = $signed(acc_out[39:0]) + $signed(acc_in[31:0]);
221 end
222 end
223 ///////对累加和开方,提高小信号的分辨率
224 ip_sqrt ip_sqrt_inst (
225 .radical ( acc_out[39:0] ),
226 .q ( data_out[19:0] ),
227 .remainder ( )
228 );
229 endmodule
View Code
上述顶层设计文件中大部分内容是各个功能模块电路的例化和连接语句,由于代码注释很详细,具体细节就不在这里赘述了,我主要介绍以下几点:
1、 其中只有唯一的一个always过程赋值语句,该语句维护了计数器cnt[15:0]的工作。总的同步启动信号start产生在cnt[15:0]为某些具体值的时候,因此cnt[15:0]技术的周期也决定了start信号产生的周期,也就是信号的周期。
2、正如我在本系列的准备篇“用Verilog-HDL状态机控制硬件接口”所介绍的,使用A/D和D/A进行F |