目次
前
次
CCD emulator
CCDを利用したラインセンサーを入手する前に
マイクロコンピュータとの接続テストに、エミュ
レータを考えました。
利用するCCDは、大阪のデジットで販売されている
ラインセンサーに含まれていて、次のタイミング
チャートを持ちます。
タイミングチャートから理解できることは、以下。
- SIは、CCDから情報を転送するトリガーとして利用
- CLKは、内蔵シフトレジスタを制御するために利用
- 128ピクセル分の情報は、A0からアナログで出力
ピクセル情報をアナログで出力していますが
デジタル出力としたいので、簡単なDACを用意
して対応します。4ビットのDACを使います。
SIがトリガーになっているので、内部カウンタを
ゼロクリアするために、使います。
ゼロクリアするときは、シフトレジスタを使い
立ち上がりエッジを使います。
process (nRESET,CLOCK)
begin
if ( nRESET = '0' ) then
iSI_SFT <= "00" ;
elsif rising_edge(CLOCK) then
iSI_SFT <= iSI_SFT(0) & iSI ;
end if ;
end process ;
iSI_TRG <= '1' when ( iSI_SFT = "01" ) else '0' ;
内部カウンタは、次のように定義します。
process (iSI_TRG,CLK)
begin
if ( iSI_TRG = '1' ) then
iCNT <= 0 ;
elsif rising_edge(CLK) then
if ( iCNT = 130 ) then
iCNT <= 0 ;
else
iCNT <= iCNT + 1 ;
end if ;
end if ;
end process ;
A0は、内部カウンタの値に応じて
4ビット値を出力すればよいので
デコーダを用意します。
iAOUT <= X"F" when ( 31 < iCNT and iCNT < 64 ) else
X"9" when ( 10 < iCNT and iCNT < 32 ) else
X"3" when ( 63 < iCNT and iCNT < 100 ) else
X"0" ;
このデコーダは、次のような波形を出力します。
デコーダ部分を変更すれば、様々なラインを実現できます。
VHDLコードにまとめます。
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity tstline is
port (
-- system
nRESET : in std_logic ;
CLOCK : in std_logic ; -- 4MHz
-- interface
SI : in std_logic ;
CLK : in std_logic ;
AOUT : out std_logic_vector(3 downto 0) ;
-- monitor
COUT : out std_logic_vector(7 downto 0) --;
);
end tstline ;
architecture behavioral of tstline is
-- input
signal iSI : std_logic ;
-- shift register
signal iSI_SFT : std_logic_vector(1 downto 0) ;
signal iSI_TRG : std_logic ;
-- internal counter
signal iCNT : integer range 0 to 130 ;
-- register
signal iAOUT : std_logic_vector(3 downto 0) ;
begin
-- input
iSI <= SI ;
-- output
AOUT <= iAOUT ;
COUT <= conv_std_logic_vector( iCNT , 8 );
-- shift registet
process (nRESET,CLOCK)
begin
if ( nRESET = '0' ) then
iSI_SFT <= "00" ;
elsif rising_edge(CLOCK) then
iSI_SFT <= iSI_SFT(0) & iSI ;
end if ;
end process ;
iSI_TRG <= '1' when ( iSI_SFT = "01" ) else '0' ;
-- internal counter
process (iSI_TRG,CLK)
begin
if ( iSI_TRG = '1' ) then
iCNT <= 0 ;
elsif rising_edge(CLK) then
if ( iCNT = 130 ) then
iCNT <= 0 ;
else
iCNT <= iCNT + 1 ;
end if ;
end if ;
end process ;
-- decoder
iAOUT <= X"F" when ( 31 < iCNT and iCNT < 64 ) else
X"9" when ( 10 < iCNT and iCNT < 32 ) else
X"3" when ( 63 < iCNT and iCNT < 100 ) else
X"0" ;
end behavioral;
ピンアサインは、以下。
# system
NET "CLOCK" LOC = "P5" ;
NET "nRESET" LOC = "P39" ;
# SPI interface
NET "AOUT<0>" LOC = "P1" ;
NET "AOUT<1>" LOC = "P2" ;
NET "AOUT<2>" LOC = "P3" ;
NET "AOUT<3>" LOC = "P4" ;
NET "CLK" LOC = "P6" ;
NET "SI" LOC = "P7" ;
# monitor output
NET "COUT<0>" LOC = "P11" ;
NET "COUT<1>" LOC = "P12" ;
NET "COUT<2>" LOC = "P13" ;
NET "COUT<3>" LOC = "P14" ;
NET "COUT<4>" LOC = "P18" ;
NET "COUT<5>" LOC = "P19" ;
NET "COUT<6>" LOC = "P20" ;
NET "COUT<7>" LOC = "P22" ;
CPLD(XilinxのXC9572)に入れてみると
マクロセルは最大72マクロセル中の14のみ
を消費するだけでした。
デコード部分を拡張しても、XC9572だけで
対応できると思われます。
対象となるArduinoのスケッチは、以下。
#include <MsTimer2.h>
#define MAXPIXELS 128
#define OFF 0
#define ON OFF+1
#define SI_BIT 2
#define CLK_BIT 1
#define LED_BIT 5
#define Threshold_MSG 0
#define SI_MSG 1
#define CLK_MSG 2
/* function prototype */
void rs_putchar(char x);
void crlf(void);
void show_help(void);
void send_si(byte x);
void send_clk(byte x);
void send_led(byte x);
void update_trigger(void);
void get_sensor(byte x);
void show_raw_values(void);
void show_binary(byte x);
void show_digit4(word x);
void clear_buffer(void);
byte get_hex(char x);
void show_value_x(byte idx,word x);
word xcopy(byte x);
/* global variables */
word sensor ;
word xmax ;
word xmin ;
word xth ;
byte xcnt ;
byte eflag ;
byte uflag ;
byte rflag ;
byte mflag ;
byte sindex ;
byte sbuf[8] ;
byte cmd ;
word gdat[MAXPIXELS] ;
byte xclkd ;
byte xsid ;
void setup()
{
/* initialize serial port */
Serial.begin(9600);
/* set initial state */
PORTB = 0x00 ;
PORTC = 0x00 ;
PORTD = 0x01 ;
/* set pin directions */
DDRB = 0xff ;
DDRC = 0xfe ;
DDRD = 0xfe ;
/* clear flags */
eflag = OFF ;
uflag = OFF ;
rflag = OFF ;
mflag = OFF ;
/* command interpreter buffer */
sindex = 0 ;
/* initialize */
xcnt = 0 ;
clear_buffer();
/* 500ms period */
MsTimer2::set(500,update_trigger);
/* enable */
MsTimer2::start();
/* set delay (us) */
xclkd = 5 ;
xsid = 10 ;
/* rapid ADC */
byte tmp ;
tmp = ADCSRA & 0xf8 ;
tmp |= 0x05 ;
ADCSRA = tmp ;
}
void loop()
{
byte i ;
/* sensing */
if ( eflag == ON ) {
/* clear flag */
eflag = OFF ;
/* sampling */
get_sensor(mflag);
/* clear flag */
if ( mflag == ON ) { mflag = OFF ; }
}
/* serial handling */
if ( uflag == ON ) {
/* clear flag */
uflag = OFF ;
/* new line */
crlf();
/* get command */
cmd = *(sbuf+0) ;
/* judge */
if ( cmd == '?' ) { show_help(); }
/* execute */
if ( cmd == 'M' ) { mflag = ON ; }
/* show */
if ( cmd == 'S' ) { show_raw_values(); }
/* show */
if ( cmd == 'B' ) { show_binary(OFF); }
/* clear raw values buffer */
if ( cmd == 'C' ) { clear_buffer(); }
/* threshold */
if ( cmd == 'T' ) {
/* copy */
xth = xcopy(4) ;
/* judge */
if ( xth > 1023 ) { xth = 1023 ; }
/* show */
show_value_x( Threshold_MSG , xth );
}
/* show with threshold */
if ( cmd == 'b' ) { show_binary(ON); }
/* set SI delay */
if ( cmd == 'I' ) {
/* copy */
xsid = (byte)xcopy(3);
/* judge */
if ( xsid < 10 ) { xsid = 10 ; }
/* show */
show_value_x( SI_MSG , xsid ) ;
}
/* CLK periode */
if ( cmd == 'P' ) {
/* copy */
xclkd = (byte)xcopy(3);
/* judge */
if ( xclkd < 5 ) { xsid = 5 ; }
/* show */
show_value_x( CLK_MSG , xclkd ) ;
}
/* show SI and CLK delay */
if ( cmd == 's' ) {
/* SI */
show_value_x( SI_MSG , xsid ) ;
/* CLK */
show_value_x( CLK_MSG , xclkd ) ;
}
}
}
void rs_putchar(char x)
{
Serial.write(x);
}
void rs_puts(char *x)
{
while ( *x ) {
rs_putchar(*x);
x++ ;
}
}
void crlf(void)
{
rs_putchar('\r');
rs_putchar('\n');
}
void show_help(void)
{
rs_puts("? help"); crlf();
rs_puts("M start measure"); crlf();
rs_puts("S show raw values"); crlf();
rs_puts("B show binary"); crlf();
rs_puts("C clear raw data buffer"); crlf();
rs_puts("T set threshold"); crlf();
rs_puts("b show binary with threshold"); crlf();
rs_puts("I set SI delay"); crlf();
rs_puts("P set CLK period"); crlf();
rs_puts("s show SI and CLK delay"); crlf();
}
void send_si(byte x)
{
if ( x ) {
PORTC |= (1 << SI_BIT);
/* delay */
delayMicroseconds(xsid);
} else {
PORTC &= ~(1 << SI_BIT);
}
}
void send_clk(byte x)
{
if ( x ) { PORTC |= (1 << CLK_BIT); }
else { PORTC &= ~(1 << CLK_BIT); }
/* delay more than or equal 5 us */
delayMicroseconds(xclkd);
}
void send_led(byte x)
{
if ( x ) { PORTB |= (1 << LED_BIT); }
else { PORTB &= ~(1 << LED_BIT); }
}
void update_trigger(void)
{
eflag = ON ;
send_led( xcnt & ON );
xcnt++ ;
}
void get_sensor(byte x)
{
byte i ;
/* start SI handling */
send_si( ON ) ;
/* show message */
if ( x == ON ) {
rs_puts("Start");
crlf();
}
/* transfer */
for ( i = 0 ; i < MAXPIXELS ; i++ ) {
/* CLK : H */
send_clk( ON ) ;
/* SI handling */
if ( i == 0 ) { send_si( OFF ) ; }
/* get value of pixel */
sensor = analogRead(0) ;
/* store */
if ( x == ON ) {
/* pseudo values */
if ( i == 0 ) {
xmax = sensor ;
xmin = sensor ;
}
/* latch data */
*(gdat+i) = sensor ;
/* update */
if ( xmax < sensor ) { xmax = sensor ; }
if ( xmin > sensor ) { xmin = sensor ; }
/* disable start trigger */
}
/* CLK : L */
send_clk( OFF ) ;
}
/* reset sensor lamp circuit */
send_clk( ON ) ;
send_clk( OFF ) ;
/* delay 20us */
delayMicroseconds(20);
/* show message */
if ( x == ON ) {
rs_puts("Complete");
crlf();
}
}
void show_raw_values(void)
{
byte i ;
word tmp ;
word xavr ;
/* calculate average */
xavr = ((xmax+xmin) >> 1) ;
/* show maximum , minimum and average */
rs_puts("Max = ") ; show_digit4( xmax ); crlf();
rs_puts("Min = ") ; show_digit4( xmin ); crlf();
rs_puts("Avr = ") ; show_digit4( xavr ); crlf();
/* raw values */
for ( i = 0 ; i < MAXPIXELS ; i++ ) {
/* decimal data */
show_digit4( *(gdat+i) );
rs_putchar(' ');
/* new line */
if ( (i % 16) == 15 ) { crlf(); }
}
}
void show_binary(byte x)
{
byte i ;
word xavr ;
char bn ;
/* calculate average */
xavr = ((xmax+xmin) >> 1) ;
/* judge */
if ( x ) { xavr = xth ; }
/* show */
for ( i = 0 ; i < MAXPIXELS ; i++ ) {
/* set character */
bn = '0' ;
if ( *(gdat+i) > xavr ) { bn = '1' ; }
/* send */
rs_putchar(bn);
/* new line */
if ( (i % 32) == 31 ) { crlf(); }
}
}
void show_digit4(word x)
{
char msg[4] ;
byte i ;
/* separate */
for ( i = 0 ; i < 4 ; i++ ) {
*(msg+3-i) = x % 10 + '0' ;
x /= 10 ;
}
/* zero suppress */
if ( *(msg+0) == '0' ) {
*(msg+0) = ' ' ;
if ( *(msg+1) == '0' ) {
*(msg+1) = ' ' ;
if ( *(msg+2) == '0' ) {
*(msg+2) = ' ' ;
}
}
}
/* send */
for ( i = 0 ; i < 4 ; i++ ) {
rs_putchar( *(msg+i) );
}
}
void show_value_x(byte idx,word x)
{
/* prompt */
if ( idx == Threshold_MSG ) { rs_puts("Threshold = "); }
if ( idx == SI_MSG ) { rs_puts("SI delay (us) = "); }
if ( idx == CLK_MSG ) { rs_puts("CLK delay (us) = "); }
/* value */
show_digit4( x ) ;
/* new line */
crlf();
}
word xcopy(byte x)
{
byte last ;
byte ii ;
word result ;
/* default */
result = 0 ;
/* calculate */
last = x ;
for ( ii = 0 ; ii < last ; ii++ ) {
/* judge */
if ( *(sbuf+1+ii) == '\r' ) break ;
/* add */
result *= 10 ;
result += get_hex( *(sbuf+1+ii) );
}
/* adjust */
if ( last == 3 && result > 255 ) {
result = 255 ;
}
return result ;
}
void clear_buffer(void)
{
for ( byte i = 0 ; i < MAXPIXELS ; i++ ) { *(gdat+i) = 0 ; }
}
byte get_hex(char x)
{
byte 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 ;
}
/* receive interrupt */
void serialEvent()
{
char ch ;
if ( Serial.available() > 0 ) {
/* get 1 character */
ch = Serial.read();
/* store */
*(sbuf+sindex) = ch ;
/* increment */
sindex++ ;
/* judge */
if ( ch == '\r' ) {
sindex = 0 ;
uflag = ON ;
}
}
}
目次
前
次