Lösung Testbench
Zuerst wird die Testbench angepasst.
Die Messfunktion misst jetzt anstatt der Periode die Anteile für High und Low:
--! measure LED period
procedure MeasureLedPeriod(constant maxCycles : in integer;
signal Led_high : out time; signal Led_low : out time) is
variable i : integer;
variable s : integer;
variable rise_1 : integer;
variable fall_1 : integer;
variable rise_2 : integer;
begin
s := 0; -- initial state
Led_high <= 0 ns; -- timeout return value
Led_low <= 0 ns; -- timeout return value
for i in 1 to maxCycles loop -- timeout condition
wait until rising_edge(Ext_Clk); -- measure in clock ticks
case s is
when 0 => -- wait for initial condition
if (Led = '0') then
s := 1; -- initial condition reached
end if;
when 1 => -- wait for rising edge
if (Led = '1') then
s := 2; -- first rising edge reached
rise_1 := i; -- remember clock tick
end if;
when 2 => -- wait for LED being off again
if (Led = '0') then
s := 3; -- LED is off again reached
fall_1 := i; -- remember clock tick
Led_high <= (fall_1 - rise_1) * Clk_period;
end if;
when 3 => -- wait for rising edge
if (Led = '1') then
s := 4; -- nothing more to do
rise_2 := i; -- remember clock tick
Led_low <= (rise_2 - fall_1) * Clk_period;
wait for 10 ps; -- Let variable value settle
return; -- got result
end if;
when others =>
return;
end case;
end loop;
end MeasureLedPeriod;
Die Überprüfungsfunktion überprüft jetzt diese Anteil und passt auch die Ausgabe entsprechend an:
--! check LED period
procedure CheckLedPeriod(constant expected : in time;
signal Led_high : inout time; signal Led_low : inout time;
signal TestErr : out std_logic) is
variable high_expected : time;
variable low_expected : time;
begin
high_expected := expected / 4;
low_expected := expected - high_expected;
MeasureLedPeriod(3*expected/Clk_period, Led_high, Led_low);
if ((Led_high = high_expected) and (Led_low = low_expected)) then
tb_report(" Expected high: " & time'Image(high_expected) &
", low: " & time'Image(low_expected) & ": passed.");
else
TestErr <= '1';
tb_report(" Expected high: " & time'Image(high_expected) &
", low: " & time'Image(low_expected) &
"; Found high: " & time'Image(Led_high) &
", low: " & time'Image(Led_low) &
": Failed!");
end if;
end CheckLedPeriod;
Der Test Case 5 wird angepasst, da es jetzt nur noch 7 anstatt 8 Schritte mit der Frequenz nach oben geht und die Testaufrufe werden natürlich auch angepasst, da anstatt der Periode jetzt _high und _low-Werte analysiert werden (diese Signale müssen natürlich auch deklariert werden!)
TestCase <= 5;
tb_report("Test Case 5: Increase LED speed to maximum");
for i in 1 to 7 loop
-- press frequency reduce button
Button(2) <= '1';
WaitCycles(10);
Button(2) <= '0';
expected_time := expected_time / 2;
CheckLedPeriod(expected_time, Led_high, Led_low, TestErr);
end loop;
Lösung UUT
Der eingeschränkte Frequenzbereich verändert die Grenzen des Selektors.
Um den Duty-Cycle von 25 % zu erhalten, ist es am einfachsten den Frequenzgenerator um ein Bit zu schieben und wieder mit dem Frequenzgenerator zu verunden.
signal CtrlFreqR : integer range 1 to 12 := 8; --! Control toggle freqency
signal FreqGen25C : std_logic_vector(12 downto 1); --! FreqGenR 25 % duty cycle
...
FreqGen25C <= FreqGenR(12 downto 1) and FreqGenR(11 downto 0);
Für die unteren beiden Bits schaut das dann so aus:
Schließlich muss noch der Multiplexer angepasst werden.
--! Multiplexer
p_mux : process (FreqGenR, FreqGen25C)
begin
case CtrlFreqR is
when 1 => LedC <= FreqGen25C(1);
when 2 => LedC <= FreqGen25C(2);
when 3 => LedC <= FreqGen25C(3);
when 4 => LedC <= FreqGen25C(4);
when 5 => LedC <= FreqGen25C(5);
when 6 => LedC <= FreqGen25C(6);
when 7 => LedC <= FreqGen25C(7);
when 8 => LedC <= FreqGen25C(8);
when 9 => LedC <= FreqGen25C(9);
when 10 => LedC <= FreqGen25C(10);
when 11 => LedC <= FreqGen25C(11);
when 12 => LedC <= FreqGen25C(12);
when others => LedC <= 'X';
end case;
end process;
Weiter geht es mit dem Projekt: SimpleState