目次
前
次
画像処理テスト
画像処理を変更したので、VHDLコードが妥当かを
テストします。
FPGA内のデジタル回路は、カメラから画像データを
受取る構造にしているので、カメラ動作をマイクロ
コンピュータで代行して、動作をテストします。
3.3Vで動作するマイクロコンピュータの手持ちは
STM8SDiscoveryがあります。
このマイクロコンピュータで、カメラ動作を代行
できるのかを確認します。
必要な信号は、以下です。
- VSYNC
- HREF
- PCLK
- CDATA(8bits)
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に相当するピンの周波数を
測定できるよう、ファームウエアを構成。
シリアルでコマンドを与え、セレクタを
切替え出力値を変更できるようにします。
コマンドは、次のように決めました。
- ? help
- E enable signal generate
- D disable signal generate
- S show current status
コマンド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周して自動停止
- トリガーを入れ、アドレスが規定値まで変化する
- 3回のトリガーで、アドレスがゼロクリアされる
シーケンサが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つを使いました。目視判定を、可能に
するテクニックです。
確認したのは、以下です。
- トリガーを入れ、シーケンサが1周して自動停止
- トリガーを入れ、アドレスが規定値まで変化する
- シーケンサから、他のシーケンサにトリガーを出力
上のVHDLコードでは、ライン数、ピクセル数を
減らし、動作確認の所要時間を短くしています。
画像処理を始める前に、2値化処理をしておいた方が
後々の処理が楽になるので、2値化を考えておきます。
動作シーケンスは、次のようにしました。
- トリガー待ち(トリガーがきたら、次ステートへ)
- アドレス、カウンタ、最大値、最小値を初期化(次ステートへ)
- カウンタが0ならば、6ステート、そうでないなら次ステート
- 指定アドレスからデータ取得(次ステート)
- 最大値、最小値、カウンタ更新後、3ステートへ
- 閾値計算、カウンタ、アドレスを初期化し次ステートへ
- カウンタが0ならば、11ステート、そうでないなら次ステート
- 指定アドレスからデータ取得(次ステート)
- 閾値と比較して、1か0を決めて保存、次ステートへ
- アドレス、カウンタを更新後、7ステートへ
- 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コードの動作は、次のように確認しました。
- マイクロコンピュータから、メモリのアドレスをゼロクリア
- データ転送(160バイト)
- 2値化処理のトリガー出力
- 処理終了待ち
- マイクロコンピュータから、メモリのアドレスをゼロクリア
- 2値化したデータを転送(ビットバイト)
マイクロコンピュータは、データの用意と操作指令を
しているだけで、他はFPGA内部のデジタル回路が実行
する環境にして、テストしました。
この程度ならば、マイクロコンピュータ内部で充分処理
できますが、画像処理をファームウエアで実現しない点
が重要です。
目次
前
次