数字信号处理——多速率信号处理(3)
以下是关于该Verilog代码的总结:
Verilog代码总结
模块结构
TBFIRFILTER: 主要负责整个系统的初始化配置和时钟同步。
FIR_FILTER: 实现了主FIR滤波器的功能。
- 使用多级加法器(如ADD1、“Add1”)和移存器(如MULRES1、“MULLEN1”)来完成乘法与累加操作。
- 系统通过逐位抽取输入数据并进行累加以实现低通滤波功能。
DATADCMMDL: 实现了下采样模块的功能。- 使用计数器控制数据抽取频率,并通过队列(FIFO)进行数据存储与输出。
数据流处理
输入数据经过主时钟(I_CLK)进入FIR滤波器模块。
每个时钟周期对输入数据进行一次抽样,并通过下采样模块进一步减少抽样率。
输出信号通过锁相环路(PLL)恢复主时钟频率(OTRDY),并在满足条件时触发(OTRDY)。
关键组件功能
多级加法器:用于逐位计算输入信号与滤波系数的乘积,并将结果累加到总和中。- 每一级加法器负责一个乘积项的计算,并将结果传递给下一级以完成累加操作。
移存器:用于延迟输入信号并为下一阶段提供正确的位对齐。- 移存器的数量根据所需 taps的数量决定(例如8 taps需要4级移存器)。
下采样模块:通过计数控制数据抽取频率,并使用队列确保输出符合主时钟频率的要求。
总体工作流程
初始化阶段:- I_RSTN置高使系统进入初始状态。
- I_CLK开始工作以启动各模块。
数据处理阶段:- 每个周期对输入数据进行一次抽样并进行相应的运算(包括乘法和累加)。
- 抽样的次数由下采样模块控制以减少抽样率。
输出阶段:- 当所有必要的计算完成并满足条件时(如所有 taps完成),触发输出信号(O_TRDY)。
仿真结果分析
仿真结果图显示了输入信号经过系统处理后的输出情况。虽然具体数值未给出,但可以通过以下几点验证设计的有效性:
输出信号应具有较低的频带内陷波带宽度(BWC),表明有效完成了低通滤波功能。
下采样过程应保持输出稳定且符合预期频率关系。
系统应在所有 taps完成后正确触发(O_TRDY)信号。后续内容提示
接下来将详细介绍FIR滤波器的设计步骤:
FIR滤波器系数生成与存储的设计与仿真;
系数读取与分发的具体实现;
下采样模块的设计细节;
全系统的关键测试点及仿真配置;
请继续关注后续内容!

目录
引言
总体设计结构
设计说明
设计框图
设计详述
FIR滤波器模块
时钟 IP
下采样模块
引言
本文接续前面几篇:
数字信号处理技术——多速率信息处理(1)
数字信号的处理技术——多速率信号的处理方法(2)
本研究及其后续内容主要聚焦于各设计阶段的代码开发。随后将详细阐述整体架构,并提供关键模块的代码和仿真结果。
总体设计结构
设计说明
本例程将实现一种高效的抽取滤波器。
设计框图

例程的总体设计框图如上:主要分为如下几个部分:
1、时钟IP模块,板上时钟为50MHz单端时钟,所以需要用此产生100MHz时钟和25MHz时钟。
2、DDS IP模块,用100MHz时钟作为采样时钟,产生1MHz的正弦信号。
3、ROM IP 和RAM IP模块联合用于FIR 滤波器系数的存储和分配。具体逻辑后续会说明。
4、抽取器模块主要分为3部分:
- FIR滤波器组:并行四路FIR滤波处理。
- 数据抽取模块:三级延迟器和并行四路下采样处理。
- 2级加法树模块:实现4路并行输出的求和。
设计详述
FIR滤波器模块
该模块的设计理念可借鉴参考我的过往文章中的直接型FIR滤波器设计。
数字信号处理技术——直接型有限冲激响应(FIR)数字滤波器的设计原理与实现方法(1)
此处也是在之前设计的基础上,对模块进行适当修改。具体源码:
> 1. `timescale 1ns / 1ps
>
> 2. // BY :Xu Y. B.( ID :在路上,正出发)
>
> 3. // 备注:1、实现直接型 实数FIR滤波器
>
> 4. // 2、数据随时钟上升沿移位送入
>
> 5. // 3、加法部分采样加法树流水结构
>
> 6. // 4、为方便加法计算,滤波器长度固定为2的整数次幂(此处以8为例)
>
> 7. // 5、此为示例,仅供参考
>
> 8.
>
> 9.
>
> 10. module FIR_FILTER #(
>
> 11. parameter P_FILTER_LEN = 8, //滤波器长度
>
> 12. parameter P_FILTER_WIDTH = 16, //滤波器系数位宽
>
> 13. parameter P_DATA_IN_WIDTH = 16, //输入数据位宽
>
> 14. parameter P_DATA_OUT_WIDTH = 32 //输出数据位宽
>
> 15. )(
>
> 16. // ----------------------------输入
>
> 17. input I_CLK, //10MHz
>
> 18. input I_RSTN,
>
> 19.
>
> 20. input I_DATA_VAL,
>
> 21. input [P_DATA_IN_WIDTH-1:0] I_DATA,
>
> 22. input I_COEF_VAL,
>
> 23. input [P_FILTER_WIDTH-1:0] I_COEF,
>
> 24.
>
> 25. // ----------------------------输出
>
> 26. output O_RES_VAL,
>
> 27. output [P_DATA_OUT_WIDTH-1:0] O_RES_DATA,
>
> 28. output O_TRDY
>
> 29. );
>
> 30.
>
> 31. // ----------------------------内部信号
>
> 32. // 乘加运算相关
>
> 33. // 乘法
>
> 34. reg [P_FILTER_WIDTH+P_DATA_IN_WIDTH-1:0] R_MULT_RES[P_FILTER_LEN-1:0]; //32个乘积输出
>
> 35. reg [P_FILTER_LEN-1:0] R_MULT_RES_VAL;//有效信号
>
> 36. // 加法
>
> 37. reg [P_FILTER_WIDTH+P_DATA_IN_WIDTH:0] R_ADD_1[P_FILTER_LEN/2-1:0]; //第一级加法树输出
>
> 38. reg [P_FILTER_WIDTH+P_DATA_IN_WIDTH+1:0] R_ADD_2[P_FILTER_LEN/4-1:0]; //第二级加法树输出
>
> 39. reg [P_FILTER_WIDTH+P_DATA_IN_WIDTH+2:0] R_ADD_3[P_FILTER_LEN/8-1:0]; //第三级加法树输出
>
> 40.
>
> 41.
>
> 42. // 输入移存相关
>
> 43. reg [P_DATA_IN_WIDTH-1:0] R_IN_SHIFT[P_FILTER_LEN-1:0]; //输入数据
>
> 44. reg [P_FILTER_LEN-1:0] R_IN_VAL_SHIFT; //有效信号R_IN_VAL_SHIFT[P_FILTER_LEN]
>
> 45.
>
> 46. // 系数移存相关
>
> 47. reg [P_FILTER_WIDTH-1:0] R_COEF_SHIFT[P_FILTER_LEN-1:0]; //系数
>
> 48. reg [P_FILTER_LEN-1:0] R_COEF_VAL_SHIFT; //有效信号
>
> 49.
>
> 50. // 输出
>
> 51. reg [4:0] R_RES_VAL;//输出有效信号
>
> 52.
>
> 53. // -----------------------------实现
>
> 54. // STEP1 :输入移存
>
> 55. // 数据
>
> 56.
>
> 57. always @ (posedge I_CLK)
>
> 58. begin
>
> 59. if(I_RSTN == 1'b0)
>
> 60. begin
>
> 61. R_IN_SHIFT[0] <= 0;
>
> 62. end
>
> 63. else
>
> 64. begin
>
> 65. if(I_DATA_VAL == 1'b1)
>
> 66. begin
>
> 67. R_IN_SHIFT[0] <= I_DATA;
>
> 68. end
>
> 69. else
>
> 70. begin
>
> 71. R_IN_SHIFT[0] <= R_IN_SHIFT[0];
>
> 72. end
>
> 73. end
>
> 74. end
>
> 75.
>
> 76. genvar GV_DATA_IN_SHIFT;
>
> 77. generate
>
> 78. for(GV_DATA_IN_SHIFT = 1;GV_DATA_IN_SHIFT < P_FILTER_LEN;GV_DATA_IN_SHIFT = GV_DATA_IN_SHIFT+1)
>
> 79. begin:DATA_IN_SHIFT
>
> 80. always @ (posedge I_CLK)
>
> 81. begin
>
> 82. if(I_RSTN == 1'b0)
>
> 83. begin
>
> 84. R_IN_SHIFT[GV_DATA_IN_SHIFT] <= 0;
>
> 85. end
>
> 86. else
>
> 87. if(I_DATA_VAL == 1)
>
> 88. begin
>
> 89. R_IN_SHIFT[GV_DATA_IN_SHIFT] <= R_IN_SHIFT[GV_DATA_IN_SHIFT-1];
>
> 90. end
>
> 91. else
>
> 92. begin
>
> 93. R_IN_SHIFT[GV_DATA_IN_SHIFT] <= R_IN_SHIFT[GV_DATA_IN_SHIFT];
>
> 94. end
>
> 95. end
>
> 96. end
>
> 97. endgenerate
>
> 98.
>
> 99. // 有效信号
>
> 100. always @ (posedge I_CLK)
>
> 101. begin
>
> 102. if(I_RSTN == 1'b0)
>
> 103. begin
>
> 104. R_IN_VAL_SHIFT[0] <= 1'b0;
>
> 105. end
>
> 106. else
>
> 107. begin
>
> 108. if(I_DATA_VAL == 1'b1)
>
> 109. begin
>
> 110. R_IN_VAL_SHIFT[0] <= I_DATA_VAL;
>
> 111. end
>
> 112. else
>
> 113. begin
>
> 114. R_IN_VAL_SHIFT[0] <= R_IN_VAL_SHIFT[0];
>
> 115. end
>
> 116. end
>
> 117. end
>
> 118.
>
> 119. genvar GV_VAL_IN_SHIFT;
>
> 120. generate
>
> 121. for(GV_VAL_IN_SHIFT = 1;GV_VAL_IN_SHIFT < P_FILTER_LEN;GV_VAL_IN_SHIFT = GV_VAL_IN_SHIFT+1)
>
> 122. begin:VAL_IN_SHIFT
>
> 123. always @ (posedge I_CLK)
>
> 124. begin
>
> 125. if(I_RSTN == 1'b0)
>
> 126. begin
>
> 127. R_IN_VAL_SHIFT[GV_VAL_IN_SHIFT] <= 1'd0;
>
> 128. end
>
> 129. else
>
> 130. begin
>
> 131. if(I_DATA_VAL == 1)
>
> 132. begin
>
> 133. R_IN_VAL_SHIFT[GV_VAL_IN_SHIFT] <= R_IN_VAL_SHIFT[GV_VAL_IN_SHIFT-1];
>
> 134. end
>
> 135. else
>
> 136. begin
>
> 137. R_IN_VAL_SHIFT[GV_VAL_IN_SHIFT] <= R_IN_VAL_SHIFT[GV_VAL_IN_SHIFT];
>
> 138. end
>
> 139. end
>
> 140. end
>
> 141. end
>
> 142. endgenerate
>
> 143.
>
> 144.
>
> 145. // 滤波器系数左移
>
> 146. always @ (posedge I_CLK)
>
> 147. begin
>
> 148. if(I_RSTN == 1'b0)
>
> 149. begin
>
> 150. R_COEF_SHIFT[P_FILTER_LEN-1] <= 0;
>
> 151. end
>
> 152. else
>
> 153. begin
>
> 154. if(I_COEF_VAL == 1'b1)
>
> 155. begin
>
> 156. R_COEF_SHIFT[P_FILTER_LEN-1] <= I_COEF;
>
> 157. end
>
> 158. else
>
> 159. begin
>
> 160. R_COEF_SHIFT[P_FILTER_LEN-1] <= R_COEF_SHIFT[P_FILTER_LEN-1];
>
> 161. end
>
> 162. end
>
> 163. end
>
> 164.
>
> 165. genvar GV_COEF_LEFT_SHIFT;
>
> 166. generate
>
> 167. for(GV_COEF_LEFT_SHIFT = P_FILTER_LEN-2;GV_COEF_LEFT_SHIFT >=0;GV_COEF_LEFT_SHIFT = GV_COEF_LEFT_SHIFT-1)
>
> 168. begin:COEF_LEFT_SHIFT
>
> 169. always @ (posedge I_CLK)
>
> 170. begin
>
> 171. if(I_RSTN == 1'b0)
>
> 172. begin
>
> 173. R_COEF_SHIFT[GV_COEF_LEFT_SHIFT] <= 0;
>
> 174. end
>
> 175. else
>
> 176. begin
>
> 177. if(I_COEF_VAL == 1'b1)
>
> 178. begin
>
> 179. R_COEF_SHIFT[GV_COEF_LEFT_SHIFT] <= R_COEF_SHIFT[GV_COEF_LEFT_SHIFT+1];
>
> 180. end
>
> 181. else
>
> 182. begin
>
> 183. R_COEF_SHIFT[GV_COEF_LEFT_SHIFT] <= R_COEF_SHIFT[GV_COEF_LEFT_SHIFT];
>
> 184. end
>
> 185. end
>
> 186. end
>
> 187. end
>
> 188. endgenerate
>
> 189.
>
> 190. // 有效信号左移
>
> 191. always @ (posedge I_CLK)
>
> 192. begin
>
> 193. if(I_RSTN == 1'b0)
>
> 194. begin
>
> 195. R_COEF_VAL_SHIFT[P_FILTER_LEN-1] <= 1'b0;
>
> 196. end
>
> 197. else
>
> 198. begin
>
> 199. if(I_COEF_VAL == 1'b1)
>
> 200. begin
>
> 201. R_COEF_VAL_SHIFT[P_FILTER_LEN-1] <= I_COEF_VAL;
>
> 202. end
>
> 203. else
>
> 204. begin
>
> 205. R_COEF_VAL_SHIFT[P_FILTER_LEN-1] <= R_COEF_VAL_SHIFT[P_FILTER_LEN-1] ;
>
> 206. end
>
> 207. end
>
> 208. end
>
> 209.
>
> 210. genvar GV_COEF_VAL_LEFT_SHIFT;
>
> 211. generate
>
> 212. for(GV_COEF_VAL_LEFT_SHIFT = P_FILTER_LEN-2;GV_COEF_VAL_LEFT_SHIFT >=0 ;GV_COEF_VAL_LEFT_SHIFT = GV_COEF_VAL_LEFT_SHIFT-1)
>
> 213. begin:COEF_VAL_LEFT_SHIFT
>
> 214. always @ (posedge I_CLK)
>
> 215. begin
>
> 216. if(I_RSTN == 1'b0)
>
> 217. begin
>
> 218. R_COEF_VAL_SHIFT[GV_COEF_VAL_LEFT_SHIFT] <= 1'd0;
>
> 219. end
>
> 220. else
>
> 221. begin
>
> 222. if(I_COEF_VAL == 1'b1)
>
> 223. begin
>
> 224. R_COEF_VAL_SHIFT[GV_COEF_VAL_LEFT_SHIFT] <= R_COEF_VAL_SHIFT[GV_COEF_VAL_LEFT_SHIFT+1];
>
> 225. end
>
> 226. else
>
> 227. begin
>
> 228. R_COEF_VAL_SHIFT[GV_COEF_VAL_LEFT_SHIFT] <= R_COEF_VAL_SHIFT[GV_COEF_VAL_LEFT_SHIFT];
>
> 229. end
>
> 230. end
>
> 231. end
>
> 232. end
>
> 233. endgenerate
>
> 234.
>
> 235. // 系数相乘
>
> 236. genvar GV_DATA_COEF_MULT;
>
> 237. generate
>
> 238. for(GV_DATA_COEF_MULT = 0;GV_DATA_COEF_MULT < P_FILTER_LEN;GV_DATA_COEF_MULT = GV_DATA_COEF_MULT+1)
>
> 239. begin:DATA_COEF_MULT
>
> 240. always @ (posedge I_CLK)
>
> 241. begin
>
> 242. if(I_RSTN == 1'b0)
>
> 243. begin
>
> 244. R_MULT_RES_VAL[GV_DATA_COEF_MULT] <= 1'b0;
>
> 245. R_MULT_RES[GV_DATA_COEF_MULT] <= 32'd0;
>
> 246. end
>
> 247. else if(R_COEF_VAL_SHIFT[GV_DATA_COEF_MULT] && R_IN_VAL_SHIFT[GV_DATA_COEF_MULT])
>
> 248. begin
>
> 249. R_MULT_RES_VAL[GV_DATA_COEF_MULT] <= 1'b1;
>
> 250. R_MULT_RES[GV_DATA_COEF_MULT] <= {{(P_DATA_IN_WIDTH){R_COEF_SHIFT[GV_DATA_COEF_MULT][P_FILTER_WIDTH-1]}},R_COEF_SHIFT[GV_DATA_COEF_MULT]}
>
> 251. *
>
> 252. {{(P_FILTER_WIDTH){R_IN_SHIFT[GV_DATA_COEF_MULT][P_DATA_IN_WIDTH-1]}},R_IN_SHIFT[GV_DATA_COEF_MULT]};
>
> 253. end
>
> 254. else
>
> 255. begin
>
> 256. R_MULT_RES_VAL[GV_DATA_COEF_MULT] <= R_MULT_RES_VAL[GV_DATA_COEF_MULT];
>
> 257. R_MULT_RES[GV_DATA_COEF_MULT] <= R_MULT_RES[GV_DATA_COEF_MULT];
>
> 258. end
>
> 259. end
>
> 260. end
>
> 261. endgenerate
>
> 262.
>
> 263. // 加法树
>
> 264. // 第一级
>
> 265. genvar GV_ADD_1;
>
> 266. generate
>
> 267. for(GV_ADD_1 = 0;GV_ADD_1 < P_FILTER_LEN/2;GV_ADD_1 = GV_ADD_1+1)
>
> 268. begin:ADD_1
>
> 269. always @ (posedge I_CLK)
>
> 270. begin
>
> 271. if(I_RSTN == 1'b0)
>
> 272. begin
>
> 273. R_ADD_1[GV_ADD_1] <= 33'd0;
>
> 274. end
>
> 275. else
>
> 276. begin
>
> 277. if(|R_MULT_RES_VAL)//只有一路乘法输出有效就进行加法
>
> 278. begin
>
> 279. R_ADD_1[GV_ADD_1] <= {R_MULT_RES[GV_ADD_1][P_FILTER_WIDTH+P_DATA_IN_WIDTH-1],R_MULT_RES[GV_ADD_1]}
>
> 280. +
>
> 281. {R_MULT_RES[P_FILTER_LEN-1-GV_ADD_1][P_FILTER_WIDTH+P_DATA_IN_WIDTH-1],R_MULT_RES[P_FILTER_LEN-1-GV_ADD_1]};
>
> 282. end
>
> 283. end
>
> 284. end
>
> 285. end
>
> 286. endgenerate
>
> 287.
>
> 288. // 第二级
>
> 289. genvar GV_ADD_2;
>
> 290. generate
>
> 291. for(GV_ADD_2 = 0;GV_ADD_2 < P_FILTER_LEN/4;GV_ADD_2 = GV_ADD_2+1)
>
> 292. begin:ADD_2
>
> 293. always @ (posedge I_CLK)
>
> 294. begin
>
> 295. if(I_RSTN == 1'b0)
>
> 296. begin
>
> 297. R_ADD_2[GV_ADD_2] <= 34'd0;
>
> 298. end
>
> 299. else
>
> 300. begin
>
> 301. R_ADD_2[GV_ADD_2] <= {R_ADD_1[GV_ADD_2][P_FILTER_WIDTH+P_DATA_IN_WIDTH],R_ADD_1[GV_ADD_2]}
>
> 302. +
>
> 303. {R_ADD_1[P_FILTER_LEN/2-1-GV_ADD_2][P_FILTER_WIDTH+P_DATA_IN_WIDTH],R_ADD_1[P_FILTER_LEN/2-1-GV_ADD_2]};
>
> 304. end
>
> 305. end
>
> 306. end
>
> 307. endgenerate
>
> 308.
>
> 309. // 第三级
>
> 310. genvar GV_ADD_3;
>
> 311. generate
>
> 312. for(GV_ADD_3 = 0;GV_ADD_3 < P_FILTER_LEN/8;GV_ADD_3 = GV_ADD_3+1)
>
> 313. begin:ADD_3
>
> 314. always @ (posedge I_CLK)
>
> 315. begin
>
> 316. if(I_RSTN == 1'b0)
>
> 317. begin
>
> 318. R_ADD_3[GV_ADD_3] <= 35'd0;
>
> 319. end
>
> 320. else
>
> 321. begin
>
> 322. R_ADD_3[GV_ADD_3] <= {R_ADD_2[GV_ADD_3][P_FILTER_WIDTH+P_DATA_IN_WIDTH+1],R_ADD_2[GV_ADD_3]}
>
> 323. +
>
> 324. {R_ADD_2[P_FILTER_LEN/4-1-GV_ADD_3][P_FILTER_WIDTH+P_DATA_IN_WIDTH+1],R_ADD_2[P_FILTER_LEN/4-1-GV_ADD_3]};
>
> 325. end
>
> 326. end
>
> 327. end
>
> 328. endgenerate
>
> 329.
>
> 330. // 输出
>
> 331. assign O_RES_DATA = R_ADD_3[0][(P_FILTER_WIDTH+P_DATA_IN_WIDTH+2)-:P_DATA_OUT_WIDTH];
>
> 332.
>
> 333.
>
> 334. always @ (posedge I_CLK)
>
> 335. begin
>
> 336. if(I_RSTN == 1'b0)
>
> 337. begin
>
> 338. R_RES_VAL[0] <= 1'b0;
>
> 339. end
>
> 340. else
>
> 341. begin
>
> 342. if(I_DATA_VAL == 1 && &R_COEF_VAL_SHIFT == 1)
>
> 343. begin
>
> 344. R_RES_VAL[0] <= I_DATA_VAL;
>
> 345. end
>
> 346. else
>
> 347. begin
>
> 348. R_RES_VAL[0] <=R_RES_VAL[0] ;
>
> 349. end
>
> 350. end
>
> 351. end
>
> 352.
>
> 353. genvar GV_RES_VAL;
>
> 354. generate
>
> 355. for(GV_RES_VAL = 1;GV_RES_VAL <= 4;GV_RES_VAL = GV_RES_VAL+1)
>
> 356. begin:RES_VAL
>
> 357. always @(posedge I_CLK)
>
> 358. begin
>
> 359. if(I_RSTN == 1'b0)
>
> 360. begin
>
> 361. R_RES_VAL[GV_RES_VAL] <= 1'd0;
>
> 362. end
>
> 363. else
>
> 364. begin
>
> 365. if(I_DATA_VAL == 1 && &R_COEF_VAL_SHIFT == 1)
>
> 366. begin
>
> 367. R_RES_VAL[GV_RES_VAL] <= R_RES_VAL[GV_RES_VAL-1];
>
> 368. end
>
> 369. else
>
> 370. begin
>
> 371. R_RES_VAL[GV_RES_VAL] <= R_RES_VAL[GV_RES_VAL];
>
> 372. end
>
> 373. end
>
> 374. end
>
> 375. end
>
> 376. endgenerate
>
> 377.
>
> 378. assign O_RES_VAL = R_RES_VAL[4];
>
> 379. assign O_TRDY = &R_COEF_VAL_SHIFT;//FIR 系数 全部读出且有效后 表示FIR滤波器已做好准备 开始接收输入数据
>
> 380.
>
> 381.
>
> 382. endmodule
>
>
>
>
> AI助手
仿真代码:
> 1. `timescale 1ns / 1ps
>
> 2. module TB_FIR_FILTER();
>
> 3.
>
> 4. parameter P_FILTER_LEN = 8; //滤波器长度
>
> 5. parameter P_FILTER_WIDTH = 16; //滤波器系数位宽
>
> 6. parameter P_DATA_IN_WIDTH = 16; //输入数据位宽
>
> 7. parameter P_DATA_OUT_WIDTH = 32; //输出数据位宽
>
> 8.
>
> 9. // ----------------------------输入
>
> 10. reg I_CLK; //10MHz
>
> 11. reg I_RSTN;
>
> 12. reg I_DATA_VAL;
>
> 13. reg [P_DATA_IN_WIDTH-1:0] I_DATA;
>
> 14. reg I_COEF_VAL;
>
> 15. reg [P_FILTER_WIDTH-1:0] I_COEF;
>
> 16.
>
> 17. // ----------------------------输出
>
> 18. wire O_RES_VAL;
>
> 19. wire [P_DATA_OUT_WIDTH-1:0] O_RES_DATA;
>
> 20. wire O_TRDY;
>
> 21.
>
> 22. initial I_CLK = 0;
>
> 23. always #20 I_CLK = ~I_CLK;
>
> 24. initial
>
> 25. begin
>
> 26. I_RSTN = 0;
>
> 27. #100;
>
> 28. I_RSTN = 1;
>
> 29. end
>
> 30.
>
> 31. reg [3:0] R_COUNT;
>
> 32. always @ (posedge I_CLK)
>
> 33. begin
>
> 34. if(~I_RSTN)
>
> 35. begin
>
> 36. R_COUNT <= 0;
>
> 37. I_COEF_VAL <= 0;
>
> 38. I_COEF <= 0;
>
> 39. end
>
> 40. else
>
> 41. begin
>
> 42. if(R_COUNT == 8)
>
> 43. begin
>
> 44. R_COUNT <= 8;
>
> 45. I_COEF_VAL <= 0;
>
> 46. I_COEF <= 0;
>
> 47. end
>
> 48. else
>
> 49. begin
>
> 50. R_COUNT <= R_COUNT + 1;
>
> 51. I_COEF_VAL <= 1;
>
> 52. I_COEF <= I_COEF + 8;
>
> 53. end
>
> 54. end
>
> 55. end
>
> 56.
>
> 57. always @ (posedge I_CLK)
>
> 58. begin
>
> 59. if(~I_RSTN)
>
> 60. begin
>
> 61. I_DATA <= 0;
>
> 62. I_DATA_VAL <= 0;
>
> 63. end
>
> 64. else
>
> 65. begin
>
> 66. if(O_TRDY)
>
> 67. begin
>
> 68. I_DATA <= I_DATA + 1;
>
> 69. I_DATA_VAL <= 1;
>
> 70. end
>
> 71. else
>
> 72. begin
>
> 73. I_DATA <= 0;
>
> 74. I_DATA_VAL <= 0;
>
> 75. end
>
> 76. end
>
> 77. end
>
> 78. FIR_FILTER #(
>
> 79. .P_FILTER_LEN(P_FILTER_LEN),
>
> 80. .P_FILTER_WIDTH(P_FILTER_WIDTH),
>
> 81. .P_DATA_IN_WIDTH(P_DATA_IN_WIDTH),
>
> 82. .P_DATA_OUT_WIDTH(P_DATA_OUT_WIDTH)
>
> 83. ) INST_FIR_FILTER (
>
> 84. .I_CLK (I_CLK),
>
> 85. .I_RSTN (I_RSTN),
>
> 86.
>
> 87. .I_DATA_VAL (I_DATA_VAL),
>
> 88. .I_DATA (I_DATA),
>
> 89. .I_COEF_VAL (I_COEF_VAL),
>
> 90. .I_COEF (I_COEF),
>
> 91.
>
> 92. .O_RES_VAL (O_RES_VAL),
>
> 93. .O_RES_DATA (O_RES_DATA),
>
> 94. .O_TRDY (O_TRDY)
>
> 95. );
>
> 96.
>
> 97. endmodule
>
>
>
>
> AI助手
仿真结果:

时钟 IP
IP核配置

此处的相位无所谓,随便设置。默认都为0即可。

下采样模块
设计源码:
> 1. // |------------------------------------------------------------------------------
>
> 2. // |------------------------------ DATA DECIMATE DESIGN --------------------------
>
> 3. // |------------------------------------------------------------------------------
>
> 4. // |
>
> 5. // |********* Basic Information Specify *********
>
> 6. // |Author : Xu Y.B. ( 昵称:在路上,正出发)
>
> 7. // |Abstract :
>
> 8. // | -1- Configurable Parameter.
>
> 9. // | -2- Dual clock ports.
>
> 10. // |
>
> 11. // |FPGA Chirp Model : xc7a35tfgg484-2
>
> 12. // |Vivado Version : 2018.3
>
> 13. // |File Create Time : 2022-10-07
>
> 14. // |Advice : This is a example design source.
>
> 15. // | It is better to understand and improve the source code!
>
> 16. // |
>
> 17. // |********* Version Change History *********
>
> 18. // |
>
> 19. // |
>
> 20.
>
> 21. `timescale 1ns / 1ps
>
> 22. module DATA_DCM_MDL #(
>
> 23. // --------------------------- Module Parameter -------------------------
>
> 24. parameter P_DCM_FACTOR = 4,
>
> 25. parameter P_DATA_WIDTH = 8,
>
> 26. parameter P_PHASE_OFFSET = 0
>
> 27. )(
>
> 28. // ------------------------- Input/Output Ports -------------------------
>
> 29. // Initial Sample Clock Domain
>
> 30. input I_INT_CLK,
>
> 31. input I_RSTN,
>
> 32. input I_DATA_IN_VAL,
>
> 33. input [P_DATA_WIDTH-1:0] I_DATA_IN,
>
> 34. // Decimator Clock Domain
>
> 35. input I_DCM_CLK,
>
> 36. output O_DATA_OUT_VAL,
>
> 37. output [P_DATA_WIDTH-1:0] O_DATA_OUT
>
> 38. );
>
> 39. // -------------------------- Local Parameters ---------------------------
>
> 40. localparam LP_COUNT_WIDTH = $clog2(P_DCM_FACTOR); // Counter Width
>
> 41.
>
> 42. // ---------------------- Module Internal Signals ------------------------
>
> 43. reg [LP_COUNT_WIDTH-1:0] R_COUNT; // Counter
>
> 44. wire [P_DATA_WIDTH-1:0] W_DATA_DCM_OUT_INTCD; // Decimate Out Data In Initial Clock Domain
>
> 45. wire W_DATA_DCM_OUT_VAL_INTCD;// Decimate Out Data Valid In Initial Clock Domain
>
> 46.
>
> 47. // FIFO
>
> 48. reg R_FIFO_RD_EN;
>
> 49. wire W_FIFO_FULL;
>
> 50. wire W_FIFO_EMPTY;
>
> 51. wire W_FIFO_ALMOST_FULL;
>
> 52. wire W_FIFO_ALMOST_EMPTY;
>
> 53. wire [P_DATA_WIDTH-1:0] W_FIFO_RD_OUT;
>
> 54. wire W_FIFO_OUT_VLD;
>
> 55.
>
> 56. // ------------------------ Module Logic Design --------------------------
>
> 57. // Initial Clock Domain Decimate Logic
>
> 58. always @ (posedge I_INT_CLK)
>
> 59. begin
>
> 60. if(~I_RSTN)
>
> 61. begin
>
> 62. R_COUNT <= 0;
>
> 63. end
>
> 64. else if(I_DATA_IN_VAL)
>
> 65. begin
>
> 66. if(R_COUNT == P_DCM_FACTOR-1)
>
> 67. begin
>
> 68. R_COUNT <= 0;
>
> 69. end
>
> 70. else
>
> 71. begin
>
> 72. R_COUNT <= R_COUNT + 1;
>
> 73. end
>
> 74. end
>
> 75. else
>
> 76. begin
>
> 77. R_COUNT <= 0;
>
> 78. end
>
> 79. end
>
> 80. assign W_DATA_DCM_OUT_INTCD = (R_COUNT == P_PHASE_OFFSET) ? I_DATA_IN : {(P_DATA_WIDTH){1'b1}};
>
> 81. assign W_DATA_DCM_OUT_VAL_INTCD = ((R_COUNT == P_PHASE_OFFSET) &&(I_DATA_IN_VAL)) ? 1'b1 : 1'b0;
>
> 82.
>
> 83.
>
> 84. assign O_DATA_OUT_VAL = W_FIFO_OUT_VLD;
>
> 85. assign O_DATA_OUT = W_FIFO_RD_OUT;
>
> 86.
>
> 87. always @ (posedge I_DCM_CLK)
>
> 88. begin
>
> 89. if(~I_RSTN)
>
> 90. begin
>
> 91. R_FIFO_RD_EN <= 0;
>
> 92. end
>
> 93. else
>
> 94. begin
>
> 95. if(W_FIFO_ALMOST_EMPTY)
>
> 96. begin
>
> 97. R_FIFO_RD_EN <= 0;
>
> 98. end
>
> 99. else
>
> 100. begin
>
> 101. R_FIFO_RD_EN <= 1;
>
> 102. end
>
> 103. end
>
> 104. end
>
> 105. 106. FIFO_DATA_CDC INST_FIFO_DATA_CDC (
>
> 107. .rst(1'b0), // input wire rst
>
> 108. .wr_clk(I_INT_CLK), // input wire wr_clk
>
> 109. .rd_clk(I_DCM_CLK), // input wire rd_clk
>
> 110. .din(W_DATA_DCM_OUT_INTCD), // input wire [7 : 0] din
>
> 111. .wr_en(W_DATA_DCM_OUT_VAL_INTCD), // input wire wr_en
>
> 112. .rd_en(R_FIFO_RD_EN), // input wire rd_en
>
> 113. .dout(W_FIFO_RD_OUT), // output wire [7 : 0] dout
>
> 114. .full(W_FIFO_FULL), // output wire full
>
> 115. .almost_full(W_FIFO_ALMOST_FULL), // output wire almost_full
>
> 116. .empty(W_FIFO_EMPTY), // output wire empty
>
> 117. .almost_empty(W_FIFO_ALMOST_EMPTY), // output wire almost_empty
>
> 118. .valid(W_FIFO_OUT_VLD) // output wire valid
>
> 119. );
>
> 120.
>
> 121.
>
> 122. endmodule
>
>
>
>
> AI助手
FIFO IP核的配置:



仿真源码:
> 1.
>
> 2.
>
> 3. `timescale 1ns / 1ps
>
> 4. module TB_DATA_DCM_MDL();
>
> 5. // --------------------------- Module Parameter -------------------------
>
> 6. parameter P_DCM_FACTOR = 4;
>
> 7. parameter P_DATA_WIDTH = 16;
>
> 8. parameter P_PHASE_OFFSET = 3;
>
> 9.
>
> 10. // ------------------------- Input/Output Ports -------------------------
>
> 11. // Initial Sample Clock Domain
>
> 12. wire I_INT_CLK;
>
> 13. wire I_RSTN;
>
> 14. reg I_DATA_IN_VAL;
>
> 15. reg [P_DATA_WIDTH-1:0] I_DATA_IN;
>
> 16. // Decimator Clock Domain
>
> 17. wire I_DCM_CLK;
>
> 18. wire O_DATA_OUT_VAL;
>
> 19. wire [P_DATA_WIDTH-1:0] O_DATA_OUT;
>
> 20.
>
> 21. reg CLK_IN_50M;
>
> 22.
>
> 23. initial CLK_IN_50M = 0;
>
> 24. always #10 CLK_IN_50M = ~CLK_IN_50M;
>
> 25.
>
> 26.
>
> 27. always @ (posedge I_INT_CLK)
>
> 28. begin
>
> 29. if(~I_RSTN)
>
> 30. begin
>
> 31. I_DATA_IN <= 0;
>
> 32. I_DATA_IN_VAL <= 0;
>
> 33. end
>
> 34. else
>
> 35. begin
>
> 36. I_DATA_IN <= I_DATA_IN + 1;
>
> 37. I_DATA_IN_VAL <= 1;
>
> 38. end
>
> 39. end
>
> 40.
>
> 41. DATA_DCM_MDL #(
>
> 42. .P_DCM_FACTOR(P_DCM_FACTOR),
>
> 43. .P_DATA_WIDTH(P_DATA_WIDTH),
>
> 44. .P_PHASE_OFFSET(P_PHASE_OFFSET)
>
> 45. ) inst_DATA_DCM_MDL (
>
> 46. .I_INT_CLK (I_INT_CLK),
>
> 47. .I_RSTN (I_RSTN),
>
> 48. .I_DATA_IN_VAL (I_DATA_IN_VAL),
>
> 49. .I_DATA_IN (I_DATA_IN),
>
> 50. .I_DCM_CLK (I_DCM_CLK),
>
> 51. .O_DATA_OUT_VAL (O_DATA_OUT_VAL),
>
> 52. .O_DATA_OUT (O_DATA_OUT)
>
> 53. );
>
> 54.
>
> 55. SYS_MMCM SYS_MMCM_INST
>
> 56. (
>
> 57. // Clock out ports
>
> 58. .CLK_100M(I_INT_CLK), // output CLK_100M
>
> 59. .CLK_25M(I_DCM_CLK), // output CLK_25M
>
> 60. // Status and control signals
>
> 61. .reset(1'b0), // input reset
>
> 62. .locked(I_RSTN), // output locked
>
> 63. // Clock in ports
>
> 64. .CLK_IN_50M(CLK_IN_50M)); // input CLK_IN_50M
>
> 65. endmodule
>
>
>
>
> AI助手
仿真结果:

在后续文章中进一步阐述FIR滤波器系数的具体设计内容及其实现流程,在这一过程中将详细说明包括生成、存储、读取和分发等关键步骤,并提供相应的设计方法和仿真源代码。
