目次

定番回路確認

 マイコンを利用した動作確認は、LEDチカチカ
 (Lチカと省略されてることが多い)ですが
 自分の中の定番回路は、蛍のエミュレートです。

 2個のLEDを使い、1個のLEDはジワリと点灯し
 他の1個は消灯ということを、交互に繰返し。

 ブレッドボード上の回路は、以下。



 発振回路を応用して、次のVHDLコードで実現。

  -- hotal
  iHOTAL(0) <= '1' when ( iCNT < iREG ) else '0' ;
  iHOTAL(1) <= not iHOTAL(0) ;

  -- PWM
  process ( nRESET , iACLK )
  begin
    if ( nRESET = '0' ) then
      iCNT <= 0 ;
    elsif rising_edge( iACLK ) then
      if ( iCNT = LAST ) then
        iCNT <= 0 ;
      else
        iCNT <= iCNT + 1 ;
      end if ;
    end if ;
  end process ;

  -- register
  process ( nRESET , iBCLK )
  begin
    if ( nRESET = '0' ) then
      iREG <= 19 ;
    elsif rising_edge( iBCLK ) then
      if ( iREG >= LAST ) then
        iREG <= 19 ;
      else
        iREG <= iREG + 3 ;
      end if ;
    end if ;
  end process ;

 2個のLEDを使うので、位相を180度変えて波形を出力。

 ジワリと点灯するのは、PWM波形をLEDに転送。
 PWM波形は、カウンタと参照レジスタを利用すれば
 簡単に生成できるので、process文を使って記述。

 カウンタは、0から99までを1kHzで生成。
 レジスタは、19から99までを1Hzで生成。
 レジスタは、増分を3にして変化の度合いを調整してます。

 システムクロックを4MHzとして、分周器を入れて
 1kHzと1Hzを生成します。ブロック図は、以下。



 ブロック図が描けば、VHDLコードに変換するだけ。

  -- divider
  process ( nRESET , CLOCK )
  begin
    if ( nRESET = '0' ) then
      iACNT <= 0 ;
    elsif rising_edge( CLOCK ) then
      if ( iACNT = ACNT_MAX ) then
        iACNT <= 0 ;
      else
        iACNT <= iACNT + 1 ;
      end if ;
    end if ;
  end process ;
  iACLK <= '1' when ( iACNT < ACNT_HALF ) else '0' ;

  process ( nRESET , iACLK )
  begin
    if ( nRESET = '0' ) then
      iBCNT <= 0 ;
    elsif rising_edge( iACLK ) then
      if ( iBCNT = BCNT_MAX ) then
        iBCNT <= 0 ;
      else
        iBCNT <= iBCNT + 1 ;
      end if ;
    end if ;
  end process ;
  iBCLK <= '1' when ( iBCNT < BCNT_HALF ) else '0' ;

 カウンタとレジスタのクロックでは、DUTY比が
 50%になるように指定。

 定数は、CONSTANTを利用して定義。

  CONSTANT ACNT_MAX  : integer := 3999 ;
  CONSTANT BCNT_MAX  : integer :=  999 ;
  CONSTANT ACNT_HALF : integer := 2000 ;
  CONSTANT BCNT_HALF : integer :=  500 ;
  CONSTANT LAST      : integer :=   99 ;

 また、レジスタはintegerを利用してわかりやすく
 かつ範囲を限定してバグが入らないようにします。

  signal iACNT : integer range 0 to ACNT_MAX ;
  signal iBCNT : integer range 0 to BCNT_MAX ;

 rangeを利用すると、std_logic_vectorを
 使わずに、ビット幅を調整できます。

 ビット幅の計算は、2進数での範囲指定と
 なるので、面倒なことは処理系に一任して
 と考えて、余計なことに頭を使わないよう
 にします。

 まとめると、以下。

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity chotal is
  Port (
    -- system 
    nRESET : in  std_logic ;
    CLOCK  : in  std_logic ; -- 4MHz
    -- clock monitor
    ACLK   : out std_logic ;
    BCLK   : out std_logic ;
    -- output
    HOTAL : out std_logic_vector(1 downto 0) --;
  );
end chotal;

architecture Behavioral of chotal is
  --
  CONSTANT ACNT_MAX  : integer := 3999 ;
  CONSTANT BCNT_MAX  : integer :=  999 ;
  CONSTANT ACNT_HALF : integer := 2000 ;
  CONSTANT BCNT_HALF : integer :=  500 ;
  CONSTANT LAST      : integer :=   99 ;
  -- divider
  signal iACNT : integer range 0 to ACNT_MAX ;
  signal iACLK : std_logic ;
  signal iBCNT : integer range 0 to BCNT_MAX ;
  signal iBCLK : std_logic ;
  -- PWM
  signal iCNT  : integer range 0 to LAST ;
  -- register
  signal iREG  : integer range 0 to LAST ;
  -- hotal
  signal iHOTAL : std_logic_vector(1 downto 0) ;
begin
  -- output
  HOTAL <= iHOTAL ;
  ACLK  <= iACLK ;
  BCLK  <= iBCLK ;

  -- hotal
  iHOTAL(0) <= '1' when ( iCNT < iREG ) else '0' ;
  iHOTAL(1) <= not iHOTAL(0) ;

  -- divider
  process ( nRESET , CLOCK )
  begin
    if ( nRESET = '0' ) then
      iACNT <= 0 ;
    elsif rising_edge( CLOCK ) then
      if ( iACNT = ACNT_MAX ) then
        iACNT <= 0 ;
      else
        iACNT <= iACNT + 1 ;
      end if ;
    end if ;
  end process ;
  iACLK <= '1' when ( iACNT < ACNT_HALF ) else '0' ;

  process ( nRESET , iACLK )
  begin
    if ( nRESET = '0' ) then
      iBCNT <= 0 ;
    elsif rising_edge( iACLK ) then
      if ( iBCNT = BCNT_MAX ) then
        iBCNT <= 0 ;
      else
        iBCNT <= iBCNT + 1 ;
      end if ;
    end if ;
  end process ;
  iBCLK <= '1' when ( iBCNT < BCNT_HALF ) else '0' ;

  -- PWM
  process ( nRESET , iACLK )
  begin
    if ( nRESET = '0' ) then
      iCNT <= 0 ;
    elsif rising_edge( iACLK ) then
      if ( iCNT = LAST ) then
        iCNT <= 0 ;
      else
        iCNT <= iCNT + 1 ;
      end if ;
    end if ;
  end process ;

  -- register
  process ( nRESET , iBCLK )
  begin
    if ( nRESET = '0' ) then
      iREG <= 19 ;
    elsif rising_edge( iBCLK ) then
      if ( iREG >= LAST ) then
        iREG <= 19 ;
      else
        iREG <= iREG + 3 ;
      end if ;
    end if ;
  end process ;

end Behavioral;

 2種のクロックを生成していることが
 わかるよう、モニタピンを使ってます。

 ピンアサインは、以下。

# system
NET "nRESET" loc = "P39" ;
NET "CLOCK"  loc = "P5"  ;

# monitor
NET "ACLK"      loc = "P1" ;
NET "BCLK"      loc = "P2" ;

# hotal
NET "CHOTAL<0>" loc = "P8" ;
NET "CHOTAL<1>" loc = "P9" ;

 LEDの点滅は、次の基板に接続して確認しました。




目次

inserted by FC2 system