三角波生成器

参考: CPLDでディジタル電子工作 (CQ文庫), pp.125ff.

アップダウンカウンターの出力をAD変換して三角波を生成する。ADコンバーターは8ビットR-2R方式にした。

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.math_real.all;

entity triangle_wave_gen is
    generic(
        F_CLK       : positive := 48_000_000;
        F_OUT_MAX   : positive := 10_000; -- 最大出力周波数。
        NUM_OUT_BITS: positive := 8;      -- 三角波出力のビット数
        TO_RAIL     : positive := 45      -- 出力レールまでの余裕
    );
    port(
        aclr_n: in std_logic;
        clk   : in std_logic;
        freq  : in std_logic_vector(integer(ceil(log2(real(1+F_OUT_MAX))))-1 downto 0);

        triangle_out: out std_logic_vector(NUM_OUT_BITS-1 downto 0)
    );
end entity;

architecture rtl of triangle_wave_gen is
    constant Q_MAX: positive := 2**NUM_OUT_BITS - 1;
    signal top_val: positive range 1 to F_CLK / 2;
begin

   -- 出力周波数の設定値が変化したらカウンターのトップ値を入れ換える。
    process(freq)
        variable freq_temp: positive range 1 to F_OUT_MAX := F_OUT_MAX;
    begin
        if unsigned(freq) > 0 then freq_temp := to_integer(unsigned(freq));
        else                       freq_temp := F_OUT_MAX;
        end if;
        top_val <= F_CLK / (2 * freq_temp);
    end process;

    process(clk, aclr_n)
        variable count: natural range  0 to F_CLK / 2 := 0;
        variable diff : integer range -1 to 1         := 1;
    begin
       -- 非同期クリア
        if aclr_n = '0' then
            count := 0;
       -- 同期カウントアップダウン
        elsif rising_edge(clk) then
            if    count <= 0       then diff :=  1;
            elsif count >= top_val then diff := -1;
            end if;
            count := count + diff;
        end if;

       -- スケーリングして出力
        triangle_out <= std_logic_vector(to_unsigned((count*(Q_MAX-2*TO_RAIL))/top_val+TO_RAIL, NUM_OUT_BITS));

    end process;
end architecture;

↓ これが10kHz
f:id:ti-nspire:20210925155542p:plain:w600
↓ これが1kHz
f:id:ti-nspire:20210925155547p:plain:w600