• FPGA project : sobel


    实验目标:

    sobel算法,处理100X100灰度图像:野火logo

    边缘检测:

    边缘检测,针对的是灰度图像,顾名思义,检测图像的边缘,是针对图像像素点的一种计算,目的是标识数字图像中灰度变化明显的点,图像的边缘检测,在保留了图像的重要结构信息的同时,剔除了可以认为不相关的信息,大幅度减少了数据量,便于图像的传输和处理。

    什么是sobel算法:

     算出来的Gxy与一个数据T比较大小,大于T则b2像素点赋值为黑色,小于赋值白色。

    我踩得坑:

    vga_pic模块,调用的时候由于图片大小需要更改,当初写vga_pic模块的时候,没有把代码中的一些数,用parameter表示,在修改的时候很麻烦。所以以后写代码的时候,大于2的参数一定要重新定义一下,代码写的应该更具复用性。

    代码复用性也是代码质量的体现。

    经验总结:

    想要沉浸式写代码,就要清清楚楚的画好时序图。在写代码之前就应该想清楚用到的每个信号的时序图应该是什么样的。

    fpga开发一大部分时间花在整体(顶层)设计上,一部分时间花在如何把想法转换为Verilog语言,一部分时间花在仿真调试上。

    我认为最重要的就是整体设计,以及画好时序图。或者有流程图或者相关的辅助你把想法转换为代码的图。

    模块框图:

    时序图: 

    特别大

    代码:

     就放sobel算法部分,和顶层。

    1. module sobel(
    2. input wire clk_50 ,
    3. input wire sys_rst_n ,
    4. input wire [7:0] pi_data ,
    5. input wire pi_flag ,
    6. output reg po_flag ,
    7. output reg [7:0] po_data
    8. );
    9. // parameter
    10. parameter MAX_LINE = 8'd100 ,
    11. MAX_COL = 8'd100 ,
    12. THR = 8'b0000_1100 ,
    13. BLACK = 8'b0000_0000 ,
    14. WHITE = 8'b1111_1111 ;
    15. // reg signal define
    16. reg [7:0] cnt_line ;
    17. reg [7:0] cnt_col ;
    18. reg wrreq1 ;
    19. reg [7:0] dataf1_in ;
    20. reg rdreq ;
    21. reg wrreq2 ;
    22. reg [7:0] dataf2_in ;
    23. reg [7:0] pi_data_reg1;
    24. reg [7:0] cnt_read ; // 对从FIFO中读出的数据个数计数。
    25. reg dataRegFlag ;
    26. reg [7:0] fifo1_reg ;
    27. reg [7:0] fifo2_reg ;
    28. reg [7:0] pi_data_reg2;
    29. reg [7:0] pi_data_reg3; // 用来保存pi_data以进行sobel运算。不是单纯的对pi_data_reg2打拍。
    30. reg flag_abc ;
    31. reg [7:0] a3 ;
    32. reg [7:0] b3 ;
    33. reg [7:0] c3 ;
    34. reg [7:0] a2 ;
    35. reg [7:0] b2 ;
    36. reg [7:0] c2 ;
    37. reg [7:0] a1 ;
    38. reg [7:0] b1 ;
    39. reg [7:0] c1 ;
    40. reg arithmetic ; // 进行sobel算法的标志。
    41. reg [8:0] gx ; // 因为有符号位,所以运算过后要多加一位。
    42. reg [8:0] gy ; // 因为有符号位,所以运算过后要多加一位。
    43. reg flag_gxy ;
    44. reg [8:0] gxy ;
    45. reg answer_flag ;
    46. // wire signal define
    47. wire rdreq_w ;
    48. wire wrreq1_w ;
    49. wire [7:0] dataf1_in_w ;
    50. wire [7:0] dataf1_out ;
    51. wire [9:0] usedw_f1 ;
    52. wire full_f1 ;
    53. wire empty_f1 ;
    54. wire wrreq2_w ;
    55. wire [7:0] dataf2_in_w ;
    56. wire [7:0] dataf2_out ;
    57. wire [9:0] usedw_f2 ;
    58. wire full_f2 ;
    59. wire empty_f2 ;
    60. /*********************************************************************/
    61. // reg [7:0] cnt_line ;
    62. always @(posedge clk_50 or negedge sys_rst_n) begin
    63. if(~sys_rst_n)
    64. cnt_line <= 8'd0 ;
    65. else if(pi_flag && cnt_col == MAX_COL - 1 && cnt_line == MAX_LINE - 1)
    66. cnt_line <= 8'd0 ;
    67. else if(pi_flag && cnt_col == MAX_COL - 1)
    68. cnt_line <= cnt_line + 1'b1 ;
    69. else
    70. cnt_line <= cnt_line ;
    71. end
    72. // reg [7:0] cnt_col ;
    73. always @(posedge clk_50 or negedge sys_rst_n) begin
    74. if(~sys_rst_n)
    75. cnt_col <= 8'd0 ;
    76. else if(pi_flag && cnt_col == MAX_COL - 1)
    77. cnt_col <= 8'd0 ;
    78. else if(pi_flag)
    79. cnt_col <= cnt_col + 1'b1 ;
    80. else
    81. cnt_col <= cnt_col ;
    82. end
    83. // reg wrreq1 ;
    84. always @(posedge clk_50 or negedge sys_rst_n) begin
    85. if(~sys_rst_n)
    86. wrreq1 <= 1'b0 ;
    87. else if(cnt_line == 0)
    88. wrreq1 <= pi_flag ;
    89. else if(((cnt_line == 2) && (cnt_col != 0))
    90. || ((cnt_line) > 2 && (cnt_line < MAX_LINE - 1))
    91. || ((cnt_line == MAX_LINE - 1) && (cnt_col == 0)))
    92. wrreq1 <= wrreq2 ;
    93. else
    94. wrreq1 <= 1'b0 ;
    95. end
    96. // reg [7:0] dataf1_in ;
    97. always @(posedge clk_50 or negedge sys_rst_n) begin
    98. if(~sys_rst_n)
    99. dataf1_in <= 8'd0 ;
    100. else if(cnt_line == 0)
    101. dataf1_in <= pi_data ;
    102. else if(((cnt_line == 2) && (cnt_col != 0))
    103. || ((cnt_line) > 2 && (cnt_line < MAX_LINE - 1))
    104. || ((cnt_line == MAX_LINE - 1) && (cnt_col == 0)))
    105. dataf1_in <= dataf2_out ;
    106. else
    107. dataf1_in <= dataf1_in ;
    108. end
    109. // reg rdreq ;
    110. always @(posedge clk_50 or negedge sys_rst_n) begin
    111. if(~sys_rst_n)
    112. rdreq <= 1'b0 ;
    113. else if(cnt_line >= 2)
    114. rdreq <= pi_flag ;
    115. else
    116. rdreq <= 1'b0 ;
    117. end
    118. // reg wrreq2 ;
    119. always @(posedge clk_50 or negedge sys_rst_n) begin
    120. if(~sys_rst_n)
    121. wrreq2 <= 1'b0 ;
    122. else if(cnt_line == 1)
    123. wrreq2 <= pi_flag ;
    124. else if((cnt_line >= 2 && cnt_line <= (MAX_LINE - 1))
    125. || (cnt_line == (MAX_LINE - 1) && (cnt_col == 0)) )
    126. wrreq2 <= rdreq ;
    127. else
    128. wrreq2 <= 1'b0 ;
    129. end
    130. // reg [7:0] dataf2_in ;
    131. always @(posedge clk_50 or negedge sys_rst_n) begin
    132. if(~sys_rst_n)
    133. dataf2_in <= 8'd0 ;
    134. else if(cnt_line == 1)
    135. dataf2_in <= pi_data ;
    136. else if((cnt_line >= 2 && cnt_line <= (MAX_LINE - 1))
    137. || (cnt_line == (MAX_LINE - 1) && (cnt_col == 0)) )
    138. dataf2_in <= pi_data_reg1 ;
    139. else
    140. dataf2_in <= dataf2_in ;
    141. end
    142. // reg [7:0] pi_data_reg1;
    143. // reg [7:0] pi_data_reg2;
    144. always @(posedge clk_50 or negedge sys_rst_n) begin
    145. if(~sys_rst_n) begin
    146. pi_data_reg1 <= 8'd0 ;
    147. pi_data_reg2 <= 8'd0 ;
    148. end else begin
    149. pi_data_reg1 <= pi_data ;
    150. pi_data_reg2 <= pi_data_reg1 ;
    151. end
    152. end
    153. // reg [7:0] cnt_read ;
    154. always @(posedge clk_50 or negedge sys_rst_n) begin
    155. if(~sys_rst_n)
    156. cnt_read <= 8'd0 ;
    157. else if(rdreq && cnt_read == MAX_COL - 1)
    158. cnt_read <= 8'd0 ;
    159. else if(rdreq)
    160. cnt_read <= cnt_read + 1'b1 ;
    161. else
    162. cnt_read <= cnt_read ;
    163. end
    164. // reg dataRegFlag ;
    165. always @(posedge clk_50 or negedge sys_rst_n) begin
    166. if(~sys_rst_n)
    167. dataRegFlag <= 1'b0 ;
    168. else
    169. dataRegFlag <= rdreq ;
    170. end
    171. // reg [7:0] fifo1_reg ;
    172. // reg [7:0] fifo2_reg ;
    173. // reg [7:0] pi_data_reg3;
    174. always @(posedge clk_50 or negedge sys_rst_n) begin
    175. if(~sys_rst_n) begin
    176. fifo1_reg <= 8'd0 ;
    177. fifo2_reg <= 8'd0 ;
    178. pi_data_reg3 <= 8'd0 ;
    179. end else begin
    180. if(dataRegFlag) begin
    181. fifo1_reg <= dataf1_out ;
    182. fifo2_reg <= dataf2_out ;
    183. pi_data_reg3 <= pi_data_reg2 ;
    184. end else begin
    185. fifo1_reg <= fifo1_reg ;
    186. fifo2_reg <= fifo2_reg ;
    187. pi_data_reg3 <= pi_data_reg3 ;
    188. end
    189. end
    190. end
    191. // reg flag_abc ;
    192. always @(posedge clk_50 or negedge sys_rst_n) begin
    193. if(~sys_rst_n)
    194. flag_abc <= 1'b0 ;
    195. else
    196. flag_abc <= dataRegFlag ;
    197. end
    198. // reg [7:0] a3 ;
    199. // reg [7:0] b3 ;
    200. // reg [7:0] c3 ;
    201. // reg [7:0] a2 ;
    202. // reg [7:0] b2 ;
    203. // reg [7:0] c2 ;
    204. // reg [7:0] a1 ;
    205. // reg [7:0] b1 ;
    206. // reg [7:0] c1 ;
    207. always @(posedge clk_50 or negedge sys_rst_n) begin
    208. if(~sys_rst_n) begin
    209. a3 <= 8'd0 ;
    210. b3 <= 8'd0 ;
    211. c3 <= 8'd0 ;
    212. a2 <= 8'd0 ;
    213. b2 <= 8'd0 ;
    214. c2 <= 8'd0 ;
    215. a1 <= 8'd0 ;
    216. b1 <= 8'd0 ;
    217. c1 <= 8'd0 ;
    218. end else begin
    219. if(flag_abc) begin
    220. a3 <= fifo1_reg ;
    221. b3 <= fifo2_reg ;
    222. c3 <= pi_data_reg3 ;
    223. a2 <= a3 ;
    224. b2 <= b3 ;
    225. c2 <= c3 ;
    226. a1 <= a2 ;
    227. b1 <= b2 ;
    228. c1 <= c2 ;
    229. end else begin
    230. a3 <= a3 ;
    231. b3 <= b3 ;
    232. c3 <= c3 ;
    233. a2 <= a2 ;
    234. b2 <= b2 ;
    235. c2 <= c2 ;
    236. a1 <= a1 ;
    237. b1 <= b1 ;
    238. c1 <= c1 ;
    239. end
    240. end
    241. end
    242. // reg arithmetic ;
    243. always @(posedge clk_50 or negedge sys_rst_n) begin
    244. if(~sys_rst_n)
    245. arithmetic <= 1'b0 ;
    246. else if(cnt_col != 1 && cnt_col != 2)
    247. arithmetic <= flag_abc ;
    248. else
    249. arithmetic <= 1'b0 ;
    250. end
    251. // reg [8:0] gx ;
    252. // reg [8:0] gy ;
    253. always @(posedge clk_50 or negedge sys_rst_n) begin
    254. if(~sys_rst_n) begin
    255. gx <= 9'd0 ;
    256. gy <= 9'd0 ;
    257. end else begin
    258. if(arithmetic) begin
    259. gx <= (a3-a1)+((b3-b1) << 1)+(c3-c1) ; // 向左移动1bit相当于扩大二倍。
    260. gy <= (a1-c1)+((a2-c2) << 1)+(a3-c3) ; // 向左移动1bit相当于扩大二倍。
    261. end else begin
    262. gx <= gx ;
    263. gy <= gy ;
    264. end
    265. end
    266. end
    267. // reg flag_gxy ;
    268. always @(posedge clk_50 or negedge sys_rst_n) begin
    269. if(~sys_rst_n)
    270. flag_gxy <= 1'b0 ;
    271. else
    272. flag_gxy <= arithmetic ;
    273. end
    274. // reg [8:0] gxy ;
    275. always @(posedge clk_50 or negedge sys_rst_n) begin
    276. if(~sys_rst_n)
    277. gxy <= 8'd0 ;
    278. else if(flag_gxy) begin
    279. case ({gx[8],gy[8]})
    280. 2'b00 : gxy <= gx[7:0] + gy[7:0] ;
    281. 2'b01 : gxy <= gx[7:0] + ~gy[7:0] + 1'b1 ;
    282. 2'b10 : gxy <= ~gx[7:0] + gy[7:0] + 1'b1 ;
    283. 2'b11 : gxy <= ~gx[7:0] + ~gy[7:0] + 2'd2 ;
    284. default: gxy <= gxy ;
    285. endcase
    286. end // gxy <= {1'b0,gx[7:0]} + {1'b0,gy[7:0]} ; // 取其绝对值相加。也就是说最高位应该为0.
    287. end
    288. // reg answer_flag ;
    289. always @(posedge clk_50 or negedge sys_rst_n) begin
    290. if(~sys_rst_n)
    291. answer_flag <= 1'b0 ;
    292. else
    293. answer_flag <= flag_gxy ;
    294. end
    295. // output signal
    296. // reg po_flag
    297. always @(posedge clk_50 or negedge sys_rst_n) begin
    298. if(~sys_rst_n)
    299. po_flag <= 1'b0 ;
    300. else if(answer_flag)
    301. po_flag <= 1'b1 ;
    302. else
    303. po_flag <= 1'b0 ;
    304. end
    305. // reg [7:0] po_data
    306. always @(posedge clk_50 or negedge sys_rst_n) begin
    307. if(~sys_rst_n)
    308. po_data <= 8'd0 ;
    309. else if(answer_flag && (gxy > THR))
    310. po_data <= BLACK ;
    311. else if(answer_flag && (gxy <= THR))
    312. po_data <= WHITE ;
    313. else
    314. po_data <= po_data ;
    315. end
    316. /*************************************************************/
    317. // 例化
    318. assign dataf1_in_w = dataf1_in ;
    319. assign dataf2_in_w = dataf2_in ;
    320. assign rdreq_w = rdreq ;
    321. assign wrreq1_w = wrreq1 ;
    322. assign wrreq2_w = wrreq2 ;
    323. fifo fifo_f1(
    324. .clock ( clk_50 ) ,
    325. .data ( dataf1_in_w ) ,
    326. .rdreq ( rdreq_w ) ,
    327. .wrreq ( wrreq1_w ) ,
    328. .empty ( empty_f1 ) ,
    329. .full ( full_f1 ) ,
    330. .q ( dataf1_out ) ,
    331. .usedw ( usedw_f1 )
    332. );
    333. fifo fifo_f2(
    334. .clock ( clk_50 ) ,
    335. .data ( dataf2_in_w ) ,
    336. .rdreq ( rdreq_w ) ,
    337. .wrreq ( wrreq2_w ) ,
    338. .empty ( empty_f2 ) ,
    339. .full ( full_f2 ) ,
    340. .q ( dataf2_out ) ,
    341. .usedw ( usedw_f2 )
    342. );
    343. endmodule

     

    1. module top(
    2. input wire sys_clk ,
    3. input wire sys_rst_n ,
    4. input wire rx ,
    5. output wire hsync ,
    6. output wire vsync ,
    7. output wire [7:0] rgb ,
    8. output wire tx
    9. );
    10. // 例化间连线
    11. wire clk_50 ;
    12. wire clk_25 ;
    13. wire rst_n ;
    14. wire po_flag_rx ;
    15. wire [7:0] po_data_rx ;
    16. wire po_flag_so ;
    17. wire [7:0] po_data_so ;
    18. pll pll_50_25(
    19. .sys_rst_n ( sys_rst_n ) ,
    20. .areset ( ~sys_rst_n ) ,
    21. .inclk0 ( sys_clk ) ,
    22. .c0 ( clk_50 ) ,
    23. .c1 ( clk_25 ) ,
    24. .locked ( rst_n )
    25. );
    26. uart_rx uart_rx_inst(
    27. .sys_clk ( clk_50 ) ,
    28. .sys_rst_n ( rst_n ) ,
    29. .rx ( rx ) ,
    30. .po_flag ( po_flag_rx ) ,
    31. .po_data ( po_data_rx )
    32. );
    33. sobel sobel_inst(
    34. .clk_50 ( clk_50 ) ,
    35. .sys_rst_n ( rst_n ) ,
    36. .pi_data ( po_data_rx ) ,
    37. .pi_flag ( po_flag_rx ) ,
    38. .po_flag ( po_flag_so ) ,
    39. .po_data ( po_data_so )
    40. );
    41. uart_tx uart_tx_inst(
    42. .sys_clk ( clk_50 ) ,
    43. .sys_rst_n ( rst_n ) ,
    44. .pi_flag ( po_flag_so ) ,
    45. .pi_data ( po_data_so ) ,
    46. .tx ( tx )
    47. );
    48. vga vga_inst(
    49. .clk_25 ( clk_25 ) ,
    50. .clk_50 ( clk_50 ) ,
    51. .rst_n ( rst_n ) ,
    52. .pi_data ( po_data_so ) ,
    53. .pi_flag ( po_flag_so ) ,
    54. .hsync ( hsync ) ,
    55. .vsync ( vsync ) ,
    56. .rgb ( rgb )
    57. );
    58. endmodule

     仿真图忘记截屏了。

    上板验证:

  • 相关阅读:
    损失函数总结
    React native新架构组成
    消息队列实现分布式事务
    虚拟化/超融合人才招聘和业务合作
    20212416 2023-2024-2 《移动平台开发与实践》综合实践
    CSS常用样式
    【JavaEE】_Spring MVC项目之建立连接
    Shiro-550 漏洞分析
    适合新手编程的软件,什么编程软件比较好比较容易入门
    聊一聊go的单元测试(goconvey、gomonkey、gomock)
  • 原文地址:https://blog.csdn.net/Meng_long2022/article/details/133716010