非同期シリアルインターフェイス(UART)で受信できるようにする

Interface (インターフェース) 2009年 09月号 [雑誌], pp.116-118

今度は受信。

シリアル通信用クロックはボーレートの16倍にする。シリアルラインがHからLに下がってそこから6クロック目(0から数えて6クロック目)がやはりLであったら確かにスタートビットであると見なし、それ以降16クロックごとにデータを読み取る。

↓ これがシミュレーション結果:
f:id:ti-nspire:20211005071220p:plain

↓ これが本体:

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

entity serial_rx is
    generic(
        F_CLK: positive := 48_000_000;
        BAUD : positive := 9600
    );
    port(
        clk   : in std_logic;
        aclr_n: in std_logic;
        din   : in std_logic;
        
        pol_inv: in std_logic; -- 0: 正論理; 1: 負論理
        
        rd  : out std_logic;
        dout: out std_logic_vector(7 downto 0)       
    );
end entity;

architecture rtl of serial_rx is
    signal buf  : std_logic_vector(7 downto 0) := (others => '0');
    signal start: std_logic                    := '1';
    signal cbit : natural range 0 to 150       :=  0 ;
    signal rx_en: std_logic                    := '0';
    
    signal din_temp: std_logic := '1';
begin
    module_clk_gen: entity work.clk_gen
    generic map(
        F_CLK    => F_CLK,
        OUT_FREQ => BAUD * 16
    )
    port map(
        aclr_n  => aclr_n,
        clk     => clk,
        clk_out => rx_en
    );


    din_temp <= din when pol_inv = '0' else not din;

    process(aclr_n, rx_en)
    begin
        if aclr_n = '0' then
            start <= '0';
            cbit  <=  0 ;
            buf   <= (others => '0');
            dout  <= (others => '0');
        elsif rising_edge(rx_en) then
            if start = '0' then
                rd <= '0';
                if din_temp = '0' then -- HからLに変化して、
                    start <= '1';
                end if;
                cbit <= 0;
            else
                case cbit is
                    when 6 => -- それが本当にスタートビットであったら、
                        if din_temp = '1' then
                            cbit  <=  0 ;
                            start <= '0';
                        else
                            cbit <= cbit + 1;
                        end if;
                    when 22|38|54|70|86|102|118|134 =>
                        cbit <= cbit + 1;
                        buf  <= din_temp & buf(7 downto 1); -- lsbから順番に読み取る。
                    when 150 =>
                        cbit  <=  0 ;
                        dout  <= buf;
                        start <= '0';
                        rd    <= '1';
                    when others =>
                        cbit <= cbit + 1;
                end case;
            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/03/2021 08:45:28"
                                                            
-- Vhdl Test Bench template for design  :  serial_rx
-- 
-- Simulation tool : ModelSim-Altera (VHDL)
-- 

LIBRARY ieee;                                               
USE ieee.std_logic_1164.all;                                

ENTITY serial_rx_vhd_tst IS
END serial_rx_vhd_tst;
ARCHITECTURE serial_rx_arch OF serial_rx_vhd_tst IS
-- constants                                                 
-- signals                                                   
SIGNAL aclr_n : STD_LOGIC;
SIGNAL clk : STD_LOGIC;
SIGNAL din : STD_LOGIC;
SIGNAL dout : STD_LOGIC_VECTOR(7 DOWNTO 0);
SIGNAL pol_inv : STD_LOGIC;
SIGNAL rd : STD_LOGIC;
COMPONENT serial_rx
    PORT (
    aclr_n : IN STD_LOGIC;
    clk : IN STD_LOGIC;
    din : IN STD_LOGIC;
    dout : OUT STD_LOGIC_VECTOR(7 DOWNTO 0);
    pol_inv : IN STD_LOGIC;
    rd : OUT STD_LOGIC
    );
END COMPONENT;
BEGIN
    i1 : serial_rx
    PORT MAP (
-- list connections between master ports and signals
    aclr_n => aclr_n,
    clk => clk,
    din => din,
    dout => dout,
    pol_inv => pol_inv,
    rd => rd
    );

    
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
    type char_array_t is array(natural range <>) of std_logic_vector;
    variable d: char_array_t(0 to 3)(7 downto 0) := (8x"3E", 8x"3F", 8x"40", 8x"41");
begin
    din <= '1'; wait for 500 us;

    for i in d'range loop
        din <= '0'; wait for 104167 ns; -- スタートビット

        for j in d(i)'reverse_range loop
            din <= d(i)(j); wait for 104167 ns;
        end loop;

        din <= '1'; wait for 104167 ns; -- ストップビット
        din <= '1'; wait for 100 ns;
    end loop;

    wait;
end process;    
    
    
END serial_rx_arch;