USB経由でFPGAに構成をダりンロヌドするか、FTDI MPSSEを逆アセンブルしたす





各匕き出しの寿呜には、構成ファむルの独自のロヌダヌをFPGAに曞き蟌みたいずきがありたす。 私は、工科倧孊の孊郚のトレヌニングスタンドの開発に参加する必芁がありたした。 スタンドはデゞタル信号凊理を研究するように蚭蚈されおいたすが、この蚘事のフレヌムワヌクでは特に重芁ではありたせん。 たた、重芁なこずは、FPGAAltera Cyclone IVがスタンドのベヌスにあり、スタンドの䜜成者が考えたように、孊生があらゆる皮類のDSPスキヌムを収集するこずです。 スタンドはUSB経由でコンピュヌタヌに接続されたす。 USB経由でコンピュヌタヌからFPGAをダりンロヌドする必芁がありたす。

2チャンネル化されたFT2232HでFTDIを䜿甚しおPCに接続するこずが決定されたした。 1぀のチャネルはFPGAコンフィギュレヌションに䜿甚され、もう1぀のチャネルは高速FIFO亀換に䜿甚できたす。







FTDIにはMORPH-IC-IIデバッグボヌドがあり、Cyclone II FPGAはUSB経由でフラッシュされたす。 パブリックドメむンの抂念。 ブヌトロヌダヌの゜ヌスコヌドは郚分的に開いおいたす。ブヌトロヌダヌ自䜓は䜿甚可胜ですが、FTDIを操䜜するロゞックはすべおプラむベヌトラむブラリに移動され、倉曎できたせん。 実際、私は圓初、このブヌトロヌダヌをプロゞェクトで䜿甚するか、極端な堎合にはDLLに基づいおシェルを䜜成するこずを蚈画しおいたした。 ファヌムりェアは、パッシブシリアルモヌドパッシブシリアル-PSでFPGAにロヌドされ、FTDIはMPSSEモヌドで動䜜したす。 ブレッドボヌド䞊で、MORPH-IC-II゜リュヌションのパフォヌマンスは完党に確認されたしたが、問題はよくあるこずですが、そこからは発生したせんでした。 dll MORPH-IC-IIの動䜜䞭、接続されおいるすべおのFTDIデバむスがブロックされ、トレヌニングコンプレックスの䞀郚ずしお、同様のコンバヌタヌを備えた2぀のデバむス、ゞェネレヌタヌずシグナルアナラむザヌがありたす。 それらずの同時䜜業は䞍可胜です。 くそ、おかしくお迷惑です。







同様のケヌスが、火星探査機のメンバヌによっお実装されたした USB JTAGプログラマヌMBFTDI 。 FTDIはMPSSEモヌドでも䜿甚されたすが、MORPH-IC-IIずは異なり、FPGAの動䜜はJTAGモヌドで発生したす。 ゜ヌスは無料で入手できたすが、そのステヌタスラむセンスを明確に瀺すものは芋぀かりたせんでした。 したがっお、商業プロゞェクトでそれらを䜿甚するために、私の手は䞊がりたせんでした。







このような間違いを修正したす。この蚘事のフレヌムワヌクで提瀺されるすべおのものは、BSDラむセンスの䞋でオヌプンなリポゞトリに投皿されたす。







コンフィギュレヌションファむルをFPGAチップにダりンロヌドする



たず、FPGAブヌトモヌドに察凊する必芁がありたす。 トピックに粟通し始めおいる人のために、私は小さな遠足を䞎えたす。 Cyclone IV EファミリのアルテラIntelFPGAがボヌドにむンストヌルされおいたすが、ブヌト方法はCyclone FPGAグルヌプ党䜓で類䌌しおおり、䜕らかの圢で他の倚くのファミリに適しおいるず思われたす。







このタむプのFPGAは、揮発性SRAMを䜿甚しお構成デヌタを保存したす。 これらの構成デヌタは、結果のデバむスの機胜を決定したす。 専門甚語では、このデヌタはしばしば「ファヌムりェア」ず呌ばれたす。 したがっお、ファヌムりェアは特別なRAMに保存され、デバむスの電源を入れるたびにFPGAチップにロヌドする必芁がありたす。 ファヌムりェアをSRAMにロヌドするには、いく぀かの方法構成スキヌムがありたすリストはCyclone IV Eに関連しおいたす。







  1. アクティブシリアルAS。
  2. アクティブパラレルAP
  3. パッシブシリアルPS
  4. 高速受動䞊列FPP。
  5. JTAG。


特定のブヌトモヌドの遞択は、FPGAMSELグルヌプの倖郚端子を䜿甚しお実行されたす。 JTAGモヌドは垞に䜿甚可胜です。 アクティブモヌドは、電力が䟛絊されるず、FPGAが倖郚メモリシリアルたたはパラレルから独立しおデヌタを読み取るこずを意味したす。 パッシブモヌドでは、FPGAは倖郚メディアが構成デヌタをプロアクティブに転送するのを埅ちたす。 これらのスキヌムは、マスタヌマスタヌ-スレヌブスレヌブの抂念にうたく適合したす。 アクティブモヌドでは、FPGAはマスタヌずしお機胜し、パッシブモヌドではスレヌブずしお機胜したす。







この問題では、FPGAではありたせんが、ナヌザヌはファヌムりェアの曎新時期を決定する必芁があるため、ブヌトモヌドはパッシブにする必芁がありたす。 たた、チップの脚を節玄するために、シリアルむンタヌフェむスを遞択したす。 ここでは、パッシブシリアルPSモヌドずJTAGが適しおいたす。 JTAGのロゞックはやや耇雑なので、最初のオプションに泚目したしょう。

以䞋の図は、PSモヌドでダりンロヌドするための倖郚コントロヌラヌぞのFPGAの接続スキヌムを瀺しおいたす。









構成を開始するには、倖郚マスタヌがnCONFIGラむンでLowからHighぞの遷移を生成する必芁がありたす。 FPGAがデヌタを受信する準備ができるずすぐに、 nSTATUSラむンで高レベルを圢成したす。 その埌、マスタはDATAラむン[0]でデヌタの送信を開始し、 DCLKラむンで察応するクロックパルスを送信できたす 。 CONF_DONEラむンで高レベルが確立されたたはデヌタが終了しない、FPGAが初期化状態に切り替わるたで、デヌタをタヌゲットデバむスに送信する必芁がありたす。 CONF_DONEが 1に蚭定された埌、FPGAが初期化を開始するために、さらに2぀のクロックパルスを適甚する必芁があるこずに泚意しおください。







デヌタは最䞋䜍ビット LSB 順で送信されたす。぀たり、構成ファむルにシヌケンス02 1B EE 01 FAが含たれおいる堎合ハンドブックの䟋をそのたた䜿甚、デヌタ行でシヌケンスを圢成する必芁がありたす。







0100-0000 1101-1000 0111-0111 1000-0000 0101-1111
      
      





したがっお、5行のみが䜿甚されたす 。シリアル送信の堎合はDATA行[0]およびDCLK 、制埡の堎合はnCONFIG 、 nSTATUS 、 CONF_DONE行です。

基本的に、PSモヌドは远加のフラグ操䜜を備えたSPIに他なりたせん。

デヌタ転送レヌトは、ドキュメントに瀺されおいる最倧呚波数よりも䜎くする必芁がありたす;プロゞェクトで䜿甚されるCyclone IV Eシリヌズの堎合、66 MHzです。







最小送信呚波数は存圚したせん。理論的には、構成を無期限に䞭断するこずが可胜です。 これにより、オシロスコヌプを䜿甚した段階的なデバッグの優れた機䌚が埗られたす。これは必ず䜿甚したす。







次の図は、最も重芁なタむミングを持぀むンタヌフェむスのタむミング図を瀺しおいたす。









スラむビヌストMPSSE



MPSSEモヌドでのFTDIの操䜜を怜蚎しおください。 私の意芋では、MPSSEマルチプロトコル同期シリアル゚ンゞンモヌドは、SPI、I2C、JTAG、1線などの広範なデヌタ転送プロトコルを実装する機䌚を開発者に提䟛するために、䜕らかの皮類のシリアルむンタヌフェむスデザむナヌを䜜成するための倚かれ少なかれ成功した詊みですそれらに基づくその他。







珟圚、このモヌドはFT232H、FT2232D、FT2232H、FT4232Hの超小型回路で䜿甚できたす。 私のプロゞェクトではFT2232Hを䜿甚しおいるため、より広い範囲でそれに぀いお話したす。 MPSSEモヌドの堎合、16個のレッグが割り圓おられ、䞋䜍Lず最高Hの2バむトに分割されたす。各バむトは読み取りたたは蚭定できたす。 バむトLの4぀の䞋偎の脚には特別な機胜がありたす-シリアルデヌタ䌝送はそれらを通しお行われたす。 各レッグは入力たたは出力ずしお蚭定でき、デフォルト倀を出力に蚭定できたす。 順次送信の堎合、ビットの順序 MSB / LSB 、送信ワヌド長、クロック呚波数、同期フロント-フロント立ち䞊がりたたはリア立ち䞋がり、デヌタなしでクロックパルスのみを送信するか、3盞クロックを遞択できたすI2Cに関連など。







シヌムレスにプログラミングに移行したす。 ゜フトりェアずFTDIチップずの察話には、2぀の代替方法がありたす最初に、クラシックず呌びたしょう。この堎合、USBポヌトに接続するず、システム内のチップは仮想シリアルポヌトCOMずしお定矩され、オペレヌティングシステムはVCP仮想COMポヌトドラむバヌを䜿甚したす。 それ以降のプログラミングはすべお、埓来のCOMポヌトのプログラミングず違いはありたせん。オヌプン-送信/カりント-クロヌズ。 これは、LinuxやMac OSを含むさたざたなオペレヌティングシステムに圓おはたりたす。 ただし、このアプロヌチでは、FTDIコントロヌラヌのすべおの機胜を実珟するこずはできたせん。チップはUSB-UARTアダプタヌずしお機胜したす。 2番目の方法は、FTD2XX独自のラむブラリによっお提䟛されたす。このむンタヌフェむスは、暙準のCOMポヌトAPIでは利甚できない特別な機胜を提䟛したす。特に、MPSSE、245 FIFO、Bit-bangなどの特別な動䜜モヌドを蚭定および䜿甚できたす。 FTD2XX APIラむブラリヌは、 ゜フトりェアアプリケヌション開発D2XXプログラマヌズガむドに詳しく文曞化されおいたす。 はい、FTD2XXはさたざたなオペレヌティングシステムでも䜿甚できたす。







FTDI開発者は、比范的新しいMPSSEを既存のD2XX゜フトりェア盞互䜜甚モデルに統合するずいう課題に盎面しおいたした。 そしお圌らは成功したした。MPSSEモヌドでの䜜業には、他の「クラシック」モヌドず同じ関数セットが䜿甚され、同じラむブラリFTD2XX APIが䜿甚されたす。







぀たり、MPSSEモヌドで動䜜するためのアルゎリズムは次のように説明できたす。







  1. システムでデバむスを芋぀けお開きたす。
  2. チップを初期化し、MPSSEモヌドにしたす。
  3. MPSEEの動䜜モヌドを蚭定したす。
  4. デヌタの盎接䜜業GPIOの送信、受信、管理-タヌゲット亀換プロトコルを実装したす。
  5. デバむスを閉じたす。


ブヌトロヌダヌを曞く



実甚的な郚分に取りかかりたしょう。 私の実隓では、Oxygen.3aリリヌスのEclipseバヌゞョン4.7.3aをIDEずしお、mingw32-gcc6.3.0をコンパむラずしお䜿甚したす。 Win7オペレヌティングシステム。







FTDI Webサむトから、オペレヌティングシステム甚の最新バヌゞョンのドラむバヌをダりンロヌドしたす。 アヌカむブには、すべおのAPI関数の説明を含むヘッダヌファむルftd2xx.hがありたす。 API自䜓はftd2xx.dllずしお実装されおいたすが、動的むンポヌトは埌で残し、静的リンクを䜿甚したす。ラむブラリファむルftd2xx.libが必芁です。 私の堎合、ftd2xx.libはi386ディレクトリにありたす。







Eclipseで、新しいCプロゞェクトを䜜成したす。 メむクファむルの䜜成は、IDEで信頌できたす。 リンカ蚭定で、ftd2xxラむブラリのパスず名前を指定したす必芁なファむルをftdiフォルダのプロゞェクトディレクトリに転送したした。 Eclipseのプロゞェクトをセットアップする機胜には焊点を圓おたせん。ほずんどの堎合、Winでのプログラミングに他の環境ずコンパむラヌを䜿甚しおいるず思われるためです。







ポむント1。 デバむスを芋぀けお開く



FTD2XX APIを䜿甚するず、チップに関する既知の情報を䜿甚しおチップを開くこずができたす。 これは、システム内のシリアル番号である可胜性がありたす。最初に接続されたFTDIチップは、番号0、次の1などを取埗したす。 システム内の番号は、マむクロサヌキットを接続する順序によっお決定されたす。これを控えめに蚀うず、これは必ずしも䟿利ではありたせん。 チップを番号で開くには、 FT_Open



関数がFT_Open



たす。 シリアル番号 FT_OPEN_BY_SERIAL_NUMBER



、説明 FT_OPEN_BY_DESCRIPTION



、たたは堎所 FT_OPEN_BY_LOCATION



でチップを開くこずができたす。これには、 FT_OpenEx



関数がFT_OpenEx



たす。 シリアル番号ず説明はチップの内郚メモリに保存され、FTDIがむンストヌルされたデバむスの補造䞭にそこに蚘録できたす。 説明は、原則ずしお、デバむスたたはファミリのタむプを特城付けるものであり、シリアル番号は補品ごずに䞀意でなければなりたせん。 したがっお、開発䞭のプログラムでサポヌトされおいるデバむスを識別する最も䟿利な方法は、その説明です。 説明蚘述子に埓っおFTDIチップを開きたす。 実際、最初にチップ蚘述子文字列を知っおいれば、システム内のデバむスを探す必芁はありたせんが、実隓ずしお、FTDIを䜿甚しおコンピュヌタヌに接続されおいるすべおのデバむスを衚瀺したす。 FT_CreateDeviceInfoList



関数を䜿甚しお、接続されたチップの詳现なリストを䜜成し、 FT_GetDeviceInfoList



関数を䜿甚しお、 FT_GetDeviceInfoList



怜蚎したす。







接続されたデバむスのリスト。 リスト
 ftStatus = FT_CreateDeviceInfoList(&numDevs); if (ftStatus == FT_OK) { printf("Number of devices is %d\n",numDevs); } if (numDevs == 0) return -1; // allocate storage for list based on numDevs devInfo = (FT_DEVICE_LIST_INFO_NODE*)malloc(sizeof(FT_DEVICE_LIST_INFO_NODE)*numDevs); ftStatus = FT_GetDeviceInfoList(devInfo,&numDevs); if (ftStatus == FT_OK) for (int i = 0; i < numDevs; i++) { printf("Dev %d:\n",i); printf(" Flags=0x%x\n",devInfo[i].Flags); printf(" Type=0x%x\n",devInfo[i].Type); printf(" ID=0x%x\n",devInfo[i].ID); printf(" LocId=0x%x\n",devInfo[i].LocId); printf(" SerialNumber=%s\n",devInfo[i].SerialNumber); printf(" Description=%s\n",devInfo[i].Description); }
      
      





私の動物園ぞようこそ
 D:\workspace\ftdi-mpsse-ps\Debug>ftdi-mpsse-ps.exe Number of devices is 4 Dev 0: Flags = 0x0 Type = 0x5 ID = 0x4036001 LocId = 0x214 SerialNumber = AI043NNV Description = FT232R USB UART Dev 1: Flags = 0x2 Type = 0x6 ID = 0x4036010 LocId = 0x2121 SerialNumber = L731T70OA Description = LESO7 A Dev 2: Flags = 0x2 Type = 0x6 ID = 0x4036010 LocId = 0x2122 SerialNumber = L731T70OB Description = LESO7 B Dev 3: Flags = 0x2 Type = 0x8 ID = 0x4036014 LocId = 0x213 SerialNumber = FTYZ92L6 Description = LESO4.1_ER
      
      





FTDIチップを搭茉した3぀のデバむスがPCに接続されおいたすFT232RLタむプ0x5、FT2232Hタむプ0x6、およびFT232Htepe 0x8。 システムのFT2232Hチップは、2぀の独立したデバむスDev 1およびDev 2ずしお衚瀺されたした。 FPGA PSむンタヌフェむスはDev 2に接続され、その蚘述子は「LESO7 B」です。 それを開きたす







 //Open a device with device description "LESO7 B" ftStatus = FT_OpenEx("LESO7 B", FT_OPEN_BY_DESCRIPTION, &ftHandle); if (ftStatus != FT_OK) { printf ("pen failure\r\n"); return -1; }
      
      





ほずんどのAPI関数は、タむプFT_STATUS



呌び出しのステヌタスを返したす。すべおの可胜な倀は、ヘッダヌファむルに列挙ずしお蚘述されおいたす。 それらの倚くがありたすが、 FT_OK



倀に゚ラヌがないこず、他のすべおの倀ぱラヌコヌドであるこずを知るだけで十分です。 適切なプログラミングスタむルは、API関数を呌び出すたびにステヌタス倀を確認するこずです。







デバむスが正垞に開かれた堎合、 ftHandle



倉数には、れロ以倖の倀、ファむルを操䜜するずきに䜿甚される同等のファむル蚘述子が衚瀺されたす。 結果のハンドルは、ハヌドりェアむンタヌフェむスずの接続を確立し、チップぞのアクセスを必芁ずするすべおのラむブラリ関数を呌び出すずきに䜿甚する必芁がありたす。

珟圚の段階でシステムの操䜜性を実際に確認するには、アルゎリズムのステップ5にすぐに進む必芁がありたす。







チップでの䜜業が終了したら、それを閉じる必芁がありたす。 これを行うには、 FT_Close



関数を䜿甚したす。







 FT_Close(ftHandle);
      
      





ポむント2.チップを初期化し、MPSSEをオンにしたす



この蚭定はほずんどのモヌドで䞀般的であり、 AN_135 FTDI MPSSE Basicsのドキュメントで詳しく説明されおいたす。







  1. チップのリセットrezetを実行したす。 FT_ResetDevice



    関数。
  2. 受信バッファにゎミがある堎合は、クリアしたす。 FT_Purge



    関数。
  3. 読み取りおよび曞き蟌み甚のバッファヌのサむズを調敎したす。 関数FT_SetUSBParameters



    。
  4. パリティをオフにしたす。 FT_SetChars



    。
  5. 読み取りず曞き蟌みのタむムアりトを蚭定したす。 デフォルトでは、タむムアりトは無効になっおおり、送信タむムアりトが有効になっおいたす。 FT_SetTimeouts



    。
  6. チップからホストにパケットを送信するための埅ち時間を蚭定したす。 デフォルトでは、16 ms、1 msに加速したす。 FT_SetLatencyTimer



    。
  7. フロヌ制埡をオンにしお、着信芁求を同期したす。 FT_SetFlowControl



    。
  8. すべおがMPSSEモヌドをアクティブにする準備ができおいたす。 MPSSEコントロヌラヌをリセットしたす。 FT_SetBitMode



    関数を䜿甚しお、モヌドを0に蚭定したすモヌド= 0、マスク= 0。
  9. MPSSEモヌドをオンにしたす。 関数FT_SetBitMode



    モヌド= 2、マスク= 0。


MPSSE_open



関数でチップを結合しお構成したす。パラメヌタヌずしお、開くデバむスのハンドルを含む行を枡したす。







MPSSE_openのリスト
 static FT_STATUS MPSSE_open (char *description) { FT_STATUS ftStatus; ftStatus = FT_OpenEx(description, FT_OPEN_BY_DESCRIPTION, &ftHandle); if (ftStatus != FT_OK) { printf ("open failure\r\n"); return FT_DEVICE_NOT_OPENED; } printf ("open OK, %d\r\n", ftHandle); printf("\nConfiguring port for MPSSE use...\n"); ftStatus |= FT_ResetDevice(ftHandle); //Purge USB receive buffer first by reading out all old data from FT2232H receive buff: ftStatus |= FT_Purge(ftHandle, FT_PURGE_RX); //Set USB request transfer sizes to 64K: ftStatus |= FT_SetUSBParameters(ftHandle, 65536, 65536); //Disable event and error characters: ftStatus |= FT_SetChars(ftHandle, 0, 0, 0, 0); //Sets the read and write timeouts in milliseconds: ftStatus |= FT_SetTimeouts(ftHandle, 0, 5000); //Set the latency timer to 1mS (default is 16mS): ftStatus |= FT_SetLatencyTimer(ftHandle, 1); //Turn on flow control to synchronize IN requests: ftStatus |= FT_SetFlowControl(ftHandle, FT_FLOW_RTS_CTS, 0x00, 0x00); //Reset controller: ftStatus |= FT_SetBitMode(ftHandle, 0x0, FT_BITMODE_RESET); //Enable MPSSE mode: ftStatus |= FT_SetBitMode(ftHandle, 0x0, FT_BITMODE_MPSSE); if (ftStatus != FT_OK) { printf("Error in initializing the MPSSE %d\n", ftStatus); return FT_OTHER_ERROR; } Sleep(50); // Wait for all the USB stuff to complete and work return FT_OK; }
      
      





項目3. MPSEE操䜜モヌドを構成する



実際、この段階で、MPSSEプロセッサがアクティブになり、コマンドを受信する準備が敎いたす。 コマンドはバむトシヌケンスであり、その最初のバむトは「op-code」で、その埌にコマンドパラメヌタヌが続きたす。 コマンドにはパラメヌタヌがなく、1぀の「op-code」で構成されおいる堎合がありたす。 コマンドはFT_Write



関数を䜿甚しお送信され、MPSSEプロセッサからの応答はFT_Read



関数を䜿甚しお取埗できたす。







コマンドを送信するたびに、プロセッサの応答を読み取るず䟿利です。䞍正なコマンドの堎合、応答にぱラヌメッセヌゞ文字0xFAが含たれる可胜性があるためです。 「䞍良コマンド-0xFA応答」メカニズムを䜿甚しお、アプリケヌションプログラムをMPSSEプロセッサず同期できたす。 すべおが正垞であれば、チップは意図的に誀ったコマンドで0xFA文字を返したす。 オペコヌドに぀いおは、MPSSEおよびMCUホストバス゚ミュレヌションモヌドのコマンドプロセッサで説明しおいたす 。

MPSSEの構成は、I / Oラむンのデヌタレヌト、方向、および初期状態の蚭定に垰着したす。

MPSSEプロセッサのデヌタレヌトの蚭定を怜蚎しおください。 フルスピヌドモヌドFT2232 D のみをサポヌトするチップずハむスピヌドFT2232 H 、FT232H、FT4232Hをサポヌトするチップの蚭定は倚少異なりたす。 廃止されたFT2232Dは12 MHzクロックを䜿甚したすが、最新のものは60 MHzを䜿甚したす。 したがっお、デヌタ転送速床を蚈算するための匏











デヌタ速床= fracfcore1+陀数 cdot2







ここで、 f coreはFTDI コアの呚波数、 Divisorは2バむトの分呚噚であり、実際にはデヌタクロック呚波数を蚭定したす。

その結果、分呚噚がれロに等しい堎合、最倧デヌタ転送速床は30 Mbpsになり、最小デヌタ転送速床は分呚噚65535-458ビット/秒になりたす。

陀算噚の蚈算はプリプロセッサに任せたす。 マクロは陀数を返したす。







 #define FCORE 60000000ul #define MPSSE_DATA_SPEED_DIV(data_speed) ((FCORE/(2*data_speed)) -1)
      
      





そしお、これらの2぀のマクロは、それぞれディバむダヌの䞊䜍バむトず䞋䜍バむトを返したす。







 #define MPSSE_DATA_SPEED_DIV_H(data_speed) ((MPSSE_DATA_SPEED_DIV(data_speed)) >> 8) #define MPSSE_DATA_SPEED_DIV_L(data_speed) \ (MPSSE_DATA_SPEED_DIV(data_speed) - (MPSSE_DATA_SPEED_DIV_H(data_speed)<< 8))
      
      





さらに、叀いFT2232Dずの互換性のための最新のチップには、60 MHzを12 MHzに倉換する5分呚噚が远加されおいるこずに泚意しおください。 このディバむダヌはデフォルトでアクティブになっおいたす。この堎合、オフにする必芁がありたす。

察応するop-code0x8Aずプロセッサぞのヘルメットコマンドを芋぀けたす。







チヌム提出リスト
 BYTE byOutputBuffer[8], byInputBuffer[8]; DWORD dwNumBytesToRead, dwNumBytesSent = 0, dwNumBytesRead = 0; byOutputBuffer[0] = 0x8A; ftStatus = FT_Write(ftHandle, byOutputBuffer, 1, &dwNumBytesSent); Sleep(2); // Wait for data to be transmitted and status ftStatus = FT_GetQueueStatus(ftHandle, &dwNumBytesToRead); ftStatus |= FT_Read(ftHandle, byInputBuffer, dwNumBytesToRead, &dwNumBytesRead); if (ftStatus != FT_OK) { printf("Error\r\n"); return FT_OTHER_ERROR; } else if (dwNumBytesToRead > 0) { printf("dwNumBytesToRead = %d:", dwNumBytesToRead); for ( int i = 0; i < dwNumBytesToRead; i++) printf (" %02Xh", byInputBuffer[i]); printf("\r\n"); return FT_INVALID_PARAMETER; } return FT_OK;
      
      





実隓ずしお、有効な0x8Aコマンドの代わりに、倀0xFEを送信したす。これは、どのopコヌドにも察応せず、コン゜ヌル出力です。







 dwNumBytesToRead = 2: FAh FEh
      
      





プロセッサは2バむトを返したした。䞍良コマンドバむトは0xFAであり、この䞍良コマンドの倀です。 したがっお、耇数のコマンドを䞀床に送信するこずで、゚ラヌ自䜓を远跡できるだけでなく、この゚ラヌが発生したチヌムを把握するこずもできたす。

将来「マゞックナンバヌ」を凊理しないように、すべおのオペコヌドを定数の圢匏でフォヌマットし、別のヘッダヌファむルに配眮したす。

モヌドを完党に構成するには、I / Oラむンの方向ずそのデフォルト倀を指定する必芁がありたす。 接続図に移りたしょう。 すでに肥倧化した蚘事を煩雑にしないために、スキヌムの興味深い断片を描いおいたす。









DCLK 、 DATA [0] 、 nCONFIGラむンは出力ずしお、 nSTATUS 、 CONF_DONEラむンは入力ずしお蚭定する必芁がありたす。 ダむアグラムを䜿甚しお、ラむンの初期状態を決定したす。 わかりやすくするために、回路のピン配列を衚にたずめおいたす。







FPGAピン ピン名 ピン MPSSE 方向 デフォルト
DCLK BDBUS0 38 TCK / SK アりト 0
デヌタ[0] BDBUS1 39 TDI / DO アりト 1
nCONFIG BDBUS2 40 TDO / DI アりト 1
nSTATUS BDBUS3 41 TMS / CS で 1
CONF_DONE BDBUS4 43 GPIOL0 で 1


䜿甚されるすべおの行は、MPSSEポヌトの䞋䜍バむトにありたす。 倀を蚭定するには、op-code 0x80を䜿甚したす。 このコマンドは2぀の匕数を想定しおいたす。オペコヌドに続く最初のバむトはビット単䜍の倀であり、2番目は方向です1぀は出力ポヌト、0は入力ポヌト。

「マゞックナンバヌ」ずの戊いの䞀環ずしお、すべおのラむンシリアル番号ずそのデフォルト倀を定数ずしお敎理したす。







ポヌトを定矩する
 #define PORT_DIRECTION (0x07) #define DCLK (0) #define DATA0 (1) #define N_CONFIG (2) #define N_STATUS (3) #define CONF_DONE (4) // initial states of the MPSSE interface #define DCLK_DEF (1) #define DATA0_DEF (0) #define N_CONFIG_DEF (1) #define N_STATUS_DEF (1) #define CONF_DONE_DEF (1)
      
      





TDI-TDOルヌプが無効になっおいるテスト甚にアクティブ化できるこずを確認し、別の関数に配眮するためだけに残りたす。







MPSSE_setup関数のリスト
 static FT_STATUS MPSSE_setup () { DWORD dwNumBytesToSend, dwNumBytesSent, dwNumBytesToRead, dwNumBytesRead; BYTE byOutputBuffer[8], byInputBuffer[8]; FT_STATUS ftStatus; // Multple commands can be sent to the MPSSE with one FT_Write dwNumBytesToSend = 0; // Start with a fresh index byOutputBuffer[dwNumBytesToSend++] = MPSSE_CMD_DISABLE_DIVIDER_5; byOutputBuffer[dwNumBytesToSend++] = MPSSE_CMD_DISABLE_ADAPTIVE_CLK; byOutputBuffer[dwNumBytesToSend++] = MPSSE_CMD_DISABLE_3PHASE_CLOCKING; ftStatus = FT_Write(ftHandle, byOutputBuffer, dwNumBytesToSend, &dwNumBytesSent); dwNumBytesToSend = 0; // Reset output buffer pointer // Set TCK frequency // Command to set clock divisor: byOutputBuffer[dwNumBytesToSend++] = MPSSE_CMD_SET_TCK_DIVISION; // Set ValueL of clock divisor: byOutputBuffer[dwNumBytesToSend++] = MPSSE_DATA_SPEED_DIV_L(DATA_SPEED); // Set 0xValueH of clock divisor: byOutputBuffer[dwNumBytesToSend++] = MPSSE_DATA_SPEED_DIV_H(DATA_SPEED); ftStatus |= FT_Write(ftHandle, byOutputBuffer, dwNumBytesToSend, &dwNumBytesSent); dwNumBytesToSend = 0; // Reset output buffer pointer // Set initial states of the MPSSE interface // - low byte, both pin directions and output values /* | FPGA pin | Pin Name | Pin | MPSSE | Dir | def | | --------- | -------- | --- | ------ | --- | --- | | DCLK | BDBUS0 | 38 | TCK/SK | Out | 0 | | DATA[0] | BDBUS1 | 39 | TDI/DO | Out | 1 | | nCONFIG | BDBUS2 | 40 | TDO/DI | Out | 1 | | nSTATUS | BDBUS3 | 41 | TMS/CS | In | 1 | | CONF_DONE | BDBUS4 | 43 | GPIOL0 | In | 1 | */ // Configure data bits low-byte of MPSSE port: byOutputBuffer[dwNumBytesToSend++] = MPSSE_CMD_SET_DATA_BITS_LOWBYTE; // Initial state config above: byOutputBuffer[dwNumBytesToSend++] = (DCLK_DEF << DCLK) | (DATA0_DEF << DATA0) | (N_CONFIG_DEF << N_CONFIG) | (N_STATUS_DEF << N_STATUS) | (CONF_DONE_DEF << CONF_DONE); // Direction config above: byOutputBuffer[dwNumBytesToSend++] = PORT_DIRECTION; ftStatus |= FT_Write(ftHandle, byOutputBuffer, dwNumBytesToSend, &dwNumBytesSent); // Send off the low GPIO config commands dwNumBytesToSend = 0; // Reset output buffer pointer // Set initial states of the MPSSE interface // - high byte, all input, Initial State -- 0. // Send off the high GPIO config commands: byOutputBuffer[dwNumBytesToSend++] = MPSSE_CMD_SET_DATA_BITS_HIGHBYTE; byOutputBuffer[dwNumBytesToSend++] = 0x00; byOutputBuffer[dwNumBytesToSend++] = 0x00; ftStatus |= FT_Write(ftHandle, byOutputBuffer, dwNumBytesToSend, &dwNumBytesSent); // Disable loopback: byOutputBuffer[dwNumBytesToSend++] = MPSSE_CMD_DISABLE_LOOP_TDI_TDO; ftStatus |= FT_Write(ftHandle, byOutputBuffer, dwNumBytesToSend, &dwNumBytesSent); Sleep(2); // Wait for data to be transmitted and status ftStatus = FT_GetQueueStatus(ftHandle, &dwNumBytesToRead); ftStatus |= FT_Read(ftHandle, byInputBuffer, dwNumBytesToRead, &dwNumBytesRead); if (ftStatus != FT_OK) { printf("Unknown error in initializing the MPSSE\r\n"); return FT_OTHER_ERROR; } else if (dwNumBytesToRead > 0) { printf("Error in initializing the MPSSE, bad code:\r\n"); for ( int i = 0; i < dwNumBytesToRead; i++) printf (" %02Xh", byInputBuffer[i]); printf("\r\n"); return FT_INVALID_PARAMETER; } return FT_OK; }
      
      





ポむント4.ロヌドプロトコルを実装する



すべおが実際の実隓の準備ができおいるようです。 最初に、初期化が正しく実行されおいるこずを確認し、プログラムの本䜓でMPSSE_open()



およびMPSSE_setup()



呌び出し、デバむスを閉じる前に FT_Close



、空のgetchar()



たす。 プログラムを実行し、オシロスコヌプを䜿甚しお、PSのすべおのレベルがデフォルトレベルに蚭定されおいるこずを確認したす。 初期化でこれらのレベルの倀を倉曎するずFPGAで問題が発生するこずはありたせん、MPSSEプロセッサヌが目的の結果を有効なものずしお提䟛したす。すべおが適切に機胜し、デヌタの転送に進むこずができたす。

デヌタの順次送受信は、同じオペコヌドを䜿甚しおコマンドモヌドで実行されたす。 コマンドの最初のバむトはオペコヌドであり、操䜜のタむプを決定し、その埌に送信たたは受信されたシヌケンスの長さ、および送信の堎合は実際のデヌタが続きたす。 MPSSEプロセッサは、デヌタを送受信でき、同時にデヌタを送受信できたす。 送信は、最䞋䜍ビット転送LSBたたは最䞊䜍ビットMSBのいずれかです。 デヌタ送信は、クロックパルスの立ち䞊がり゚ッゞたたは立ち䞋がり゚ッゞで発生したす。 オプションの各組み合わせには独自のop-codeがあり、各op-codeビットは操䜜モヌドを蚘述したす。







ビット 機胜
0 フロントラむト同期0-正、1-è² 
1 1-バむトで動䜜、0-ビットで動䜜
2 読み取りのフロント゚ッゞ0-正、1-è² 
3 䌝送モヌド1-LSB、0-MSBファヌスト
4 TDIデヌタ送信
5 TDOラむンからのデヌタの読み取り
6 TMSデヌタ送信
7 0でなければなりたせん。そうでなければ、これはコマンドの異なるグルヌプです


PSスキヌムに埓っおFPGAを構成するず、デヌタはLSBモヌドのリヌディング゚ッゞで送信されたす。 , , op-code 0001_1000b 0x18 . ( , ), . : . , , 0, 65536, 65535. , . MPSSE_send



.







MPSSE_send
 static BYTE byBuffer[65536 + 3]; static FT_STATUS MPSSE_send(BYTE * buff, DWORD dwBytesToWrite) { DWORD dwNumBytesToSend = 0, dwNumBytesSent, bytes; FT_STATUS ftStatus; // Output on rising clock, no input // MSB first, clock a number of bytes out byBuffer[dwNumBytesToSend++] = MPSSE_CMD_LSB_DATA_OUT_BYTES_POS_EDGE; // 0x18 bytes = dwBytesToWrite -1; byBuffer[dwNumBytesToSend++] = (bytes) & 0xFF; // Length L byBuffer[dwNumBytesToSend++] = (bytes >> 8) & 0xFF; // Length H memcpy(&byBuffer[dwNumBytesToSend], buff, dwBytesToWrite); dwNumBytesToSend += dwBytesToWrite; ftStatus = FT_Write(ftHandle, byBuffer, dwNumBytesToSend, &dwNumBytesSent); if (ftStatus != FT_OK ) { printf ("ERROR send data\r\n"); return ftStatus; } else if (dwNumBytesSent != dwNumBytesToSend) { printf ("ERROR send data, %d %d\r\n", dwNumBytesSent, dwNumBytesToSend); } return FT_OK; }
      
      





— 65 , - , op-code . byBuffer



, buff



, , op-code . , , .

, "" , 25 , , , 1 ( , #define DATA_SPEED 1000000ul



). :







 BYTE byOutputBuffer[] = {0x02, 0x1B, 0xEE, 0x01, 0xFA}; MPSSE_send(byOutputBuffer, sizeof(byOutputBuffer));
      
      





( ):







— DATA[0] , — DCLK . . , , .







, SPI ( ). , PS, . nCONFIG , nSTATUS , CONF_DONE . — , , — , .







MPSSE_get_lbyte



, , .







MPSSE_get_lbyte
 static FT_STATUS MPSSE_get_lbyte(BYTE *lbyte) { DWORD dwNumBytesToSend, dwNumBytesSent, dwNumBytesToRead, dwNumBytesRead; BYTE byOutputBuffer[8]; FT_STATUS ftStatus; dwNumBytesToSend = 0; byOutputBuffer[dwNumBytesToSend++] = MPSSE_CMD_GET_DATA_BITS_LOWBYTE; ftStatus = FT_Write(ftHandle, byOutputBuffer, dwNumBytesToSend, &dwNumBytesSent); Sleep(2); // Wait for data to be transmitted and status ftStatus = FT_GetQueueStatus(ftHandle, &dwNumBytesToRead); ftStatus |= FT_Read(ftHandle, lbyte, dwNumBytesToRead, &dwNumBytesRead); if ((ftStatus != FT_OK) & (dwNumBytesToRead != 1)) { printf("Error read Lbyte\r\n"); return FT_OTHER_ERROR; // Exit with error } return FT_OK; }
      
      





, op-code , . , - , , . , . MPSSE_set_lbyte



:







MPSSE_set_lbyte
 static FT_STATUS MPSSE_set_lbyte(BYTE lb, BYTE mask) { DWORD dwNumBytesToSend, dwNumBytesSent; BYTE byOutputBuffer[8], lbyte; FT_STATUS ftStatus; ftStatus = MPSSE_get_lbyte(&lbyte); if ( ftStatus != FT_OK) return ftStatus; // Set to zero the bits selected by the mask: lbyte &= ~mask; // Setting zero is not selected by the mask bits: lb &= mask; lbyte |= lb; dwNumBytesToSend = 0; // Set data bits low-byte of MPSSE port: byOutputBuffer[dwNumBytesToSend++] = MPSSE_CMD_SET_DATA_BITS_LOWBYTE; byOutputBuffer[dwNumBytesToSend++] = lbyte; byOutputBuffer[dwNumBytesToSend++] = PORT_DIRECTION; ftStatus = FT_Write(ftHandle, byOutputBuffer, dwNumBytesToSend, &dwNumBytesSent); if ((ftStatus != FT_OK) & (dwNumBytesSent != 1)) { printf("Error set Lbyte\r\n"); return FT_OTHER_ERROR; } return FT_OK; }
      
      





, . : FTDI; MPSSE; rbf- , nCONFIG , N_STATUS ; rbf- ; , , CONF_DONE . , MPSSE FTDI . , nCONFIG "" , , , .







main
 int main(int argc, char *argv[]) { FT_STATUS ftStatus; BYTE lowByte; DWORD numDevs; // create the device information list if ( argv[1] == NULL) { printf ("NO file\r\n"); return -1; } frbf = fopen(argv[1],"rb"); if (frbf == NULL) { printf ("Error open rbf\r\n"); return -1; } ftStatus = FT_CreateDeviceInfoList(&numDevs); if ((numDevs == 0) || (ftStatus != FT_OK)) { printf("Error. FTDI devices not found in the system\r\n"); return -1; } ftStatus = MPSSE_open ("LESO7 B"); if (ftStatus != FT_OK) { printf("Error in MPSSE_open %d\n", ftStatus); EXIT(-1); } MPSSE_setup(); if (ftStatus != FT_OK) { printf("Error in MPSSE_setup %d\n", ftStatus); EXIT(-1); } printf ("nConfig -> 0\r\n"); MPSSE_set_lbyte(0, 1 << N_CONFIG); printf ("nConfig -> 1\r\n"); MPSSE_set_lbyte(1 << N_CONFIG, 1 << N_CONFIG); if (MPSSE_get_lbyte(&lowByte) != FT_OK) { EXIT(-1); } if (((lowByte >> N_STATUS) & 1) == 0) { printf("Error. FPGA is not responding\r\n"); EXIT(-1); } int i = 0; size_t readBytes = 0; // Send the configuration file: do { readBytes = fread(buff, 1, MPSSE_PCK_SEND_SIZE, frbf); if (MPSSE_send(buff, readBytes) != FT_OK) EXIT(-1); putchar('*'); if (!((++i)%16)) printf("\r\n"); } while (readBytes == MPSSE_PCK_SEND_SIZE); printf("\r\n"); memset(buff, 0x00, sizeof(buff)); MPSSE_send(buff, 1); //        ? printf("Load complete\r\n"); // wait CONF_DONE set // A low-to-high transition on the CONF_DONE pin indicates that the configuration is // complete and initialization of the device can begin. i = 0; do { if (MPSSE_get_lbyte(&lowByte) != FT_OK) { printf ("Error read CONF_DONE\r\n"); EXIT(-1); } if (i++ > TIMEOUT_CONF_DONE) { printf ("Error CONF_DONE\r\n"); EXIT(-1); } Sleep(2); } while (((lowByte >> CONF_DONE) & 1) == 0); printf("Configuration complete\r\n"); FT_Close(ftHandle); fclose(frbf); }
      
      





プログラムを開始する䟋







 pen "LESO7 B" OK nConfig -> 0 nConfig -> 1 ** Load complete Configuration complete
      
      





rbf- . . 30 / .

, - JTAG.







関連資料



  1. FTDI-MPSSE-Altera PS . .
  2. . . .
  3. Software Application Development D2XX Programmer's Guide . FTDI. API D2XX.
  4. FTDI MPSSE Basics. Application Note AN_135 . . FTDI MPSSE. .
  5. MPSSEおよびMCUホストバス゚ミュレヌションモヌド甚のコマンドプロセッサ。泚AN_108アプリケヌション。オペコヌドのリファレンス。それなしでは仕方ありたせん。
  6. D2XXドラむバヌ。FTDIドラむバヌ。



All Articles