目次
前
次
センサー動作確認
センサーとして2台のカメラを利用します。
実際のコースは、天井から蛍光灯による照明と
窓から入る太陽光で、場所ごとに照度や映込み
があります。
今回、偏光板を利用して、コース面の状態が場所
と照明によるバラツキが少なくなるようにします。
知人の光学専門家である大学教授が、実験で不要
になったとのでと、頂いたモノ。
これを通して、コース面を撮影した場合との比較
をしてみます。
バーコードスキャナ(BCS)で、光学系での違いがでる
のかも実験してみます。BCSは、mugen2012で使った
ものを用意します。
H8/3048FOne基板と128kバイトのSRAMが手元に残って
いたので、画像を保存するための基板を半田付けです。
MCRに利用されていた基板ですが、34ピン、20ピンの
コネクタをつけて、ジャックインできるようにして
あります。
SRAMは、アドレス、データ、コントロールの3種類
のバスが必要なので、次のように結線しました。
- P17 - A07 P27 - A15 P37 - D7
- P16 - A06 P26 - A14 P36 - D6
- P15 - A05 P25 - A13 P35 - D5
- P14 - A04 P24 - A12 P34 - D4
- P13 - A03 P23 - A11 P33 - D3
- P12 - A02 P22 - A10 P32 - D2
- P11 - A01 P21 - A09 P31 - D1
- P10 - A00 P20 - A08 P30 - D0
- P53 - A16
- P52 - nCS
- P51 - nOE
- P50 - nWR
ポート5の3ピンは、負論理なので抵抗で
プルアップしてあります。
GBCとH8/3048FOneを接続するには、9ピン
次のようにします。
- START - P81 (output)
- SIN - P65 (output)
- LOAD - P66 (output)
- XRST - P82 (output)
- XCK - P64 (output)
- READ - P83 (input)
- Vout - P70 (input)
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 ;
}
シリアルインタフェースを利用するために、次の
コマンドを用意しました。
- ? help
- L lamp flashing
- M test motor
- D dump memory
- F fill memory
- W write data to SRAM
コマンドに関して、簡単に説明します。
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ビット単位で合成したのでは、時間
が掛かりすぎると判断したから。
シリアルインタフェースで接続して、動作確認できる
仕様とするために、コマンドを以下のようにしました。
- ? help
- W set data
- F show frame buffer context
- C clear frame buffer context
- D display on LCD
- G GBC handling
GBCを扱うときは、すべてコマンド'G'を利用します。
コマンドに続く数字で、機能を切り替えていきます。
- G0 initialize
- G1 take picture
- G2 convert and show on LCD
- G3 clear gbc buffer
- G4 show gbc buffer
ソースコードにまとめると、以下。
#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)
目次
前
次