上篇簡單的介紹後,本篇將深入介紹MPSSE中,常用到的Command,
作為下一篇實作部分的引導!
本文預計主要分成以下小節:
以上部分用來分別探討,從初始化開始到常用的TDI、TDO、TMS等訊號處理的Commands
由於FT2232晶片中其實沒Register等東西需要設定,初始化的方式也很簡單,
傳幾個Commands把需要的東西打開/關閉,讓他可以在指定的功能下使用!
底下分成幾個小節分別說明這些部分!
一般在初始化的時候,必要設定每根訊號線的初始值及訊號線的方向(Input/Output),
在MPSSE中會將16根訊號線拆成High Byte、Low Byte兩組,然後利用各自的Command設定初始值(Value)及方向(Direction)
例如:
我希望將這16根訊號線的初始值(Value)設定為0x0808(LSB對應GPIO 0、MSB對應GPIO 15)和方向(Direction)設定為0x0a1b,則使用下面兩組Commands:
"0x80, 0x08, 0x1b" 和 "0x82, 0x08, 0x0a"
轉換的方式如下:
0x0808 = (0000 1000 0000 1000)
0x0a1b = (0000 1010 0001 1011)
對應到Pin上:
Pin # | Value | Direction |
---|---|---|
ADBUS0 | 0 | 1 |
ADBUS1 | 0 | 1 |
ADBUS2 | 0 | 0 |
ADBUS3 | 1 | 1 |
ADBUS4 | 0 | 1 |
ADBUS5 | 0 | 0 |
ADBUS6 | 0 | 0 |
ADBUS7 | 0 | 0 |
ACBUS0 | 0 | 0 |
ACBUS1 | 0 | 1 |
ACBUS2 | 0 | 0 |
ACBUS3 | 1 | 1 |
ACBUS4 | 0 | 0 |
ACBUS5 | 0 | 0 |
ACBUS6 | 0 | 0 |
ACBUS7 | 0 | 0 |
表示其中ADBUS3、ACBUS3初始值為1,
而且ADBUS0、ADBUS1、ADBUS3、ADBUS4、ACBUS1、ACBUS3皆為Output!
當然,作為一個USB和JTAG溝通之間的橋梁,不免俗的一定要有Command來控制Adapter出TCK的速度!
首先介紹一下FT2232H中,Clock的計算方式:
在FT2232H中內部預設使用的頻率是60 MHz,計算方式如下!
其中,ValueH、ValueL為使用者設定的部分,主要是將原先的除數分成前8-bits的ValueH和後8-bits的ValueL!
為了相容於前版的FT2232D中使用的12 MHz,因此在FT2232H中而外提供指令將原先頻率先除頻(Frequency divider)變成12 MHz,因此計算方式也可以變成如下所示!
以下是Value和頻率對應的關係:
Value | 60 MHz max TCK | 12 MHz max TCK |
---|---|---|
0x0000 | 15 MHz | 3 MHz |
0x0001 | 10 MHz | 2 MHz |
0x0002 | 7.5 MHz | 1.5 MHz |
.... | ||
.... | ||
0xFFFF | 457.763 Hz |
因此在這邊介紹兩組共三個MPSSE Command!
第一組是除頻器的開關(Clk Divide by 5):
第二組則是負責設定Value的MPSSE Command:
0x86, ValueL, ValueH: 負責設定CLK的除數(Divisor),輸出指定的TCK
FT2232H中,提供一個自我測試的功能,讓TDI可以接回TDO中,測試TDI傳輸和TDO接收是否正常:
不過由於我們在JTAG中基本上是不需要用到Loopback,所以一般在初始化階段中,會送"0x85"將這個功能關閉!
最後介紹一個特殊的應用:
當如果不需要使用Adapter中的TCK功能時,可以利用Target端傳過來的RTCK作為同步用!
這部分應用比較特殊,OpenOCD中在支援這功能時也有特殊限制,詳細內容可以參考: 「FAQ 2. RTCK, also known as: Adaptive Clocking - What is it?」
在這邊介紹一下FT2232H中支援這個功能的開關:
JTAG訊號的控制,只要分成TCK、TDI、TDO和TMS等四根,
其中TCK由Adatper控制外,剩餘三根的資料進/出、資料長度、資料內容等等,
則全交由使用者自行決定,因此在MPSSE Command中,編碼主要有以下的規則:
由於在JTAG中規定,資料必須由LSB優先傳輸,因此我們只需要考慮Bit 3為1的那些Command,
請參考下節內容!
以下Command皆是由LSB開始發送,請參考以下Command Table:
OPCODE | Read TDO? (Bit 5) | Write TDI? (Bit 4) | -VE CLK Read? (Bit 2) | Bits? (Bit 1) | -VE CLK Write? (Bit 0) |
---|---|---|---|---|---|
0x18 | - | YES | - | BYTES | +VE |
0x19 | - | YES | - | BYTES | -VE |
0x1A | - | YES | - | BITS | +VE |
0x1B | - | YES | - | BITS | -VE |
0x28 | YES | - | +VE | BYTES | - |
0x2C | YES | - | -VE | BYTES | - |
0x2A | YES | - | +VE | BITS | - |
0x2E | YES | - | -VE | BITS | - |
0x39 | YES | YES | +VE | BYTES | -VE |
0x3C | YES | YES | -VE | BYTES | +VE |
0x3B | YES | YES | +VE | BITS | -VE |
0x3E | YES | YES | -VE | BITS | +VE |
不過在JTAG中,當TCK上升(+VE CLK)時,
TDI資料應該就已經要先準備好等待寫入,因此只需要考慮"-VE CLK Write"、"+VE CLK Read"的那些Command!
所以可以將這個Table簡化成下面的部分:
OPCODE | Read TDO? (Bit 5) | Write TDI? (Bit 4) | -VE CLK Read? (Bit 2) | Bits? (Bit 1) | -VE CLK Write? (Bit 0) |
---|---|---|---|---|---|
0x19 | - | YES | - | BYTES | -VE |
0x1B | - | YES | - | BITS | -VE |
0x28 | YES | - | +VE | BYTES | - |
0x2A | YES | - | +VE | BITS | - |
0x39 | YES | YES | +VE | BYTES | -VE |
0x3B | YES | YES | +VE | BITS | -VE |
以下拆成三組來介紹:
首先是純寫TDI的部分:
(LengthH | LengthL)+1
個Byte (*註1)Length+1
個Bits(*註1) 參考下圖範例:
再來是純讀TDO的部分:
(LengthH | LengthL)+1
個ByteLength+1
個Bits
最後是同時讀寫的部分:
這部分主要使用以下兩種Command:
注意: 這邊有個小小"tricky"的地方,就是Byte1的Bit 7在TMS開始傳輸前,「會被放到TDI上」
最後,當然要介紹一下這些Command送到FTDI晶片中時,要怎麼執行,
很簡單,就是送一個0x87: Send Immediate指令就行了!
他會將晶片中的Buffer整個送出到Target端,並將結果送回PC中!
FTDI整本文件約莫30頁,不過實際應用到的部分就是那幾個,
難的是如何應用這幾個Commnads完成JTAG、TDI、TDO、TMS等訊號的控制,
並將資料回傳至上層!
明天的文章中,將作本系列最後的總結: 探討OpenOCD中如何支援MPSSE,將上層的JTAG Commands轉成對應的MPSSE Command,並支援FTDI-based Debug Adapter從初始化、設定到傳送JTAG Commands等等功能的實作和背後的秘密!
如果真的解釋沒很清楚,歡迎留言 (含金量高!?)