目次

ファームウエア変更

 画像処理を変更したので、ファームウエアも
 変更します。

 ファームウエアから見ると、FPGAには16本のレジスタが
 あります。レジスタアドレスを指定して、パラメータを
 入出力しやすいように、モータ、カメラデータとエンコーダ
 に分けたラッパー関数を作成します。

 モータ用関数

    typedef unsigned char  UBYTE ;

    void  put_motor_duty(UBYTE x);
    void  put_motor_dir(UBYTE x);
    UBYTE get_motor_duty(UBYTE fr);
    UBYTE get_motor_dir(UBYTE fr);

  DUTY比設定は、関数put_motor_dutyを使います。

  DUTY比は0〜99で7ビットで指定できるので
  前輪、後輪の区別に8ビット目を利用します。
  0で前輪、1で後輪のDUTY比指定とします。

  現在のDUTY比は、関数get_motor_dutyで
  取得します。前輪、後輪の指定が必要と
  なるので、引数を一つにします。

  方向指定は、関数put_motor_dirを利用します。
  DUTY比設定同様、8ビット目を前輪、後輪の
  選択指定に利用します。方向は、0、1、2で
  前輪は、2(左)、1(右)、0(中央)で指定
  します。
  後輪は2(後退)、1(前進)、0(停止)と
  仕様を決めます。

 エンコーダカウントパルス取得関数

    typedef unsigned shoft UWORD ;

    UWORD get_pulse_count(void);

  FPGAのレジスタは、パルスカウントの上位
  下位を8ビットに分けて出力してくるので
  16ビットで参照できるようにします。

 センターライン位置取得関数

    UBYTE get_top(void);
    UBYTE get_middle(void);
    UBYTE get_bottom(void);

  3ラインの各ラインにおける、センターライン
  位置を、TOP、MIDDLE、BOTTOMに分けて取得する
  ようにします。

 ライン幅取得関数

    UBYTE get_top_width(void);
    UBYTE get_middle_width(void);
    UBYTE get_bottom_width(void);

  各ラインにおける、センターラインの幅を
  TOP、MIDDLE、BOTTOMに分けて取得します。

 ライン位置指定関数

    void put_line_number(UBYTE which,UBYTE x);

  TOP、MIDDLE、BOTTOMのどれかをwhichで
  ライン位置をxで指定します。

 これらの関数は、ARMとFPGAとのデータ交換でできて
 いるため、データ交換用の2つの関数のラッパーに
 なるようにします。

 2つのデータ交換関数は、次のように定義しました。

#define MASKFF 0xff

UBYTE get_fpga_reg(UBYTE ax)
{
  volatile UBYTE adr ;
  volatile UBYTE result ;
  /* judge */
  if ( ax > 15 ) { return 0 ; }
  /* change inputs */
  GP3DAT &= 0x00ffffff ;
  /* address */
  adr = 0x10+ax ;
  /* set address and enable OE */
  GP2DAT &= 0xff00ffff ;
  GP2DAT |= (adr << 16) ;
  /* get data */
  result = GP3DAT & MASKFF ;
  /* change outputs */
  GP3DAT |= 0xff000000 ;

  return result ;
}

#define S_TRG 22

void  put_fpga_reg(UBYTE ax,UBYTE dx)
{
  volatile UBYTE adr ;
  /* judge */
  if ( ax > 15 ) return ;
  /* address */
  adr = 0x20+ax ;
  /* send address */
  GP2DAT &= 0xff00ffff ;
  GP2DAT |= (adr << 16) ;
  /* send data */
  GP3DAT &= 0xff00ffff ;
  GP3DAT |= (dx << 16) ;
  /* trigger */
  GP2DAT |=  (1 << S_TRG) ; /* trigger H */
  adr = 0 ;	/* delay */
  GP2DAT &= ~(1 << S_TRG) ; /* trigger L */
}

 2関数を土台にして、ラッパー関数を定義します。

void  put_motor_duty(UBYTE x)
{
  volatile UBYTE adr ;
  volatile UBYTE dat ;
  /* address */
  adr = FP_ADR ;
  if ( x & 0x80 ) { adr = RP_ADR ; }
  /* data */
  dat = x & 0x7f ;
  /* send */
  put_fpga_reg(adr,dat);
}

void  put_motor_dir(UBYTE x)
{
  volatile UBYTE adr ;
  volatile UBYTE dat ;
  /* front or rear */
  adr = FD_ADR ;
  if ( x & 0x80 ) { adr = RD_ADR ; }
  /* data */
  dat = x & 3 ;
  /* send */
  put_fpga_reg(adr,dat);
}

UBYTE get_motor_duty(UBYTE fr)
{
  volatile UBYTE adr ;
  /* front or rear */
  adr = FP_ADR ;
  if ( fr ) { adr = RP_ADR ; }
  /* result */
  return get_fpga_reg(adr);
}

UBYTE get_motor_dir(UBYTE fr)
{
  volatile UBYTE adr ;
  /* front or rear */
  adr = FD_ADR ;
  if ( fr ) { adr = RD_ADR ; }
  /* result */
  return get_fpga_reg(adr);
}

UWORD get_pulse_count(void)
{
  volatile UBYTE dh ;
  volatile UBYTE dl ;
  /* get upper byte */
  dh = get_fpga_reg(ROTU) ;
  /* get lower byte */
  dh = get_fpga_reg(ROTL) ;
  /* result */
  return( (dh << 8) | dl ) ;
}

UBYTE get_top(void)
{
  return get_fpga_reg(LTOP);
}

UBYTE get_middle(void)
{
  return get_fpga_reg(LMID);
}

UBYTE get_bottom(void)
{
  return get_fpga_reg(LBOT);
}

UBYTE get_top_width(void)
{
  return get_fpga_reg(DTOP);
}

UBYTE get_middle_width(void)
{
  return get_fpga_reg(DMID);
}

UBYTE get_bottom_width(void)
{
  return get_fpga_reg(DBOT);
}

 関数put_fpga_regがあると、どのラインを画像処理の
 対象に指定するかの関数put_line_numberは不要と判断
 しました。階層構造は、下図となります。



 マシンの保護とパワーセーブするため、指定距離の
 走行およびスタートから指定時間経過したならば
 モータを停止させます。

 距離に相当するカウント値は関数get_pulse_countで
 取得できます。スタート時のカウント値にオフセット
 を加えて、1秒ごとに、指定距離まで到達したかを
 チェックします。

 スタート時のパルスカウント値から、停止距離相当の
 カウント値を求めるコードは、以下。
    #define MAX_RUN_PULSE 28000

    target_distance = get_pulse_count() + MAX_RUN_PULSE ;

 指定距離を走行したならば、モータを停止するには
 次のコードで指定します。
    if ( get_pulse_count() > target_distance ) {
      put_motor_duty( 0 ) ;
      put_motor_duty( 0x80 ) ;
    }

 マシンの電源を入れてから、どのくらい時間が経過
 しているのかは、次のようにシステムタイマを利用
 します。

 0.1msごとのタイマー割込みを検出して、変数timcntを
 インクリメントしていきます。
  if ( (IRQSTA & RTOS_TIMER_BIT) == RTOS_TIMER_BIT ) {
    /* clear timer0 interrupt flag */
    T0CLRI = 0xff ;
    /* increment */
    timcnt++ ;
  }

 MCR大会では、1台のマシンに許されるコース占有時間は
 1分程度なので、60000msが経過したならばモータを停止
 するコードを定義します。

 スタート時点のカウント値に、許容時間カウント値を
 加えておきます。
    #define MAX_RUN_TIME  600000

    target_timcnt = timcnt + MAX_RUN_TIME ;

 指定時間を走行したならば、モータを停止するには
 次のコードで指定します。
    if ( target_timcnt > timcnt ) {
      put_motor_duty( 0 ) ;
      put_motor_duty( 0x80 ) ;
    }

 実際は、計数フラグを用意して判定します。
  flag = 0 ;
  if ( target_timcnt > timcnt ) {
    flag++ ;
  }
  if ( get_pulse_count() > target_distance ) {
    flag++ ;
  }
  if ( flag ) {
    /* stop motors */
    put_motor_dir( FRONT_CENTER );
    put_motor_dir( REAR_FORWARD );
    put_motor_duty( 0 );
    put_motor_duty( MASK80 | 0 );
  }

 カメラからの画像データ取得と一部の画像処理は
 FPGAが担当するので、ファームウエアはRealTimeOS
 を利用します。

 各タスクの担当する内容は、以下とします。

  • SSTART (task0) スタートトリガー判定
  • BLIND_RUN (task1) 情報なし直進
  • NORMAL_RUN (task2) 通常走行
  • CRANK_RUN (task3) クランク走行
  • LANE_CHANGE (task4) レーンチェンジ走行
  • SENSING (task5) センサーデータ生成
  • MEASURE (task6) 距離、時間計測
  • SDEBUG (task7) デバッガ
  • LEDFLASH (task8) 状態対応LED表示  タスクの動作を、詳しく書いて机上デバッグ  していきます。  SSTART   スタートトリガーの判定と他タスク起動を担当。   スタートトリガーは、タイマー割込みで   シフトレジスタにスイッチの状態を読み   込み、チャタリング除去します。   これだけでは、IDLEかRUNかを判定できない   ので、動作状態を表す変数system_statusを   用意し、その値で走行か停止かを確定します。   状態変数system_statusの設定とともに、動作   タスクを起動します。また、最長走行距離と   動作時間を設定します。   状態変数を使うと、スイッチをスタートと   ストップのどちらにも利用できます。   タスク内部のコードは、以下です。 void tsk0_proc(void) { /* get data */ str_sft <<= 1 ; str_sft &= MASK07 ; if ( GP0DAT & MASK20 ) { str_sft |= ON ; } /* judge */ if ( str_sft == 3 ) { if ( system_status == IDLE ) { /* IDLE -> RUN */ system_status = RUN ; /* enable BLIND_RUN */ rsm_tsk(BLIND_RUN); sus_tsk(LEDFLASH); /* stop LED flashing */ turn_off_led(); /* set 1 minite */ target_timcnt = timcnt + MAX_RUN_TIME ; /* set 100m */ target_distance = get_pulse_count() + MAX_RUN_PULSE ; } else { /* RUN -> IDLE */ system_status = IDLE ; sus_tsk(NORMAL_RUN); sus_tsk(CRANK_RUN); sus_tsk(LANE_CHANGE); rsm_tsk(LEDFLASH); /* stop */ fdir = FRONT_CENTER ; rdir = REAR_FORWARD ; fduty = 0 ; rduty = (MASK80 | 0) ; put_motor_dir( fdir ) ; put_motor_dir( rdir ) ; put_motor_duty( fduty ) ; put_motor_duty( rduty ) ; } } /* cycle 20ms */ wai_tsk( 2 ); }   スイッチのチャタリング除去のため、20ms   ごとに動作する、周期関数にしました。  BLIND_RUN   センサーの情報を利用しない、直進をします。   タスクSSTARTからREADYにされ、与えられた動作を   終了すると、タスクNORMAL_RUNをREADYにします。   自身は、SUSPEND状態になります。   内部は、単純なシーケンサにします。   500msごとに、後輪に与えるDUTY比を変え   タイヤの空転を回避します。タイヤが空   回りすると、思いもよりない方向に進む   ので、その対策です。またモータの焼き   つき防止の意味もあります。   タスク内部のコードは、以下。 void tsk1_proc(void) { /* show mode */ turn_on_led(LED_BLIND); /* select CENTER */ put_motor_dir( FRONT_CENTER ) ; put_motor_dir( REAR_FORWARD ) ; /* sequencer */ switch ( bstate ) { /* duty 5% */ case 0 : rduty = (MASK80 | 5) ; break ; /* duty 15% */ case 1 : rduty = (MASK80 | 15) ; break ; /* duty 25% */ case 2 : rduty = (MASK80 | 25) ; break ; /* duty 45% */ case 3 : rduty = (MASK80 | 45) ; break ; /* duty 65% */ case 4 : rduty = (MASK80 | 65) ; break ; /* duty 75% */ case 5 : rduty = (MASK80 | 75) ; break ; /* others */ default : break ; } put_motor_duty( rduty ); /* increment */ bstate++ ; /* judge */ if ( bstate < 6 ) { wai_tsk(50) ; /* 500ms interval */ } else { bstate = 0 ; rsm_tsk(NORMAL_RUN) ; slp_tsk(); turn_off_led(); } }  NORMAL_RUN   コース上にセンターラインがある場合の走行を   担当するタスクです。   タスクBLIND_RUNからREADYにされ、センサー値で   タスクCRANK_RUN、LANE_CHANGEをSUSPENDからREADY   にします。   センサーデータは、TOP、MIDDLE、BOTTOMの3ライン   のセンター位置、幅をFPGAが出力するので、ファーム   ウエアで、8ビットに変換します。   クランク、レーンチェンジの判定は、BOTOMでない   2つのラインの状態で判定します。   タスク内部のコードは、以下。 void tsk2_proc(void) { volatile UBYTE topx ; volatile UBYTE midx ; volatile UBYTE sensorx ; volatile UBYTE flag2 ; /* show mode */ turn_on_led(LED_NORMAL); /* default */ flag2 = OFF ; topx = xsjp.topx ; midx = xsjp.midx ; sensorx = xsjp.botx ; /* judge */ if ( sensorx == STATE_CENTER ) { fdir = FRONT_CENTER ; rdir = REAR_FORWARD ; fduty = 0 ; rduty = (MASK80 | 50); } if ( sensorx == STATE_TINY_RIGHT ) { fdir = FRONT_RIGHT ; rdir = REAR_FORWARD ; fduty = 50 ; rduty = (MASK80 | 75); } if ( sensorx == STATE_RIGHT ) { fdir = FRONT_RIGHT ; rdir = REAR_FORWARD ; fduty = 75 ; rduty = (MASK80 | 55); } if ( sensorx == STATE_BIG_RIGHT ) { fdir = FRONT_RIGHT ; rdir = REAR_FORWARD ; fduty = 90 ; rduty = (MASK80 | 45); } if ( sensorx == STATE_TINY_LEFT ) { fdir = FRONT_LEFT ; rdir = REAR_FORWARD ; fduty = 50 ; rduty = (MASK80 | 75); } if ( sensorx == STATE_LEFT ) { fdir = FRONT_LEFT ; rdir = REAR_FORWARD ; fduty = 70 ; rduty = (MASK80 | 55); } if ( sensorx == STATE_BIG_LEFT ) { fdir = FRONT_LEFT ; rdir = REAR_FORWARD ; fduty = 90 ; rduty = (MASK80 | 45); } /* set motor duty ratio */ put_motor_dir( fdir ); put_motor_dir( rdir ); put_motor_duty( fduty ); put_motor_duty( rduty ); /* judge CRANK mark */ if ( topx == STATE_ALL_WHITE || midx == STATE_ALL_WHITE ) { white_state = WHITE_STATE_ALL ; rsm_tsk( CRANK_RUN ); flag2 = ON ; } /* judge LANE LEFT CHANGE mark */ if ( topx == STATE_LEFT_WHITE || midx == STATE_LEFT_WHITE ) { white_state = WHITE_STATE_LEFT ; rsm_tsk( LANE_CHANGE ); flag2 = ON ; } /* judge LANE RIGHT CHANGE mark */ if ( topx == STATE_RIGHT_WHITE || midx == STATE_RIGHT_WHITE ) { white_state = WHITE_STATE_RIGHT ; rsm_tsk( LANE_CHANGE ); flag2 = ON ; } /* delay */ if ( flag2 == ON ) { slp_tsk() ; turn_off_led(); } else { wai_tsk(1) ; /* 10ms interval */ } }  クランク、レーンチェンジのマークは3パターン  あるので、変数white_stateにより、CRANK_RUNと  LANE_CHANGEでの動作を判定できるようにします。  CRANK_RUN   クランクマークを検出してから、右あるいは左に   あるクランクを通過するまでを、担当します。   タスクNORMA_RUNからREADYにされ、センサー値で   タスクNORMALRUNをSUSPENDからREADYにします。   右あるいは左に方向転換するので、シーケンサで   動きを制御します。   シーケンスは、以下とします。
  • 0ステート 設定時間分、直進と指定(1ステートに遷移)
  • 1ステート 設定時間経過していいれば、2ステートに遷移
  • 2ステート 右あるいは左に白線が偏っていれば、3ステートに遷移
  • 3ステート センサーが示す方向に回転開始、4ステートに遷移
  • 4ステート センサーライン検出まで回転継続、検出すると5ステートに遷移
  • 5ステート タスクNORMAL_RUNをREADYに、自身はSUSPENDに   タスク内部のコードは、以下。 void tsk3_proc(void) { volatile UBYTE topx ; volatile UBYTE midx ; /* show mode */ turn_on_led(LED_CRANK); /* get sensor data */ topx = xsjp.topx ; midx = xsjp.midx ; /* sequencer */ switch ( cstate ) { /* blind run until minimum distance */ case 0 : cstate = 1 ; ccnt = 30 ; put_motor_dir( FRONT_CENTER ); put_motor_dir( REAR_FORWARD ); put_motor_duty( MASK80 | 75 ); break ; /* delay */ case 1 : if ( ccnt == 0 ) { cstate = 2 ; } else { ccnt-- ; } break ; /* until CRANK location */ case 2 : if ( topx == STATE_LEFT_WHITE || midx == STATE_LEFT_WHITE ) { cstate = 3 ; white_state = WHITE_STATE_LEFT ; } if ( topx == STATE_RIGHT_WHITE || midx == STATE_RIGHT_WHITE ) { cstate = 3 ; white_state = WHITE_STATE_RIGHT ; } break ; /* turn */ case 3 : cstate = 4 ; if ( white_state == WHITE_STATE_LEFT ) { put_motor_dir( FRONT_LEFT ); put_motor_duty( 50 ); } if ( white_state == WHITE_STATE_RIGHT ) { put_motor_dir( FRONT_RIGHT ); put_motor_duty( 50 ); } put_motor_dir( REAR_FORWARD ); put_motor_duty( MASK80 | 50 ); break ; /* judge center */ case 4 : if ( topx == STATE_CENTER || midx == STATE_CENTER ) { cstate = 5 ; put_motor_dir( FRONT_CENTER ); } break ; /* return first state */ case 5 : break ; /* */ default : break ; } /* delay */ if ( cstate < 5 ) { wai_tsk(1) ; /* 10ms interval */ } else { cstate = 0 ; put_motor_dir( FRONT_CENTER ); put_motor_dir( REAR_FORWARD ); put_motor_duty( MASK80 | 75 ); white_state = WHITE_STATE_NONE ; slp_tsk() ; turn_off_led(); rsm_tsk( NORMAL_RUN ); } }  LANE_CHANGE   レーンチェンジマークを検出してから、センターライン   なしの位置まで移動します。そこで、右あるいは左に   レーンを変え、次にセンターラインを検出するまでを   担当します。   タスクNORMA_RUNからREADYにされ、センサー値で   タスクNORMALRUNをSUSPENDからREADYにします。   右あるいは左に方向転換するので、シーケンサで   動きを制御します。   シーケンスは、以下とします。
  • 0ステート センターラインがなくなるまで直進(センターラインなしで、1ステートに遷移)
  • 1ステート 変数white_stateの値により、右か左に方向変更(2ステートに遷移)
  • 2ステート 設定時間経過まで方向を右か左にし、時間経過後3ステートに遷移
  • 3ステート 設定時間経過まで直進、その後4ステートに遷移
  • 4ステート 直進、5ステートに遷移
  • 5ステート センターラインを検出するまで直進、検出後6ステートに遷移
  • 6ステート 右あるいは左にセンターラインが来たら、7ステートに遷移
  • 7ステート 設定時間経過まで回転、その後8ステートに遷移
  • 8ステート タスクNORMAL_RUNをREADYに、自身はSUSPENDに   タスク内部のコードは、以下。 void tsk4_proc(void) { volatile UBYTE xtop ; volatile UBYTE xmid ; /* show mode */ turn_on_led(LED_LANE); /* get sensor data */ xtop = xsjp.topx ; xmid = xsjp.midx ; /* sequencer */ switch ( lstate ) { /* forward until ALL_BLACK */ case 0 : if ( xtop == STATE_ALL_BLACK || xmid == STATE_ALL_BLACK ) { lstate = 1 ; } break ; /* judge turn */ case 1 : lstate = 2 ; lcnt = 10 ; fdir = FRONT_RIGHT ; if ( white_state == WHITE_STATE_LEFT ) { fdir = FRONT_LEFT ; } put_motor_dir( fdir ); put_motor_duty( 80 ); break ; /* turn delay */ case 2 : if ( lcnt == 0 ) { lstate = 3 ; put_motor_dir( FRONT_CENTER ); } else { lcnt-- ; } break ; /* blind run */ case 3 : lstate = 4 ; lcnt = 10 ; put_motor_dir( REAR_FORWARD ) ; put_motor_duty( MASK80 | 75 ) ; break ; /* blind run delay */ case 4 : if ( lcnt == 0 ) { lstate = 5 ; } else { lcnt-- ; } break ; /* judge center */ case 5 : if ( xtop == STATE_CENTER || xmid == STATE_CENTER ) { lstate = 6 ; } break ; /* judge turn (reverse) */ case 6 : lstate = 7 ; lcnt = 10 ; fdir = FRONT_LEFT ; if ( white_state == WHITE_STATE_LEFT ) { fdir = FRONT_RIGHT ; } put_motor_dir( fdir ); put_motor_duty( 80 ); break ; /* turn (reverse) delay */ case 7 : if ( lcnt == 0 ) { lstate = 8 ; put_motor_dir( FRONT_CENTER ); } else { lcnt-- ; } break ; /* return first state */ case 8 : break ; /* */ default : break ; } /* delay */ if ( lstate < 8 ) { wai_tsk(1) ; /* 10ms interval */ } else { lstate = 0 ; put_motor_dir( FRONT_CENTER ); put_motor_dir( REAR_FORWARD ); put_motor_duty( MASK80 | 75 ); white_state = WHITE_STATE_NONE ; slp_tsk() ; turn_off_led(); rsm_tsk( NORMAL_RUN ); } }  SENSING   FPGAからの画像処理データを取得します。   カメラは、フレームレートが30なので1秒に   30回画像更新されます。30ms毎に、FPGAから   センサー関係パラメータを取得します。   FPGAからは、センターライン位置、幅を取得   できるので、これらから8ビットセンサーを   生成します。   位置、幅を構造体変数に入れ、専用関数で   8ビットセンサーを生成します。   専用関数は、後で定義します。   タスク内部のコードは、以下。 void tsk5_proc(void) { /* get data */ *(sensor+0) = get_top() ; *(sensor+1) = get_middle() ; *(sensor+2) = get_bottom() ; /* get width */ *(sensor+3) = get_top_width() ; *(sensor+4) = get_middle_width() ; *(sensor+5) = get_bottom_width() ; if ( system_status == IDLE ) { top_center = *(sensor+0) ; middle_center = *(sensor+1) ; bottom_center = *(sensor+2) ; top_width = *(sensor+3) ; middle_width = *(sensor+4) ; bottom_width = *(sensor+5) ; } /* judge */ xsjp.topx = *(sensor+0) ; xsjp.midx = *(sensor+1) ; xsjp.botx = *(sensor+2) ; xsjp.topw = *(sensor+3) ; xsjp.midw = *(sensor+4) ; xsjp.botw = *(sensor+5) ; perform_sensing(xsjp); /* send trigger */ send_cam_trigger(); /* */ wai_tsk( 3 ) ; /* 30ms */ }  センサーデータを位置、幅の2種に分けて  グローバル変数に入れています。スタート  する前に、3ラインの位置、幅を記憶して  おき、走行中の位置、幅で8ビットデータ  を生成します。  MEASURE   スタートしてからの移動距離、経過時間を   カウントしていきます。カウント値が所定   の値を超えたときに、モータを停止します。   距離カウントはエンコーダパルスの積算値で   算出し、システムタイマのカウント値により   経過時間を判断します。   距離カウンタがあれば、周期タスクによる   時間差から、移動スピードを算出できます。   移動スピードから、登坂、下坂の判定が可能   ですが、必要になったときに入れます。   タスク内部のコードは、以下。 void tsk6_proc(void) { volatile UBYTE flag ; /* update */ pre_rcnt = cur_rcnt ; /* get */ cur_rcnt = get_pulse_count(); /* differencial pulse count */ dif_rcnt = cur_rcnt - pre_rcnt ; /* judge */ flag = 0 ; if ( target_timcnt > timcnt ) { flag++ ; } if ( get_pulse_count() > target_distance ) { flag++ ; } if ( flag ) { /* stop RUN */ sus_tsk(NORMAL_RUN); sus_tsk(CRANK_RUN); sus_tsk(LANE_CHANGE); /* stop motors */ put_motor_dir( FRONT_CENTER ); put_motor_dir( REAR_FORWARD ); put_motor_duty( 0 ); put_motor_duty( MASK80 | 0 ); } /* interval */ wai_tsk( 10 ) ; /* 100ms */ }  SDEBUG   ハードウエアをシリアルインタフェース   から与えるコマンドでテストします。   モータ関係の設定、画像処理によるセンターライン   の位置、幅、カメラ初期化等に加え、エンコーダ   パルス値を表示します。   他に、カメラ内部のレジスタ値がどうなって   いるのかを表示します。   どんなコマンドを持っているのかは、ヘルプ(?)を   入力することで、わかるようにしておきます。   タスク内部のコードは、以下。 void tsk7_proc(void) { volatile UBYTE msg[6] ; volatile UWORD epulse ; volatile UBYTE tmp7 ; volatile UBYTE loop7 ; /* default */ tmp7 = 0 ; /* judge flag */ if ( uflag == OFF ) return ; /* new line */ crlf(); /* clear flag */ uflag = OFF ; /* judge */ cmd = *(sbuf+0) ; if ( cmd == '?' ) { show_help(); } /* initialize CAMERA */ if ( cmd == 'I' ) { push_tsk_state(); turn_off_led(); init_cam( *(sbuf+1)-'0' ) ; pop_tsk_state(); } /* set front parameters */ if ( cmd == 'F' || cmd == 'R' ) { /* duty */ duty = get_hex( *(sbuf+1) ) ; duty *= 10 ; duty += get_hex( *(sbuf+2) ) ; /* direction */ direction = get_hex( *(sbuf+3) ) ; /* rear or front */ if ( cmd == 'R' ) { rdir = direction ; rduty = duty ; } else { fdir = direction ; fduty = duty ; } /* impress */ put_motor_dir( fdir ) ; put_motor_dir( rdir ) ; put_motor_dir( fduty ) ; put_motor_dir( MASK80 | rduty ) ; } /* get encoder pulse */ if ( cmd == 'P' ) { epulse = get_pulse_count(); /* separate */ *(msg+0) = epulse / 10000 ; epulse %= 10000 ; *(msg+1) = epulse / 1000 ; epulse %= 1000 ; *(msg+2) = epulse / 100 ; epulse %= 100 ; *(msg+3) = epulse / 10 ; *(msg+4) = epulse % 10 ; *(msg+5) = '\0' ; /* conversion */ for ( loop7 = 0 ; loop7 < 5 ; loop7++ ) { *(msg+loop7) = asc_hex[ *(msg+loop7) ] ; } /* show */ rs_puts( msg ) ; /* new line */ crlf() ; } /* show duty */ if ( cmd == 'S' ) { show_duty(); } /* show sensor data */ if ( cmd == 'D' ) { /* sensor */ for ( epulse = 0 ; epulse < 3 ; epulse++ ) { /* top */ tmp7 = get_top() ; /* middle */ if ( epulse == 1 ) { tmp7 = get_middle() ; } /* bottom */ if ( epulse == 2 ) { tmp7 = get_bottom() ; } /* separate */ *(msg+0) = 'S' ; *(msg+1) = ' ' ; *(msg+2) = tmp7 / 100 ; tmp7 %= 100 ; *(msg+3) = tmp7 / 10 ; *(msg+4) = tmp7 % 10 ; *(msg+5) = '\0' ; /* conversion */ for ( loop7 = 2 ; loop7 < 5 ; loop7++ ) { *(msg+loop7) = asc_hex[ *(msg+loop7) ] ; } rs_puts( msg ) ; crlf(); } /* width */ for ( epulse = 0 ; epulse < 3 ; epulse++ ) { /* top */ tmp7 = get_top_width() ; /* middle */ if ( epulse == 1 ) { tmp7 = get_middle_width() ; } /* bottom */ if ( epulse == 2 ) { tmp7 = get_bottom_width() ; } /* separate */ *(msg+0) = 'W' ; *(msg+1) = ' ' ; *(msg+2) = tmp7 / 100 ; tmp7 %= 100 ; *(msg+3) = tmp7 / 10 ; *(msg+4) = tmp7 % 10 ; *(msg+5) = '\0' ; /* conversion */ for ( loop7 = 2 ; loop7 < 5 ; loop7++ ) { *(msg+loop7) = asc_hex[ *(msg+loop7) ] ; } rs_puts( msg ) ; crlf(); } } /* show eeprom data */ if ( cmd == 'e' ) { /* show */ for ( loop7 = 0 ; loop7 < 64 ; loop7++ ) { /* get data */ eeprom_dat = eeprom_get( loop7 ) ; /* show */ show_value( (eeprom_dat >> 8) & MASKFF ); show_value( eeprom_dat & MASKFF ); rs_putchar( ' ' ); /* new line */ if ( (loop7 % 8) == 7 ) { crlf() ; } } crlf(); } /* store eeprom data */ if ( cmd == 'E' ) { /* generate address */ eeprom_adr = 0 ; eeprom_adr += get_hex( *(sbuf+1) ) ; eeprom_adr <<= 4 ; eeprom_adr += get_hex( *(sbuf+2) ) ; /* generate data */ eeprom_dat = 0 ; eeprom_dat += get_hex( *(sbuf+3) ) ; eeprom_dat <<= 4 ; eeprom_dat += get_hex( *(sbuf+4) ) ; eeprom_dat <<= 4 ; eeprom_dat += get_hex( *(sbuf+5) ) ; eeprom_dat <<= 4 ; eeprom_dat += get_hex( *(sbuf+6) ) ; /* judge and store */ if ( eeprom_adr < 64 ) { eeprom_put(eeprom_adr,eeprom_dat) ; } else { rs_puts("Address Error !"); } crlf(); } /* show register values */ if ( cmd == 'V' ) { push_tsk_state(); turn_off_led(); show_reg() ; pop_tsk_state(); } }  LEDFLASH   IDLE状態にあるときに、LEDを点滅します。   走行中の状態は、ひとつのLEDの点灯で表示します。   IDLE状態のときに、点滅します。   30msごとに、4つのLEDに異なるビット   パターンを出力します。   LEDの点滅には、シーケンサを利用します。   カウンタを一つ使い、0〜5を繰り返して   点灯位置が左右に振れるように見せます。   タスク内部のコードは、以下。 void tsk8_proc(void) { /* impress */ turn_on_led( cyclic[fstate] ); /* update state */ fstate++ ; /* judge */ if ( fstate == 6 ) { fstate = 0 ; } /* interval 300ms */ wai_tsk(30); }
    カメラパラメータ処理  OV7670を最適な状態で動かすためには  設定パラメータを何度か変更します。  何度もコンパイル、リンクするのは面倒  なのでEEPROMにパラメータを保存します。  EEPROMには、AT93C46を使うことに。  64x16ビットなので、64アドレスに  1ワード(16ビット)が割付けられて  います。  ARMのGPIOで残っているのは、P4なので  次のように接続します。  AT93C46を扱うために、3つの関数を定義します。
    • eeprom_ewen
    • eeprom_put
    • eeprom_get
     ROMに不用意にデータをライトしないように  電源オンでは、書込み禁止となっています。  書込みできるようにするため、eeprom_ewenを  使います。  1ワードのデータライト、リードには  eeprom_put、eeprom_getを使います。  ビット処理が主体になるので、サブ関数  send_bitxを定義します。 void send_bitx(UBYTE x) { ULONG tmp; UBYTE loc ; /* get now value */ tmp = GP4DAT ; /* get location */ loc = x & MASK3F ; /* clear */ tmp &= ~(1 << loc); /* judge */ if ( x & MASK80 ) { tmp |= (1 << loc); } /* put value */ GP4DAT = tmp ; }  eeprom_ewenは、次のタイミングチャートを使います。  send_bitxを定義します。  タイミングチャートを利用して、関数を定義します。 void eeprom_ewen(void) { UWORD tmp ; UBYTE i ; /* SB , OP code , dummy */ tmp = 0x130 ; /* enable chip select */ send_bitx(MASK80 | EEPROM_CS_BIT) ; /* send */ for ( i = 0 ; i < 9 ; i++ ) { /* impress DI */ send_bitx(EEPROM_DI_BIT) ; if ( tmp & 0x100 ) { send_bitx(MASK80 | EEPROM_DI_BIT) ; } /* SK : H */ send_bitx(MASK80 | EEPROM_SK_BIT) ; /* shift */ tmp <<= 1 ; /* SK : L */ send_bitx(EEPROM_SK_BIT) ; } /* clear DI */ send_bitx(EEPROM_DI_BIT) ; /* disable chip select */ send_bitx(EEPROM_CS_BIT) ; }  データを保存する場合、次のタイミングチャートを利用します。  関数は、以下。 void eeprom_put(UBYTE ax,UWORD dx) { UWORD tmp ; UBYTE i ; /* judge */ if ( ax > 63 ) return ; /* SB , OP code , dummy */ tmp = 0x140 | (ax & MASK3F) ; /* enable chip select */ send_bitx(MASK80 | EEPROM_CS_BIT) ; /* send address */ for ( i = 0 ; i < 9 ; i++ ) { /* impress DI */ send_bitx(EEPROM_DI_BIT) ; if ( tmp & 0x100 ) { send_bitx(MASK80 | EEPROM_DI_BIT) ; } /* SK : H */ send_bitx(MASK80 | EEPROM_SK_BIT) ; /* shift */ tmp <<= 1 ; /* SK : L */ send_bitx(EEPROM_SK_BIT) ; } /* send data */ for ( i = 0 ; i < 16 ; i++ ) { /* impress DI */ send_bitx(EEPROM_DI_BIT) ; if ( dx & 0x8000 ) { send_bitx(MASK80 | EEPROM_DI_BIT) ; } /* SK : H */ send_bitx(MASK80 | EEPROM_SK_BIT) ; /* shift */ dx <<= 1 ; /* SK : L */ send_bitx(EEPROM_SK_BIT) ; } /* disable chip select */ send_bitx(EEPROM_CS_BIT) ; /* delay */ delay_ms(10) ; }  データを取出すには、SKに同期してからDOの値  を1ビットごとに取得します。  関数は、以下。 UWORD eeprom_get(UBYTE ax) { UWORD result ; UWORD tmp ; UBYTE i ; /* judge */ if ( ax > 63 ) { return 0 ; } /* SB , OP code , dummy */ tmp = 0x180 | (ax & MASK3F) ; /* enable chip select */ send_bitx(MASK80 | EEPROM_CS_BIT) ; /* send address */ for ( i = 0 ; i < 9 ; i++ ) { /* impress DI */ send_bitx(EEPROM_DI_BIT) ; if ( tmp & 0x100 ) { send_bitx(MASK80 | EEPROM_DI_BIT) ; } /* SK : H */ send_bitx(MASK80 | EEPROM_SK_BIT) ; /* shift */ tmp <<= 1 ; /* SK : L */ send_bitx(EEPROM_SK_BIT) ; } /* default */ result = 0 ; /* get data */ for ( i = 0 ; i < 16 ; i++ ) { /* shift */ result <<= 1 ; /* SK : H */ send_bitx(MASK80 | EEPROM_SK_BIT) ; /* get data */ if ( GP4DAT & 1 ) { result |= ON ; } /* SK : L */ send_bitx(EEPROM_SK_BIT) ; } /* disable chip select */ send_bitx(EEPROM_CS_BIT) ; return result ; }  カメラのパラメータは、最終で次の関数を実行する  ことにしました。 put_sccb_data(0x12,0x80); delay_ms(200); //200ms rs_puts("Complete reset"); crlf(); put_sccb_data(0x11,0x80) ; /* internal CLKRC */ put_sccb_data(0x3b,0x0a) ; /* disable night mode */ put_sccb_data(0x3a,0x04) ; /* normal graphic */ put_sccb_data(0x12,0x10) ; /* select YUV */ put_sccb_data(0x8c,0x00) ; /* select xRGB */ put_sccb_data(0x40,0xd0) ; /* COM15 [00] - [FF] */ put_sccb_data(0x17,0x16) ; /* HSTART */ put_sccb_data(0x18,0x04) ; /* HSTOP */ put_sccb_data(0x32,0x24) ; /* HREF */ put_sccb_data(0x19,0x02) ; /* VSTART */ put_sccb_data(0x1a,0x7a) ; /* VSTOP */ put_sccb_data(0x03,0x0a) ; /* VREF */ put_sccb_data(0x15,0x02) ; /* HREF */ put_sccb_data(0x0c,0x04) ; /* disable DCW */ put_sccb_data(0x3e,0x1a) ; /* DCW PCLK */ /* put_sccb_data(0x72,0x22) ; */ /* put_sccb_data(0x73,0xf2) ; */ put_sccb_data(0x92,0xfe) ; /* DM_LNL */ put_sccb_data(0x93,0x01) ; /* DM_LNH */ rs_puts("Exit initialize"); crlf();  18回、パラメータを出力しているだけなので  EEPROMのアドレス0〜17までの18ワードに  データを保存しておき、それらを転送すると  パラメータ設定が終了するようにします。  EEPROMの1ワード設定値は、次のようにしました。 0x00 : 0x1280 0x01 : 0x1180 0x02 : 0x3b0a 0x03 : 0x3a04 0x04 : 0x1210 0x05 : 0x8c00 0x06 : 0x40d0 0x07 : 0x1716 0x08 : 0x1804 0x09 : 0x3224 0x0a : 0x1902 0x0b : 0x1a7a 0x0c : 0x030a 0x0d : 0x1502 0x0e : 0x0c04 0x0f : 0x3e1a 0x10 : 0x92fe 0x11 : 0x9301  カメラの初期化は、EEPROMの中に格納された値を  使えばよいので、次のように記述できます。 for ( i = 0 ; i < 18 ; i++ ) { /* get 1 word */ tmpx = eeprom_get(i); /* separate */ ax = (tmpx >> 8) & 0xff ; dx = tmpx & 0xff ; /* store */ put_sccb_data(ax,dx); /* delay */ if ( i == 0 ) { delay_ms(200); rs_puts("Complete reset"); crlf(); } } rs_puts("Exit initialize"); crlf();  実際にカメラにSCCB経由でパラメータを設定し  正しく値が設定されているのかを、調べると  次のようになりました。  EEPROMに入れてあるアドレス、データが確実に  カメラのレジスタ値と同じになっていることを  確認できました。
    ファームウエアソースコード  これまでの内容を実装したソースコードは、以下。 #include <ADuC7026.h> #define OFF 0 #define ON OFF+1 #define NO 0 #define YES NO+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 MASK03 0x03 #define MASK01 0x01 #define MASKF0 0xF0 #define MASK07 0x07 #define MASK3F 0x3f #define MASK7F 0x7f #define SCCB_ID_WR 0x42 #define SCCB_ID_RD 0x43 #define S_SCL 21 #define S_SDA 20 #define S_CTRG 23 #define S_TRG 22 #define TSK_ID_MAX 10 #define TSK_ID0 0 #define TSK_ID1 1 #define TSK_ID2 2 #define TSK_ID3 3 #define TSK_ID4 4 #define TSK_ID5 5 #define TSK_ID6 6 #define TSK_ID7 7 #define TSK_ID8 8 #define TSK_ID9 9 typedef struct { void (*tsk)(void); UWORD wcount ; } TCBP ; TCBP tcb[TSK_ID_MAX]; #define TTS_SUSPEND 0 #define TTS_WAIT TTS_SUSPEND+1 #define TTS_READY TTS_SUSPEND+2 volatile UWORD ready ; volatile UWORD suspend; volatile UWORD waitq ; volatile UWORD run_tsk; volatile UBYTE tflag ; volatile UWORD tsk_state[3] ; /*-----------------------*/ /* system call prototype */ /*-----------------------*/ void init_os(void); void cre_tsk(UBYTE tid,void (*tsk)(void)); void sta_tsk(UBYTE tid,UBYTE sta); void rsm_tsk(UBYTE tid); void sus_tsk(UBYTE tid); void slp_tsk(void); void wai_tsk(UWORD x); UBYTE is_tsk_ready(UBYTE tid); void timer_handler(void); void push_tsk_state(void); void pop_tsk_state(void); void rs_putchar(UBYTE x); void crlf(void); void rs_puts(UBYTE *x); UBYTE get_hex(UBYTE x); void show_help(void); void init_cam(void); void put_sccb_start(void); void put_sccb_stop(void); void put_sccb_data(UBYTE ax,UBYTE dx); UBYTE get_sccb_data(UBYTE ax); UBYTE load_cam(UBYTE adr); void show_reg(void); void send_cam(UBYTE adr,UBYTE dat); void delay_sccb(UBYTE x); void delay_ms(UWORD x); void show_value(UBYTE x); /*---------------*/ /* FPGA handling */ /*---------------*/ typedef struct { UBYTE topx ; UBYTE midx ; UBYTE botx ; UBYTE topw ; UBYTE midw ; UBYTE botw ; } SJP ; SJP xsjp ; void put_fpga_reg(UBYTE ax,UBYTE dx); UBYTE get_fpga_reg(UBYTE ax); void put_motor_duty(UBYTE x); void put_motor_dir(UBYTE x); UBYTE get_motor_duty(UBYTE ax); void show_duty(void); void show_data(UBYTE x); void send_cam_trigger(void); void turn_off_led(void); void turn_on_led(UBYTE x); UBYTE perform_judge(UBYTE xw,UBYTE xl,UBYTE yc,UBYTE yw); void perform_sensing(SJP x); UWORD get_pulse_count(void); UBYTE get_top(void); UBYTE get_middle(void); UBYTE get_bottom(void); UBYTE get_top_width(void); UBYTE get_middle_width(void); UBYTE get_bottom_width(void); void eeprom_ewen(void); void eeprom_put(UBYTE ax,UWORD dx); UWORD eeprom_get(UBYTE ax); void send_bitx(UBYTE x); /* 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 ULONG timcnt ; volatile ULONG target_timcnt ; volatile UWORD target_distance ; volatile UWORD vscnt ; volatile UBYTE vtrg ; volatile UBYTE ptrg ; volatile UBYTE str_sft ; volatile UBYTE str_trg ; volatile UBYTE fduty ; volatile UBYTE rduty ; volatile UBYTE fdir ; volatile UBYTE rdir ; volatile UBYTE tsensor; volatile UBYTE msensor; volatile UBYTE bsensor; volatile UBYTE eeprom_adr ; volatile UWORD eeprom_dat ; #define ILAST 30000 #define S_MODE_BIT 18 #define FRONT_CENTER 0x00 #define FRONT_RIGHT 0x01 #define FRONT_LEFT 0x02 #define REAR_STOP 0x80 #define REAR_FORWARD 0x81 #define REAR_REVERSE 0x82 #define STATE_WAIT 0 #define STATE_NORMAL 1 #define STATE_CRANK 2 #define STATE_LANEC 3 #define SSTART TSK_ID0 #define BLIND_RUN TSK_ID1 #define NORMAL_RUN TSK_ID2 #define CRANK_RUN TSK_ID3 #define LANE_CHANGE TSK_ID4 #define SENSING TSK_ID5 #define MEASURE TSK_ID6 #define SDEBUG TSK_ID7 #define LEDFLASH TSK_ID8 #define ONE_SHOT TSK_ID9 #define WHITE_STATE_NONE 0 #define WHITE_STATE_RIGHT 1 #define WHITE_STATE_LEFT 2 #define WHITE_STATE_ALL 3 #define ALL_BLACK 0x00 #define ALL_WHITE 0xff #define STATE_ALL_BLACK 0 #define STATE_BIG_RIGHT 1 #define STATE_RIGHT 2 #define STATE_TINY_RIGHT 3 #define STATE_CENTER 4 #define STATE_TINY_LEFT 5 #define STATE_LEFT 6 #define STATE_BIG_LEFT 7 #define STATE_RIGHT_WHITE 8 #define STATE_LEFT_WHITE 9 #define STATE_ALL_WHITE 10 #define FD_ADR 0 #define FP_ADR 1 #define RD_ADR 2 #define RP_ADR 3 #define DTOP 4 #define DMID 5 #define DBOT 6 #define CDATX 7 #define TOPS 8 #define MIDS 9 #define BOTS 10 #define LTOP 11 #define LMID 12 #define LBOT 13 #define ROTU 14 #define ROTL 15 #define LED_BLIND 0 #define LED_NORMAL 1 #define LED_CRANK 2 #define LED_LANE 3 #define LED_NONE 4 #define EEPROM_CS_BIT 19 #define EEPROM_SK_BIT 18 #define EEPROM_DI_BIT 17 volatile system_status ; volatile UBYTE bstate ; volatile UBYTE cstate ; volatile UBYTE ccnt ; volatile UBYTE lstate ; volatile UBYTE lcnt ; volatile UBYTE direction ; volatile UBYTE white_state ; volatile UWORD cur_rcnt ; volatile UWORD pre_rcnt ; volatile UWORD dif_rcnt ; volatile UBYTE cyclic[6] = {LED_BLIND,LED_NORMAL,LED_CRANK,LED_LANE,LED_CRANK,LED_NORMAL}; volatile UBYTE fstate ; void tsk0_proc(void); void tsk1_proc(void); void tsk2_proc(void); void tsk3_proc(void); void tsk4_proc(void); void tsk5_proc(void); void tsk6_proc(void); void tsk7_proc(void); void tsk8_proc(void); void tsk9_proc(void); #define IDLE 0 #define RUN IDLE+1 #define MAX_RUN_PULSE 28000 #define MAX_RUN_TIME 60000 volatile UBYTE duty ; volatile UBYTE top_center ; volatile UBYTE middle_center ; volatile UBYTE bottom_center ; volatile UBYTE top_width ; volatile UBYTE middle_width ; volatile UBYTE bottom_width ; volatile ULONG last_timcnt ; int main(void) { volatile TCBP pcur_tsk ; /* initialize user */ init_usr(); /* */ init_os(); /* regist task */ cre_tsk(SSTART ,tsk0_proc); cre_tsk(BLIND_RUN ,tsk1_proc); cre_tsk(NORMAL_RUN ,tsk2_proc); cre_tsk(CRANK_RUN ,tsk3_proc); cre_tsk(LANE_CHANGE,tsk4_proc); cre_tsk(SENSING ,tsk5_proc); cre_tsk(MEASURE ,tsk6_proc); cre_tsk(SDEBUG ,tsk7_proc); cre_tsk(LEDFLASH ,tsk8_proc); cre_tsk(ONE_SHOT ,tsk9_proc); /* initialize task states */ sta_tsk(SSTART ,TTS_READY); sta_tsk(BLIND_RUN ,TTS_SUSPEND); sta_tsk(NORMAL_RUN ,TTS_SUSPEND); sta_tsk(CRANK_RUN ,TTS_SUSPEND); sta_tsk(LANE_CHANGE,TTS_SUSPEND); sta_tsk(SENSING ,TTS_READY); sta_tsk(MEASURE ,TTS_SUSPEND); sta_tsk(SDEBUG ,TTS_READY); sta_tsk(LEDFLASH ,TTS_READY); sta_tsk(ONE_SHOT ,TTS_READY); /* show message */ rs_puts("Hello"); crlf(); /* initialize camera */ init_cam() ; /* sensor trigger */ send_cam_trigger(); /* endless loop */ while (ON) { /* get target task state */ pcur_tsk = tcb[run_tsk] ; /* perform task */ if ( is_tsk_ready( run_tsk ) == YES ) { (*(pcur_tsk.tsk))(); } /* change next task */ run_tsk++; if ( run_tsk == TSK_ID_MAX ) { run_tsk = TSK_ID0 ; } /* timer handling */ if ( tflag ) { /* clear flag */ tflag = OFF ; /* update */ timer_handler(); } } /* 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 ; /* echo back */ rs_putchar(ch) ; /* store */ *(sbuf+sindex) = ch ; sindex++ ; /* judge */ if ( ch == '\r' ) { sindex = 0 ; uflag = ON ; } } } /* judge timer0 interruption (1ms) */ if ( (IRQSTA & RTOS_TIMER_BIT) == RTOS_TIMER_BIT ) { /* clear timer0 interrupt flag */ T0CLRI = 0xff ; /* increment */ timcnt++ ; /* judge */ if ( (timcnt & MASK0F) == 10 ) { tflag = ON ; } if ( (timcnt & 0x7ff) == 1000 ) { 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 ; str_trg = OFF ; vtrg = OFF ; ptrg = OFF ; /* clear counter */ sindex = 0 ; vscnt = 0 ; str_sft = 0 ; white_state = WHITE_STATE_NONE ; bstate = 0 ; /* blinde run */ cstate = 0 ; /* crank run */ ccnt = 0 ; lstate = 0 ; /* lane change */ lcnt = 0 ; fstate = 0 ; /* flashing LED */ /* 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 */ { /* use GPIO */ GP0CON = 0x00000000 ; /* */ GP0DAT = 0xDF1F0000 ; } /* P1 */ { /* use UART */ GP1CON = 0x00000011 ; /* */ GP1DAT = 0xfef00000 ; } /* P2 */ { /* all bits outputs */ GP2DAT = 0xff000000 ; } /* P3 */ { /* all bits outputs */ GP3DAT = 0xff000000 ; } /* P4 */ { GP4DAT = 0xfe000000 ; } /* initialize timer 0 (10kHz) */ { T0LD = 10440 ; /* (10.44MHz / 1) / 1kHz */ T0CON = 0xc0 ; /* enable , cyclic , 1/1 */ } timcnt = 0 ; fduty = 0 ; rduty = 0 ; fdir = FRONT_CENTER ; rdir = REAR_FORWARD - MASK80 ; /* clear rotary counter */ cur_rcnt = 0 ; pre_rcnt = 0 ; dif_rcnt = cur_rcnt - pre_rcnt ; /* target line */ put_fpga_reg(LTOP,10) ; put_fpga_reg(LMID,30) ; put_fpga_reg(LBOT,50) ; /* pseudo center */ top_center = 80 ; middle_center = 80 ; bottom_center = 80 ; top_width = 10 ; middle_width = 10 ; bottom_width = 10 ; /* enable Read / Write */ eeprom_ewen(); /* stop motor */ put_motor_dir( 0x00 ); put_motor_duty( 0x00 ); put_motor_dir( REAR_FORWARD ); put_motor_duty( MASK80 | 0x00 ); /* enable timer 0 and UART interrupt */ IRQEN = RTOS_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("I initialize camera") ; crlf(); rs_puts("D show duty") ; crlf(); rs_puts("F set front duty and direction") ; crlf(); rs_puts("R set rear duty and direction") ; crlf(); rs_puts("P pulse count") ; crlf(); rs_puts("S show sensor parameters") ; crlf(); rs_puts("V show registers") ; crlf(); rs_puts("E put data to EEPROM") ; crlf(); rs_puts("e show contents of EEPROM") ; crlf(); rs_puts("L put target line") ; crlf(); rs_puts("l show target line") ; crlf(); } void show_reg(void) { UBYTE i ; UBYTE tmp ; UBYTE tmpx ; UBYTE msg[3] ; /* horizontal ruler */ for ( i = 0 ; i < 4 ; i++ ) { rs_putchar(' ') ; } /* 0 -> F */ for ( i = 0 ; i < 16 ; i++ ) { rs_putchar('+'); rs_putchar( asc_hex[i] ) ; rs_putchar(' '); } /* new line */ crlf(); /* show */ for ( i = 0 ; i < 160 ; i++ ) { /* vertical ruler */ if ( (i & MASK0F) == 0 ) { rs_putchar('+'); rs_putchar( asc_hex[ i >> 4 ] ) ; rs_putchar('0'); rs_putchar(' '); } /* get register data */ tmp = load_cam(i) ; /* separate */ *(msg+0) = ((tmp >> 4) & MASK0F) ; *(msg+1) = (tmp & MASK0F) ; /* show */ rs_putchar( asc_hex[*(msg+0)] ) ; rs_putchar( asc_hex[*(msg+1)] ) ; rs_putchar(' '); /* new line */ tmpx = i & MASK0F ; if ( tmpx == 15 ) { crlf(); } } /* new line */ crlf(); /* FPGA internal registers */ for ( i = 0 ; i < 16 ; i++ ) { /* get data */ tmp = get_fpga_reg( i ) ; tmpx = tmp ; /* separate */ *(msg+0) = tmp / 100 ; tmp %= 100 ; *(msg+1) = tmp / 10 ; *(msg+2) = tmp % 10 ; /* conversion */ *(msg+0) = asc_hex[ *(msg+0) ] ; *(msg+1) = asc_hex[ *(msg+1) ] ; *(msg+2) = asc_hex[ *(msg+2) ] ; /* show */ if ( tmpx < 100 ) { *(msg+0) = ' ' ; } rs_putchar( *(msg+0) ) ; rs_putchar( *(msg+1) ) ; rs_putchar( *(msg+2) ) ; rs_putchar(' '); /* new line */ tmpx = i & MASK07 ; if ( tmpx == 7 ) { crlf(); } } /* new line */ crlf(); } void put_sccb_start(void) { /* both high level */ GP4DAT |= ((1 << S_SCL) | (1 << S_SDA)) ; /* SCL = ON ; SDA = ON */ /* 0 -> SDA */ GP4DAT &= ~(1 << S_SDA) ; /* SCL = ON ; SDA = OFF */ /* 0 -> SCL */ GP4DAT &= ~(1 << S_SCL) ; /* SCL = OFF ; SDA = OFF */ } void put_sccb_stop(void) { /* both low level */ GP4DAT &= 0xffcfffff ; /* SCL = OFF ; SDA = OFF */ /* 1 -> SCL */ GP4DAT |= (1 << S_SCL) ; /* SCL = ON ; SDA = OFF */ /* both high level */ GP4DAT |= (1 << S_SDA) ; /* SCL = ON ; SDA = ON */ } void put_sccb_data(UBYTE ax,UBYTE dx) { UWORD tmp ; UBYTE i ; UBYTE j ; /* start condition */ put_sccb_start(); /* */ for ( j = 0 ; j < 3 ; j++ ) { /* set condition word */ tmp = SCCB_ID_WR ; if ( j == 1 ) { tmp = ax ; } if ( j == 2 ) { tmp = dx ; } /* transfer */ for ( i = 0 ; i < 8 ; i++ ) { /* impress data */ GP4DAT &= ~(1 << S_SDA) ; if ( tmp & MASK80 ) { GP4DAT |= (1 << S_SDA) ; } /* SCL : H */ GP4DAT |= (1 << S_SCL) ; /* shift */ tmp <<= 1 ; /* SCL : L */ GP4DAT &= ~(1 << S_SCL) ; } /* change input */ GP4DAT &= 0xefffffff ; /* SCL : H */ GP4DAT |= (1 << S_SCL) ; /* dummy load */ tmp = GP4DAT & MASK10 ; /* SCL : L */ GP4DAT &= ~(1 << S_SCL) ; /* change output */ GP4DAT |= 0x10000000 ; } /* stop condition */ put_sccb_stop(); } UBYTE get_sccb_data(UBYTE ax) { UBYTE result ; UBYTE i ; UBYTE j ; UBYTE tmp ; /* start condition */ put_sccb_start() ; /* send address */ for ( j = 0 ; j < 2 ; j++ ) { /* set parameter */ tmp = SCCB_ID_WR ; if ( j == 1 ) { tmp = ax ; } /* transfer */ for ( i = 0 ; i < 8 ; i++ ) { /* send 1 bit */ GP4DAT &= ~(1 << S_SDA) ; if ( tmp & MASK80 ) { GP4DAT |= (1 << S_SDA) ; } /* SCL : H */ GP4DAT |= (1 << S_SCL) ; /* shift */ tmp <<= 1 ; /* SCL : L */ GP4DAT &= ~(1 << S_SCL) ; } /* dummy read */ { /* change input */ GP4DAT &= 0xefffffff ; /* SCL : H */ GP4DAT |= (1 << S_SCL) ; /* dummy input */ tmp = GP4DAT & MASK10 ; /* SCL : L */ GP4DAT &= ~(1 << S_SCL) ; /* change output */ GP4DAT |= 0x10000000 ; } } /* stop condition */ put_sccb_stop() ; /* start condition */ put_sccb_start() ; /* send code */ { /* set parameter */ tmp = SCCB_ID_RD ; /* transfer */ for ( i = 0 ; i < 8 ; i++ ) { /* send 1 bit */ GP4DAT &= ~(1 << S_SDA) ; if ( tmp & MASK80 ) { GP4DAT |= (1 << S_SDA) ; } /* SCL : H */ GP4DAT |= (1 << S_SCL) ; /* shift */ tmp <<= 1 ; /* SCL : L */ GP4DAT &= ~(1 << S_SCL) ; } /* dummy read */ { /* change input */ GP4DAT &= 0xefffffff ; /* SCL : H */ GP4DAT |= (1 << S_SCL) ; /* dummy input */ tmp = GP4DAT & MASK10 ; /* SCL : L */ GP4DAT &= ~(1 << S_SCL) ; /* change output */ GP4DAT |= 0x10000000 ; } } /* get data */ { result = 0 ; /* change input */ GP4DAT &= 0xefffffff ; /* get */ for ( i = 0 ; i < 8 ; i++ ) { /* shift */ result <<= 1 ; /* SCL : H */ GP4DAT |= (1 << S_SCL) ; /* data */ if ( GP4DAT & MASK10 ) { result |= ON ; } /* SCL : L */ GP4DAT &= ~(1 << S_SCL) ; } /* dummy read */ { /* SCL : H */ GP4DAT |= (1 << S_SCL) ; /* dummy input */ tmp = GP4DAT & MASK10 ; /* SCL : L */ GP4DAT &= ~(1 << S_SCL) ; /* change output */ GP4DAT |= 0x10000000 ; } } /* stop condition */ put_sccb_stop() ; return result ; } void send_cam(UBYTE adr,UBYTE dat) { put_sccb_data(adr,dat); } UBYTE load_cam(UBYTE adr) { return get_sccb_data(adr) ; } void delay_ms(UWORD x) { ULONG last ; /* calculate */ last = timcnt + 10 * x ; /* wait */ while ( timcnt < last ) ; } void init_cam(void) { UBYTE i ; UWORD tmpx ; UBYTE ax ; UBYTE dx ; /* loop */ for ( i = 0 ; i < 18 ; i++ ) { /* get 1 word */ tmpx = eeprom_get(i); /* separate */ ax = (tmpx >> 8) & 0xff ; dx = tmpx & 0xff ; /* store */ put_sccb_data(ax,dx); /* delay */ if ( i == 0 ) { delay_ms(200); } } } void put_fpga_reg(UBYTE ax,UBYTE dx) { volatile UBYTE adr ; /* generate address */ adr = (ax & MASK0F) ; adr |= 0x20 ; /* send address */ GP2DAT &= 0xff00ffff ; /* clear */ GP2DAT |= (adr << 16) ; /* add parameter */ /* send data */ GP3DAT &= 0xff00ffff ; GP3DAT |= (dx << 16) ; /* trigger */ GP2DAT |= (1 << S_TRG) ; /* trigger H */ ax <<= 1 ; /* delay */ GP2DAT &= ~(1 << S_TRG) ; /* trigger L */ ax <<= 1 ; /* delay */ } UBYTE get_fpga_reg(UBYTE ax) { volatile UBYTE adr ; volatile UBYTE result ; /* generate address */ adr = (ax & MASK0F) ; adr |= 0x10 ; /* change inputs */ GP3DAT &= 0x00ffffff ; /* set address and enable OE */ GP2DAT &= 0xff00ffff ; GP2DAT |= (adr << 16) ; /* get data */ result = GP3DAT & MASKFF ; /* change outputs */ GP3DAT |= 0xff000000 ; return result ; } UBYTE get_motor_duty(UBYTE ax) { return get_fpga_reg( ax ); } void put_motor_duty(UBYTE x) { volatile UBYTE adr ; volatile UBYTE dat ; /* address */ adr = FP_ADR ; /* register address 0x01 */ if ( x & MASK80 ) { adr = RP_ADR ; } /* register address 0x03 */ /* data */ dat = x & MASK7F ; /* send */ put_fpga_reg(adr,dat); } void put_motor_dir(UBYTE x) { volatile UBYTE adr ; volatile UBYTE dat ; /* front or rear */ adr = FD_ADR ; /* register address = 0x00 */ if ( x & MASK80 ) { adr = RD_ADR ; } /* register address = 0x02 */ /* data */ dat = x & MASK03 ; /* send */ put_fpga_reg(adr,dat); } void send_cam_trigger(void) { GP2DAT |= (1 << S_CTRG); GP2DAT &= ~(1 << S_CTRG); } void show_duty(void) { UBYTE i ; UBYTE msg[7] ; /* clear buffer */ for ( i = 0 ; i < 7 ; i++ ) { *(msg+i) = '\0' ; } *(msg+1) = ' ' ; *(msg+4) = ' ' ; /* front */ *(msg+0) = 'F' ; *(msg+2) = (fduty / 10) + '0' ; *(msg+3) = (fduty % 10) + '0' ; *(msg+5) = fdir + '0' ; rs_puts( msg ); crlf(); /* rear */ *(msg+0) = 'R' ; *(msg+2) = (rduty / 10) + '0' ; *(msg+3) = (rduty % 10) + '0' ; *(msg+5) = rdir + '0' ; rs_puts( msg ); crlf(); /* FPGA front */ i = get_motor_duty(FP_ADR) ; *(msg+0) = 'F' ; *(msg+2) = (i / 10) + '0' ; *(msg+3) = (i % 10) + '0' ; *(msg+5) = fdir + '0' ; rs_puts( msg ); crlf(); /* FPGA rear */ i = get_motor_duty(RP_ADR) ; *(msg+0) = 'R' ; *(msg+2) = (i / 10) + '0' ; *(msg+3) = (i % 10) + '0' ; *(msg+5) = rdir + '0' ; rs_puts( msg ); crlf(); } void show_data(UBYTE x) { int i ; UBYTE tmp ; /* */ tmp = x ; /* show */ for ( i = 7 ; i > -1 ; i-- ) { rs_putchar( ((tmp >> i) & 1) + '0'); } crlf(); } void show_value(UBYTE x) { rs_putchar( asc_hex[ (x >> 4) & MASK0F ] ) ; rs_putchar( asc_hex[ x & MASK0F ] ) ; } /* turn off all LEDs */ void turn_off_led(void) { GP1DAT |= 0x00f00000 ; } /* turn on target LED */ void turn_on_led(UBYTE x) { /* judge */ if ( x > LED_LANE ) { return ; } /* turn off all LEDs */ turn_off_led(); /* turn on target LED */ GP1DAT &= ~(1 << (x+20)); } UBYTE perform_judge(UBYTE xw,UBYTE xl,UBYTE yc,UBYTE yw) { volatile UBYTE result ; /* default */ if ( xw == 0 ) { result = STATE_ALL_BLACK ; } else { if ( xw == MASKFF ) { result = STATE_ALL_WHITE ; } else { if ( xw <= yw ) { if ( xl < yc ) { result = STATE_TINY_LEFT ; if ( xl < yc - 10 ) { result = STATE_LEFT ; } if ( xl < yc - 20 ) { result = STATE_BIG_LEFT ; } } if ( xl == yc ) { result = STATE_CENTER ; } if ( xl > yc ) { result = STATE_TINY_RIGHT ; if ( xl > yc + 10 ) { result = STATE_RIGHT ; } if ( xl > yc + 20 ) { result = STATE_BIG_RIGHT ; } } } else { if ( xl < 10 ) { result = STATE_LEFT_WHITE ; } if ( xl > 150 ) { result = STATE_RIGHT_WHITE ; } } } } return result ; } void perform_sensing(SJP x) { UBYTE xwidth ; UBYTE xloc ; /* judge TOP */ xwidth = x.topx ; xloc = x.topw ; tsensor = perform_judge(xwidth,xloc,top_center,top_width); /* judge MIDDLE */ xwidth = x.midx ; xloc = x.midw ; msensor = perform_judge(xwidth,xloc,middle_center,middle_width); /* judge BOTTOM */ xwidth = x.botx ; xloc = x.botw ; bsensor = perform_judge(xwidth,xloc,bottom_center,bottom_width); } UWORD get_pulse_count(void) { volatile UWORD result ; /* get upper byte */ result = get_fpga_reg(ROTU) ; result <<= 8 ; /* get lower byte */ result |= get_fpga_reg(ROTL) ; /* result */ return( result ) ; } UBYTE get_top(void) { return get_fpga_reg(LTOP); } UBYTE get_middle(void) { return get_fpga_reg(LMID); } UBYTE get_bottom(void) { return get_fpga_reg(LBOT); } UBYTE get_top_width(void) { return get_fpga_reg(DTOP); } UBYTE get_middle_width(void) { return get_fpga_reg(DMID); } UBYTE get_bottom_width(void) { return get_fpga_reg(DBOT); } /* start trigger handling */ void tsk0_proc(void) { /* get data */ str_sft <<= 1 ; str_sft &= MASK07 ; if ( GP0DAT & MASK20 ) { str_sft |= ON ; } /* judge */ if ( str_sft == 3 ) { if ( system_status == IDLE ) { /* IDLE -> RUN */ system_status = RUN ; rsm_tsk(BLIND_RUN); rsm_tsk(MEASURE); rsm_tsk(SENSING); sus_tsk(LEDFLASH); sus_tsk(ONE_SHOT); turn_off_led(); /* set 1 minite */ target_timcnt = timcnt + MAX_RUN_TIME ; /* clear distance */ put_fpga_reg( ROTL , 0 ); put_fpga_reg( ROTU , 0 ); /* set 100m */ target_distance = get_pulse_count() + MAX_RUN_PULSE ; } else { /* RUN -> IDLE */ system_status = IDLE ; sus_tsk(NORMAL_RUN); sus_tsk(CRANK_RUN); sus_tsk(LANE_CHANGE); sus_tsk(SENSING); sus_tsk(MEASURE); rsm_tsk(LEDFLASH); rsm_tsk(ONE_SHOT); /* stop */ fdir = FRONT_CENTER ; rdir = REAR_FORWARD ; fduty = 0 ; rduty = (MASK80 | 0) ; put_motor_dir( fdir ) ; put_motor_dir( rdir ) ; put_motor_duty( fduty ) ; put_motor_duty( rduty ) ; } } /* cycle 20ms */ wai_tsk( 2 ); } /* BLIND_RUN */ void tsk1_proc(void) { /* show mode */ turn_on_led(LED_BLIND); /* select CENTER */ put_motor_dir( FRONT_CENTER ) ; put_motor_dir( REAR_FORWARD ) ; /* sequencer */ switch ( bstate ) { /* duty 5% */ case 0 : rduty = (MASK80 | 5) ; break ; /* duty 15% */ case 1 : rduty = (MASK80 | 15) ; break ; /* duty 25% */ case 2 : rduty = (MASK80 | 25) ; break ; /* duty 45% */ case 3 : rduty = (MASK80 | 45) ; break ; /* duty 65% */ case 4 : rduty = (MASK80 | 65) ; break ; /* duty 75% */ case 5 : rduty = (MASK80 | 75) ; break ; /* others */ default : break ; } put_motor_duty( rduty ); /* increment */ bstate++ ; /* judge */ if ( bstate < 6 ) { wai_tsk(50) ; /* 500ms interval */ } else { bstate = 0 ; /* rsm_tsk(SENSING) ; */ rsm_tsk(NORMAL_RUN) ; slp_tsk(); turn_off_led(); } } /* NORMAL_RUN */ void tsk2_proc(void) { volatile UBYTE topx ; volatile UBYTE midx ; volatile UBYTE sensorx ; volatile UBYTE flag2 ; /* show mode */ turn_on_led(LED_NORMAL); /* default */ flag2 = OFF ; topx = tsensor ; midx = msensor ; sensorx = bsensor ; /* judge */ if ( sensorx == STATE_CENTER ) { fdir = FRONT_CENTER ; rdir = REAR_FORWARD ; fduty = 0 ; rduty = (MASK80 | 50); } if ( sensorx == STATE_TINY_RIGHT ) { fdir = FRONT_RIGHT ; rdir = REAR_FORWARD ; fduty = 50 ; rduty = (MASK80 | 75); } if ( sensorx == STATE_RIGHT ) { fdir = FRONT_RIGHT ; rdir = REAR_FORWARD ; fduty = 75 ; rduty = (MASK80 | 55); } if ( sensorx == STATE_BIG_RIGHT ) { fdir = FRONT_RIGHT ; rdir = REAR_FORWARD ; fduty = 90 ; rduty = (MASK80 | 45); } if ( sensorx == STATE_TINY_LEFT ) { fdir = FRONT_LEFT ; rdir = REAR_FORWARD ; fduty = 50 ; rduty = (MASK80 | 75); } if ( sensorx == STATE_LEFT ) { fdir = FRONT_LEFT ; rdir = REAR_FORWARD ; fduty = 70 ; rduty = (MASK80 | 55); } if ( sensorx == STATE_BIG_LEFT ) { fdir = FRONT_LEFT ; rdir = REAR_FORWARD ; fduty = 90 ; rduty = (MASK80 | 45); } /* set motor duty ratio */ put_motor_dir( fdir ); put_motor_dir( rdir ); put_motor_duty( fduty ); put_motor_duty( rduty ); /* judge CRANK mark */ if ( topx == STATE_ALL_WHITE || midx == STATE_ALL_WHITE ) { white_state = WHITE_STATE_ALL ; rsm_tsk( CRANK_RUN ); flag2 = ON ; } /* judge LANE LEFT CHANGE mark */ if ( topx == STATE_LEFT_WHITE || midx == STATE_LEFT_WHITE ) { white_state = WHITE_STATE_LEFT ; rsm_tsk( LANE_CHANGE ); flag2 = ON ; } /* judge LANE RIGHT CHANGE mark */ if ( topx == STATE_RIGHT_WHITE || midx == STATE_RIGHT_WHITE ) { white_state = WHITE_STATE_RIGHT ; rsm_tsk( LANE_CHANGE ); flag2 = ON ; } /* delay */ if ( flag2 == ON ) { slp_tsk() ; turn_off_led(); } else { wai_tsk(1) ; /* 10ms interval */ } } /* CRANK_RUN */ void tsk3_proc(void) { volatile UBYTE topx ; volatile UBYTE midx ; /* show mode */ turn_on_led(LED_CRANK); /* */ topx = tsensor ; midx = msensor ; /* sequencer */ switch ( cstate ) { /* blind run until minimum distance */ case 0 : cstate = 1 ; ccnt = 30 ; put_motor_dir( FRONT_CENTER ); put_motor_dir( REAR_FORWARD ); put_motor_duty( MASK80 | 75 ); break ; /* delay */ case 1 : if ( ccnt == 0 ) { cstate = 2 ; } else { ccnt-- ; } break ; /* until CRANK location */ case 2 : if ( topx == STATE_LEFT_WHITE || midx == STATE_LEFT_WHITE ) { cstate = 3 ; white_state = WHITE_STATE_LEFT ; } if ( topx == STATE_RIGHT_WHITE || midx == STATE_RIGHT_WHITE ) { cstate = 3 ; white_state = WHITE_STATE_RIGHT ; } break ; /* turn */ case 3 : cstate = 4 ; if ( white_state == WHITE_STATE_LEFT ) { put_motor_dir( FRONT_LEFT ); put_motor_duty( 50 ); } if ( white_state == WHITE_STATE_RIGHT ) { put_motor_dir( FRONT_RIGHT ); put_motor_duty( 50 ); } put_motor_dir( REAR_FORWARD ); put_motor_duty( MASK80 | 50 ); break ; /* judge center */ case 4 : if ( topx == STATE_CENTER || midx == STATE_CENTER ) { cstate = 5 ; put_motor_dir( FRONT_CENTER ); } break ; /* return first state */ case 5 : break ; /* */ default : break ; } /* delay */ if ( cstate < 5 ) { wai_tsk(1) ; /* 10ms interval */ } else { cstate = 0 ; /* direction and duty ratio */ fdir = FRONT_CENTER ; rdir = REAR_FORWARD ; fduty = 0 ; rduty = MASK80 | 75 ; /* set motor duty ratio */ put_motor_dir( fdir ); put_motor_dir( rdir ); put_motor_duty( fduty ); put_motor_duty( rduty ); /* */ white_state = WHITE_STATE_NONE ; slp_tsk() ; turn_off_led(); rsm_tsk( NORMAL_RUN ); } } /* LANE_CHANGE */ void tsk4_proc(void) { volatile UBYTE xtop ; volatile UBYTE xmid ; /* show mode */ turn_on_led(LED_LANE); /* */ xtop = tsensor ; xmid = msensor ; /* sequencer */ switch ( lstate ) { /* forward until ALL_BLACK */ case 0 : if ( xtop == STATE_ALL_BLACK || xmid == STATE_ALL_BLACK ) { lstate = 1 ; } break ; /* judge turn */ case 1 : lstate = 2 ; lcnt = 10 ; fdir = FRONT_RIGHT ; if ( white_state == WHITE_STATE_LEFT ) { fdir = FRONT_LEFT ; } put_motor_dir( fdir ); put_motor_duty( 80 ); break ; /* turn delay */ case 2 : if ( lcnt == 0 ) { lstate = 3 ; put_motor_dir( FRONT_CENTER ); } else { lcnt-- ; } break ; /* blind run */ case 3 : lstate = 4 ; lcnt = 10 ; put_motor_dir( REAR_FORWARD ) ; put_motor_duty( MASK80 | 75 ) ; break ; /* blind run delay */ case 4 : if ( lcnt == 0 ) { lstate = 5 ; } else { lcnt-- ; } break ; /* judge center */ case 5 : if ( xtop == STATE_CENTER || xmid == STATE_CENTER ) { lstate = 6 ; } break ; /* judge turn (reverse) */ case 6 : lstate = 7 ; lcnt = 10 ; fdir = FRONT_LEFT ; if ( white_state == WHITE_STATE_LEFT ) { fdir = FRONT_RIGHT ; } put_motor_dir( fdir ); put_motor_duty( 80 ); break ; /* turn (reverse) delay */ case 7 : if ( lcnt == 0 ) { lstate = 8 ; put_motor_dir( FRONT_CENTER ); } else { lcnt-- ; } break ; /* return first state */ case 8 : break ; /* */ default : break ; } /* delay */ if ( lstate < 8 ) { wai_tsk(1) ; /* 10ms interval */ } else { lstate = 0 ; /* direction and duty ratio */ fdir = FRONT_CENTER ; rdir = REAR_FORWARD ; fduty = 0 ; rduty = MASK80 | 75 ; /* set motor duty ratio */ put_motor_dir( fdir ); put_motor_dir( rdir ); put_motor_duty( fduty ); put_motor_duty( rduty ); /* */ white_state = WHITE_STATE_NONE ; slp_tsk() ; turn_off_led(); rsm_tsk( NORMAL_RUN ); } } /* SENSING */ void tsk5_proc(void) { /* get data */ xsjp.topx = get_top() ; xsjp.midx = get_middle(); xsjp.botx = get_bottom(); /* get width */ xsjp.topw = get_top_width() ; xsjp.midw = get_middle_width(); xsjp.botw = get_bottom_width(); /* generate sensor data */ perform_sensing(xsjp); /* */ wai_tsk(10) ; /* 100ms */ } /* MEASURE */ void tsk6_proc(void) { volatile UBYTE flag6 ; /* update */ pre_rcnt = cur_rcnt ; /* get */ cur_rcnt = get_pulse_count(); /* differencial pulse count */ dif_rcnt = cur_rcnt - pre_rcnt ; /* judge */ flag6 = 0 ; if ( timcnt > target_timcnt ) { flag6++ ; } if ( get_pulse_count() > target_distance ) { flag6++ ; } if ( flag6 ) { /* stop RUN */ sus_tsk(NORMAL_RUN); sus_tsk(CRANK_RUN); sus_tsk(LANE_CHANGE); rsm_tsk(LEDFLASH); /* stop motors */ put_motor_dir( FRONT_CENTER ); put_motor_dir( REAR_STOP ); put_motor_duty( 0 ); put_motor_duty( MASK80 | 0 ); } /* interval */ if ( flag6 ) { slp_tsk(); rs_puts("Timer Over !"); crlf(); } else { wai_tsk( 100 ) ; /* 1000ms */ } } /* SDEBUG */ void tsk7_proc(void) { volatile UBYTE msg[6] ; volatile UWORD epulse ; volatile UBYTE tmp7 ; volatile UBYTE loop7 ; /* default */ tmp7 = 0 ; /* judge flag */ if ( uflag == OFF ) return ; /* new line */ crlf(); /* clear flag */ uflag = OFF ; /* judge */ cmd = *(sbuf+0) ; if ( cmd == '?' ) { show_help(); } /* initialize CAMERA */ if ( cmd == 'I' ) { push_tsk_state(); turn_off_led(); init_cam() ; pop_tsk_state(); } /* set front parameters */ if ( cmd == 'F' || cmd == 'R' ) { /* duty */ duty = get_hex( *(sbuf+1) ) ; duty *= 10 ; duty += get_hex( *(sbuf+2) ) ; /* direction */ direction = get_hex( *(sbuf+3) ) ; /* front */ if ( cmd == 'F' ) { fduty = duty ; fdir = direction ; /* impress */ put_motor_duty( fduty ) ; put_motor_dir( fdir ) ; } /* rear */ if ( cmd == 'R' ) { rdir = direction ; rduty = duty ; /* impress */ put_motor_duty( MASK80 | rduty ) ; put_motor_dir( REAR_FORWARD ) ; } } /* get encoder pulse */ if ( cmd == 'P' ) { epulse = get_pulse_count(); /* separate */ *(msg+0) = epulse / 10000 ; epulse %= 10000 ; *(msg+1) = epulse / 1000 ; epulse %= 1000 ; *(msg+2) = epulse / 100 ; epulse %= 100 ; *(msg+3) = epulse / 10 ; *(msg+4) = epulse % 10 ; *(msg+5) = '\0' ; /* conversion */ for ( loop7 = 0 ; loop7 < 5 ; loop7++ ) { *(msg+loop7) = asc_hex[ *(msg+loop7) ] ; } /* show */ rs_puts( msg ) ; /* new line */ crlf() ; } /* show duty */ if ( cmd == 'D' ) { show_duty(); } /* show sensor data */ if ( cmd == 'S' ) { /* sensor */ for ( epulse = 0 ; epulse < 3 ; epulse++ ) { /* top */ tmp7 = get_top() ; /* middle */ if ( epulse == 1 ) { tmp7 = get_middle() ; } /* bottom */ if ( epulse == 2 ) { tmp7 = get_bottom() ; } /* separate */ *(msg+0) = 'S' ; *(msg+1) = ' ' ; *(msg+2) = tmp7 / 100 ; tmp7 %= 100 ; *(msg+3) = tmp7 / 10 ; *(msg+4) = tmp7 % 10 ; *(msg+5) = '\0' ; /* conversion */ for ( loop7 = 2 ; loop7 < 5 ; loop7++ ) { *(msg+loop7) = asc_hex[ *(msg+loop7) ] ; } rs_puts( msg ) ; crlf(); } /* width */ for ( epulse = 0 ; epulse < 3 ; epulse++ ) { /* top */ tmp7 = get_top_width() ; /* middle */ if ( epulse == 1 ) { tmp7 = get_middle_width() ; } /* bottom */ if ( epulse == 2 ) { tmp7 = get_bottom_width() ; } /* separate */ *(msg+0) = 'W' ; *(msg+1) = ' ' ; *(msg+2) = tmp7 / 100 ; tmp7 %= 100 ; *(msg+3) = tmp7 / 10 ; *(msg+4) = tmp7 % 10 ; *(msg+5) = '\0' ; /* conversion */ for ( loop7 = 2 ; loop7 < 5 ; loop7++ ) { *(msg+loop7) = asc_hex[ *(msg+loop7) ] ; } rs_puts( msg ) ; crlf(); } } /* show eeprom data */ if ( cmd == 'e' ) { /* show */ for ( loop7 = 0 ; loop7 < 64 ; loop7++ ) { /* get data */ eeprom_dat = eeprom_get( loop7 ) ; /* show */ show_value( (eeprom_dat >> 8) & MASKFF ); show_value( eeprom_dat & MASKFF ); rs_putchar( ' ' ); /* new line */ if ( (loop7 % 8) == 7 ) { crlf() ; } } crlf(); } /* store eeprom data */ if ( cmd == 'E' ) { /* generate address */ eeprom_adr = 0 ; eeprom_adr += get_hex( *(sbuf+1) ) ; eeprom_adr <<= 4 ; eeprom_adr += get_hex( *(sbuf+2) ) ; /* generate data */ eeprom_dat = 0 ; eeprom_dat += get_hex( *(sbuf+3) ) ; eeprom_dat <<= 4 ; eeprom_dat += get_hex( *(sbuf+4) ) ; eeprom_dat <<= 4 ; eeprom_dat += get_hex( *(sbuf+5) ) ; eeprom_dat <<= 4 ; eeprom_dat += get_hex( *(sbuf+6) ) ; /* judge and store */ if ( eeprom_adr < 64 ) { eeprom_put(eeprom_adr,eeprom_dat) ; } else { rs_puts("Address Error !"); } crlf(); } /* show register values */ if ( cmd == 'V' ) { push_tsk_state(); turn_off_led(); show_reg() ; pop_tsk_state(); } /* put target line */ if ( cmd == 'L' ) { /* get value */ tmp7 = get_hex( *(sbuf+1) ) ; tmp7 *= 10 ; tmp7 += get_hex( *(sbuf+2) ) ; /* get location */ loop7 = *(sbuf+3) ; /* store */ if ( loop7 == 'T' ) { put_fpga_reg(LTOP,tmp7) ; } if ( loop7 == 'M' ) { put_fpga_reg(LMID,tmp7) ; } if ( loop7 == 'B' ) { put_fpga_reg(LBOT,tmp7) ; } } /* show target line */ if ( cmd == 'l' ) { *(msg+1) = ' ' ; *(msg+4) = '\0' ; for ( loop7 = 0 ; loop7 < 3 ; loop7++ ) { /* top */ tmp7 = get_fpga_reg(LTOP) ; *(msg+0) = 'T' ; /* middle */ if ( loop7 == 1 ) { tmp7 = get_fpga_reg(LMID) ; *(msg+0) = 'M' ; } /* bottom */ if ( loop7 == 2 ) { tmp7 = get_fpga_reg(LBOT) ; *(msg+0) = 'B' ; } /* show */ *(msg+2) = asc_hex[ tmp7 / 10 ] ; *(msg+3) = asc_hex[ tmp7 % 10 ] ; rs_puts( msg ) ; crlf() ; } } } /* LED flash */ void tsk8_proc(void) { /* impress */ turn_on_led( cyclic[fstate] ); /* update state */ fstate++ ; /* judge */ if ( fstate == 6 ) { fstate = 0 ; } /* interval 300ms */ wai_tsk(30); } /* get first data */ void tsk9_proc(void) { /* store */ top_center = get_top() ; middle_center = get_middle(); bottom_center = get_bottom(); top_width = get_top_width() ; middle_width = get_middle_width(); bottom_width = get_bottom_width(); /* interval 100ms */ wai_tsk(100); } /*------------------*/ /* system call body */ /*------------------*/ void init_os(void) { ready = 0 ; suspend = 0 ; waitq = 0 ; tflag = OFF ; } void cre_tsk(UBYTE tid,void (*tsk)(void)) { tcb[tid].tsk = tsk; tcb[tid].wcount = 0; } void sta_tsk(UBYTE tid,UBYTE sta) { volatile UWORD tmp ; tmp = (1 << tid); if ( sta == TTS_READY ) { ready |= tmp; } if ( sta == TTS_SUSPEND ) { suspend |= tmp; } if ( sta == TTS_WAIT ) { waitq |= tmp; } } void rsm_tsk(UBYTE tid) { volatile UWORD tmp ; tmp = (1 << tid); ready |= tmp; suspend &= ~tmp; waitq &= ~tmp; } void sus_tsk(UBYTE tid) { volatile UWORD tmp ; tmp = (1 << tid); ready &= ~tmp; suspend |= tmp; waitq &= ~tmp; } void slp_tsk(void) { sus_tsk(run_tsk); } void wai_tsk(UWORD x) { volatile UWORD tmp ; tmp = (1 << run_tsk); ready &= ~tmp; suspend &= ~tmp; waitq |= tmp; tcb[run_tsk].wcount = x ; } UBYTE is_tsk_ready(UBYTE tid) { return( (ready >> tid) & 1 ) ; } void timer_handler(void) { volatile UWORD xtmp; volatile UBYTE loop; /* call timer handling */ xtmp = waitq ; for ( loop = 0 ; loop < TSK_ID_MAX ; loop++ ) { if ( xtmp & ON ) { tcb[loop].wcount-- ; if ( tcb[loop].wcount == 0 ) { rsm_tsk(loop); } } xtmp >>= 1 ; } } void push_tsk_state(void) { /* store */ *(tsk_state+0) = ready ; *(tsk_state+1) = suspend ; *(tsk_state+2) = waitq ; /* resume */ ready = (1 << SDEBUG) ; suspend = 0 ; waitq = 0 ; } void pop_tsk_state(void) { /* resume */ ready = *(tsk_state+0) ; suspend = *(tsk_state+1) ; waitq = *(tsk_state+2) ; } void eeprom_ewen(void) { UWORD tmp ; UBYTE i ; /* SB , OP code , dummy */ tmp = 0x130 ; /* enable chip select */ send_bitx(MASK80 | EEPROM_CS_BIT) ; /* send */ for ( i = 0 ; i < 9 ; i++ ) { /* impress DI */ send_bitx(EEPROM_DI_BIT) ; if ( tmp & 0x100 ) { send_bitx(MASK80 | EEPROM_DI_BIT) ; } /* SK : H */ send_bitx(MASK80 | EEPROM_SK_BIT) ; /* shift */ tmp <<= 1 ; /* SK : L */ send_bitx(EEPROM_SK_BIT) ; } /* clear DI */ send_bitx(EEPROM_DI_BIT) ; /* disable chip select */ send_bitx(EEPROM_CS_BIT) ; } void eeprom_put(UBYTE ax,UWORD dx) { UWORD tmp ; UBYTE i ; /* judge */ if ( ax > 63 ) return ; /* SB , OP code , dummy */ tmp = 0x140 | (ax & MASK3F) ; /* enable chip select */ send_bitx(MASK80 | EEPROM_CS_BIT) ; /* send address */ for ( i = 0 ; i < 9 ; i++ ) { /* impress DI */ send_bitx(EEPROM_DI_BIT) ; if ( tmp & 0x100 ) { send_bitx(MASK80 | EEPROM_DI_BIT) ; } /* SK : H */ send_bitx(MASK80 | EEPROM_SK_BIT) ; /* shift */ tmp <<= 1 ; /* SK : L */ send_bitx(EEPROM_SK_BIT) ; } /* send data */ for ( i = 0 ; i < 16 ; i++ ) { /* impress DI */ send_bitx(EEPROM_DI_BIT) ; if ( dx & 0x8000 ) { send_bitx(MASK80 | EEPROM_DI_BIT) ; } /* SK : H */ send_bitx(MASK80 | EEPROM_SK_BIT) ; /* shift */ dx <<= 1 ; /* SK : L */ send_bitx(EEPROM_SK_BIT) ; } /* disable chip select */ send_bitx(EEPROM_CS_BIT) ; /* delay */ delay_ms(10) ; } UWORD eeprom_get(UBYTE ax) { UWORD result ; UWORD tmp ; UBYTE i ; /* judge */ if ( ax > 63 ) { return 0 ; } /* SB , OP code , dummy */ tmp = 0x180 | (ax & MASK3F) ; /* enable chip select */ send_bitx(MASK80 | EEPROM_CS_BIT) ; /* send address */ for ( i = 0 ; i < 9 ; i++ ) { /* impress DI */ send_bitx(EEPROM_DI_BIT) ; if ( tmp & 0x100 ) { send_bitx(MASK80 | EEPROM_DI_BIT) ; } /* SK : H */ send_bitx(MASK80 | EEPROM_SK_BIT) ; /* shift */ tmp <<= 1 ; /* SK : L */ send_bitx(EEPROM_SK_BIT) ; } /* default */ result = 0 ; /* get data */ for ( i = 0 ; i < 16 ; i++ ) { /* shift */ result <<= 1 ; /* SK : H */ send_bitx(MASK80 | EEPROM_SK_BIT) ; /* get data */ if ( GP4DAT & 1 ) { result |= ON ; } /* SK : L */ send_bitx(EEPROM_SK_BIT) ; } /* disable chip select */ send_bitx(EEPROM_CS_BIT) ; return result ; } void send_bitx(UBYTE x) { ULONG tmp; UBYTE loc ; /* get now value */ tmp = GP4DAT ; /* get location */ loc = x & MASK3F ; /* clear */ tmp &= ~(1 << loc); /* judge */ if ( x & MASK80 ) { tmp |= (1 << loc); } /* put value */ GP4DAT = tmp ; }  実走行とハードウエアのテストのための関数を  入れているため、非常に長くなっています。  これだけ長くても、9kbyte程度です。  ピンアサインは、次のように変更しています。 P0.7 = -- P0.6 = -- P0.5 = start trigger P0.4 = -- P0.3 = -- P0.2 = -- P0.1 = -- P0.0 = -- P1.7 = stateLED3(LANE_CHANGE) P1.6 = stateLED2(CRANK_RUN) P1.5 = stateLED1(NORMAL_RUN) P1.4 = stateLED0(BLIND_RUN) P1.3 = -- P1.2 = -- P1.1 = SOUT(serial) P1.0 = SIN (serial) P2.7 = CENA P2.6 = TRG P2.5 = WR P2.4 = OE P2.3 = LSEL3 P2.2 = LSEL2 P2.1 = LSEL1 P2.0 = LSEL0 P3.7 = BIO(7) P3.6 = BIO(6) P3.5 = BIO(5) P3.4 = BIO(4) P3.3 = BIO(3) P3.2 = BIO(2) P3.1 = BIO(1) P3.0 = BIO(0) P4.7 = monitor LED P4.6 = ----- P4.5 = SCCB_SCL P4.4 = SCCB_SDA P4.3 = EEPROM_CS P4.2 = EEPROM_SK P4.1 = EEPROM_DI P4.0 = EEPROM_DO  これを叩き台として、走行精度を上げていきます。
  • 目次

    inserted by FC2 system