LoginSignup
1
0

More than 1 year has passed since last update.

MAX10 FPGAとポケコンPC-G850VSとでUART通信

Last updated at Posted at 2021-10-23

1. 概要

三好 健文, 高前田 伸也,『Interface (インターフェース)』, 2009年09月号, CQ出版, pp.116-118に紹介されているUARTモジュールを試す。『FPGA/PLD入門記事全集』, 2014年, CQ出版にも収録されている。

負論理にできるようにしたこと、読み取り完了信号rdのタイミングを少し変えたこと以外はテキストのままである。

2. ポケコンPC-G850VS側の準備

ここにあるターミナルソフトウェアをインストールする。今回はg850vterm.ihxをインストールした。インストールできたら、ターミナルを起動し、[BASIC]ボタンを押して設定する。

3. MAX10 FPGA側の準備

下の4つのVHDLをコンパイルして書き込む。

トップレベルエンティティを見る/隠す
UART.vhd
library ieee;
use ieee.std_logic_1164.all;

entity UART is
    generic(
        F_CLK  : positive  := 48_000_000; -- 評価ボードに載っているクロックをそのまま使う。
        BAUD   : positive  := 9600;
        POL_INV: std_logic := '1' -- 0: 正論理, 1: 負論理
    );
    port(
        clk   : in std_logic;
        aclr_n: in std_logic;

        rx: in  std_logic;
        tx: out std_logic;

        rx_data: out std_logic_vector(7 downto 0); -- 受信したデータ
        tx_data: in  std_logic_vector(7 downto 0); -- 送信するデータ

        rd: out std_logic; -- 受信完了信号
        wr: in  std_logic; -- 送信命令

        tx_ready: out std_logic -- 送信可能か
    );
end entity;

architecture rtl of UART is
begin
    module_rx: entity work.serial_rx
    generic map(
        F_CLK   => F_CLK,
        BAUD    => BAUD,
        POL_INV => POL_INV
    )
    port map(
        clk    => clk,
        aclr_n => aclr_n,
        rd     => rd,
        din    => rx,
        dout   => rx_data
    );

    module_tx: entity work.serial_tx
    generic map(
        F_CLK   => F_CLK,
        BAUD    => BAUD,
        POL_INV => POL_INV
    )
    port map(
        clk    => clk,
        aclr_n => aclr_n,
        wr     => wr,
        din    => tx_data,
        dout   => tx,
        ready  => tx_ready
    );
end architecture;

シリアル通信用クロック生成器を見る/隠す
clk_gen.vhd
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: positive := 9600
        );
    port(
        aclr_n : in  std_logic;
        clk    : in  std_logic;
        clk_out: out std_logic
    );
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;

TXモジュールを見る/隠す
serial_tx.vhd
-- 参考: Interface (インターフェース), 2009年09月号, pp.116-118, CQ出版

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;
        POL_INV: std_logic := '0' -- 0: 正論理; 1: 負論理 
    );
    port(
        clk   : in std_logic;
        aclr_n: in std_logic;
        wr    : in std_logic;
        din   : in std_logic_vector(7 downto 0);

        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);
    signal buf   : std_logic_vector(7 downto 0);

    signal tx_en: std_logic;
    signal load : std_logic;
    signal run  : std_logic;

    signal cbit : natural range 0 to 7;
    signal state: natural range 0 to 2;

    signal dout_temp: std_logic;

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 => tx_en
    );

    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(tx_en, aclr_n)
    begin
        if aclr_n = '0' then
            dout_temp <= '1';
            cbit      <=  0 ;
            state     <=  0 ;
            run       <= '0';
        elsif rising_edge(tx_en) 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;

RXモジュールを見る/隠す
serial_rx.vhd
-- 参考: Interface (インターフェース), 2009年09月号, pp.116-118, CQ出版

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;
        POL_INV: std_logic := '0' -- 0: 正論理; 1: 負論理 
    );
    port(
        clk   : in std_logic;
        aclr_n: in std_logic;
        din   : in std_logic;

        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);
    signal start: std_logic;
    signal cbit : natural range 0 to 159;
    signal rx_en: std_logic;

    signal din_temp: std_logic;
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 -- RXラインが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 => -- 16クロックごとに、
                        buf  <= din_temp & buf(7 downto 1); -- lsbから順番に読み取って、
                        cbit <= cbit + 1;
                    when 135 =>
                        dout  <= buf; -- 全部読み取り終えたらすぐにデータを確保して、
                        cbit <= cbit + 1;
                    when 159 => -- ストップビットの末尾で、
                        cbit  <=  0 ;
                        start <= '0';
                        rd    <= '1'; -- 受信完了信号を出す。
                    when others =>
                        cbit <= cbit + 1;
                end case;
            end if;
        end if;
    end process;
end architecture;

4. 実際に動かす

4.1 全体の接続図

ポケコンから受信した1文字をそっくりそのまま送り返す。ここでは送受両ラインともこのモジュールでレベル変換したが、ポケコン(RX) <- MAX10 (TX)のラインはレベル変換しなくてもよい。
image.png

4.2 実行結果

ターミナルのエコーをオンにしているので同じ文字が2回ずつ表示される。

4.3 ロジアナによる観測結果

今、受信した'a'をそのまま送り返したところ。通信ラインは負論理である。

image.png

5. ファイル一式

https://github.com/ti-nspire/VHDL_for_Quartus_Prime/tree/main/UART_ver_2

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0