新聞中心

EEPW首頁 > 嵌入式系統(tǒng) > 設計應用 > FPGA:數(shù)字示波器 2 - 雙端口 RAM

FPGA:數(shù)字示波器 2 - 雙端口 RAM

作者: 時間:2024-01-12 來源:EEPW編譯 收藏

FIFO使我們能夠非??焖俚孬@得工作設計。
但對于我們簡單的示波器來說,這有點矯枉過正。

我們需要一種機制來存儲來自一個時鐘域(100MHz)的數(shù)據(jù),并在另一個時鐘域(25MHz)中讀取數(shù)據(jù)。 一個簡單的雙端口RAM就可以做到這一點。 缺點是兩個時鐘域之間的所有同步(FIFO為我們所做的)現(xiàn)在必須“手動”完成。

本文引用地址:http://butianyuan.cn/article/202401/454719.htm

觸發(fā)

“基于 FIFO”的示波器設計沒有明確的觸發(fā)機制。
讓我們改變一下。 現(xiàn)在,每次從串行端口接收到字符時,示波器都會被觸發(fā)。 當然,這仍然不是一個非常有用的設計,但我們稍后會對其進行改進。

我們使用“async_receiver”從串行端口接收數(shù)據(jù):

wire [7:0] RxD_data;
async_receiver async_rxd(.clk(clk), .RxD(RxD), .RxD_data_ready(RxD_data_ready), .RxD_data(RxD_data));


每當收到一個新角色時,“RxD_data_ready”就會升高一個時鐘。 我們用它來觸發(fā)示波器。

同步

我們需要將這種“RxD_data_ready變高”的信息從“clk”(25MHz)域傳輸?shù)健癱lk_flash”(100MHz)域。

首先,當接收到字符時,信號“startAcquisition”變?yōu)楦唠娖健?/span>

reg startAcquisition;
wire AcquisitionStarted;

always @(posedge clk)
if(~startAcquisition)
  startAcquisition <= RxD_data_ready;
else
if(AcquisitionStarted)
  startAcquisition <= 0;


我們使用 2 個觸發(fā)器形式的同步器(將此“startAcquisition”傳輸?shù)搅硪粋€時鐘域)。

reg startAcquisition1; always @(posedge clk_flash) startAcquisition1 <= startAcquisition;
reg startAcquisition2; always @(posedge clk_flash) startAcquisition2 <= startAcquisition1;


最后,一旦另一個時鐘域“看到”信號,它就會“回復”(使用另一個同步器“獲取”)。

reg Acquiring;
always @(posedge clk_flash)
if(~Acquiring)
  Acquiring <= startAcquisition2;  // start acquiring?
else
if(&wraddress)  // done acquiring?
  Acquiring <= 0;

reg Acquiring1; always @(posedge clk) Acquiring1 <= Acquiring;
reg Acquiring2; always @(posedge clk) Acquiring2 <= Acquiring1;
assign AcquisitionStarted = Acquiring2;


回復將重置原始信號。

雙端口RAM

現(xiàn)在觸發(fā)器可用,我們需要一個雙端口RAM來存儲數(shù)據(jù)。
請注意 RAM 的每一側如何使用不同的時鐘。

ram512 ram_flash(
  .data(data_flash_reg), .wraddress(wraddress), .wren(Acquiring), .wrclock(clk_flash),
  .q(ram_output), .rdaddress(rdaddress), .rden(rden), .rdclock(clk)

);


使用二進制計數(shù)器可以輕松創(chuàng)建 ram 地址總線。
首先是寫地址:

reg [8:0] wraddress;
always @(posedge clk_flash) if(Acquiring) wraddress <= wraddress + 1;


和讀取地址:

reg [8:0] rdaddress;
reg Sending;
wire TxD_busy;

always @(posedge clk)
if(~Sending)
  Sending <= AcquisitionStarted;
else
if(~TxD_busy)
begin
  rdaddress <= rdaddress + 1;
  if(&rdaddress) Sending <= 0;
end


請注意每個計數(shù)器如何使用不同的時鐘。

最后,我們將數(shù)據(jù)發(fā)送到 PC:

wire TxD_start = ~TxD_busy & Sending;
wire rden = TxD_start;

wire [7:0] ram_output;
async_transmitter async_txd(.clk(clk), .TxD(TxD), .TxD_start(TxD_start), .TxD_busy(TxD_busy), .TxD_data(ram_output));

完整的設計

module oscillo(clk, RxD, TxD, clk_flash, data_flash);
input clk;
input RxD;
output TxD;

input clk_flash;
input [7:0] data_flash;

///////////////////////////////////////////////////////////////////
wire [7:0] RxD_data;
async_receiver async_rxd(.clk(clk), .RxD(RxD), .RxD_data_ready(RxD_data_ready), .RxD_data(RxD_data));

reg startAcquisition;
wire AcquisitionStarted;

always @(posedge clk)
if(~startAcquisition)
  startAcquisition <= RxD_data_ready;
else
if(AcquisitionStarted)
  startAcquisition <= 0;

reg startAcquisition1; always @(posedge clk_flash) startAcquisition1 <= startAcquisition ;
reg startAcquisition2; always @(posedge clk_flash) startAcquisition2 <= startAcquisition1;

reg Acquiring;
always @(posedge clk_flash)
if(~Acquiring)
  Acquiring <= startAcquisition2;
else
if(&wraddress)
  Acquiring <= 0;

reg [8:0] wraddress;
always @(posedge clk_flash) if(Acquiring) wraddress <= wraddress + 1;

reg Acquiring1; always @(posedge clk) Acquiring1 <= Acquiring;
reg Acquiring2; always @(posedge clk) Acquiring2 <= Acquiring1;
assign AcquisitionStarted = Acquiring2;

reg [8:0] rdaddress;
reg Sending;
wire TxD_busy;

always @(posedge clk)
if(~Sending)
  Sending <= AcquisitionStarted;
else
if(~TxD_busy)
begin
  rdaddress <= rdaddress + 1;
  if(&rdaddress) Sending <= 0;
end

wire TxD_start = ~TxD_busy & Sending;
wire rden = TxD_start;

wire [7:0] ram_output;
async_transmitter async_txd(.clk(clk), .TxD(TxD), .TxD_start(TxD_start), .TxD_busy(TxD_busy), .TxD_data(ram_output));

///////////////////////////////////////////////////////////////////
reg [7:0] data_flash_reg; always @(posedge clk_flash) data_flash_reg <= data_flash;

ram512 ram_flash(
  .data(data_flash_reg), .wraddress(wraddress), .wren(Acquiring), .wrclock(clk_flash),
  .q(ram_output), .rdaddress(rdaddress), .rden(rden), .rdclock(clk)
);

endmodule




評論


相關推薦

技術專區(qū)

關閉