目次

センサー動作確認

 センサーとして2台のカメラを利用します。



 実際のコースは、天井から蛍光灯による照明と
 窓から入る太陽光で、場所ごとに照度や映込み
 があります。

 今回、偏光板を利用して、コース面の状態が場所
 と照明によるバラツキが少なくなるようにします。



 知人の光学専門家である大学教授が、実験で不要
 になったとのでと、頂いたモノ。
 これを通して、コース面を撮影した場合との比較
 をしてみます。

 バーコードスキャナ(BCS)で、光学系での違いがでる
 のかも実験してみます。BCSは、mugen2012で使った
 ものを用意します。



 H8/3048FOne基板と128kバイトのSRAMが手元に残って
 いたので、画像を保存するための基板を半田付けです。



 MCRに利用されていた基板ですが、34ピン、20ピンの
 コネクタをつけて、ジャックインできるようにして
 あります。

 SRAMは、アドレス、データ、コントロールの3種類
 のバスが必要なので、次のように結線しました。

 ポート5の3ピンは、負論理なので抵抗で
 プルアップしてあります。

 GBCとH8/3048FOneを接続するには、9ピン
 次のようにします。

 BarCodeScannerは、次の回路で接続します。



 SHをトリガーとして、LMC555が160usの間カウンタ
 74HC4040をリセットします。
 2つのクロックで、カウンタを動かし、256カウント
 ごとにCCDの出力データをラッチさせます。
 シフトレジスタで8データ分記憶後、2048カウント
 目に8ビットデータを出力レジスタに転送します。

 モニター用に8ビット分のLEDを接続します。

 10ピンケーブルコネクタを利用して
 H8/3048FOneや他のマイコン基板に
 接続します。

 等価回路を、CPLDに入れてみました。

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

entity bcs is
  port (
    -- system
    nRESET : in  std_logic ;
    CLOCK  : in  std_logic ; -- 400kHz
    -- shift clock
    SCLK   : in  std_logic ; -- 200kHz
    -- input
    SH     : in  std_logic ;
    SDAT   : in  std_logic ;
    -- output
    REGOUT : out std_logic_vector(7 downto 0) ;
    LOUT   : out std_logic_vector(7 downto 0) --;
  ) ;
end bcs;

architecture Behavioral of bcs is
  -- constant values
  constant TCNT0 : integer := 256 ;
  constant TCNT1 : integer := 512 ;
  constant TCNT2 : integer := 768 ;
  constant TCNT3 : integer := 1024 ;
  constant TCNT4 : integer := 1280 ;
  constant TCNT5 : integer := 1536 ;
  constant TCNT6 : integer := 1792 ;
  constant TCNT7 : integer := 2048 ;
  -- state machine
  signal iSTATE   : std_logic_vector(1 downto 0);
  signal iXRST    : std_logic ;
  -- trigger
  signal iSH_SFT : std_logic_vector(2 downto 0);
  signal iSH_TRG : std_logic ;
  -- counter
  signal iCNT     : integer range 0 to 2090 ;
  signal iSENABLE : std_logic ;
  -- shift register
  signal iSFTREG : std_logic_vector(7 downto 0);
  -- data register
  signal iREG : std_logic_vector(7 downto 0);

begin
  -- output
  REGOUT <= iREG ;
  LOUT   <= not iREG ;

  -- trigger
  process (nRESET,CLOCK)
  begin
    if ( nRESET = '0' ) then
      iSH_SFT <= "000" ;
    elsif rising_edge(CLOCK) then
      iSH_SFT <= iSH_SFT(1 downto 0) & SH ;
    end if ;
  end process ;
  iSH_TRG <= '1' when ( iSH_SFT = "011" or iSH_SFT = "001" ) else '0' ;

  -- state machine
  process (nRESET,CLOCK)
  begin
    if ( nRESET = '0' ) then
      iSTATE <= "00" ;
    elsif rising_edge(CLOCK) then
      case conv_integer(iSTATE) is
        -- wait trigger
        when 0 => if ( iSH_TRG = '1' ) then
                    iSTATE <= "01" ;
                  else
                    iSTATE <= "00" ;
                  end if ;
        -- clear counter
        when 1 => iSTATE <= "11" ;
        -- wait maximum count
        when 3 => if ( iCNT = 2060 ) then
                    iSTATE <= "10" ;
                  else
                    iSTATE <= "11" ;
                  end if ;
        -- return first state
        when 2 => iSTATE <= "00" ;
        -- default
        when others => iSTATE <= "00" ;
      end case ;
    end if ;
  end process ;
  iXRST <= '0' when ( iSTATE = "01" ) else '1' ;

  -- counter
  process (nRESET,iXRST,SCLK)
  begin
    if ( nRESET = '0' or iXRST = '0' ) then
      iCNT <= 0 ;
    elsif rising_edge(SCLK) then
      iCNT <= iCNT + 1 ;
    end if ;
  end process ;

  iSENABLE <= '1' when ( iCNT = TCNT0 ) else
              '1' when ( iCNT = TCNT1 ) else
              '1' when ( iCNT = TCNT2 ) else
              '1' when ( iCNT = TCNT3 ) else
              '1' when ( iCNT = TCNT4 ) else
              '1' when ( iCNT = TCNT5 ) else
              '1' when ( iCNT = TCNT6 ) else
              '1' when ( iCNT = TCNT7 ) else
              '0' ;

  -- data shift register
  process (nRESET,SCLK)
  begin
    if ( nRESET = '0' ) then
      iSFTREG <= (others => '0') ;
    elsif rising_edge(SCLK) then
      if ( iSENABLE = '1' ) then
        iSFTREG <= iSFTREG(6 downto 0) & SDAT ;
      end if ;
    end if ;
  end process ;

  -- latch
  process (nRESET,CLOCK)
  begin
    if ( nRESET = '0' ) then
      iREG <= (others => '0') ;
    elsif rising_edge(CLOCK) then
      if ( iSTATE = "10" ) then
        iREG <= iSFTREG ;
      end if ;
    end if ;
  end process ;

end Behavioral;

 H8と組合わせる場合、H8/3052F基板上のCPLDに実装します。



 GBCを接続する前に、H8/3048FOne基板の動作を
 確認するファームウエアを作成しました。

/* 14.7456 */
/* #define SYS_CLOCK_14_7456 */
/* 24.576 */
#define SYS_CLOCK_24_576
#include <3048.h>

/* define data type */
typedef unsigned char  UBYTE ;
typedef          char  SBYTE ;
typedef unsigned short UWORD ;
typedef          short SWORD ;
typedef unsigned long  ULONG ;

/*--------------------*/
/* declare port macro */
/*--------------------*/
#define P1DDR P1.DDR 
#define P2DDR P2.DDR 
#define P3DDR P3.DDR 
#define P4DDR P4.DDR 
#define P5DDR P5.DDR 
#define P6DDR P6.DDR 
#define P8DDR P8.DDR 
#define P9DDR P9.DDR 
#define PADDR PA.DDR 
#define PBDDR PB.DDR 

#define P1DR P1.DR.BYTE 
#define P2DR P2.DR.BYTE 
#define P3DR P3.DR.BYTE 
#define P4DR P4.DR.BYTE 
#define P5DR P5.DR.BYTE 
#define P6DR P6.DR.BYTE 
#define P7DR P7.DR.BYTE 
#define P8DR P8.DR.BYTE 
#define P9DR P9.DR.BYTE 
#define PADR PA.DR.BYTE 
#define PBDR PB.DR.BYTE 

#define OFF 0
#define ON  OFF+1

#define ITU0_AREG 24575

#define SRAM_PG P5.DR.BIT.B3
#define SRAM_CS P5.DR.BIT.B2
#define SRAM_OE P5.DR.BIT.B1
#define SRAM_WR P5.DR.BIT.B0

#define MASKFF 0xff

#define PCNTMAX 100

ULONG timcnt ;
UBYTE uflag ;
UBYTE sindex ;
UBYTE sbuf[32];
UBYTE cmd ;

UBYTE asc_hex[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'} ;
UBYTE right_duty ;
UBYTE left_duty ;
UBYTE right_dutyx ;
UBYTE left_dutyx ;
UBYTE pcnt ;
UBYTE bport ;

UBYTE lcnt ;

UWORD myadr ;
UBYTE mydat ;

void  user_io(void) ;
UBYTE get_road(void) ;
void  send_led(UBYTE x) ;
UBYTE get_sram(UWORD xadr) ;
void  put_sram(UWORD xadr,UBYTE xdat) ;

void  init_sci_1(TBaudRate x);
void  rs1_putchar(UBYTE x);
void  rs1_crlf(void);
void  rs1_puts(UBYTE *x);
void  show_help(void);
void  show_value(UBYTE x);
UBYTE get_hex(UBYTE x);
void  show_value_decimal(UBYTE x);
UBYTE get_adr_dat(UBYTE *ptr);

void  init_timer0(void);

int main(void)
{
  UBYTE tmp ;
  UWORD loop ;
  /* disabel interrupt */
  DI ;
  user_io();
  /* enable interrupt */
  EI ;
  /* opening message */
  rs1_puts("Hello"); rs1_crlf() ;
  /* endless loop */
  while ( ON ) {
    /* command interpreter */
    if ( uflag == ON ) {
      /* clear flag */
      uflag = OFF ;
      /* new line */
      rs1_crlf();
      /* get command */
      cmd = *(sbuf+0) ;
      /* help */
      if ( cmd == '?' ) { show_help() ; }
      /* lamp flashing */
      if ( cmd == 'L' ) {
        /* get pattern */
        tmp = get_hex( *(sbuf+1) ) ;
        tmp <<= 4 ;
        tmp |= get_hex( *(sbuf+2) ) ;
        /* impress */
        bport &= 0x3f ;
        if ( tmp == 0x11 ) { lcnt = 0x30 ; }
        if ( tmp == 0x01 ) { lcnt = 0xb0 ; }
        if ( tmp == 0x10 ) { lcnt = 0x70 ; }
        if ( tmp == 0x00 ) { lcnt = 0xc0 ; }
        bport |= lcnt ;
      }
      /* motor */
      if ( cmd == 'M' ) {
        /* get duty ratio */
        tmp = get_hex( *(sbuf+1) );
        tmp *= 10 ;
        tmp += get_hex( *(sbuf+2) );
        /* deliver */
        if ( *(sbuf+3) == 'R' ) { right_duty = tmp ; }
        if ( *(sbuf+3) == 'L' ) { left_duty  = tmp ; }
        if ( *(sbuf+3) == 'B' ) { 
          right_duty = tmp ; 
          left_duty  = tmp ; 
        }
        /* show */
        rs1_puts("LEFT  = ") ; show_value_decimal( left_duty ); 
        rs1_puts("RIGHT = ") ; show_value_decimal( right_duty ); 
      }
      /* dump memory */
      if ( cmd == 'D' ) {
        /* get upper address */
        myadr = get_adr_dat( sbuf+1 );
        myadr <<= 8 ;
        myadr &= 0xff00 ;
        /* show */
        for ( loop = 0 ; loop < 256 ; loop++ ) {
          /* get data from memory */
          mydat = get_sram( myadr );
          /* address increment */
          myadr++ ;
          /* show */
          rs1_putchar( asc_hex[ (mydat >> 4) & 0x0f ] );
          rs1_putchar( asc_hex[ mydat & 0x0f ] );
          rs1_putchar(' ');
          /* new line */
          if ( (loop % 16) == 15 ) { rs1_crlf() ; }
        }
      }
      /* fill memory */
      if ( cmd == 'F' ) {
        /* get upper address */
        myadr = get_adr_dat( sbuf+1 );
        myadr <<= 8 ;
        myadr &= 0xff00 ;
        /* get data */
        mydat = get_adr_dat( sbuf+3 );
        /* store */
        for ( loop = 0 ; loop < 256 ; loop++ ) {
          /* put data to memory */
          put_sram( myadr , mydat );
          /* address increment */
          myadr++ ;
        }
      }
      /* write data to SRAM */
      if ( cmd == 'W' ) {
        /* get address */
        myadr = get_adr_dat( sbuf+1 );
        myadr <<= 8 ;
        myadr &= 0xff00 ;
        myadr |= get_adr_dat( sbuf+3 ) ;
        /* get data */
        mydat = get_adr_dat( sbuf+5 );
        /* store */
        put_sram( myadr , mydat );
      }
    }
    /* */
    tmp = get_road() ;
    send_led( tmp );
  }
  /* dummy */
  return 0 ;
}

void user_io(void)
{
  /* Port 1 */
  P1DR  = 0x00 ;
  P1DDR = 0xff ;
  /* Port 2 */
  P2DR  = 0x00 ;
  P2DDR = 0xff ;
  /* Port 3 */
  P3DR  = 0x00 ;
  P3DDR = 0xff ;
  /* Port 4 */
  P4DR  = 0x00 ;
  P4DDR = 0xff ;
  /* Port 5 */
  P5DR  = 0xff ;
  P5DDR = 0xff ;
  /* Port 6 */
  P6DR  = 0x00 ;
  P6DDR = 0x00 ;
  /* Port 8 */
  P8DR  = 0x00 ;
  P8DDR = 0xff ;
  /* Port A */
  PADR  = 0x00 ;
  PADDR = 0xff ;
  /* Port B */
  PBDR  = 0xc0 ;
  PBDDR = 0xcf ;
  /* */
  uflag = OFF ;
  /* clear SCI buffer */
  *(sbuf+0) = 0 ;
  sindex = 0 ;
  /* */
  init_sci_1(br57600);
  right_duty = 0 ;
  left_duty = 0 ;
  right_dutyx = 0 ;
  left_dutyx  = 0 ;
  init_timer0();
  timcnt = 0 ;
  pcnt = 0 ;
  bport = 0xf0 ;
  lcnt = 0 ;
  myadr = 0 ;
  mydat = 0 ;
}

UBYTE get_road(void)
{
  return P7.DR.BYTE ;
}

void  send_led(UBYTE x)
{
  P4DR = x ;
}

UBYTE get_sram(UWORD xadr)
{
  UBYTE result ;
  /* PORT 3 input */
  P3DDR = 0x00 ;
  /* impress upper address */
  P2DR = (xadr >> 8) & MASKFF ;
  /* impress lower address */
  P1DR = xadr & MASKFF ;
  /* enable CS */
  SRAM_CS = OFF ;
  /* enable OE */
  SRAM_OE = OFF ;
  /* dummy */
  result = 0 ;
  /* get */
  result = P3DR ;
  /* disable OE */
  SRAM_OE = ON ;
  /* disable CS */
  SRAM_CS = ON ;  
  /* PORT 3 output */
  P3DDR = 0xff ;

  return result ;
}

void  put_sram(UWORD xadr,UBYTE xdat)
{
  UBYTE dummy ;
  /* impress data */
  P3DR = xdat ;
  /* impress upper address */
  dummy = (xadr >> 8) & MASKFF ;
  P2DR = dummy ;
  /* impress lower address */
  dummy = xadr & MASKFF ;
  P1DR = dummy ;
  /* enable CS */
  SRAM_CS = OFF ;
  /* enable WR */
  SRAM_WR = OFF ;
  /* dummy */
  dummy = 0 ;
  /* disable WR */
  SRAM_WR = ON ;
  /* disable CS */
  SRAM_CS = ON ;
}

/*+++++++++++++++++++++++++*/
/* SCI_1 receive interrupt */
/*+++++++++++++++++++++++++*/
void  init_sci_1(TBaudRate x)
{
  volatile UWORD i;
  /* SCR : Serial Control Register
    7 bit TIE  -> 0 Transmit Interrupt Enable(disable)
    6 bit RIE  -> 0 Receive  Interrupt Enable(disable)
    5 bit TE   -> 0 Transmit Enable(disable)
    4 bit RE   -> 0 Receive  Enable(disable)
    3 bit MPIE -> 0 Multi Processor Interrupt Enable(disable)
    2 bit TEIE -> 0 Transmit End Interrupt Enable(disable)
    1 bit CKE1 -> 0 Clock Source (Use Internal Baud Rate Generator)
    0 bit CKE0 -> 0 
  */
  SCI1.SCR.BYTE = 0 ;
  /* SMR : Serial Mode Register
    7 bit C/nA -> 0 Communication Mode(Asynchronous)
    6 bit CHR  -> 0 data Charactor (8 bits)
    5 bit PE   -> 0 Parity Enable(disable)
    4 bit O/nE -> 0 Parity Mode(even)
    3 bit STOP -> 0 Stop Bit(1 bit)
    2 bit MP   -> 0 Multi Processor(disable)
    1 bit CKS1 -> 0 Clock Source ( φ )
    0 bit CKS0 -> 0 
  */
  SCI1.SMR.BYTE = 0 ;
  /* data transfer speed */
  SCI1.BRR = x ;
  /* wait 1 frame */
  for (i = 0; i < 3000 ; i++) ;
  /* enable Transmmit and Receive with interrupt */
  SCI1.SCR.BYTE = 0x70 ;
}

/*+++++++++++++++++++++++++*/
/* SCI_1 receive interrupt */
/*+++++++++++++++++++++++++*/
void int_rxi1(void)
{
  volatile UBYTE ch,dummy ;
  /* clear flag */
  dummy = SCI1.SSR.BYTE ;
  SCI1.SSR.BIT.RDRF = OFF ;
  /* get a character */
  ch = SCI1.RDR ;
  /* store */
  *(sbuf+sindex) = ch ;
  sindex++ ;
  /* check */
  if ( ch == '\r' ) {
    *(sbuf+sindex) = 0 ;
    sindex = 0 ;
    uflag  = ON ;
  }
}

/*+++++++++++++++*/
/* SCI_1 putchar */
/*+++++++++++++++*/
void rs1_putchar(UBYTE x)
{
  /* wait data transfer */
  while ( SCI1.SSR.BIT.TDRE == OFF ) ;
  /* put */
  SCI1.TDR = x ;
  SCI1.SSR.BIT.TDRE = OFF ;
}

/*++++++++++++*/
/* SCI_1 puts */
/*++++++++++++*/
void rs1_puts(UBYTE *x)
{
  /* send 1 charactors */
  while ( *x ) {
    rs1_putchar(*x);
    x++ ;
  }
}

/*++++++++++++*/
/* SCI_1 crlf */
/*++++++++++++*/
void rs1_crlf(void)
{
  rs1_putchar('\r');
  rs1_putchar('\n');
}

/*++++++++++++++++++++*/
/* SCI_1 command help */
/*++++++++++++++++++++*/
void show_help(void)
{
  rs1_puts("? help")               ; rs1_crlf();
  rs1_puts("L lamp flashing")      ; rs1_crlf();
  rs1_puts("M test motor")         ; rs1_crlf();
  rs1_puts("D dump memory")        ; rs1_crlf();
  rs1_puts("F fill memory")        ; rs1_crlf();
  rs1_puts("W write data to SRAM") ; rs1_crlf();
}

UBYTE get_hex(UBYTE x)
{
  UBYTE result ;
  /* default */
  result = 0 ;
  /* judge */
  if ( '0' <= x && x <= '9' ) { result = x - '0' ; }
  if ( 'A' <= x && x <= 'F' ) { result = x - 'A' + 10 ; }
  if ( 'a' <= x && x <= 'f' ) { result = x - 'a' + 10 ; }

  return result ;
}

void  init_timer0(void)
{
  /* stop timer */
  ITU.TSTR.BIT.STR0 = OFF ;
  /* TOER : Timer Output Enable Register
        7 **** -> 0
        6 **** -> 0
        5 EXB4 -> 0
        4 EXA4 -> 0
        3 EB3  -> 0
        2 EB4  -> 0
        1 EA4  -> 0
        0 EA3  -> 0
  */
  ITU.TOER.BYTE = 0 ;
  /* TIOR : Timer I/O Control Register
        7 **** -> 0
        6 IOB2 -> 0 GRB is not output compare match register
        5 IOB1 -> 0
        4 IOB0 -> 0
        3 **** -> 0
        2 IOA2 -> 0 GRA is not output compare match register
        1 IOA1 -> 0
        0 IOA0 -> 0
  */
  ITU0.TIOR.BYTE = 0 ;
  /* TCR : Timer Control Register
        7 ****  -> 0
        6 CCLR1 -> 0 clear TCNT if GRA = TCNT
        5 CCLR0 -> 1
        4 CKEG1 -> 0 rising edge
        3 CKEG0 -> 0
        2 TPSC2 -> 0 φ利用
        1 TPSC1 -> 0
        0 TPSC0 -> 0
  */
  ITU0.TCR.BYTE = 0x20 ;
  /* TIER : Timer Interrupt Enable Register
        7 ****  -> 0
        6 ***   -> 0
        5 ***   -> 0
        4 ***   -> 0
        3 ***   -> 0
        2 OVIE  -> 0
        1 IMIEB -> 0
        0 IMIEA -> 1 select compare match interrupt
  */
  ITU0.TIER.BIT.IMIEA = ON ;
  /* reference */
  ITU0.GRA = ITU0_AREG ;
  ITU0.GRB = 0xffff ;
  /* counter */
  ITU0.TCNT = 0 ;
  /* start timer */
  ITU.TSTR.BIT.STR0 = ON ;
}

/*+++++++++++++++++++++++++++++++++++++*/
/* ITU0 interrupt with compare match A */
/*                        1ms interval */
/*+++++++++++++++++++++++++++++++++++++*/
void int_imia0(void)
{
  volatile UBYTE dummy ;
  /* clear flag */
  dummy = ITU0.TSR.BIT.IMFA ;
  ITU0.TSR.BIT.IMFA = OFF ;
  /* increment */
  timcnt++ ;
  /* judge */
  dummy = 0 ;
  if ( pcnt < left_dutyx  ) { dummy |= 0x04 ; }
  if ( pcnt < right_dutyx ) { dummy |= 0x01 ; }
  bport &= 0xf0 ;
  bport |= dummy ;
  PBDR = bport ;
  /* increment */
  pcnt++ ;
  /* judge */
  if ( pcnt == PCNTMAX ) {
    pcnt = 0 ;
    left_dutyx  = left_duty ;
    right_dutyx = right_duty ;
  }
}

void  show_value_decimal(UBYTE x)
{
  UBYTE msg[4] ;
  /* 100 */
  *(msg+0) = x / 100 ; x %= 100 ;
  *(msg+1) = x / 10 ;
  *(msg+2) = x % 10 ;
  *(msg+3) = 0 ;
  /* convert */
  *(msg+0) = asc_hex[*(msg+0)] ;
  *(msg+1) = asc_hex[*(msg+1)] ;
  *(msg+2) = asc_hex[*(msg+2)] ;
  /* send */
  rs1_puts(msg);
  /* new line */
  rs1_crlf() ;
}

UBYTE get_adr_dat(UBYTE *ptr)
{
  UBYTE result ;
  /* get first byte */
  result = get_hex( *ptr );
  result <<= 4 ;
  /* pointer increment */
  ptr++ ;
  /* add second byte */
  result |= get_hex( *ptr ) ;

  return result ;
}

 シリアルインタフェースを利用するために、次の
 コマンドを用意しました。

 コマンドに関して、簡単に説明します。

 Lコマンド
  1文字に続けて、2進数で2ビットの
  点灯パターンを与えます。

  (例) L11{enter} 左右の2LED点灯
      L10{enter} 左LED点灯、右LED消灯
      L01{enter} 左LED消灯、右LED点灯
      L00{enter} 左右の2LED消灯

 Mコマンド
  1文字に続けて、10進数で2桁のDUTY比を
  入力。最後にL、R、Bのいずれかの文字を与え
  enterを押します。
   L : Left R : Right B : Both

  (例) 左モータに12%DUTY比のパルスを出力。
      M12L{enter}

 Dコマンド
  1文字に続けて、16進数で2桁でSRAMのアドレス
  上位8ビットを指定。256バイトを表示する。

  (例) 0x0100からの256バイトを表示。
      D01{enter}

 Fコマンド
  1文字に続けて、16進数で2桁でSRAMのアドレス
  上位8ビットを指定。次の16進数2桁で1バイト
  のデータを指定。

  (例) 0x0200からの256バイトに0x55を設定。
      F0255{enter}

 Wコマンド
  1文字に続けて、16進数で4桁でSRAMのアドレス
  続けて16進数の2桁で1バイトを指定。
  1バイト分のデータを設定。

  (例) 0x1234に56バイトを設定。
      W123456{enter}

 ここまでは、接続したハードウエアをテストする内容でした。
 次にGameBoyCameraを接続して動かすことを考えます。
 メカにマウントする基板は、写真のものにします。

 H8/3048FOne基板に、34ピン、20ピンコネクタを接続し
 下にある基板と接続します。下の基板には、ドライブ
 回路、LED、スイッチをつけています。



 スイッチはスタートだけなので、タイマー割込みで
 シフトレジスタに状態を入れ、立下りエッジの判断
 をします。

  /* increment */
  bcnt++ ;
  /* start trigger */
  if ( bcnt == 10 ) {
    bcnt = 0 ;
    start_sft <<= 1 ;
    start_sft &= 0x07 ;
    if ( !(PBDR & 0x10) ) { start_sft |= ON ; }
    if ( start_sft == 0x03 || start_sft == 0x01 ) { sflag = ON ; }
  }

 チャタリング除去のために、10msごとにスイッチの
 状態を読み取り、更新します。

 GameBoyCameraは、パラメータ設定後撮影するため
 コマンドGを用意します。

 Gコマンド
  SRAMの固定アドレスを指定して、関数cam_getを
  呼出します。
  cam_getの内部シーケンスは、リセット、パラメータ
  設定、撮影開始、データ変換、データ保存とします。
  Gコマンドの処理は、次のように単純にします。

      if ( cmd == 'G' ) { cam_get( 0x4000 ) ; }

  関数cam_getは、次のように定義しました。

void  cam_get(UWORD x)
{
  UWORD xmadr ;
  UWORD i ;
  UWORD j ;
  UBYTE adv ;
  /* get store entrance */
  xmadr = x ;
  /* initialize */
  j = 0 ;
  /* reset */
  cam_rst();
  /* set parameters */
  for ( i = 0 ; i < 8 ; i++ ) {
    cam_param( cam_param_value[i] ) ;
  }
  /* loop */
  cam_start();
  for ( i = 0 ; i < GMAX ; i++ ) {
    /* impress H */
    CAM_XCK = ON ;
    /* impress L */
    CAM_XCK = OFF ;
    /* judge READ level */
    if ( CAM_READ == OFF ) continue ;
    /* get A/D value */
    adv = get_cam() ;
    /* transfer data to SRAM */
    put_sram(j,adv);
    /* address increment */
    xmadr++ ;
    /* counter increment */
    j++ ;
    /* ? complete */
    if ( j > LMAX ) break ;
  }
}

 パラメータを再設定したいので、コマンドPを用意します。

 Pコマンド
  1文字に続けて、16進数で1桁でレジスタ番号を
  指定します。続けて2桁の16進数でパラメータ値
  を指定します。

  (例) レジスタ4に0x12を設定。
      P412{enter}

  レジスタ番号とパラメータ値を表示するように
  しておきます。

      if ( cmd == 'P' ) {
        /* get address */
        myadr = *(sbuf+1) - '0' ;
        /* get data */
        mydat = get_adr_dat( sbuf+2 ) ;
        /* store */
        *(cam_param_value+myadr) = mydat ;
        /* show */
        for ( loop = 0 ; loop < 8 ; loop++ ) {
          /* get data */
          mydat = *(cam_param_value+loop) ;
          /* conversion and send */
          rs1_putchar( loop + '0' ) ;
          rs1_putchar(':');
          rs1_putchar( asc_hex[ (mydat >> 4) & 0x0f ] );
          rs1_putchar( asc_hex[ mydat & 0x0f ] );
          /* new line */
          rs1_crlf(); 
        }
      }

 GameBoyCameraは128x128でデータを処理するので
 1ライン=128として、1ライン分を表示する関数
 を定義します。

void  show_recode(UWORD eadr)
{
  UWORD myadrx ;
  UBYTE tmp ;
  UBYTE loop ;
  UBYTE xmax ;
  UBYTE xmin ;
  /* set entry address */
  myadrx = eadr ;
  /* default */
  xmax = 0 ;
  xmin = 255 ;
  /* loop */
  for ( loop = 0 ; loop < 128 ; loop++ ) {
    /* get data from SRAM */
    tmp = get_sram( myadr ) ;
    /* address increment */
    myadrx++ ;
    /* update max and min */
    if ( tmp > xmax ) { xmax = tmp ; }
    if ( tmp < xmin ) { xmin = tmp ; }
    /* show */
    show_value_decimal(tmp,OFF);
    rs1_putchar( ' '  ) ;
    /* new line */
    if ( (loop % 16) == 15 ) { rs1_crlf() ; }
  }
  /* max */
  rs1_puts("Max = "); show_value_decimal(xmax,ON);
  /* min */
  rs1_puts("Min = "); show_value_decimal(xmin,ON);
}

 開始アドレスを与えると、10進数で1ライン分のデータ
 128個を表示します。また、最大値、最小値も表示し
 閾値を判断しやすくします。

 さらに、開始アドレスと閾値をあたえて2値化した内容
 を表示する関数も定義します。

void  show_recode_binary(UWORD eadr,UBYTE thx)
{
  UWORD myadrx ;
  UBYTE tmp ;
  UBYTE loop ;
  UBYTE bdat ;
  /* set entry address */
  myadrx = eadr ;
  /* loop */
  for ( loop = 0 ; loop < 128 ; loop++ ) {
    /* get data from SRAM */
    tmp = get_sram( myadr ) ;
    /* address increment */
    myadrx++ ;
    /* judge */
    bdat = '0' ;
    if ( tmp > thx ) { bdat++ ; }
    /* show 1 bit */
    rs1_putchar( bdat ) ;
  }
  /* new line */
  rs1_crlf() ;
}

 画像データを格納してあるSRAMの領域は固定なので
 アドレスの上位8ビットと閾値を入力すると、2進
 で表示するコマンドBを用意します。

      if ( cmd == 'B' ) {
        /* get address */
        myadr = get_adr_dat( sbuf+1 );
        myadr <<= 8 ;
        myadr &= 0xff00 ;
        myadr |= get_adr_dat( sbuf+3 ) ;
        /* get data */
        mydat = get_adr_dat( sbuf+5 );
        /* show */
        for ( loop = 0 ; loop < 128 ; loop++ ) {
          /* put data to memory */
          show_recode_binary( myadr , mydat );
          /* block address increment */
          myadr += 128 ;
        }
      }

 Bコマンド
  1文字に続けて、16進数で2桁でアドレス上位8ビットを
  指定します。続けて2桁の16進数で閾値を指定します。

  (例) アドレス0x0400からのデータを閾値99(0x63)
      で2値化して表示。
            B0463{enter}

 ここまでファームウエアを作成して動作確認
 しましたが、シリアルインタフェースで画像
 データを取り出して、表示するのはしんどい
 ので、GBCとモノクログラフィックLCDを接続
 してテストしてみました。



 H8/3052Fの内蔵SRAMは、8kバイトあるので
 このうちの半分をGBC用フレームバッファにし
 グラフィックLCDのフレームバッファを1k
 バイト確保できます。これで5kバイト消費
 で、外部SRAMを使わずに対応できます。

 モノクログラフィックLCDのライン数は64で
 ピクセル数は128ですが、奇数ピクセルだけ
 を利用して64ドットx64ピクセルにします。

 カメラでコースを撮影しても、128ライン中の
 上64ラインのどれかを使うと考えれば、外部
 のSRAMに全データを保存する必要なしと判断
 しました。

 128ピクセルを64ドットにするには、奇数ピクセル
 を入力したときに、配列に1バイトの数値で入れ
 表示するときに、0〜255の値を0か1に変換
 します。



 1ラインは、表示用の8バイトを構成したなら
 グラフィックLCDのフレームバッファに転送して
 専用処理に渡します。

 64ピクセルを64ドットに変換するには、64ピクセル
 中の最大値、最小値を求め、その平均を計算して
 平均より大きいと1、平均値以下では0とします。

 64ドットは、8ドットごとにまとめて
 8バイトに変換します。



 8ドットはシフト処理で生成し、8ドットx8を
 一気に処理できるようにします。走行していると
 64ビットを1ビット単位で合成したのでは、時間
 が掛かりすぎると判断したから。

 シリアルインタフェースで接続して、動作確認できる
 仕様とするために、コマンドを以下のようにしました。

 GBCを扱うときは、すべてコマンド'G'を利用します。
 コマンドに続く数字で、機能を切り替えていきます。

 ソースコードにまとめると、以下。

#include "3052.h"

typedef unsigned char  UBYTE ;
typedef unsigned short UWORD ;
typedef unsigned long  ULONG ;
typedef   signed char  SBYTE ;
typedef   signed short SWORD ;

#define NO  0
#define YES 1

/*----------------*/
/* user variables */
/*----------------*/
#define ITU1_AREG 24999

typedef union {
  struct {
    unsigned char B7:1;
    unsigned char B6:1;
    unsigned char B5:1;
    unsigned char B4:1;
    unsigned char B3:1;
    unsigned char B2:1;
    unsigned char B1:1;
    unsigned char B0:1;
  } BIT ;
  unsigned char DR ;
} FLAGSP ;

FLAGSP x_flags ;

ULONG timcnt ;

#define SFLAG x_flags.BIT.B0
#define TFLAG x_flags.BIT.B1
#define UFLAG x_flags.BIT.B2
#define STRG  x_flags.BIT.B3
#define GFLAG x_flags.BIT.B4

#define P1DDR P1.DDR
#define P1DR  P1.DR.BYTE
#define P2DDR P2.DDR
#define P2DR  P2.DR.BYTE
#define P3DDR P3.DDR
#define P3DR  P3.DR.BYTE
#define P4DDR P4.DDR
#define P4DR  P4.DR.BYTE
#define P5DDR P5.DDR
#define P5DR  P5.DR.BYTE
#define P6DDR P6.DDR
#define P6DR  P6.DR.BYTE
#define P8DDR P8.DDR
#define P8DR  P8.DR.BYTE
#define P7DR  P7.DR.BYTE
#define P9DDR P9.DDR
#define P9DR  P9.DR.BYTE
#define PADDR PA.DDR
#define PADR  PA.DR.BYTE
#define PBDDR PB.DDR
#define PBDR  PB.DR.BYTE

#define MASKFFFF 0xffff
#define MASKFF   0xff
#define MASKCF   0xcf
#define MASK0F   0x0f
#define MASK3F   0x3f
#define MASK07   0x07
#define OFF      0
#define ON       OFF+1

#define MAXCOUNT 60
#define MAXADR   512

#define MASK80 0x80

#define LCD_DAT 7
#define LCD_CLK 6
#define LCD_RST 5
#define LCD_CS2 4
#define LCD_CS1 3
#define LCD_RS  2
#define LCD_RW  1
#define LCD_E   0

#define LCD_RS_H 1
#define LCD_RS_L 0

#define SEL_LEFT  2
#define SEL_RIGHT 1
#define SEL_NONE  0

#define GMAX 512

#define YMAX 8
#define XMAX 64

#define GBC_IDLE  0
#define GBC_BUSY  1

#define GBC_START P3.DR.BIT.B0
#define GBC_SIN   P4.DR.BIT.B7
#define GBC_LOAD  P4.DR.BIT.B6
#define GBC_XRST  P4.DR.BIT.B5
#define GBC_XCK   P4.DR.BIT.B4
#define GBC_READ  P6.DR.BIT.B3

void init_sci_1(TBaudRate x);
void rs1_putchar(UBYTE x);
void rs1_crlf(void);
void rs1_puts(UBYTE *x);
void show_help(void);

UBYTE sindex ;
UBYTE sbuf[16];
UBYTE cmd ;
UBYTE asc_hex[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'} ;

UBYTE glcdl[MAXADR];
UBYTE glcdr[MAXADR];
UBYTE lcd_page_buf[XMAX];

UBYTE src[8] ;
UBYTE dst[8] ;

UBYTE gbc_state ;
UWORD gcounter ;
UBYTE gbc_buf[4096] ;

/*--------------------------------*/
/* Insert user functions protoype */
/*--------------------------------*/
void  user_initialize(void);
void  init_timer1(void);
UBYTE get_hex(UBYTE x);
void  delay_ms(UWORD x);

void  binary_display(UBYTE x);
void  lcd_primitive(UBYTE which,UBYTE x);
void  lcd_dat(UBYTE x);
void  lcd_cmd(UBYTE x);
void  lcd_select_plane(UBYTE x);
void  lcd_display(UBYTE x);
void  lcd_show(void);
void  lcd_rst(void);
void  init_lcd(void);

void  lcd_set_start_line(UBYTE x);
void  lcd_set_address(UBYTE x);
void  lcd_set_page(UBYTE x);
void  lcd_locate(UBYTE pgx,UBYTE idx);
void  lcd_set_data(UBYTE *ptr,UBYTE sx,UBYTE lx) ;

void  send_gbc(UBYTE gadr,UBYTE x);
void  send_rst(void);
void  send_start(void);
void  init_gbc(void);
void  get_gbc(void);
UBYTE get_gbc_dat(void);
void  gbc_convert(void);
void  gbc_clear(void);
void  gbc_show(void);

/*------*/
/* main */
/*------*/
int main(void)
{
  UBYTE xx ;
  UBYTE yy ;
  UBYTE xdat ;
  UBYTE eflag ;
  /* disable interrupt */
  DI ;
  /* initialize */
  user_initialize();
  /* enable interrupt */
  EI ;
  /* opening message */
  rs1_puts("Hello"); rs1_crlf();
  /* initialize LCD */
  init_lcd();
  /* initialize GBC */
  init_gbc();
  /* loop */
  while ( ON ) {
    /* command interpreter */
    if ( UFLAG == ON ) {
      /* clear flag */
      UFLAG = OFF ;
      /* new line */
      rs1_crlf();
      /* get command */
      cmd = *(sbuf+0) ;
      /* judge */
      if ( cmd == '?' ) { show_help() ; }
      /* show frame buffer context */
      if ( cmd == 'F' ) {
        /* line */
        for ( yy = 0 ; yy < 64 ; yy++ ) {
          /* line number */
          rs1_putchar( asc_hex[(yy >> 4) & MASK0F] );
          rs1_putchar( asc_hex[yy & MASK0F] );
          rs1_putchar(':');
          /* raster */
          for ( xx = 0 ; xx < 16 ; xx++ ) {
            /* get 1 byte */
            if ( xx < 8 ) { xdat = *(glcdl+xx+8*yy) ; }
            else          { xdat = *(glcdr+(xx-8)+8*yy) ; }
            /* show 1 byte with hexadecimal format */
            rs1_putchar( asc_hex[(xdat >> 4) & MASK0F] );
            rs1_putchar( asc_hex[xdat & MASK0F] );
            if ( xx < 15 ) { rs1_putchar('_'); }
          }
          /* new line */
          rs1_crlf();
        }
        /* new line */
        rs1_crlf();
      }
      /* set 1 byte to frame buffer */
      if ( cmd == 'W' ) {
        /* get X axies */
        xx = 10 * get_hex( *(sbuf+1) ) + get_hex( *(sbuf+2) );
        /* get Y axies */
        yy = 10 * get_hex( *(sbuf+3) ) + get_hex( *(sbuf+4) );
        /* get data */
        xdat = (get_hex( *(sbuf+5) ) << 4) | get_hex( *(sbuf+6) );
        /* judge */
        eflag = 0 ;
        if ( xx > 15 ) {
          rs1_puts("X location error !"); 
          eflag++ ;
          rs1_crlf();
        }
        if ( yy > 63 ) {
          rs1_puts("Y location error !"); 
          eflag++ ;
          rs1_crlf();
        }
        /* store */
        if ( eflag == 0 ) {
          if ( xx < 8 ) { *(glcdl+xx+8*yy) = xdat ; }
          else          { *(glcdr+(xx-8)+8*yy) = xdat ; }
        }
      }
      /* show */
      if ( cmd == 'D' ) { lcd_show(); }
      /* clear */
      if ( cmd == 'C' ) {
        /* get bit data */
        eflag = get_hex( *(sbuf+1) );
        xdat = 0 ;
        if ( eflag ) { xdat = MASKFF ; }
        /* set value to frame buffer */
        for ( yy = 0 ; yy < 64 ; yy++ ) {
          for ( xx = 0 ; xx < 8 ; xx++ ) {
            *(glcdl+xx+8*yy) = xdat ; /* left */
            *(glcdr+xx+8*yy) = xdat ; /* right */
          }
        }
        /* transfer */
        lcd_show(); 
      }
      /* GBC handling */
      if ( cmd == 'G' ) {
        /* get parameter */
        eflag = get_hex( *(sbuf+1) );
        /* initialize */
        if ( eflag == 0 ) { init_gbc() ; }
        /* get picture */
        if ( eflag == 1 ) {
          GFLAG = GBC_BUSY ;
          gbc_state = 0 ;
        }
        /* conversion */
        if ( eflag == 2 ) {
          gbc_convert() ;
          lcd_show();
        }
        /* clear gbc buffer */
        if ( eflag == 3 ) { gbc_clear() ; }
        /* show */
        if ( eflag == 4 ) { gbc_show() ; }
      }
    }
    /* GBC take picture */
    get_gbc();
  }
  return 0 ;
}

/*-----------------------*/
/* Insert user functions */
/*-----------------------*/
void user_initialize(void)
{
  /* PORT 1 */
  P1DR  = 0 ;
  P1DDR = MASKFF ; /* all outputs */
  /* PORT 2 */
  P2DR  = 0 ;
  P2DDR = MASKFF ; /* all outputs */
  /* PORT 3 */
  P3DR  = 0 ;
  P3DDR = MASKFF ; /* all outputs */
  /* PORT 4 */
  P4DR  = 0x20 ;
  P4DDR = MASKFF ; /* all outputs */
  /* PORT 6 */
  P6DR  = 0x00 ;
  P6DDR = 0xf7 ; /* all outputs */
  /* PORT 8 */
  P8DR  = 0      ;
  P8DDR = MASKFF ; /* all outputs */
  /* PORT A */
  PADR  = 0      ;
  PADDR = MASKFF ; /* all outputs */
  /* PORT B */
  PBDR  = 0 ;
  PBDDR = 0xff ; /* all outputs */
  /* initialize */
  init_timer1();
  /* clear flags */
  x_flags.DR = 0 ;
  /* clear SCI buffer */
  *(sbuf+0) = 0 ; sindex = 0 ;
  /* initialize */
  timcnt = 0 ;
  /* SCI */
  init_sci_1(br38400);
  /* GameBoyCamera state */
  gbc_state = 0 ;
}

void init_timer1(void)
{
  /* stop timer */
  ITU.TSTR.BIT.STR1 = OFF ;
  /* TOER : Timer Output Enable Register
        7 **** -> 0
        6 **** -> 0
        5 EXB4 -> 0
        4 EXA4 -> 0
        3 EB3  -> 0
        2 EB4  -> 0
        1 EA4  -> 0
        0 EA3  -> 0
  */
  ITU.TOER.BYTE = 0 ;
  /* TIOR : Timer I/O Control Register
        7 **** -> 0
        6 IOB2 -> 0 GRB is not output compare match register
        5 IOB1 -> 0
        4 IOB0 -> 0
        3 **** -> 0
        2 IOA2 -> 0 GRA is not output compare match register
        1 IOA1 -> 0
        0 IOA0 -> 0
  */
  ITU1.TIOR.BYTE = 0 ;
  /* TCR : Timer Control Register
        7 ****  -> 0
        6 CCLR1 -> 0 clear TCNT if GRA = TCNT
        5 CCLR0 -> 1
        4 CKEG1 -> 0 rising edge
        3 CKEG0 -> 0
        2 TPSC2 -> 0 φ利用
        1 TPSC1 -> 0
        0 TPSC0 -> 0
  */
  ITU1.TCR.BYTE = 0x20 ;
  /* TIER : Timer Interrupt Enable Register
        7 ****  -> 0
        6 ***   -> 0
        5 ***   -> 0
        4 ***   -> 0
        3 ***   -> 0
        2 OVIE  -> 0
        1 IMIEB -> 0
        0 IMIEA -> 1 select compare match interrupt
  */
  ITU1.TIER.BIT.IMIEA = ON ;
  /* reference */
  ITU1.GRA = ITU1_AREG ;
  ITU1.GRB = MASKFFFF ;
  /* counter */
  ITU1.TCNT = 0 ;
  /* start timer */
  ITU.TSTR.BIT.STR1 = ON ;
}

/*+++++++++++++++++++++++++++++++++++++*/
/* ITU1 interrupt with compare match A */
/*                     1ms interval */
/*+++++++++++++++++++++++++++++++++++++*/
void int_imia1(void)
{
  UBYTE dummy ;
  /* clear flag */
  dummy = ITU1.TSR.BIT.IMFA ;
  ITU1.TSR.BIT.IMFA = OFF ;
  /* increment */
  timcnt++ ;
  /* judge 10ms passed */
  if ( timcnt & 10 ) { STRG = ON ; }
  /* judge 1000ms passed */
  if ( timcnt & 100 ) { TFLAG = ON ; }
}

/*+++++++++++++++++++++++++*/
/* SCI_1 receive interrupt */
/*+++++++++++++++++++++++++*/
void  init_sci_1(TBaudRate x)
{
  volatile UWORD i;
  /* SCR : Serial Control Register
    7 bit TIE  -> 0 Transmit Interrupt Enable(disable)
    6 bit RIE  -> 0 Receive  Interrupt Enable(disable)
    5 bit TE   -> 0 Transmit Enable(disable)
    4 bit RE   -> 0 Receive  Enable(disable)
    3 bit MPIE -> 0 Multi Processor Interrupt Enable(disable)
    2 bit TEIE -> 0 Transmit End Interrupt Enable(disable)
    1 bit CKE1 -> 0 Clock Source (Use Internal Baud Rate Generator)
    0 bit CKE0 -> 0 
  */
  SCI1.SCR.BYTE = 0 ;
  /* SMR : Serial Mode Register
    7 bit C/nA -> 0 Communication Mode(Asynchronous)
    6 bit CHR  -> 0 data Charactor (8 bits)
    5 bit PE   -> 0 Parity Enable(disable)
    4 bit O/nE -> 0 Parity Mode(even)
    3 bit STOP -> 0 Stop Bit(1 bit)
    2 bit MP   -> 0 Multi Processor(disable)
    1 bit CKS1 -> 0 Clock Source ( φ )
    0 bit CKS0 -> 0 
  */
  SCI1.SMR.BYTE = 0 ;
  /* data transfer speed */
  SCI1.BRR = x ;
  /* wait 1 frame */
  for (i = 0; i < 3000 ; i++) ;
  /* enable Transmmit and Receive with interrupt */
  SCI1.SCR.BYTE = 0x70 ;
}

/*+++++++++++++++++++++++++*/
/* SCI_1 receive interrupt */
/*+++++++++++++++++++++++++*/
void int_rxi1(void)
{
  volatile UBYTE ch,dummy ;
  /* clear flag */
  dummy = SCI1.SSR.BYTE ;
  SCI1.SSR.BIT.RDRF = OFF ;
  /* get a character */
  ch = SCI1.RDR ;
  /* store */
  *(sbuf+sindex) = ch ;
  sindex++ ;
  /* check */
  if ( ch == '\r' ) {
    *(sbuf+sindex) = 0 ;
    sindex = 0 ;
    UFLAG  = ON ;
  }
}

/*+++++++++++++++*/
/* SCI_1 putchar */
/*+++++++++++++++*/
void rs1_putchar(UBYTE x)
{
  /* wait data transfer */
  while ( SCI1.SSR.BIT.TDRE == OFF ) ;
  /* put */
  SCI1.TDR = x ;
  SCI1.SSR.BIT.TDRE = OFF ;
}

/*++++++++++++*/
/* SCI_1 puts */
/*++++++++++++*/
void rs1_puts(UBYTE *x)
{
  while ( *x ) {
    /* send 1 charactors */
    rs1_putchar(*x);
    x++ ;
  }
}

/*++++++++++++*/
/* SCI_1 crlf */
/*++++++++++++*/
void rs1_crlf(void)
{
  rs1_putchar('\r');
  rs1_putchar('\n');
}

/*++++++++++++++++++++*/
/* SCI_1 command help */
/*++++++++++++++++++++*/
void show_help(void)
{
  rs1_puts("? help")                        ; rs1_crlf();
  rs1_puts("W set data")                    ; rs1_crlf();
  rs1_puts(" column(15) line(64) data(16)") ; rs1_crlf();
  rs1_puts("F show frame buffer context")   ; rs1_crlf();
  rs1_puts("C clear frame buffer context")  ; rs1_crlf();
  rs1_puts("D display on LCD")              ; rs1_crlf();
  rs1_puts("G GBC handling")                ; rs1_crlf();
  rs1_puts("  G0 initialize  GBC")          ; rs1_crlf();
  rs1_puts("  G1 take picture")             ; rs1_crlf();
  rs1_puts("  G2 convert and show on LCD")  ; rs1_crlf();
  rs1_puts("  G3 clear gbc buffer")         ; rs1_crlf();
  rs1_puts("  G4 show gbc buffer")          ; rs1_crlf();
}

void lcd_show(void)
{
  UBYTE ax ;
  UBYTE ay ;
  UBYTE i ;
  UBYTE j ;
  UBYTE k ;
  UBYTE *xptr ;
  UWORD aidx ;
  for ( k = 0 ; k < 2 ; k++ ) {
    /* select plane */
    lcd_select_plane(SEL_LEFT);
    xptr = glcdl ;
    if ( k ) {
     lcd_select_plane(SEL_RIGHT); 
      xptr = glcdr ;
    }
    /* disable plane */
    lcd_display(OFF);
    /* transfer data */
    lcd_set_start_line(0) ;
    /* left plane */
    for ( ay = 0 ; ay < 8 ; ay++ ) {
      /* clear page buffer */
      for ( i = 0 ; i < 64 ; i++ ) { *(lcd_page_buf+i) = 0 ; }
      /* raster */
      for ( ax = 0 ; ax < 8 ; ax++ ) {
        /* get vertical data */
        for ( i = 0 ; i < 8 ; i++ ) {
          aidx = ax+8*(7-i)+64*ay ;
          *(src+i) = *(xptr+aidx) ;
        }
        /* arrange (vertical -> horizontal) */
        for ( i = 0 ; i < 8 ; i++ ) {
          /* clear destination */
          *(dst+i) = 0 ;
          /* rotate with right 90 degree */
          for ( j = 0 ; j < 8 ; j++ ) {
            *(dst+i) |= ((*(src+j) & MASK80) >> j) ;
          }
          /* shift */
          for ( j = 0 ; j < 8 ; j++ ) { *(src+j) <<= 1 ; }
        }
        /* copy */
        for ( i = 0 ; i < 8 ; i++ ) {
          aidx = (ax << 3) ;
          *(lcd_page_buf+aidx+i) = *(dst+i) ;
        }
      }
      /* transfer page buffer */
      {
        /* set address */
        lcd_locate(ay,0);
        /* transfer data */
        lcd_set_data(lcd_page_buf,0,63) ;
      }
    }
    /* enable plane */
    lcd_display(ON);
  }
  /* */
  lcd_select_plane(SEL_NONE); 
}

UBYTE get_hex(UBYTE x)
{
  UBYTE result ;
  /* default */
  result = 0 ;
  /* convert */
  if ( '0' <= x && x <= '9' ) { result = x - '0' ; }
  if ( 'A' <= x && x <= 'F' ) { result = x - 'A' + 10 ; }
  if ( 'a' <= x && x <= 'f' ) { result = x - 'a' + 10 ; }

  return result ;
}

void delay_ms(UWORD x)
{
  ULONG target ;
  /* calculate last value */
  target = timcnt + x ;
  /* wait */
  while ( timcnt < target ) ;
}

void  binary_display(UBYTE x)
{
  UBYTE loop ;
  UBYTE bdat ;
  /* show */
  for ( loop = 0 ; loop < 8 ; loop++ ) {
    bdat = '0' ;
    if ( x & MASK80 ) { bdat++ ; }
    rs1_putchar( bdat );
    x <<= 1 ;
  }
}

void  lcd_primitive(UBYTE which,UBYTE x)
{
  UBYTE loop ;
  UBYTE tmp  ;
  /* get data */
  tmp = x ;
  /* Write mode */
  PBDR &= ~(1 << LCD_RW);
  /* data transfer to 74HC164 */
  for ( loop = 0 ; loop < 8 ; loop++ ) {
    /* set bit datum */
    PBDR &= ~(1 << LCD_DAT) ;
    if ( tmp & MASK80 ) { PBDR |= (1 << LCD_DAT) ; }
    /* CLOCK : H */
    PBDR |= (1 << LCD_CLK) ;
    /* shift */
    tmp <<= 1 ;
    /* CLOCK : L */
    PBDR &= ~(1 << LCD_CLK) ;
  }
  /* confirm RS */
  PBDR &= ~(1 << LCD_RS) ;
  if ( which ) { PBDR |= (1 << LCD_RS) ; }
  /* latch */
  PBDR |= (1 << LCD_E) ;
  PBDR &= ~(1 << LCD_DAT) ; /* dummy */
  PBDR &= ~(1 << LCD_E) ;
  /* read mode */
  PBDR |= (1 << LCD_RW);
}

void  lcd_dat(UBYTE x)
{
  lcd_primitive(ON,x) ;
}

void  lcd_cmd(UBYTE x)
{
  lcd_primitive(OFF,x) ;
}

void  lcd_select_plane(UBYTE x)
{
  /* CS1 = 0 , CS2 = 0 */
  PBDR &= ~(1 << LCD_CS1);
  PBDR &= ~(1 << LCD_CS2);
  /* */
  if ( x == SEL_LEFT  ) { PBDR |= (1 << LCD_CS1); }
  if ( x == SEL_RIGHT ) { PBDR |= (1 << LCD_CS2); }
}

void  lcd_display(UBYTE x)
{
  lcd_cmd(0x3E | x);
}

void  lcd_set_address(UBYTE x)
{
  /* check */
  if ( x >= XMAX ) return ;
  /* send address */
  lcd_cmd(0x40 | x);
}

void  lcd_set_page(UBYTE x)
{
  /* check */
  if ( x >= YMAX ) return ;
  /* send address */
  lcd_cmd(0xb8 | x);
}

void  lcd_set_start_line(UBYTE x)
{
  /* check */
  if ( x >= XMAX ) return ;
  /* send address */
  lcd_cmd(0xC0 | x);
}

void  lcd_locate(UBYTE pgx,UBYTE idx)
{
  lcd_set_page(pgx);
  lcd_set_address(idx);
}

void  lcd_set_data(UBYTE *ptr,UBYTE sx,UBYTE lx)
{
  UBYTE loop ;
  UBYTE last ;
  /* calculate length */
  last = lx - sx + 1 ;
  /* store */
  for ( loop = 0 ; loop < last ; loop++ ) {
    lcd_dat( *(ptr+loop) );
  }
}

void  lcd_rst(void)
{
  /* nRESET : L */
  PBDR &= ~(1 << LCD_RST) ;
  /* wait 1ms */
  delay_ms(1);
  /* nRESET : H */
  PBDR |=  (1 << LCD_RST) ;
}

void  init_lcd(void)
{
  /* reset */
  lcd_rst() ;
  /* delay 30 ms */
  delay_ms( 30 ) ;
  /* select first line */
  lcd_cmd(0xC0);
  /* display on */
  lcd_cmd(0x3f);
}

void  send_gbc(UBYTE gadr,UBYTE x)
{
  UWORD px ;
  UBYTE loop ;
  /* judge */
  if ( gadr > 7 ) return ;
  /* generate code */
  px = (gadr << 8) | x ;
  /* transfer */
  for ( loop = 0 ; loop < 11 ; loop++ ) {
    /* impress LOAD */
    GBC_LOAD = OFF ;
    if ( loop == 10 ) { GBC_LOAD = ON ; }
    /* impress bit data */
    GBC_SIN = OFF ;
    if ( px & 0x400 ) { GBC_SIN = ON ; }
    /* CLOCK : H */
    GBC_XCK = ON ;
    /* shift */
    px <<= 1 ;
    /* CLOCK : L */
    GBC_XCK = OFF ;
  }
  /* return initial logic state */
  GBC_SIN  = OFF ;
  GBC_LOAD = OFF ;
}

void  send_rst(void)
{
  /* enable RESET */
  GBC_XRST = OFF ;
  /* CLOCK : H */
  GBC_XCK = ON ;
  /* CLOCK : L */
  GBC_XCK = OFF ;
  /* disable */
  GBC_XRST = ON ;
}

void  send_start(void)
{
  /* enable RESET */
  GBC_START = ON ;
  /* CLOCK : H */
  GBC_XCK = ON ;
  /* CLOCK : L */
  GBC_XCK = OFF ;
  /* disable */
  GBC_START = OFF ;
}

void  init_gbc(void)
{
  /* reset */
  send_rst() ;
  /* send parameters */
  send_gbc(0,0x80) ;
  send_gbc(1,0x00) ;
  send_gbc(2,0x00) ;
  send_gbc(3,0x80) ;
  send_gbc(4,0x00) ;
  send_gbc(5,0x01) ;
  send_gbc(6,0x00) ;
  send_gbc(7,0x01) ;
}

void  get_gbc(void)
{
  UBYTE tmp ;
  UWORD xcnt ;
  /* judge */
  if ( GFLAG == GBC_IDLE ) return ;
  /* auto run */
  switch (gbc_state) {
    /* send start trigger */
    case 0 : send_start() ;
             gbc_state = 1 ;
             rs1_puts("START") ; rs1_crlf() ;
             break ;
    /* exposure */
    case 1 : GBC_XCK = ON ;
             gbc_state = 2 ;
             break ;
    /* exposure judge */
    case 2 : GBC_XCK = OFF ;
             gbc_state = 1 ;
             if ( GBC_READ == ON ) {
               gbc_state = 3 ;
               gcounter = 0 ;
             }
             break ;
    /* get GBC data */
    case 3 : tmp = get_gbc_dat() ;
             /* store */
             if ( gcounter & 1 ) {
               xcnt = (gcounter >> 1) ;
               *(gbc_buf+xcnt) = tmp ;
             }
             gcounter++ ;
             gbc_state = 4 ;
             break ;
    /* get data XCK : H */
    case 4 : GBC_XCK = ON ;
             gbc_state = 5 ;
             break ;
    /* get data XCK : L */
    case 5 : GBC_XCK = OFF ;
             gbc_state = 6 ;
             break ;
    /* get GBC data */
    case 6 : tmp = get_gbc_dat() ;
             /* store */
             if ( gcounter & 1 ) {
               xcnt = (gcounter >> 1) ;
               *(gbc_buf+xcnt) = tmp ;
             }
             gcounter++ ;
             gbc_state = 7 ;
             break ;
    /* judge complete */
    case 7 : gbc_state = 4 ;
             if ( gcounter == 8192 ) {
               gbc_state = 8 ;
             }
             break ;
    /* exit */
    case 8 : gbc_state = 9 ;
             GFLAG = GBC_IDLE ;
               rs1_puts("COMPLETE !") ; rs1_crlf() ;
             break ;
    /* */
    default : break ;
  }
}

UBYTE get_gbc_dat(void)
{
  UBYTE dummy ;
  UBYTE result ;
  /* initialize */
  AD.ADCSR.BYTE = 0x08 ;
  /* start conversion */
  AD.ADCSR.BIT.ADST = ON ;
  /* wait */
  while ( AD.ADCSR.BIT.ADF == OFF ) ;
  /* clear flag */
  AD.ADCSR.BIT.ADF = OFF ;
  /* stop conversion */
  AD.ADCSR.BIT.ADST = OFF ;
  /* get data */
  result = (UBYTE)((AD.ADDRA >> 7) & MASKFF);

  return result ;
}

void  gbc_convert(void)
{
  UBYTE ax ;
  UBYTE ay ;
  UBYTE block_buf[64] ;
  UBYTE xmax ;
  UBYTE xmin ;
  UBYTE xavr ;
  
  for ( ay = 0 ; ay < 64 ; ay++ ) {
    /* transfer 1 line */
    for ( ax = 0 ; ax < 64 ; ax++ ) {
      *(block_buf+ax) = *(gbc_buf+ax+64*ay) ;
    }
    /* calculate average */
    xmax = *(block_buf+0) ;
    xmin = *(block_buf+0) ;
    for ( ax = 1 ; ax < 64 ; ax++ ) {
      if ( *(block_buf+ax) > xmax ) { 
        xmax = *(block_buf+ax) ;
      }
      if ( *(block_buf+ax) < xmin ) { 
        xmin = *(block_buf+ax) ;
      }
    }
    xavr = (xmax + xmin) >> 1 ;
    /* convert logical value */
    for ( ax = 0 ; ax < 64 ; ax++ ) {
      xmin = OFF ;
      if ( *(block_buf+ax) > xavr ) { xmin = ON ; }
      *(block_buf+ax) = xmin ;
    }
    /* generate 8 byte */
    for ( ax = 0 ; ax < 8 ; ax++ ) {
      /* concatenate */
      for ( xmax = 0 ; xmax < 8 ; xmax++ ) {
        for ( xmin = 0 ; xmin < 8 ; xmin++ ) {
          /* shift */
          *(dst+xmin) <<= 1 ;
          /* add LSB */
          *(dst+xmin) |= *(block_buf+xmin+8*xmax) ;
        }
      }
    }
    /* copy */
    for ( ax = 0 ; ax < 8 ; ax++ ) {
      *(glcdl+ax+8*ay) = *(dst+ax) ;
    }
  }
}

void  gbc_clear(void)
{
  UWORD loop ;
  for ( loop = 0 ; loop < 4096 ; loop++ ) {
    *(gbc_buf+loop) = 0 ;
  }
}

void  gbc_show(void)
{
  UWORD loop ;
  UBYTE tmp ;

  for ( loop = 0 ; loop < 4096 ; loop++ ) {
    /* line number */
    if ( (loop % 64) == 0 ) {
      rs1_putchar( asc_hex[(loop >> 12) & MASK0F] ) ;
      rs1_putchar( asc_hex[(loop >> 8) & MASK0F] ) ;
      rs1_putchar( asc_hex[(loop >> 4) & MASK0F] ) ;
      rs1_putchar( asc_hex[loop & MASK0F] ) ;
      rs1_putchar(' ');
    }
    /* dead space */
    if ( (loop % 64) == 32 ) {
      rs1_puts("     ");
    }
    /* get 1 byte */
    tmp = *(gbc_buf+loop) ;
    /* show */
    rs1_putchar( asc_hex[(tmp >> 4) & MASK0F] ) ;
    rs1_putchar( asc_hex[tmp & MASK0F] ) ;
    /* new line */
    if ( (loop % 32) == 31 ) { rs1_crlf() ; }
  }
}

 グラフィックLCDとのインタフェースは、次のように
 してあります。



 実走行で利用しないので、シフトレジスタ
 で、H8と接続するピン数を減らしています。

(under construction)

目次

inserted by FC2 system