Câu trả lời:
Xây dựng bộ đếm 18 bit. Mỗi khi nó đạt 250.000, hãy lật một cái lật. 50 MHz / 250.000 = 200 Hz. Việc bấm một pin ở 200 Hz mang lại cho bạn 100 Hz với chu kỳ nhiệm vụ 50 phần trăm. Nếu bạn chỉ cần một xung có tần số lặp lại 100 Hz, thì hãy xây dựng bộ đếm 19 bit và tạo xung khi nó đạt 500.000.
May mắn thay, 250.000 và 500.000 đều là số nguyên. Tạo ra một chu kỳ nhiệm vụ 50 phần trăm hoàn hảo với một ước số lẻ có nghĩa là bạn cần phải lật đầu ra trên một cạnh tăng và tắt trên một cạnh giảm. Trên một Xilinx FPGA, điều này có thể được thực hiện với ODDR / ODDR2 và bộ đếm có một chút gãi đầu để có được các đầu vào D0 / D1 được đặt chính xác. Tuy nhiên, điều này chỉ hoạt động để gửi tín hiệu ra khỏi chip thông qua chân I / O, vì đầu ra của ODDR / ODDR2 không thể được sử dụng trong một thiết kế. Một xung thực sự là tất cả những gì bạn cần trong một thiết kế, mặc dù.
Tạo bất cứ thứ gì có tỷ lệ không nguyên sẽ phức tạp hơn. Nếu đó là một phần hợp lý, bạn có thể sử dụng PLL hoặc DDS để trợ giúp, một mình hoặc kết hợp với bộ đếm. Nếu nó không phải là một phần hợp lý, thì bạn ít nhiều gặp may mắn trừ khi bạn có thể ước chừng nó với một phần hợp lý. Nếu PLL không khả dụng, sẽ không đủ thấp hoặc bạn không thể có tỷ lệ đúng từ kết hợp PLL và bộ đếm, thì bạn có thể sử dụng DDS phân đoạn. Ý tưởng với DDS phân đoạn là bạn thêm hằng số vào bộ tích lũy trên mỗi chu kỳ đồng hồ và chuyển đổi đầu ra khi bộ tích lũy cuộn qua. Điều này sẽ tạo ra một đầu ra với một chút jitter, nhưng nó có thể tạo ra một tần số trung bình chính xác. Để tạo ra sóng vuông 100 Hz 50 phần trăm với bộ tích lũy 32 bit, tất cả những gì bạn cần làm là thêm 100 * 2 ^ 32 / 50e6 = 8589. 93459 ~ = 8590 mỗi chu kỳ đồng hồ. MSB của bộ tích lũy sẽ chuyển đổi ở mức 50e6 / (2 ^ 32 * 8590) = 100.00076145 Hz. Tích lũy càng lớn, điều này sẽ càng chính xác. Độ phân giải tần số của bộ tích lũy 32 bit khá tốt - nếu bạn tăng hoặc giảm 1 LSB, bạn sẽ nhận được 98.989119 hoặc 100.012403 Hz. Tuy nhiên, bạn sẽ nhận được khoảng thời gian +/- 1 của cái được gọi là jitter xác định. Nói cách khác, các cạnh được lượng tử hóa theo thời gian đồng hồ và do đó có thể lên đến 1/2 thời gian đồng hồ sớm hoặc muộn. Không giống như jitter thông thường, nếu bạn xem jitter xác định trên máy hiện sóng, bạn sẽ thấy phân phối rất đơn giản của thời gian chu kỳ với hai hoặc nhiều trung bình riêng biệt, trái ngược với một phân phối trơn tru. Ngoài ra, vì .00076145 là phần bù và không phải là mức trung bình, nên pha sẽ dần thay đổi theo đồng hồ hệ thống.
Ví dụ Verilog để tạo 100 Hz từ 50 MHz với chu kỳ nhiệm vụ 50%:
// generate 100 Hz from 50 MHz
reg [17:0] count_reg = 0;
reg out_100hz = 0;
always @(posedge clk_50mhz or posedge rst_50mhz) begin
if (rst_50mhz) begin
count_reg <= 0;
out_100hz <= 0;
end else begin
if (count_reg < 249999) begin
count_reg <= count_reg + 1;
end else begin
count_reg <= 0;
out_100hz <= ~out_100hz;
end
end
end
Ví dụ Verilog để tạo ra xung 10 Hz lặp lại 100 Hz từ xung nhịp 50 MHz:
// generate 100 Hz pulse chain from 50 MHz
reg [18:0] count_reg = 0;
reg out_100hz = 0;
always @(posedge clk_50mhz or posedge rst_50mhz) begin
if (rst_50mhz) begin
count_reg <= 0;
out_100hz <= 0;
end else begin
out_100hz <= 0;
if (count_reg < 499999) begin
count_reg <= count_reg + 1;
end else begin
count_reg <= 0;
out_100hz = 1;
end
end
end
Ví dụ Verilog để tạo đầu ra 10 MHz với chu kỳ nhiệm vụ 50% từ đồng hồ 250 MHz với ODDR2 trên Spartan 6:
// generate 10 MHz from 250 MHz
// 25 cycle counter, falling edge interpolated
reg [4:0] count_reg = 0;
reg q0 = 0;
reg q1 = 0;
always @(posedge clk_250mhz or posedge rst_250mhz) begin
if (rst_250mhz) begin
count_reg <= 0;
q0 <= 0;
q1 <= 0;
end else begin
if (count_reg < 24) begin
count_reg <= count_reg + 1;
end else begin
count_reg <= 0;
end
q0 <= count_reg < 12;
q1 <= count_reg < 13;
end
end
ODDR2
clk_10mhz_out_oddr2_inst
(
.Q(clk_10mhz_out),
.C0(clk_250mhz),
.C1(~clk_250mhz),
.CE(1),
.D0(q0),
.D1(q1),
.R(0),
.S(0)
);
Ví dụ mã Verilog để tạo 100 Hz từ 50 MHz với chu kỳ nhiệm vụ 50% bằng cách sử dụng bộ tích lũy:
// generate 100 Hz from 50 MHz
reg [31:0] count_reg = 0;
wire out_100hz = count_reg[31];
always @(posedge clk_50mhz or posedge rst_50mhz) begin
if (rst_50mhz) begin
count_reg <= 0;
end else begin
count_reg <= count_reg + 8590; //(((100 * 1 << 32) + 50000000/2) / 50000000)
end
end