目次

画像処理テスト

 画像処理を変更したので、VHDLコードが妥当かを
 テストします。

 FPGA内のデジタル回路は、カメラから画像データを
 受取る構造にしているので、カメラ動作をマイクロ
 コンピュータで代行して、動作をテストします。



 3.3Vで動作するマイクロコンピュータの手持ちは
 STM8SDiscoveryがあります。



 このマイクロコンピュータで、カメラ動作を代行
 できるのかを確認します。

 必要な信号は、以下です。

 FPGAは、13本の信号を受取ります。
 STM8SDiscoveryは、これらの信号
 を出力できるだけのピンを持ちます。

 次に、タイミングチャートで動作を見てみます。



 タイミングチャートに相当する信号生成が
 どの程度のコードになるのかをLSICで記述
 してみます。(関数test_handlerで生成
 信号に相当する動作をエミュレート)

#include <stdio.h>

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

#define OFF 0
#define ON  OFF+1

#define PBIT 4
#define HBIT 3
#define VBIT 2

#define LHALF  60
#define LMAX   120
#define PMAX   160
#define PBEGIN 75
#define PEND   85

UBYTE state ;

UBYTE lcnt ;
UBYTE pcnt ;
UBYTE csig ;
UBYTE cdat ;

UBYTE ydat[PMAX] ;
UBYTE uvdat[PMAX] ;
UBYTE ydummy[PMAX] ;
UBYTE uvdummy[PMAX] ;

void binary_display(UBYTE x);
void sig_out(void);
void test_handler(void);

void main(void)
{
  int i ;
  /* initialize */
  for ( i = 0 ; i < PMAX ; i++ ) {
    *(ydat+i)  = 0x00 ;
    if ( PBEGIN <= i && i <= PEND ) { *(ydat+i)  = 0x70 ; }
    *(uvdat+i)   = 0x55 ;
    *(ydummy+i)  = 0x00 ;
    *(uvdummy+i) = 0xff ;
  }
  /* handling */
  csig = 0 ;
  state = 0 ;
  i = 0 ;
  while ( 1 ) {
    if ( lcnt >= LHALF ) break ;
    test_handler();
    i++ ;
  }
}

void binary_display(UBYTE x)
{
  int i ;
  for ( i = 4 ; i > 1 ; i-- ) {
    putchar(((x >> i) & 1) + '0');
  }
}

void sig_out(void)
{
  printf("state(%2d) lcnt(%03d) pcnt(%03d) ",state,lcnt,pcnt);
  binary_display( csig );
  printf(" X\"%02X\"\n",cdat);
}

void test_handler(void)
{
  UBYTE tmp;

  switch (state) {
    /* send VSYNC */
    case 0  : csig |= (1 << VBIT);
              lcnt = 0 ;
              pcnt = 0 ;
              state = 1 ;
              break ;
    /* PCLK : H */
    case 1  : csig |= (1 << PBIT);
              state = 2 ;
              break ;
    /* PCLK : L */
    case 2  : csig &= ~(1 << PBIT);
              csig &= ~(1 << VBIT);
              state = 3 ;
              break ;
    /* judge line count */
    case 3  : state = 4 ;
              if ( lcnt == LMAX ) {
                lcnt  = 0 ;
                state = 15 ; 
              }
              break ;
    /* send HREF */
    case 4  : csig |= (1 << HBIT);
              pcnt  = 0 ;
              state = 5 ;
              break ;
    /* judge pixel count */
    case 5  : state = 6 ;
              if ( pcnt == PMAX ) {
                pcnt  = 0 ;
                state = 13 ;
                csig &= ~(1 << HBIT);
              }
              break ;
    /* send Y data */
    case 6  : tmp = *(ydat+pcnt) ;
              if ( lcnt >= LHALF ) { tmp = *(ydummy+pcnt) ; }
              cdat = tmp ;
              state = 7 ;
              break ;
    /* PCLK : H */
    case 7  : csig |= (1 << PBIT);
              state = 8 ;
              break ;
    /* PCLK : L */
    case 8  : csig &= ~(1 << PBIT);
              state = 9 ;
              break ;
    /* send UV data */
    case 9  : tmp = *(uvdat+pcnt) ;
              if ( lcnt >= LHALF ) { tmp = *(uvdummy+pcnt) ; }
              cdat = tmp ;
              state = 10 ;
              break ;
    /* PCLK : H */
    case 10 : csig |= (1 << PBIT);
              state = 11 ;
              break ;
    /* PCLK : L */
    case 11 : csig &= ~(1 << PBIT);
              pcnt++ ;
              state = 12 ;
              break ;
    /* looping */
    case 12 : state = 5 ;
              break ;
    /* update line counter */
    case 13 : state = 14 ;
              lcnt++ ;
              break ;
    /* line looping */
    case 14 : state = 3 ;
              break ;
    /* return first state */
    case 15 : state = 0 ;
              break ;
    /* */
    default : state = 0 ;
              break ;
  }
  sig_out();
}

 タイミングチャートの動作をエミュレート
 しているかをファイルに入れて確認します。

 PCLK、HREF、VSYNCは、この順に3ビットの
 パターンで組合せているので、それを見て
 信号が生成されていることを判断します。

state( 1) lcnt(000) pcnt(000) 001 X"00"  : enable VSYNC
state( 2) lcnt(000) pcnt(000) 101 X"00"
state( 3) lcnt(000) pcnt(000) 000 X"00"  : disable VSYNC
state( 4) lcnt(000) pcnt(000) 000 X"00"
state( 5) lcnt(000) pcnt(000) 010 X"00"  : enable HREF
state( 6) lcnt(000) pcnt(000) 010 X"00"
state( 7) lcnt(000) pcnt(000) 010 X"00"
state( 8) lcnt(000) pcnt(000) 110 X"00"  * send Y signal
state( 9) lcnt(000) pcnt(000) 010 X"00"
state(10) lcnt(000) pcnt(000) 010 X"55"
state(11) lcnt(000) pcnt(000) 110 X"55"  * send U or V signal
state(12) lcnt(000) pcnt(001) 010 X"55"
state( 5) lcnt(000) pcnt(001) 010 X"55"
state( 6) lcnt(000) pcnt(001) 010 X"55"
state( 7) lcnt(000) pcnt(001) 010 X"00"
state( 8) lcnt(000) pcnt(001) 110 X"00"  * send Y signal
state( 9) lcnt(000) pcnt(001) 010 X"00"
state(10) lcnt(000) pcnt(001) 010 X"55"
state(11) lcnt(000) pcnt(001) 110 X"55"
  <中略>
state(12) lcnt(000) pcnt(159) 010 X"55"
state( 5) lcnt(000) pcnt(159) 010 X"55"
state( 6) lcnt(000) pcnt(159) 010 X"55"
state( 7) lcnt(000) pcnt(159) 010 X"00"
state( 8) lcnt(000) pcnt(159) 110 X"00"  * send Y signal
state( 9) lcnt(000) pcnt(159) 010 X"00"
state(10) lcnt(000) pcnt(159) 010 X"55"
state(11) lcnt(000) pcnt(159) 110 X"55"  * send U or V signal
state(12) lcnt(000) pcnt(160) 010 X"55"
state( 5) lcnt(000) pcnt(160) 010 X"55"
state(13) lcnt(000) pcnt(000) 000 X"55"  : disable HREF
state(14) lcnt(001) pcnt(000) 000 X"55"
state( 3) lcnt(001) pcnt(000) 000 X"55"
state( 4) lcnt(001) pcnt(000) 000 X"55"
state( 5) lcnt(001) pcnt(000) 010 X"55"  : enable HREF
state( 6) lcnt(001) pcnt(000) 010 X"55"
state( 7) lcnt(001) pcnt(000) 010 X"00"
state( 8) lcnt(001) pcnt(000) 110 X"00"  * send Y signal
state( 9) lcnt(001) pcnt(000) 010 X"00"
state(10) lcnt(001) pcnt(000) 010 X"55"
state(11) lcnt(001) pcnt(000) 110 X"55"  * send U or V signal
state(12) lcnt(001) pcnt(001) 010 X"55"
state( 5) lcnt(001) pcnt(001) 010 X"55"

 ファイル内容を見る限り、関数test_handlerの
 論理で信号を生成できるようです。

 printf、putchar等で実現されている内容を
 STM8SDiscoveryのポートに出力するように
 改造するとカメラの代行になります。

 LSICで記述した内容を、そのまま利用したいので
 関数sig_outにポートへデータ出力する処理を記述
 します。



 次のように変更します。

void sig_out(void)
{
  /* PCLK HREF VSYNC */
  GPIO_Write(GPIOC,csig);
  /* data */
  GPIO_Write(GPIOB,cdat);
}

 関数test_handlerは、タイマー割込みで起動
 すれば、プログラムが勝手に動かしてくれる
 ようにします。

  if ( tflag == ON ) {
    /* clear flag */
    tflag = OFF ;
    /* call handling function */
    test_handler();
  }

 マイクロコンピュータが動作しているかを
 確認するため、シリアルでコマンドを与え
 テストできるようにします。

 周波数測定ができるマルチメータがあるので
 VSYNC、HREF、PCLKに相当するピンの周波数を
 測定できるよう、ファームウエアを構成。



 シリアルでコマンドを与え、セレクタを
 切替え出力値を変更できるようにします。
 コマンドは、次のように決めました。

 コマンドE、Dによりフラグをセットあるいは
 リセットして、ポート出力値を変更します。

typedef unsigned char UBYTE ;

void sig_out(void)
{
  volatile UBYTE xportc ;
  volatile UBYTE xportb ;
  /* store */
  xportc = csig ;
  xportb = cdat ;
  /* judge */
  if ( eflag == OFF ) {
    xportc = 0x00 ;
    xportb = 0x00 ;
  }
  /* PCLK HREF VSYNC */
  GPIO_Write(GPIOC,xportc);
  /* data */
  GPIO_Write(GPIOB,xportb);
}

 動作をシリアルで制御したいので、コマンド
 インタプリタを定義します。

  if ( uflag == ON ) {
    /* clear flag */
    uflag = OFF ;
    /* new line */
    crlf();
    /* get command */
    cmd = *(sbuf+0) ;
    /* judge */
    if ( cmd == '?' ) { show_help() ; }
    if ( cmd == 'E' ) { eflag = ON ; }
    if ( cmd == 'D' ) { eflag = OFF ; }
    if ( cmd == 'S' ) {
      if ( eflag == ON ) { rs_puts("enable")  ; }
      else               { rs_puts("disable") ; }
    }
  }

 主要処理を定義したので、まとめます。

#include "stm8s.h"

#define OFF 0
#define ON  OFF+1

#define NO  0
#define YES NO+1

#define CLKF 16000000
#define ARR4 256

#define PBIT 4
#define HBIT 3
#define VBIT 2

#define LHALF  60
#define LMAX   120
#define PMAX   160
#define PBEGIN 75
#define PEND   85

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

#define BSIZE 8 

#define MAX_CNT  5

/* global variables */
UBYTE uflag ;
UBYTE eflag ;
UBYTE tflag ;
UBYTE cmd ;
UBYTE sindex ;
SBYTE sbuf[BSIZE] ;

UBYTE csig ;
UBYTE cdat ;
UBYTE state ;

UBYTE lcnt ;
UBYTE pcnt ;

/* function prototype */
void init_usr(void);
void rs_putchar(SBYTE x);
void rs_puts(SBYTE *x);
void crlf(void);
void show_help(void);
void sig_out(void);

void main(void)
{
  UBYTE tmp ;
  /* initialize system */
  init_usr();
  /* enable interrupt */
  enableInterrupts();
  /* endless loop */
  while (ON) {
    /* UART handling */
    if ( uflag == ON ) {
      /* clear flag */
      uflag = OFF ;
      /* new line */
      crlf();
      /* get command */
      cmd = *(sbuf+0) ;
      /* judge */
      if ( cmd == '?' ) { show_help() ; }
      if ( cmd == 'E' ) { eflag = ON ; }
      if ( cmd == 'D' ) { eflag = OFF ; }
      if ( cmd == 'S' ) {
        if ( eflag == ON ) { rs_puts((SBYTE *)"enable")  ; }
        else               { rs_puts((SBYTE *)"disable") ; }
      }
    }
    /* timer handling */
    if ( tflag == ON ) {
      /* clear flag */
      tflag = OFF ;
      /* sequencer */
      switch (state) {
        /* send VSYNC */
        case 0  : csig |= (1 << VBIT);
                  lcnt = 0 ;
                  pcnt = 0 ;
                  state = 1 ;
                  break ;
        /* PCLK : H */
        case 1  : csig |= (1 << PBIT);
                  state = 2 ;
                  break ;
        /* PCLK : L */
        case 2  : csig &= ~(1 << PBIT);
                  csig &= ~(1 << VBIT);
                  state = 3 ;
                  break ;
        /* judge line count */
        case 3  : state = 4 ;
                  if ( lcnt == LMAX ) {
                    lcnt  = 0 ;
                    state = 15 ; 
                  }
                  break ;
        /* send HREF */
        case 4  : csig |= (1 << HBIT);
                  pcnt  = 0 ;
                  state = 5 ;
                  break ;
        /* judge pixel count */
        case 5  : state = 6 ;
                  if ( pcnt == PMAX ) {
                    pcnt  = 0 ;
                    state = 13 ;
                    csig &= ~(1 << HBIT);
                  }
                  break ;
        /* send Y data */
        case 6  : tmp = 0x00 ;
                  if ( PBEGIN <= pcnt && pcnt <= PEND ) { tmp = 0x70 ; }
                  if ( lcnt >= LHALF ) { tmp = 0x00 ; }
                  cdat = tmp ;
                  state = 7 ;
                  break ;
        /* PCLK : H */
        case 7  : csig |= (1 << PBIT);
                  state = 8 ;
                  break ;
        /* PCLK : L */
        case 8  : csig &= ~(1 << PBIT);
                  state = 9 ;
                  break ;
        /* send UV data */
        case 9  : tmp = 0x55 ;
                  if ( lcnt >= LHALF ) { tmp = 0xff ; }
                  cdat = tmp ;
                  state = 10 ;
                  break ;
        /* PCLK : H */
        case 10 : csig |= (1 << PBIT);
                  state = 11 ;
                  break ;
        /* PCLK : L */
        case 11 : csig &= ~(1 << PBIT);
                  pcnt++ ;
                  state = 12 ;
                  break ;
        /* looping */
        case 12 : state = 5 ;
                  break ;
        /* update line counter */
        case 13 : state = 14 ;
                  lcnt++ ;
                  break ;
        /* line looping */
        case 14 : state = 3 ;
                  break ;
        /* return first state */
        case 15 : state = 0 ;
                  break ;
        /* */
        default : state = 0 ;
                  break ;
      }
      sig_out();
    }
  }
}

void init_usr(void)
{
  /* select clock */
  CLK_ClockSwitchConfig( CLK_SWITCHMODE_AUTO, CLK_SOURCE_HSE, DISABLE, CLK_CURRENTCLOCKSTATE_DISABLE );
  /* initialize port direcitions */
  GPIO_Init(GPIOC, GPIO_PIN_ALL, GPIO_MODE_OUT_PP_HIGH_FAST);
  GPIO_Init(GPIOB, GPIO_PIN_ALL, GPIO_MODE_OUT_PP_HIGH_FAST);
  /* initialize UART2 */
  UART2_Init(19200,UART2_WORDLENGTH_8D,UART2_STOPBITS_1,UART2_PARITY_NO,  UART2_SYNCMODE_CLOCK_DISABLE, UART2_MODE_TXRX_ENABLE);
  UART2_ITConfig(UART2_IT_RXNE_OR,ENABLE);
  UART2_Cmd(ENABLE);
  /* initialize timer 4 */
	TIM4_DeInit();
	/* initialize counter 250 */
	TIM4_SetCounter(MAX_CNT+1);
	/* 16MHz / 128 / 250 = 2ms */
	TIM4_TimeBaseInit(TIM4_PRESCALER_128,255);
	/* configure */		
	TIM4_ITConfig(TIM4_IT_UPDATE,ENABLE);
	/* enable timer 4 */
	TIM4_Cmd(ENABLE);
  /* clear flags */
  uflag = OFF ;
  eflag = OFF ;
  tflag = OFF ;
  /* clear buffer index */
  sindex = 0 ;
  state = 0 ;
}

void rs_putchar(SBYTE x)
{
  /* transfer 1 byte */
  UART2_SendData8(x);
  /* wait */
  while ((UART2->SR & UART2_SR_TXE ) != UART2_SR_TXE );
}

void rs_puts(SBYTE *x)
{
  while ( *x != '\0' ) {
    rs_putchar( *x );
    x++ ;
  }
}

void crlf(void)
{
  rs_putchar('\r');
  rs_putchar('\n');
}

void show_help(void)
{
  rs_puts((SBYTE *)"? help");
  rs_puts((SBYTE *)"E enable");
  rs_puts((SBYTE *)"D disable");
  rs_puts((SBYTE *)"S show status");
}

void sig_out(void)
{
  /* judge */
  if ( eflag == OFF ) {
    /* PCLK HREF VSYNC */
    GPIO_Write(GPIOC,0x00);
    /* data */
    GPIO_Write(GPIOB,0x00);
  } else {
    /* PCLK HREF VSYNC */
    GPIO_Write(GPIOC,csig);
    /* data */
    GPIO_Write(GPIOB,cdat);
  }
}

/*
  receive interruption
*/
void UART2RX_ISR(void) interrupt 21
{
  UBYTE ch ;
  /* get 1 byte from module */
  ch = (UBYTE)UART2_ReceiveData8();
  /* store */
  *(sbuf+sindex) = ch ;
  sindex++ ;
  /* judge */
  if ( ch == '\r' ) {
    sindex = 0 ;
    uflag = ON ;
  }
}

/*
  timer4 interruption
*/
void TIM4_interrupt(void) interrupt 23
{
  /* clear interrupt flag */
  TIM4_ClearFlag(TIM4_FLAG_UPDATE);
  /* initialize counter 250 */
  TIM4_SetCounter(MAX_CNT+1);
  /* set flag */
  tflag = ON ;
}

#ifdef USE_FULL_ASSERT
void assert_failed(UBYTE* file,ULONG line)
{
  while (ON)  {  }
}
#endif

 このソースコードで問題がなかったのですが
 DemoVersionの開発環境では、LINKERが最終
 HEXコードを生成できず、テストは振出しに。

 H8/3052Fはテスト基板があるので、電圧
 コンバータを作り、FPGAに接続します。



 H8/3052Fのファームウエアは、以下です。

#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

#define PBIT 4
#define HBIT 3
#define VBIT 2

#define LHALF  60
#define LMAX   120
#define PMAX   160
#define PBEGIN 75
#define PEND   85

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

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 AFLAG  x_flags.BIT.B0
#define EFLAG  x_flags.BIT.B1
#define TFLAG  x_flags.BIT.B2
#define RFLAG  x_flags.BIT.B3
#define UFLAG  x_flags.BIT.B4

#define P6DDR P6.DDR
#define P6DR  P6.DR.BYTE
#define P4DDR P4.DDR
#define P4DR  P4.DR.BYTE
#define P7DR  P7.DR.BYTE
#define P8DDR P8.DDR
#define P8DR  P8.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 OFF      0
#define ON       OFF+1

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 sig_out(void);
void test_handler(void);

UBYTE sindex ;
UBYTE sbuf[8];
UBYTE cmd ;

UBYTE cnt ;

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

UBYTE state ;

UBYTE lcnt ;
UBYTE pcnt ;
UBYTE csig ;
UBYTE cdat ;

UBYTE ydat[PMAX] ;
UBYTE uvdat[PMAX] ;
UBYTE ydummy[PMAX] ;
UBYTE uvdummy[PMAX] ;

/*--------------------------------*/
/* Insert user functions protoype */
/*--------------------------------*/
void  user_initialize(void);
void  init_timer0();
void  init_timer1();

UBYTE get_hex(UBYTE x);
void  delay_ms(UWORD x);

/*------*/
/* main */
/*------*/
int main(void)
{
  UWORD i ;
  UWORD dlast ;
  UBYTE tmp ;
  /* disable interrupt */
  DI ;
  /* initialize */
  user_initialize();
  /* enable interrupt */
  EI ;
  /* clear sram */
  rs1_puts("Hello");
  /* 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() ; }
      if ( cmd == 'E' ) {
        EFLAG = ON  ; 
        state = 0   ;
      }
      if ( cmd == 'D' ) {
        EFLAG = OFF ; 
        PADR  = 0 ;
        PBDR  = 0 ;
      }
      if ( cmd == 'S' ) {
        if ( EFLAG == ON ) { rs1_puts("enable")  ; }
        else               { rs1_puts("disable") ; }
      }
    }
    /* test handling */
    if ( TFLAG == ON ) {
      /* clear flag */
      TFLAG = OFF ;
      /* drive */
      test_handler();
    }
    /* test handling */
    if ( AFLAG == ON ) {
      /* clear flag */
      AFLAG = OFF ;
      /* increment */
      cnt++ ;
      tmp = 0x00 ;
      if ( cnt & 1 ) { tmp = MASKFF ; }
      if ( EFLAG == OFF ) { tmp = 0x00 ; }
      /* impress */
      P6DR = tmp ;
    }
  }
  return 0 ;
}

/*-----------------------*/
/* Insert user functions */
/*-----------------------*/
void user_initialize(void)
{
  /* PORT 6 */
  P6DR  = 0x00 ;
  P6DDR = MASKFF ; /* all output */
  /* PORT 8 */
  P8DR  = 0 ;
  P8DDR = 0xf0 ; /* upper nibble : outputs , lower nibble : inputs */
  /* PORT A */
  PADR  = 0 ;
  PADDR = MASKFF ; /* all outputs */
  /* PORT B */
  PBDR  = 0 ;
  PBDDR = MASKFF ; /* all outputs */
  /* PORT 4 */
  P4DR  = MASKFF ; /* disable all */
  P4DDR = MASKFF ; /* all outputs */
  /* enable external interruption */
  INTC.IER.BYTE  = 0x0f ;
  INTC.ISCR.BYTE = 0x0f ;
  /* initialize timers */
  init_timer0();
  init_timer1();
  /* clear flags */
  x_flags.DR = 0 ;
  /* clear SCI buffer */
  *(sbuf+0) = 0 ; sindex = 0 ;
  /* initialize */
  timcnt = 0 ;
  cnt = 0 ;
  state = 0 ;
  for ( pcnt = 0 ; pcnt < PMAX ; pcnt++ ) {
    *(ydat+pcnt)    = 0 ;
    *(ydummy+pcnt)  = 0 ;
    if ( PBEGIN <= pcnt && pcnt <= PEND ) {
      *(ydat+pcnt)    = 0x80 ;
      *(ydummy+pcnt)  = 0x08 ;
    }
    *(uvdat+pcnt)   = 0x55 ;
    *(uvdummy+pcnt) = 0xaa ;
  }
  /* initialize SCI */
  init_sci_1(br19200);
}

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 = MASKFFFF ;
  /* counter */
  ITU0.TCNT = 0 ;
  /* start timer */
  ITU.TSTR.BIT.STR0 = ON ;
}

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 ;
}

/*+++++++++++++++++++++++++++++++++++++*/
/* ITU0 interrupt with compare match A */
/*                        1ms interval */
/*+++++++++++++++++++++++++++++++++++++*/
void int_imia0(void)
{
  UBYTE dummy ;
  /* clear flag */
  dummy = ITU0.TSR.BIT.IMFA ;
  ITU0.TSR.BIT.IMFA = OFF ;
  /* increment */
  timcnt++ ;
  /* judge */
  if ( (timcnt & 0x1ff) == 500 ) { AFLAG = ON ; }
}

/*+++++++++++++++++++++++++++++++++++++*/
/* ITU1 interrupt with compare match A */
/*                     0.01ms interval */
/*+++++++++++++++++++++++++++++++++++++*/
void int_imia1(void)
{
  UBYTE dummy ;
  /* clear flag */
  dummy = ITU1.TSR.BIT.IMFA ;
  ITU1.TSR.BIT.IMFA = OFF ;
  /* judge */
  TFLAG = ON ;
}

/*++++++++++++++++++*/
/* SCI_1 initialize */
/*++++++++++++++++++*/
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++ ;
  }
  /* CR LF */
  rs1_crlf();
}

/*++++++++++++*/
/* 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_puts("E enable");
  rs1_puts("D disable");
  rs1_puts("S show state");
}

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 sig_out(void)
{
  UBYTE xporta ;
  UBYTE xportb ;
  /* store */
  xporta = csig ;
  xportb = cdat ;
  /* judge */
  if ( EFLAG == OFF ) {
    xporta = 0x00 ;
    xportb = 0x00 ;
  }
  /* impress */
  PADR = xporta ;
  PBDR = xportb ;
}

void test_handler(void)
{
  UBYTE tmp;
  /* judge */
  if ( EFLAG == OFF ) return ;
  /* sequencer */
  switch (state) {
    /* send VSYNC : H */
    case 0  : csig |= (1 << VBIT);
              lcnt = 0 ;
              pcnt = 0 ;
              state = 1 ;
              break ;
    /* send VSYNC : L */
    case 1  : csig &= ~(1 << VBIT);
              state = 2 ;
              break ;
    /* PCLK : H */
    case 2  : csig |= (1 << PBIT);
              state = 3 ;
              break ;
    /* PCLK : L */
    case 3  : csig &= ~(1 << PBIT) ;
              state = 4 ;
              break ;
    /* judge line count */
    case 4  : state = 5 ;
              if ( lcnt == LMAX ) {
                lcnt  = 0 ;
                state = 16 ; 
              }
              break ;
    /* send HREF */
    case 5  : csig |= (1 << HBIT);
              pcnt  = 0 ;
              state = 6 ;
              break ;
    /* judge pixel count */
    case 6  : state = 7 ;
              if ( pcnt == PMAX ) {
                pcnt  = 0 ;
                state = 14 ;
                csig &= ~(1 << HBIT);
              }
              break ;
    /* send Y data */
    case 7  : tmp = *(ydat+pcnt) ;
              if ( lcnt >= LHALF ) { tmp = *(ydummy+pcnt) ; }
              cdat = tmp ;
              state = 8 ;
              break ;
    /* PCLK : H */
    case 8  : csig |= (1 << PBIT);
              state = 9 ;
              break ;
    /* PCLK : L */
    case 9  : csig &= ~(1 << PBIT);
              state = 10 ;
              break ;
    /* send UV data */
    case 10 : tmp = *(uvdat+pcnt) ;
              if ( lcnt >= LHALF ) { tmp = *(uvdummy+pcnt) ; }
              cdat = tmp ;
              state = 11 ;
              break ;
    /* PCLK : H */
    case 11 : csig |= (1 << PBIT);
              state = 12;
              break ;
    /* PCLK : L */
    case 12 : csig &= ~(1 << PBIT);
              pcnt++ ;
              state = 13 ;
              break ;
    /* looping */
    case 13 : state = 6 ;
              break ;
    /* update line counter */
    case 14 : state = 15 ;
              lcnt++ ;
              break ;
    /* line looping */
    case 15 : state = 4 ;
              break ;
    /* return first state */
    case 16 : state = 0 ;
              break ;
    /* */
    default : state = 0 ;
              break ;
  }
  sig_out();
}

 H8は5V電源動作なので、3.3V動作のFPGAを
 接続する前に、5V動作CPLDで動作をテスト
 することに。

 内部シーケンサ動作を確認します。
 画像データの差分を求めるシーケンサの
 動作をLED、スイッチボードで確認する
 ためのVHDLコードは、以下です。

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

entity xtst2 is
  generic (
    TOPX : integer := 12 ;
    XMAX : integer := 4000 -- ;
  );
  port (
    -- system
    nRESET : in  std_logic ;
    CLOCK  : in  std_logic ;
    -- trigger 
    HTRG   : in  std_logic ;
    -- 
    GOUT : out std_logic_vector(7 downto 0) ;
    ROUT : out std_logic_vector(7 downto 0) --;
  );
end xtst2 ;

architecture behavioral of xtst2 is
  -- 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 ;
  -- synchronizer
  signal iMCLK : std_logic ;
  -- synchronizer
  signal iHTRG_SFT : std_logic_vector(2 downto 0) ;
  signal iHTRG     : std_logic ;
  -- sequencer
  signal iHSTATE : integer range 0 to 15 ;
  signal iHCNT   : integer range 0 to 25 ;
  signal iHFLAG  : integer range 0 to 3  ;
  signal iADR    : std_logic_vector(7 downto 0) ;
begin
  -- component 
  CLKX : clkgenx generic map (TOPX,XMAX) port map (nRESET,CLOCK,iMCLK) ;

  -- monitor output
  ROUT <= not iADR ;
  GOUT <= (not conv_std_logic_vector(iHFLAG,4)) & (not conv_std_logic_vector(iHSTATE,4)) ;

  -- synchronizer 
  process (nRESET,iMCLK) 
  begin
    if ( nRESET = '0' ) then
      iHTRG_SFT <= "000" ;
    elsif rising_edge( iMCLK ) then
      iHTRG_SFT <= iHTRG_SFT(1 downto 0) & (not HTRG) ;
    end if ;
  end process ;
  iHTRG <= '1' when ( iHTRG_SFT = "011" or iHTRG_SFT = "001" ) else '0' ;

  -- sensor data generator sequencer
  process (nRESET,iMCLK)
  begin
    if ( nRESET = '0' ) then
      iHSTATE <= 0 ;
      iHCNT   <= 0 ;
      iHFLAG  <= 0 ;
      iADR    <= (others => '0') ;
    elsif rising_edge(iMCLK) then
      case iHSTATE is
        -- wait trigger
        when 0 => if ( iHTRG = '1' ) then
                    iHSTATE <= 1 ; -- next
                    iHCNT   <= 0 ;
                  else
                    iHSTATE <= 0 ; -- stay
                  end if ;
        -- judge
        when 1 => if ( iHCNT = 15 ) then
                    iHSTATE <= 5 ; -- exit loop
                  else
                    iHSTATE <= 2 ; -- handling loop
                  end if ;
        -- get data 
        when 2 => iHSTATE <= 3 ; -- next
        -- compare
        when 3 => iHSTATE <= 4 ; -- next
        -- update pointer and address  
        when 4 => iHSTATE <= 1 ; -- loop
                  iHCNT   <= iHCNT + 1 ;
                  iADR    <= iADR + '1' ;
        -- calculate location and distance
        when 5 => iHSTATE <= 6 ; -- next
        -- store parameters
        when 6 => iHSTATE <= 7 ; -- next
        -- update line
        when 7 => iHSTATE <= 8 ; -- next
                  iHFLAG  <= iHFLAG + 1 ;
        -- judge last line
        when 8 => iHSTATE <= 9 ; -- next
                  if ( iHFLAG = 3 ) then
                    iADR   <= (others => '0') ;
                    iHFLAG <= 0 ;
                  end if ;
        -- return first state
        when 9 => iHSTATE <= 0 ;
        -- default 
        when others => 
                  iHSTATE <= 0 ;
      end case ;
    end if ;
  end process ;

end behavioral;

 確認したのは、以下です。

 シーケンサが1周していることがわかると
 計算処理のコードにバグがありと、見当が
 つきます。

 上のVHDLコードでは、ピクセル数を減らして
 動作確認の所要時間を短くしています。

 カメラ動作シーケンサをエミュレーションする
 VHDLコードは、以下です。

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

entity xtst3 is
  generic (
    TOPX : integer := 16 ;
    XMAX : integer := 65500 -- ;
  );
  port (
    -- system
    nRESET : in  std_logic ;
    CLOCK  : in  std_logic ;
    -- trigger 
    CTRG   : in  std_logic ;
    -- 
    AOUT : out std_logic ;
    BOUT : out std_logic ;
    GOUT : out std_logic_vector(7 downto 0) ;
    ROUT : out std_logic_vector(7 downto 0) ;
    YOUT : out std_logic_vector(7 downto 0) --;
  );
end xtst3 ;

architecture behavioral of xtst3 is
  -- 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 ;
  -- synchronizer
  signal iMCLK : std_logic ;
  -- synchronizer
  signal iCTRG_SFT : std_logic_vector(2 downto 0) ;
  signal iCTRG     : std_logic ;
  -- sequencer
  signal iCSTATE   : integer range 0 to 7 ;
  signal iLCNT     : integer range 0 to 16 ;
  signal iPCNT     : integer range 0 to 32 ;
  signal iATRG_SFT : std_logic_vector(1 downto 0) ;
  signal iATRG     : std_logic ;
begin
  -- component 
  CLKX : clkgenx generic map (TOPX,XMAX) port map (nRESET,CLOCK,iMCLK) ;

  -- monitor output
  AOUT <= not iATRG ;
  BOUT <= iATRG ;
  ROUT <= not conv_std_logic_vector(iPCNT,8) ;
  GOUT <= not conv_std_logic_vector(iLCNT,8) ;
  YOUT <= not conv_std_logic_vector(iCSTATE,8) ;

  -- synchronizer 
  process (nRESET,iMCLK) 
  begin
    if ( nRESET = '0' ) then
      iCTRG_SFT <= "000" ;
    elsif rising_edge( iMCLK ) then
      iCTRG_SFT <= iCTRG_SFT(1 downto 0) & (not CTRG) ;
    end if ;
  end process ;
  iCTRG <= '1' when ( iCTRG_SFT = "011" or iCTRG_SFT = "001" ) else '0' ;

  -- camera sequencer
  process (nRESET,iMCLK)
  begin
    if ( nRESET = '0' ) then
      iCSTATE   <= 0 ;
      iLCNT     <= 0 ;
      iPCNT     <= 0 ;
      iATRG_SFT <= "00" ;
    elsif rising_edge(iMCLK) then
      case iCSTATE is
        -- wait trigger from micom
        when 0 => if ( iCTRG = '1' ) then
                    iCSTATE <= 1 ; -- next
                  else
                    iCSTATE <= 0 ; -- stay
                  end if ;
        -- wait VSYNC trigger
        when 1 => iCSTATE <= 2 ; -- next
                  iLCNT   <= 0 ;
        -- judge line counter 
        when 2 => if ( iLCNT = 16 ) then
                    iCSTATE <= 7 ; -- exit
                  else
                    iCSTATE <= 3 ; -- loop
                  end if ;
        -- store even data (Y) 
        when 3 => iCSTATE   <= 4 ; -- next
                  iATRG_SFT <= iATRG_SFT(0) & '1' ;
        -- skip odd data (U or V) and store data
        when 4 => iCSTATE   <= 5 ; -- next
                  iATRG_SFT <= iATRG_SFT(0) & '1' ;
        -- judge pixel counter
        when 5 => if ( iPCNT = 32 ) then
                    iCSTATE <= 6 ; -- state : 6
                    iPCNT   <= 0 ;
                    iLCNT   <= iLCNT + 1 ;
                  else
                    iPCNT   <= iPCNT + 1 ;
                    iCSTATE <= 3 ; -- state : 3
                  end if ;
                  iATRG_SFT <= "00" ;
        -- new line handling
        when 6 => iCSTATE <= 2 ; -- state : 2
        -- return first state 
        when 7 => iCSTATE <= 0 ; -- state : 0
                  iLCNT   <= 0 ;
        -- default 
        when others => 
                  iCSTATE <= 0 ;
      end case ;
    end if ;
  end process ;
  --  store Y data trigger
  iATRG <= iATRG_SFT(1) and iATRG_SFT(0) ;

end behavioral;

 カメラから画像データを入力する都度、他の
 シーケンサにトリガーを与え、DualPortMemory
 に輝度データを保存します。

 シフトレジスタを利用して、トリガーを生成
 します。シフトレジスタを、2ビットとして
 2ビットともに1のとき、トリガーを出します。

 LEDでトリガー出力を確認するため、2ピンを
 使いました。

 トリガーありで点灯するLED、トリガーなしで点灯
 するLEDの2つを使いました。目視判定を、可能に
 するテクニックです。

 確認したのは、以下です。

 上のVHDLコードでは、ライン数、ピクセル数を
 減らし、動作確認の所要時間を短くしています。

 画像処理を始める前に、2値化処理をしておいた方が
 後々の処理が楽になるので、2値化を考えておきます。

 動作シーケンスは、次のようにしました。
  1. トリガー待ち(トリガーがきたら、次ステートへ)
  2. アドレス、カウンタ、最大値、最小値を初期化(次ステートへ)
  3. カウンタが0ならば、6ステート、そうでないなら次ステート
  4. 指定アドレスからデータ取得(次ステート)
  5. 最大値、最小値、カウンタ更新後、3ステートへ
  6. 閾値計算、カウンタ、アドレスを初期化し次ステートへ
  7. カウンタが0ならば、11ステート、そうでないなら次ステート
  8. 指定アドレスからデータ取得(次ステート)
  9. 閾値と比較して、1か0を決めて保存、次ステートへ
  10. アドレス、カウンタを更新後、7ステートへ
  11. 1ステートにもどる
 画像データは、残しておきたいので、画像データと  2値化したデータの保存先は、別にしておきます。  この処理をCで記述すると、以下。 #include <stdio.h> typedef unsigned char UBYTE ; typedef signed char SBYTE ; typedef unsigned short UWORD ; typedef signed short SWORD ; #define NO 0 #define YES NO+1 #define OFF 0 #define ON OFF+1 #define MASKFF 0xff #define MASK7F 0x7f UBYTE xport ; #define PORT xport ; UBYTE cbstate ; UBYTE cbflag ; UBYTE badr ; UBYTE bmax ; UBYTE bmin ; UBYTE tmpx ; UBYTE bcnt ; UBYTE thv ; #define IMAX 0 #define IMIN 255 #define IBCNT 160 UBYTE gdat[IBCNT]; UBYTE bdat[IBCNT]; void conv_binary(void); void main(void) { int i ; /* initialize */ for ( i = 0 ; i < 160 ; i++ ) { *(gdat+i) = 0 ; *(bdat+i) = 0 ; } *(gdat+80) = 128 ; *(gdat+81) = 140 ; *(gdat+82) = 150 ; *(gdat+83) = 128 ; *(gdat+84) = 80 ; *(gdat+85) = 40 ; /* show */ for ( i = 0 ; i < 160 ; i++ ) { printf("%3d ",*(gdat+i)) ; if ( (i % 16) == 15 ) { putchar('\n') ; } } putchar('\n') ; /* conversion */ cbstate = 0 ; cbflag = OFF ; for ( i = 0 ; i < 1000 ; i++ ) { if ( i == 10 ) { cbflag = ON ; } conv_binary(); } /* show */ for ( i = 0 ; i < 160 ; i++ ) { putchar( '0' + *(bdat+i) ) ; putchar( ' ' ); if ( (i % 16) == 15 ) { putchar('\n') ; } } putchar('\n') ; } void conv_binary(void) { switch (cbstate) { /* wait trigger */ case 0 : if ( cbflag == ON ) { cbstate = 1 ; } else { cbstate = 0 ; } break ; /* initialize */ case 1 : badr = 0 ; bcnt = IBCNT; bmax = IMAX ; bmin = IMIN ; cbstate = 2 ; break ; /* judge */ case 2 : if ( bcnt == 0 ) { cbstate = 6 ; } else { cbstate = 3 ; } break ; /* get graphic data */ case 3 : cbstate = 4 ; tmpx = *(gdat+badr) ; break ; /* update */ case 4 : cbstate = 5 ; if ( bmax < tmpx ) { bmax = tmpx ; } if ( bmin > tmpx ) { bmin = tmpx ; } badr++ ; bcnt-- ; break ; /* loop */ case 5 : cbstate = 2 ; break ; /* calculate */ case 6 : cbstate = 7 ; thv = ((bmax + bmin) >> 1) ; badr = 0 ; bcnt = IBCNT; break ; /* judge */ case 7 : if ( bcnt == 0 ) { cbstate = 11; } else { cbstate = 8 ; } break ; /* get graphic data */ case 8 : cbstate = 9 ; tmpx = *(gdat+badr) ; break ; /* compare */ case 9 : cbstate = 10 ; bmax = 0 ; if ( tmpx > thv ) { bmax = 1 ; } break ; /* update */ case 10 : cbstate = 7 ; *(bdat+badr) = bmax ; badr++ ; break ; /* return first state */ case 11 : cbstate = 0 ; break ; /* */ default : cbstate = 0 ; break ; } }  この関数をコンパイル、リンクしてテストしました。  結果は、以下です。 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 128 140 150 128 80 40 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0  関数conv_binaryは、正しく動いている  ことを確認できました。  関数conv_binaryを、VHDLコードに変換します。 process (nRESET,CLOCK) begin if ( nRESET = '0' ) then iBSTATE <= "0000" ; -- address iCADRB <= (others => '0') ; iBADRA <= (others => '0') ; -- data iBDAT <= (others => '0') ; iBDIA <= (others => '0') ; elsif rising_edge(CLOCK) then case conv_integer(iBSTATE) is -- wait trigger when 0 => if ( iBTRG = '1' ) then iBSTATE <= "0001" ; -- next else iBSTATE <= "0000" ; -- stay end if ; -- initialize when 1 => iBSTATE <= "0010" ; -- next iBCNT <= 0 ; -- get data when 2 => iBSTATE <= "0011" ; -- next iBDAT <= iDOB ; iBCNT <= iBCNT + 1 ; -- increment counter -- address increment when 3 => iBSTATE <= "0100" ; -- next iCADRB <= iCADRB + 1 ; iBDIA <= X"00" ; -- compare when 4 => iBSTATE <= "0101" ; -- next -- conversion if ( iBFLAG = 0 ) then if ( conv_integer(iBDAT) > iTHV ) then iBDIA <= X"01" ; else iBDIA <= X"00" ; end if ; end if ; -- store when 5 => iBSTATE <= "0110" ; -- next -- address increment when 6 => iBSTATE <= "0111" ; -- next iBADRA <= iBADRA + '1' ; -- judge when 7 => if ( iBCNT = PCNT_MAX ) then iBSTATE <= "1000" ; -- next else iBSTATE <= "0010" ; -- loop end if ; -- return first sate when 8 => iBSTATE <= "0000" ; -- next iBCNT <= 0 ; -- default when others => iBSTATE <= "0000" ; end case ; end if ; end process ; -- binary data store trigger iBWEA <= '1' when ( iBSTATE = "0101" ) else '0' ;  VHDLコードの動作は、次のように確認しました。
  1. マイクロコンピュータから、メモリのアドレスをゼロクリア
  2. データ転送(160バイト)
  3. 2値化処理のトリガー出力
  4. 処理終了待ち
  5. マイクロコンピュータから、メモリのアドレスをゼロクリア
  6. 2値化したデータを転送(ビットバイト)
 マイクロコンピュータは、データの用意と操作指令を  しているだけで、他はFPGA内部のデジタル回路が実行  する環境にして、テストしました。  この程度ならば、マイクロコンピュータ内部で充分処理  できますが、画像処理をファームウエアで実現しない点  が重要です。
目次

inserted by FC2 system