<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)を選択するときは2PKTEND 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)でコンパイルしています。
- #include <avr/io.h>
- #include <avr/interrupt.h>
- #include <avr/pgmspace.h>
- #include <avr/sleep.h>
- #include <inttypes.h>
- #define PC_IN 0x30
- #define PC_OUT 0x31
- void print(char *fmt, ... );
- int main(void){
- unsigned short i,dl,dh;
- //MISO is output & set 'H'
- sbi(DDRB, 4);
- sbi(PORTB, 4);
- DDRB=0xc7;
- DDRC=PC_IN;
- sbi(PORTB,6); //PKTEND=1;
- sbi(PORTB,7); //SLCS=1
- sbi(PORTB,0); //SLOE=1
- sbi(PORTC,4); //SLRD=1
- sbi(PORTC,5); //SLWR=1
- cbi(PORTB,1); //FIFOADR0=0;
- i=0;
- //EP2 -> EP6 Loop Back test
- for(;;){
- if(bit_is_clear(PINC,1)){ //FLAGA==0 (EP2 is not empty)
- //read from fifo
- DDRC=PC_IN;
- DDRD=0x00;
- cbi(PORTB,2); //FIFOADR1=0;
- cbi(PORTB,7); //SLCS=0
- cbi(PORTB,0); //SLOE=0
- cbi(PORTC,4); //SLRD=0
- sbi(PORTC,4); //SLRD=1
- dl=PIND;
- dh=PINC;
- sbi(PORTB,0); //SLOE=1
- sbi(PORTB,7); //SLCS=1
- //write to fifo
- sbi(PORTB,2); //FIFOADR1=1;
- DDRC=PC_OUT;
- DDRD=0xff;
- PORTD=dl;
- if(dh & 1){
- sbi(PORTC,0);
- }
- else{
- cbi(PORTC,0);
- }
- cbi(PORTB,7); //SLCS=0
- cbi(PORTC,5); //SLWR=0
- sbi(PORTC,5); //SLWR=1
- sbi(PORTB,7); //SLCS=1
- }
- }
- return 0;
- }
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)
受信用
- #include <windows.h>
- #include <stdio.h>
- #include "cusb.h"
- #include "fx2fw.h"
- #include "fx2fw_prog.h"
- u8 buf[1024*1024];
- HANDLE dev_handle;
- int main( int argc, char *argv[] ){
- u8 cmd[512];
- s32 i,j,fifo_len;
- if(cusb_init(-1,&dev_handle,fw_bin,"F2FW","V100")){
- printf("Can't found EZ-USB.\n");
- exit(-1);
- }
- i=0;
- cmd[i++]=CMD_USBCS;
- usb_bulk_write(&dev_handle,CPIPE,cmd,i);
- usb_bulk_read(&dev_handle,RFIFO,buf,1);
- if(buf[0] & 0x80){
fifo_len=512; //Hi-Speed
- }
- else{
- fifo_len=64; //Full-Speed
- }
- for(i=0;i<fifo_len;i++){ //initial data set
- buf[i]=i;
- }
- i=0;
- cmd[i++]=CMD_MODE;
- cmd[i++]=MODE_FIFO|MODE_16BIT; //FIFO, 16bit
- usb_bulk_write(&dev_handle,CPIPE,cmd,i);
- for(j=0;j<4;j++){
- usb_bulk_write(&dev_handle,TFIFO,buf,fifo_len);
- usb_bulk_read(&dev_handle,RFIFO,buf,fifo_len);
- }
- }
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信号を使用して、エンドポイントに途中まで書き込んだ状態で、エンドポイントの転送を行うサンプルも用意しておきます。こちらからダウンロードしてください。