マシン完成
メカハードの上に、マイコン関係基板を載せ
カメラを取り付けられるようにしました。
(前年度の反省から、カメラを配置した
前方が軽くなるようにしてあります。)
最頂部まで130mm程度になり、車検をパスできる車高に。
カメラ基板は、ネームプレートを利用した
角度を可変できる構造にしました。
傾け状態
立てた状態
画像処理を実現するためには、40MHz程度のクロックが
必要と判断し、マイコンとしてARMのADuC7026、FPGAと
してSpartan3の50kゲート品を基板に入れました。
ARMのクロック周波数が41.78MHz
Spartan3のクロック周波数を40MHz
にして動かします。
ARMの担当内容は、以下。
スタートスイッチを判断し、FPGAを動かす。
FPGA生成のセンサーデータから制御パラメータ計算
FPGAに対し移動指示
Spartan3の担当内容は、次のように。
カメラを制御し、画像データを取得
画像データからセンサーデータ生成
ARMの要求によりセンサーデータを出力
ARMの指示によりモータ制御
コースに照射するLED光制御
電源は、ENELOOPタイプのバッテリーを
使うことに。
4本を1組として、モータ用とマイコン用に
分けて使います。マイコン用は、基板の下に
モータ用はベース台車の電池ボックスに入れ
使います。
ARMとSpartan3の接続が、設計通りかを調べるため
ファームウエアとVHDLコードを書きました。
接続テストなので、ARMから出力したデータをSpartan3
が受け取り、LEDに表示する仕様にしました。
ARMのファームウエアは、以下です。
#include <ADuC7026.h>
#define OFF 0
#define ON OFF+1
/* data definitions */
typedef unsigned char UBYTE ;
typedef signed char SBYTE ;
typedef unsigned short UWORD ;
typedef signed short SWORD ;
typedef unsigned long ULONG ;
typedef signed long SLONG ;
void IRQ_Handler(void) __irq;
void init_usr(void);
#define MASKFF 0xFF
#define MASK0F 0x0F
#define MASK80 0x80
#define MASK40 0x40
#define MASK20 0x20
#define MASK10 0x10
#define MASK08 0x08
#define MASK04 0x04
#define MASK02 0x02
#define MASK01 0x01
#define MASKF0 0xF0
ULONG timcnt ;
void rs_putchar(UBYTE x);
void crlf(void);
void rs_puts(UBYTE *x);
UBYTE get_hex(UBYTE x);
void show_help(void);
void show_led(void);
/* global variables */
volatile UBYTE uflag ;
volatile UBYTE sbuf[8] ;
volatile UBYTE sindex ;
volatile UBYTE cmd ;
volatile UBYTE asc_hex[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
volatile UBYTE p2dat ;
volatile UBYTE p3dat ;
int main(void)
{
UBYTE tmp ;
/* initialize user */
init_usr();
/* show message */
rs_puts("Hello"); crlf();
/* endless loop */
while(ON)
{
/* command interrpreter */
if ( uflag == ON ) {
/* clear flag */
uflag = OFF ;
/* judge */
cmd = *(sbuf+0) ;
if ( cmd == '?' ) { show_help(); }
/* set port values */
if ( cmd == 'F' || cmd == 'R' ) {
crlf();
/* value */
tmp = get_hex( *(sbuf+1) ) ;
tmp <<= 4 ;
tmp |= get_hex( *(sbuf+2) ) ;
/* P2 or P3 */
if ( cmd == 'R' ) {
p3dat = tmp ;
GP3DAT &= 0xff00ffff ;
GP3DAT |= (tmp << 16) ;
} else {
p2dat = tmp ;
GP2DAT &= 0xff00ffff ;
GP2DAT |= (tmp << 16) ;
}
}
/* show duty */
if ( cmd == 'S' ) { show_led(); }
}
}
/* dummy return */
return (0);
}
void IRQ_Handler(void) __irq
{
volatile UBYTE ch ;
/* judge UART receive interruption */
if ( (IRQSTA & UART_BIT) == UART_BIT ) {
/* judge */
if ( COMSTA0 & 1 ) {
/* clear flag */
ch = COMRX ;
*(sbuf+sindex) = ch ;
sindex++ ;
if ( ch == '\r' ) {
sindex = 0 ;
uflag = ON ;
}
}
}
/* judge timer3 interruption (1s) */
if ( (IRQSTA & WATCHDOG_TIMER_BIT) == WATCHDOG_TIMER_BIT ) {
/* clear timer3 interrupt flag */
T3CLRI = 0xff ;
/* blink */
GP4DAT ^= (1 << 23);
}
}
void init_usr(void)
{
/* select clock 10.44MHz
initialized in start up routine
*/
PLLKEY1 = 0xaa ;
PLLCON = 0x01 ;
PLLKEY2 = 0x55 ;
/* power control
initialized in start up routine
*/
/* clear flag */
uflag = OFF ;
/* clear counter */
timcnt = 0 ;
/* initialize UART */
{
/* set baud rate 19200 bps CD = 2 */
COMCON0 = 0x80 ; /* select COMDIV1 and COMDIV0 */
COMDIV0 = 0x11 ;
COMDIV1 = 0x00 ;
/* set conditions */
COMCON0 = 0x03 ; /* select COMRX and COMTX , 8bit data , 1 stop bit , no parity */
/* enable interrupt */
COMIEN0 = 0x01 ; /* ERBFI */
}
/* P0 */
{
/* */
GP0DAT = 0xFF3C0000 ;
}
/* P1 */
{
/* use UART */
GP1CON = 0x00000011 ;
/* */
GP1DAT = 0xfe000000 ;
}
/* P2 */
{
/* all bits outputs */
GP2DAT = 0xff000000 ;
}
/* P3 */
{
/* all bits outputs */
GP3DAT = 0xff000000 ;
}
/* P4 */
{
GP4DAT = 0xff000000 ;
}
/* initialize timer 3 (1s) */
{
T3LD = 32768 ; /* (32.768kHz / 32768) = 1 Hz */
T3CON = 0xc0 ; /* enable , cyclic , 1/1 */
}
/* clear */
p2dat = 0 ;
p3dat = 0 ;
/* enable timer 3 interrupt and UART interrupt */
IRQEN = WATCHDOG_TIMER_BIT | UART_BIT ;
}
/* UART putchar */
void rs_putchar(UBYTE x)
{
/* ? transmmit buffer empty */
while( (COMSTA0 & 0x40) == 0 ) ;
/* set value */
COMTX = x ;
}
/* carriage return and line feed */
void crlf(void)
{
rs_putchar('\r');
rs_putchar('\n');
}
/* UART puts */
void rs_puts(UBYTE *x)
{
while ( *x != '\0' ) {
rs_putchar( *x ) ;
x++ ;
}
}
/* convert ASCII to number */
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 ;
}
/* show help */
void show_help(void)
{
rs_puts("? help") ; crlf();
rs_puts("F set P2 values") ; crlf();
rs_puts("R set P3 values") ; crlf();
rs_puts("S show") ; crlf();
}
void show_led(void)
{
UBYTE i ;
UBYTE msg[9] ;
/* clear buffer */
for ( i = 0 ; i < 9 ; i++ ) { *(msg+i) = '\0' ; }
/* P2 */
for ( i = 0 ; i < 8 ; i++ ) {
*(msg+i) = ((p2dat >> (7-i)) & 1) + '0' ;
}
rs_puts("P2 ");
rs_puts( msg );
crlf();
/* P3 */
for ( i = 0 ; i < 8 ; i++ ) {
*(msg+i) = ((p3dat >> (7-i)) & 1) + '0' ;
}
rs_puts("P3 ");
rs_puts( msg );
crlf();
}
P2、P3をSpartan3と接続しています。
端末からLEDの点灯パターンを、ARMに与えて
接続をチェックします。
Spartan3のVHDLコードです。
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity clktst is
generic (
TOPX : integer := 7 ;
XMAX : integer := 100 ;
TOPY : integer := 11 ;
YMAX : integer := 1250 --;
);
port (
-- system
nRESET : in std_logic ;
CLOCK : in std_logic ;
-- inputs
GP2 : in std_logic_vector(7 downto 0) ;
GP3 : in std_logic_vector(7 downto 0) ;
-- outputs
GDAT0 : out std_logic_vector(7 downto 0) ;
GDAT1 : out std_logic_vector(7 downto 0) ;
GDAT2 : out std_logic_vector(7 downto 0) ;
-- monitor
RLED : out std_logic ;
GLED : out std_logic --;
);
end clktst ;
architecture Behavioral of clktst is
-- component clock generator
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 ;
-- clock
signal iMCLK : std_logic ;
signal iSCLK : std_logic ;
-- pin check
signal iCNT : integer range 0 to 80 ;
signal iGDAT : std_logic_vector(7 downto 0) ;
signal iGDAT0 : std_logic_vector(7 downto 0) ;
signal iGDAT1 : std_logic_vector(7 downto 0) ;
begin
-- component clock generator (20MHz/100kHz = 200)
CLKX : clkgenx generic map (TOPX,XMAX) port map (nRESET,CLOCK,iMCLK);
-- component clock generator (100kHz/1250 = 4Hz)
CLKY : clkgenx generic map (TOPY,YMAX) port map (nRESET,iMCLK,iSCLK);
-- output
GLED <= not iMCLK ;
RLED <= not iSCLK ;
GDAT0 <= not iGDAT0 ;
GDAT1 <= not iGDAT1 ;
GDAT2 <= not iGDAT ;
-- counter
process (nRESET,iSCLK)
begin
if ( nRESET = '0' ) then
iCNT <= 0 ;
elsif rising_edge(iSCLK) then
iCNT <= iCNT + 1 ;
if ( iCNT = 80 ) then
iCNT <= 0 ;
end if ;
end if ;
end process ;
iGDAT <= "00000001" when ( iCNT = 0 ) else
"00000010" when ( iCNT = 1 ) else
"00000100" when ( iCNT = 2 ) else
"00001000" when ( iCNT = 3 ) else
"00010000" when ( iCNT = 4 ) else
"00100000" when ( iCNT = 5 ) else
"01000000" when ( iCNT = 6 ) else
"10000000" when ( iCNT = 7 ) else
"00000000" ;
-- latch
process (nRESET,iMCLK)
begin
if ( nRESET = '0' ) then
iGDAT0 <= (others => '0') ;
iGDAT1 <= (others => '0') ;
elsif rising_edge(iMCLK) then
iGDAT0 <= GP3 ;
iGDAT1 <= GP2 ;
end if ;
end process ;
end Behavioral;
LEDは負論理で動作してるので、ARMから受け取った
データを反転して、出力します。
Spartan3の接続仕様は、次のUCFファイルの内容になります。
# Spartan3 50k gates
# system
NET "CLOCK" LOC = "P36" ;
NET "nRESET" LOC = "P50" ;
# G0
NET "GDAT0<0>" LOC = "P1" | DRIVE = 8 | SLEW = SLOW ;
NET "GDAT0<1>" LOC = "P2" | DRIVE = 8 | SLEW = SLOW ;
NET "GDAT0<2>" LOC = "P4" | DRIVE = 8 | SLEW = SLOW ;
NET "GDAT0<3>" LOC = "P5" | DRIVE = 8 | SLEW = SLOW ;
NET "GDAT0<4>" LOC = "P8" | DRIVE = 8 | SLEW = SLOW ;
NET "GDAT0<5>" LOC = "P9" | DRIVE = 8 | SLEW = SLOW ;
NET "GDAT0<6>" LOC = "P11" | DRIVE = 8 | SLEW = SLOW ;
NET "GDAT0<7>" LOC = "P12" | DRIVE = 8 | SLEW = SLOW ;
# G1 (camera data signals)
NET "GDAT1<0>" LOC = "P13" | DRIVE = 8 | SLEW = SLOW ;
NET "GDAT1<1>" LOC = "P14" | DRIVE = 8 | SLEW = SLOW ;
NET "GDAT1<2>" LOC = "P15" | DRIVE = 8 | SLEW = SLOW ;
NET "GDAT1<3>" LOC = "P16" | DRIVE = 8 | SLEW = SLOW ;
NET "GDAT1<4>" LOC = "P17" | DRIVE = 8 | SLEW = SLOW ;
NET "GDAT1<5>" LOC = "P21" | DRIVE = 8 | SLEW = SLOW ;
NET "GDAT1<6>" LOC = "P22" | DRIVE = 8 | SLEW = SLOW ;
NET "GDAT1<7>" LOC = "P23" | DRIVE = 8 | SLEW = SLOW ;
# G2
# group G2 (camera control signals)
NET "GDAT2<0>" LOC = "P27" | DRIVE = 8 | SLEW = SLOW ;
NET "GDAT2<1>" LOC = "P28" | DRIVE = 8 | SLEW = SLOW ;
NET "GDAT2<2>" LOC = "P30" | DRIVE = 8 | SLEW = SLOW ;
NET "GDAT2<3>" LOC = "P32" | DRIVE = 8 | SLEW = SLOW ;
NET "GDAT2<4>" LOC = "P34" | DRIVE = 8 | SLEW = SLOW ;
NET "GDAT2<5>" LOC = "P35" | DRIVE = 8 | SLEW = SLOW ;
NET "GDAT2<6>" LOC = "P53" | DRIVE = 8 | SLEW = SLOW ;
NET "GDAT2<7>" LOC = "P54" | DRIVE = 8 | SLEW = SLOW ;
# Bank 4 (2.5V) G3
NET "RLED" LOC = "P47" | DRIVE = 8 | SLEW = SLOW ;
NET "GLED" LOC = "P49" | DRIVE = 8 | SLEW = SLOW ;
# G3
NET "GP3<0>" LOC = "P55" ;
NET "GP3<1>" LOC = "P59" ;
NET "GP3<2>" LOC = "P60" ;
NET "GP3<3>" LOC = "P61" ;
NET "GP3<4>" LOC = "P62" ;
NET "GP3<5>" LOC = "P63" ;
NET "GP3<6>" LOC = "P64" ;
NET "GP3<7>" LOC = "P65" ;
# G4
NET "GP2<0>" LOC = "P67" ;
NET "GP2<1>" LOC = "P68" ;
NET "GP2<2>" LOC = "P71" ;
NET "GP2<3>" LOC = "P72" ;
NET "GP2<4>" LOC = "P74" ;
NET "GP2<5>" LOC = "P75" ;
NET "GP2<6>" LOC = "P79" ;
NET "GP2<7>" LOC = "P80" ;
システムを、ブロック図で示すと以下。
画像データ処理、モータ制御はFPGAが担当し
ARMは移動のための情報処理を担当します。
ARMでの画像データ処理することも可能ですが
割込み等が頻発すると、移動処理が疎かになる
ので、FPGAに任せられる内容は、すべて任せる
ようにします。
動かすために、必要となる内容は以下。
- タイヤ直径35mm 1回転で進む距離は約10.5mm
- 前部にLED射光器をおく
- 後部にエンコーダを接続
エンコーダは、1回転3パルス出力する仕様で
16ビットカウンタを利用すると、65537まで
パルスカウントできます。
1回転=10.5mmなので、16ビットカウント値を
フルで当てると、約230mまで判断できます。
MCRのコースは、1周60m前後なのでマイコンか
FPGA内に16ビットカウンタをひとつ用意すると
1周走り終わったかを判定できます。
他に、車体スピードも逆算で求められる
ので、精度の高い走行が可能になります。
目次
前
次