Interface (インターフェース) 2009年 09月号 [雑誌], pp.116-118
コードは下の2点を除いてほぼテキストのままである。
- 出力の極性を切り替えられるようにした(負論理にもできるようにした)。
- コンポーネントとして呼び出しているシリアル通信クロック生成用分周器のコードが『FPGA/PLD入門記事全集[2200ページ収録CD-ROM付き]: 月刊トランジスタ技術,Interface,Design Wave Magazine10年分(2001-2010)から集大成 (アーカイブスシリーズ)』に収録されていなかったため独自に書いた。
↓ これがシミュレーション結果(dinの8ビット値がストップビットに続いてlsbファーストでdoutから出力されている):
↓ これが本体:
library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; entity serial_tx is generic( F_CLK: positive := 48_000_000; BAUD : positive := 9600 ); port( clk : in std_logic; aclr_n: in std_logic; wr : in std_logic; din : in std_logic_vector(7 downto 0); pol_inv: in std_logic; -- 0: 正論理; 1: 負論理 dout : out std_logic; ready: out std_logic ); end entity; architecture rtl of serial_tx is signal in_din: std_logic_vector(7 downto 0) := (others => '0'); signal buf : std_logic_vector(7 downto 0) := (others => '0'); signal serial_clk: std_logic := '0'; signal load: std_logic := '0'; signal run : std_logic := '0'; signal cbit : natural range 0 to 7 := 0 ; signal state: natural range 0 to 2 := 0 ; signal dout_temp: std_logic := '0'; begin module_clk_gen: entity work.clk_gen generic map( F_CLK => F_CLK, OUT_FREQ => BAUD ) port map( aclr_n => aclr_n, clk => clk, clk_out => serial_clk ); ready <= '1' when run = '0' and load = '0' else '0'; dout <= dout_temp when pol_inv = '0' else not dout_temp; process(clk, aclr_n) begin if aclr_n = '0' then load <= '0'; elsif rising_edge(clk) then if wr = '1' and run = '0' then load <= '1'; in_din <= din; end if; if load = '1' and run = '1' then load <= '0'; end if; end if; end process; process(serial_clk, aclr_n) begin if aclr_n = '0' then dout_temp <= '1'; cbit <= 0 ; state <= 0 ; run <= '0'; elsif rising_edge(serial_clk) then case state is when 0 => cbit <= 0; if load then dout_temp <= '0'; --スタートビット state <= state + 1; buf <= in_din; run <= '1'; else dout_temp <= '1'; run <= '0'; end if; when 1 => if cbit <= 6 then dout_temp <= buf(cbit); -- lsbから順番に送信する。 cbit <= cbit + 1; elsif cbit = 7 then dout_temp <= buf(cbit); state <= state + 1; end if; when 2 => dout_temp <= '1'; --ストップビット state <= 0 ; when others => state <= 0; end case; end if; end process; end architecture;
↓ これがシリアル通信クロック生成器(テキストは分周器にしてあるがここでは分周比ではなく出力周波数で指定できるようにした):
library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; entity clk_gen is generic( F_CLK : positive := 48_000_000; OUT_FREQ: natural := 9600 --OUT_FREQ: positive := 9600 * 16 ); port( aclr_n : in std_logic; clk : in std_logic; clk_out: out std_logic := '0' ); end entity; architecture rtl of clk_gen is begin process(aclr_n, clk) constant TOP_VAL: natural := F_CLK/(OUT_FREQ * 2) - 1; variable count : natural range 0 to TOP_VAL := 0; begin if aclr_n = '0' then count := 0; elsif rising_edge(clk) then if count >= TOP_VAL then clk_out <= not clk_out; count := 0; else count := count + 1; end if; end if; end process; end architecture;
↓ これがテストベンチ:
-- Copyright (C) 2020 Intel Corporation. All rights reserved. -- Your use of Intel Corporation's design tools, logic functions -- and other software and tools, and any partner logic -- functions, and any output files from any of the foregoing -- (including device programming or simulation files), and any -- associated documentation or information are expressly subject -- to the terms and conditions of the Intel Program License -- Subscription Agreement, the Intel Quartus Prime License Agreement, -- the Intel FPGA IP License Agreement, or other applicable license -- agreement, including, without limitation, that your use is for -- the sole purpose of programming logic devices manufactured by -- Intel and sold by Intel or its authorized distributors. Please -- refer to the applicable agreement for further details, at -- https://fpgasoftware.intel.com/eula. -- *************************************************************************** -- This file contains a Vhdl test bench template that is freely editable to -- suit user's needs .Comments are provided in each section to help the user -- fill out necessary details. -- *************************************************************************** -- Generated on "10/02/2021 15:20:16" -- Vhdl Test Bench template for design : serial_tx -- -- Simulation tool : ModelSim-Altera (VHDL) -- LIBRARY ieee; USE ieee.std_logic_1164.all; ENTITY serial_tx_vhd_tst IS END serial_tx_vhd_tst; ARCHITECTURE serial_tx_arch OF serial_tx_vhd_tst IS -- constants -- signals SIGNAL aclr_n : STD_LOGIC; SIGNAL clk : STD_LOGIC; SIGNAL din : STD_LOGIC_VECTOR(7 DOWNTO 0); SIGNAL dout : STD_LOGIC; SIGNAL pol_inv : STD_LOGIC; SIGNAL ready : STD_LOGIC; SIGNAL wr : STD_LOGIC; COMPONENT serial_tx PORT ( aclr_n : IN STD_LOGIC; clk : IN STD_LOGIC; din : IN STD_LOGIC_VECTOR(7 DOWNTO 0); dout : OUT STD_LOGIC; pol_inv : IN STD_LOGIC; ready : OUT STD_LOGIC; wr : IN STD_LOGIC ); END COMPONENT; BEGIN i1 : serial_tx PORT MAP ( -- list connections between master ports and signals aclr_n => aclr_n, clk => clk, din => din, dout => dout, pol_inv => pol_inv, ready => ready, wr => wr ); process begin aclr_n <= '1'; pol_inv <= '0'; wait; end process; process begin clk <= '1'; wait for 10417 ps; clk <= '0'; wait for 10417 ps; end process; process begin wr <= '0'; wait for 100 us; wr <= '1'; din <= 8b"1011_0101"; wait for 100 ns; wr <= '0'; wait for 1200 us; wr <= '1'; din <= 8b"1011_0111"; wait for 100 ns; wr <= '0'; wait; end process; END serial_tx_arch;