1.乒乓操作原理
乒乓操作是一個主要用於數據流控制的處理技巧,典型的乒乓操作如圖所示:
外部輸入數據流通過“輸入數據選擇控制”模塊送入兩個數據緩沖區中,數據緩沖模塊可以為任何存儲模塊,比較常用的存儲單元為雙口RAM(Dual RAM),SRAM,SDRAM,FIFO等。
在第1個緩沖周期,將輸入的數據流緩存到“數據緩沖1”模塊,在第2個緩沖周期,“輸入數據選擇控制”模塊將輸入的數據流緩存到“數據緩沖2”模塊的同時,“輸出數據選擇控制”模塊將“數據緩沖1”模塊第一個周期緩存的數據流送到“后續處理”,模塊進行后續的數據處理,在第三個緩沖周期,在“輸入數據選擇控制”模塊的再次切換后,輸入的數據流緩存到“數據緩沖1”模塊,與此同時,“輸出數據選擇控制”模塊也做出切換,將“數據緩沖2”模塊緩存的第二個周期的數據送到“后續處理模塊”,如此循環。
這里正是利用了乒乓操作完成數據的無縫緩沖與處理,乒乓操作可以通過“輸入數據選擇控制”和“輸出數據選擇控制”按節拍,相互配合地進行來回切換,將經過緩沖的數據流沒有停頓的送到“后續處理模塊”。
比如將乒乓操作運用在液晶顯示的控制模塊上,如圖所示。
對於外部接口傳輸的圖像數據,以一幀圖像為單位進行SDRAM的切換控制,當SDRAM1緩存圖像數據時,液晶顯示的是SDRAM2的數據圖像;反之,當SDRAM2緩存圖像數據時,液晶顯示的是SDRAM1的數據圖像,如此反復,這樣出路的好處在於液晶顯示圖像切換瞬間完成,掩蓋了可能比較緩慢的圖像數據流變換過程。
2.FPGA乒乓操作代碼
2.1 FPGA設計代碼
1 module pingpang 2 ( 3 input clk , 4 input rst_n , 5 input [7:0] data_in , // 輸入數據 6 output reg [7:0] data_out // 輸出數據 7 ); 8 9 // ------------------------------------------------------ // 10 reg [7:0] buffer1 ; // 緩存1 11 reg [7:0] buffer2 ; // 緩存2 12 reg wr_flag ; // 寫標志,wr_flag=0,寫buffer1,wr_flag=1,寫buffer2 13 reg rd_flag ; // 讀標志,rd_flag=0,讀buffer2,rd_flag=1,讀buffer1 14 reg state ; // 狀態機,0:寫1讀2,1:寫2讀1,狀態轉移和輸出分開編碼 15 // ------------------------------------------------------ // 16 // 狀態轉移 17 always @ (posedge clk or negedge rst_n) 18 begin 19 if(rst_n == 1'b0) 20 begin 21 state <= 'b0; 22 end 23 else 24 begin 25 state <= !state; 26 //case(state) 27 // 1'b0 : state <= 1'b0; // 寫1讀2->寫2讀1 28 // 1'b1 : state <= 1'b1; // 寫2讀1->寫1讀2 29 // default : state <= 1'b0; 30 //endcase 31 end 32 end 33 // ------------------------------------------------------ // 34 // 狀態輸出 35 always @ (state) 36 begin 37 case(state) 38 1'b0: 39 begin 40 wr_flag = 1'b0; // 寫1 41 rd_flag = 1'b0; // 讀2 42 end 43 1'b1: 44 begin 45 wr_flag = 1'b1; // 寫2 46 rd_flag = 1'b1; // 讀1 47 end 48 default: 49 begin 50 wr_flag = 1'b0; 51 rd_flag = 1'b0; 52 end 53 endcase 54 end 55 // ------------------------------------------------------ // 56 // 寫buffer數據 57 always @ (posedge clk or negedge rst_n) 58 begin 59 if(rst_n == 1'b0) 60 begin 61 buffer1 <= 8'b0; 62 buffer2 <= 8'b0; 63 end 64 else 65 begin 66 case(wr_flag) 67 1'b0 : buffer1 <= data_in; // wr_flag = 0,寫buffer1 68 1'b1 : buffer2 <= data_in; // wr_flag = 1,寫buffer2 69 default : 70 begin 71 buffer1 <= 8'b0; 72 buffer2 <= 8'b0; 73 end 74 endcase 75 end 76 end 77 // ------------------------------------------------------ // 78 // 讀buffer數據 79 always @ (posedge clk or negedge rst_n) 80 begin 81 if(rst_n == 1'b0) 82 begin 83 data_out <= 8'b0; 84 end 85 else 86 begin 87 case(rd_flag) 88 1'b0 : data_out <= buffer2; // rd_flag=0,讀buffer2 89 1'b1 : data_out <= buffer1; // rd_flag=1,讀buffer1 90 default : data_out <= 8'b0; 91 endcase 92 end 93 end 94 // ------------------------------------------------------ // 95 endmodule
2.2 FPGA仿真代碼
`timescale 1ns / 1ps module pingpang_tb(); reg clk ; reg rst_n ; reg [7:0] data_in ; wire[7:0] data_out; always #10 clk = ~clk; initial begin rst_n <= 1'b0 ; clk <= 1'b0 ; #2010; rst_n <= 1'b1 ; end always @(posedge clk or negedge rst_n) begin if(!rst_n) data_in <= 'd0; else data_in <= data_in + 1'b1; end pingpang dut ( .clk (clk ), .rst_n (rst_n ), .data_in (data_in ), .data_out (data_out ) ); endmodule
3.仿真結果

