目次

GBCモニタ装置

 GameBoyCameraの出力データをモニタする装置を
 作成して、デバッグ効率を上げるようにしました。

 10x10のドットマトリクスLEDを利用した装置は
 以下です。



 回路図は、以下です。



 10x10のドットマトリクスLEDなので、2つのコネクタで
 操作できるよう、レジスタを2個、デコーダを1個利用
 しています。

 回路動作テストに、ATTiny2313で簡単なプログラムを
 作成しました。

#include <avr/io.h>
#include <avr/interrupt.h>

#define OFF 0
#define ON  OFF+1

typedef unsigned char  UBYTE ;
typedef unsigned short UWORD ;

volatile UBYTE tflag ;
volatile UBYTE sflag ;

volatile UWORD ledx   ;
volatile UWORD led_line[10] ;
volatile UBYTE lindex ;

volatile UWORD scnt ;
volatile UBYTE cnt ;
  
#define MASKFF 0xff
#define MASK1F 0x1f
#define MASK0F 0x0f
#define MASKF0 0xf0

#define LTRGU 0x80
#define LTRGL 0x40

#define SCNTMAX 4000

/*--------------------------------*/
/* Insert user functions protoype */
/*--------------------------------*/
void  user_initialize(void);
void  led_handling(void);
void  init_led_pat(UBYTE x);

/*------*/
/* main */
/*------*/
int main(void)
{
  /* disable interrupt */
  cli();
  /* initialize port and variables */
  user_initialize();
  /* enable interrupt */
  sei();
  /* endless loop */
  cnt = 0 ;
  while ( ON ) {
    /* dot matrix LED handling */
    if ( tflag ) { 
      tflag = OFF ;
      led_handling();
    }
    /* update pattern  */
    if ( sflag ) { 
      sflag = OFF ;
      /* update */
      cnt++ ;
      if ( cnt == 4 ) { cnt = 0 ; }
      init_led_pat(cnt);
    }
  }
  /* dummy */
  return 0 ;
}

/*-----------------------*/
/* Insert user functions */
/*-----------------------*/
void user_initialize(void)
{
  /* PORT B */
  PORTB = 0b00000000 ; /* 00000000 */
  DDRB  = 0b11111111 ; /* oooooooo */
  /* PORT D */
  PORTD = 0b00000000 ; /* 00000000 */
  DDRD  = 0b11111111 ; /* oooooooo */
  /* */
  tflag = OFF ;
  sflag = OFF ;
  scnt = 0 ;
  /* initialize timer0 */
  {
    /* CTC */
    TCCR0A = (1 << WGM01);
    /* 4MHz / 8 = 500kHz */
    TCCR0B = (1 << CS01) ;
    /* clear */
    TCNT0 = 0 ;
    /* set compare registers */
    OCR0A = 249 ; /* generate 2kHz */
    OCR0B = 255 ;
    /* enable compare match interrupt */
    TIMSK = (1 << OCIE0A);
  }
  /* initialize pattern */
  lindex = 0 ;
  init_led_pat(0);
}

void  led_handling(void)
{
  /* disable line */
  PORTD = MASKFF ;
  /* dot matrix LED handling */
  ledx = *(led_line+lindex) ;
  /* lower side */
  PORTB = ((ledx & MASK1F) ^ MASK1F) | LTRGL ;
  PORTB &= ~LTRGL ;
  /* upper side */
  ledx >>= 5 ;
  PORTB = ((ledx & MASK1F) ^ MASK1F) | LTRGU ;
  PORTB &= ~LTRGU ;
  /* select line */
  PORTD = lindex ;
  /* update */
  lindex++ ;
  if ( lindex == 10 )  { lindex = 0 ; }
}

void  init_led_pat(UBYTE x)
{
  UBYTE i ;
  /* clear */
  for ( i = 0 ; i < 10 ; i++ ) { *(led_line+i) = 0 ; }
  /* generate */
  switch ( x ) {
    case 1 :
      *(led_line+0) = 0x03ff ;
      *(led_line+1) = 0x03ff ;
      *(led_line+2) = 0x03ff ;
      *(led_line+3) = 0x03ff ;
      *(led_line+4) = 0x03ff ;
      break ;
    case 2 :
      *(led_line+5) = 0x03ff ;
      *(led_line+6) = 0x03ff ;
      *(led_line+7) = 0x03ff ;
      *(led_line+8) = 0x03ff ;
      *(led_line+9) = 0x03ff ;
      break ; 
    case 3 :
      *(led_line+0) = 0x0155 ;
      *(led_line+2) = 0x0155 ;
      *(led_line+4) = 0x0155 ;
      *(led_line+6) = 0x0155 ;
      *(led_line+8) = 0x0155 ;
      *(led_line+1) = 0x02aa ;
      *(led_line+3) = 0x02aa ;
      *(led_line+5) = 0x02aa ;
      *(led_line+7) = 0x02aa ;
      *(led_line+9) = 0x02aa ;
      break ;
    default :
      *(led_line+0) = 0x02aa ;
      *(led_line+2) = 0x02aa ;
      *(led_line+4) = 0x02aa ;
      *(led_line+6) = 0x02aa ;
      *(led_line+8) = 0x02aa ;
      *(led_line+1) = 0x0155 ;
      *(led_line+3) = 0x0155 ;
      *(led_line+5) = 0x0155 ;
      *(led_line+7) = 0x0155 ;
      *(led_line+9) = 0x0155 ;
      break ; 
  }
}

/* timer0 interrupt */
ISR(TIMER0_COMPA_vect)
{
  tflag = ON ;
  scnt++ ;
  if ( scnt == SCNTMAX ) {
    scnt = 0 ;
    sflag = ON ;
  }
}

 動作は単純で、2秒ごとに4つの出力パターンを変更します。

 表示は、0.5msごとに10ライン分のデータを74LS373に記憶させて
 いきます。この処理はエンドレスで、マイコンに電源は供給中
 ずっと繰り返します。

 ファームウエアで実現した内容を、VHDLコードに変換し
 CPLDのCoolRunnerIIでも動かしてみました。

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

entity dledc is
  generic (
    TOPX : integer := 4 ; 
    RMAX : integer := 9 --;
  );
  port(
    -- system
    nRESET : in  std_logic ;
    CLOCK  : in  std_logic ;
    -- output
    LTRGU : out std_logic ;
    LTRGL : out std_logic ;
    LDAT  : out std_logic_vector(4 downto 0) ;
    LADR  : out std_logic_vector(3 downto 0) --;
  );
end dledc;

architecture Behavioral of dledc is
  -- clock component
  component clkgenx is
    generic (
      TOPX : integer ; 
      RMAX : integer --;
    );
    port (
      -- system
      nRESET : in  std_logic ;
      CLOCK  : in  std_logic ;
      -- output
      CLKOUT : out std_logic -- ;
    );
  end component ;
  -- clock generator
  signal iPCLK  : std_logic ;
  signal iCNT   : integer range 0 to 200000 ;
  signal iCYCLE : std_logic_vector( 1 downto 0) ;
  -- run sequencer
  signal iLDAT  : std_logic_vector( 4 downto 0) ;
  signal iLDATX : std_logic_vector(99 downto 0) ;
  signal iLADR  : integer range 0 to 15 ;
  signal iPTR   : integer range 0 to 90 ;
  signal iSTATE : integer range 0 to 7 ;
begin
  -- clock generator
  CLKP : clkgenx generic map (TOPX,RMAX) port map (nRESET,CLOCK,iPCLK);

  -- output
  LTRGU <= '1' when ( iSTATE = 0 ) else '0' ;
  LTRGL <= '1' when ( iSTATE = 2 ) else '0' ;
  LDAT  <= not iLDAT  ;
  LADR  <= conv_std_logic_vector(iLADR,4) when ( iSTATE > 3 ) else "1111" ;

  -- decode 
  iLDATX(99 downto 90) <= "1010101010" when (iCYCLE = 0) else
                          "1111111111" when (iCYCLE = 1) else
                          "0101010101" when (iCYCLE = 3) else
                          "0000000000" ;

  iLDATX(89 downto 80) <= "1010101010" when (iCYCLE = 0) else
                          "1111111111" when (iCYCLE = 1) else
                          "0101010101" when (iCYCLE = 3) else
                          "0000000000" ;

  iLDATX(79 downto 70) <= "1010101010" when (iCYCLE = 0) else
                          "1111111111" when (iCYCLE = 1) else
                          "0101010101" when (iCYCLE = 3) else
                          "0000000000" ;

  iLDATX(69 downto 60) <= "1010101010" when (iCYCLE = 0) else
                          "1111111111" when (iCYCLE = 1) else
                          "0101010101" when (iCYCLE = 3) else
                          "0000000000" ;

  iLDATX(59 downto 50) <= "1010101010" when (iCYCLE = 0) else
                          "1111111111" when (iCYCLE = 1) else
                          "0101010101" when (iCYCLE = 3) else
                          "0000000000" ;

  iLDATX(49 downto 40) <= "1010101010" when (iCYCLE = 0) else
                          "1111111111" when (iCYCLE = 2) else
                          "0101010101" when (iCYCLE = 3) else
                          "0000000000" ;

  iLDATX(39 downto 30) <= "1010101010" when (iCYCLE = 0) else
                          "1111111111" when (iCYCLE = 2) else
                          "0101010101" when (iCYCLE = 3) else
                          "0000000000" ;

  iLDATX(29 downto 20) <= "1010101010" when (iCYCLE = 0) else
                          "1111111111" when (iCYCLE = 2) else
                          "0101010101" when (iCYCLE = 3) else
                          "0000000000" ;

  iLDATX(19 downto 10) <= "1010101010" when (iCYCLE = 0) else
                          "1111111111" when (iCYCLE = 2) else
                          "0101010101" when (iCYCLE = 3) else
                          "0000000000" ;

  iLDATX( 9 downto  0) <= "1010101010" when (iCYCLE = 0) else
                          "1111111111" when (iCYCLE = 2) else
                          "0101010101" when (iCYCLE = 3) else
                          "0000000000" ;
  -- cyclic update
  process (nRESET,iPCLK)
  begin
    if ( nRESET = '0' ) then
      iCNT   <= 0 ;
      iCYCLE <= "00" ;
    elsif rising_edge( iPCLK ) then
      iCNT <= iCNT + 1 ;
      if ( iCNT = 200000 ) then
        iCNT   <= 0 ;
        iCYCLE <= iCYCLE + '1' ;
      end if ;
    end if ;
  end process ;

  -- sequnecer
  process (nRESET,iPCLK)
  begin
    if ( nRESET = '0' ) then
      iLDAT  <= "00000" ;
      iLADR  <= 0 ;
      iPTR   <= 0 ;
      iSTATE <= 0 ;
    elsif rising_edge(iPCLK) then
      -- state machine
      case iSTATE is
        -- send upper 5 bits
        when 0 => iLDAT  <= iLDATX(99-iPTR downto 95-iPTR) ;
                  iSTATE <= 1 ;
        -- send upper trigger
        when 1 => iSTATE <= 2 ;
        -- send lower 5 bits
        when 2 => iLDAT  <= iLDATX(94-iPTR downto 90-iPTR) ;
                  iSTATE <= 3 ;
        -- send lower trigger
        when 3 => iSTATE <= 4 ;
        -- enable address
        when 4 => iSTATE <= 5 ;
        -- update 
        when 5 => iLADR  <= iLADR + 1 ;
                  iPTR   <= iPTR + 10 ;
                  iSTATE <= 6 ;
        -- return first state 
        when 6 => iSTATE <= 0 ;
                  if ( iLADR = 10 ) then
                    iLADR <= 0 ;
                    iPTR  <= 0 ;
                  end if ;
        -- default  
        when others =>
                  iSTATE <= 0 ;
      end case ;
    end if ;
  end process ;

end Behavioral;

 データパターンを出力すると、次のようになります。



(under construction)

目次

inserted by FC2 system