<FIFOモード>

FX2FWの最後のモードはFIFOモードです。FIFOモードは簡単にいえば、FX2をFIFOメモリーと見立てて使用するモードです。
GPIFモードの場合はウエーブデータを作成する必要がありましたが、FIFOモードでは不要です。
外部回路が簡単にFIFOにアクセスできるようであれば、FIFOを使用するのも良いかもしれません。

FIFOアクセスに必要な信号
信号 方向
(FX2から見て)
用途
SLCS IN FIFOのチップセレクト
外部回路がアクセス時にLにする
SLOE IN データーバスのアウトプットイネーブル
外部回路がLにするとデーターバスに出力される
SLRD IN FIFOメモリーのリード信号
外部回路がリードするときにLにする
SLWR IN FIFOメモリーのライト信号
外部回路がライトするときにLにする
FD IN/OUT FIFOメモリーのデータバス
8bitあるいは16bitで使用できる
FIFOADR IN PC->外部回路のFIFO(EP2)を選択するときは0
外部回路->PCのFIFO(EP6)を選択するときは2
PKTEND IN FIFOは512byte(64byte)書き込まないと、パケットが転送されないが、
PKTENDをLにすることで途中でもパケットの転送を行う
FLAGA OUT PC->外部回路のFIFO(EP2)が空でないときにLになる(EP2-EmptyFlag)
FLAGB OUT 外部回路->PCのFIFO(EP6)が満杯でないときにLになる(EP6-FullFlag)
FLAGC OUT 外部回路->PCのFIFO(EP6)が空でないときにLになる(EP6-EmptyFlag)


実際にFIFOモードの動作を確認するためには、何らかの外部回路が必要になります。
今回はATMEL社のAVRマイコンのMega48を使用することにしました。
FX2、カメレオンUSBロジアナ、AVRとの接続に関してはこちらのページをご参照ください。

<ループバック>

とりあえず簡単な例として、PCから出力したデータを外部回路であるAVRがFIFO経由で読み取り、それをFIFO経由でPCに書き込むループバックを題材にしてみます。

まずAVR側のプログラム(main.c)からです。WinAVR(GNU-C)でコンパイルしています。
  1. #include <avr/io.h>
  2. #include <avr/interrupt.h>
  3. #include <avr/pgmspace.h>
  4. #include <avr/sleep.h>
  5. #include <inttypes.h>

  6. #define PC_IN 0x30
  7. #define PC_OUT 0x31

  8. void print(char *fmt, ... );

  9. int main(void){
  10.   unsigned short i,dl,dh;

  11.   //MISO is output & set 'H'
  12.   sbi(DDRB, 4);
  13.   sbi(PORTB, 4);


  14.   DDRB=0xc7;
  15.   DDRC=PC_IN;
  16.   sbi(PORTB,6); //PKTEND=1;
  17.   sbi(PORTB,7); //SLCS=1
  18.   sbi(PORTB,0); //SLOE=1
  19.   sbi(PORTC,4); //SLRD=1
  20.   sbi(PORTC,5); //SLWR=1
  21.   cbi(PORTB,1); //FIFOADR0=0;
  22.   i=0;

  23.   //EP2 -> EP6 Loop Back test
  24.   for(;;){
  25.     if(bit_is_clear(PINC,1)){ //FLAGA==0 (EP2 is not empty)
  26.       //read from fifo
  27.       DDRC=PC_IN;
  28.       DDRD=0x00;
  29.       cbi(PORTB,2); //FIFOADR1=0;
  30.       cbi(PORTB,7); //SLCS=0
  31.       cbi(PORTB,0); //SLOE=0
  32.       cbi(PORTC,4); //SLRD=0
  33.       sbi(PORTC,4); //SLRD=1
  34.       dl=PIND;
  35.       dh=PINC;
  36.       sbi(PORTB,0); //SLOE=1
  37.       sbi(PORTB,7); //SLCS=1

  38.       //write to fifo
  39.       sbi(PORTB,2); //FIFOADR1=1;
  40.       DDRC=PC_OUT;
  41.       DDRD=0xff;
  42.       PORTD=dl;
  43.       if(dh & 1){
  44.         sbi(PORTC,0);
  45.       }
  46.       else{
  47.         cbi(PORTC,0);
  48.       }
  49.       cbi(PORTB,7); //SLCS=0
  50.       cbi(PORTC,5); //SLWR=0
  51.       sbi(PORTC,5); //SLWR=1
  52.       sbi(PORTB,7); //SLCS=1
  53.     }
  54.   }
  55.   return 0;
  56. }
1-5行目 WinAVR関連ヘッダのインクルードです。

6-7行目 AVRのPCのbit0がデータバスに接続されているので、DDRCレジスタに書き込んで入力・出力を切り替えるための値

8、11-13行目 EZ-USBを使用したAVRライター&開発環境用の処理。詳しくはここのページを参照してください

14-15行目 ポートの入出力方向の設定

16-20行目 FIFOを制御するための各種信号の初期設定

21行目 EP2(PC->外部回路)とEP6(外部回路->PC)の2つのFIFOの切り替えはFIFOADRで行います。
EP2選択時は0、EP6選択時は2のため、FIFOADR0はいずれの場合でもLになります。

24-54行目 メイン処理で、EP2にPCからデータを読み取り、そのままEP6に書き出します。

25行目 EP2にデータが書き込まれると、FLGAがLになる

27-28行目 データーバスを入力に設定

29-32行目 SLCS、SLOE、SLRDをLにセット
EP2を選択するためFIFOADR1=0

34-35行目 データを読み込む

36-37行目 SLCS、SLOEをHにしてFIFOを開放

39行目 EP6を選択するためにFIFOADR1=1

40-41行目 データバスを出力に切り替え

42-48行目 データを出力

49-50行目 SLCS、SLWRをLにしてEP2に書き込む

51-52行目 SLCS、SLWRをHにしてFIFOを開放


PC側のプログラム(main.c)はこのようになります

使用するパイプ
プログラム中での
名前
エンドポイント パイプ番号 用途
CPIPE OUT2 1 コマンド、
パラメータ、
送信用
TFIFO OUT2
(EP2)
0 EP2(PC->外部回路)
送信用
RFIFO IN6
(EP6)
2 コマンド結果、
EP6(外部回路->PC)
受信用

  1. #include <windows.h>
  2. #include <stdio.h>

  3. #include "cusb.h"
  4. #include "fx2fw.h"
  5. #include "fx2fw_prog.h"

  6. u8 buf[1024*1024];
  7. HANDLE dev_handle;

  8. int main( int argc, char *argv[] ){
  9.   u8 cmd[512];
  10.   s32 i,j,fifo_len;

  11.   if(cusb_init(-1,&dev_handle,fw_bin,"F2FW","V100")){
  12.     printf("Can't found EZ-USB.\n");
  13.   exit(-1);
  14.   }

  15.   i=0;
  16.   cmd[i++]=CMD_USBCS;
  17.   usb_bulk_write(&dev_handle,CPIPE,cmd,i);
  18.   usb_bulk_read(&dev_handle,RFIFO,buf,1);
  19.   if(buf[0] & 0x80){
        fifo_len=512; //Hi-Speed
  20.   }
  21.   else{
  22.     fifo_len=64; //Full-Speed
  23.   }

  24.   for(i=0;i<fifo_len;i++){ //initial data set
  25.     buf[i]=i;
  26.   }

  27.   i=0;
  28.   cmd[i++]=CMD_MODE;
  29.   cmd[i++]=MODE_FIFO|MODE_16BIT; //FIFO, 16bit
  30.   usb_bulk_write(&dev_handle,CPIPE,cmd,i);

  31.   for(j=0;j<4;j++){
  32.     usb_bulk_write(&dev_handle,TFIFO,buf,fifo_len);
  33.     usb_bulk_read(&dev_handle,RFIFO,buf,fifo_len);
  34.   }
  35. }
16-23行目 CMD_USBCSコマンドを使用してFX2がUSB2.0あるいはUSB1.0のどちらに接続されているか調べて、USBの種別にあわせたエンドポイントの長さをセットします。
これによって、USB2.0/USB1.0のどちらでも動作できます。

24-26行目 転送するデータの初期化

28-30行目 FX2FWのモードをFIFOモードに設定。
データバスの幅は16bitを指定します。

32行目 パイプTFIFOにエンドポイントの長さ分のデータを書き込みます。

33行目 パイプRFIFOからエンドポイントの長さ分のデータを読み込みます。

実際に実行したときの波形の一部です

SLWRをLにしてデータを書き込んでいます。書き込みが完了すると、FLAGCがL(EP6が空でない)になるのが確認できます。

AVRのソースおよびPC側のソース一式はこちらからダウンロードしてください。

別のサンプルでAVR側からPKTEND信号を使用して、エンドポイントに途中まで書き込んだ状態で、エンドポイントの転送を行うサンプルも用意しておきます。こちらからダウンロードしてください。