實現(xiàn)MAXQ2000微控制器的JTAG加載主機
進入JTAG程序加載模式
需要按照以下步驟使MAXQ2000進入JTAG啟動加載程序模式。- 初始化TAP控制器,重新設置它,進入Test-Logic-Reset狀態(tài)。
- 設置指令寄存器(IR)為100b,使能系統(tǒng)編程模式。
- 設置數(shù)據(jù)寄存器(DR)為001b。這使得SPE(系統(tǒng)編程使能)位為1,使能啟動加載程序,設置PSS[1:0] (編程源選擇)位為00b,選擇JTAG接口。
- 保持nRESET低電平,復位MAXQ2000。
- 釋放nRESET。這導致MAXQ2000指向程序ROM (8000h)中的標準復位點。程序ROM代碼將檢查SPE和PSS位值,相應地激活JTAG啟動加載程序。在這一點,啟動加載程序運行,準備接收JTAG命令。
- 設置指令寄存器(IR)為010b,使能調試模式。該模式用于和JTAG啟動加載程序或者調試引擎進行通信;在這一例子中,我們將使用該模式和啟動加載程序進行通信。
- 10位數(shù)據(jù)移位通過DR,開始向JTAG啟動加載程序發(fā)送命令。
#define IR_DEBUG 010b ; Debug Mode#define IR_BYPASS 011b ; Bypass Mode (default)#define IR_SYSTEM_PROG 100b ; System Programming Mode (activate loader); System Programming Register settings#define SP_EXECUTE 000b ; Bootloader disabled#define SP_LOAD_JTAG 001b ; Activate JTAG bootloader #define SP_LOAD_UART 011b ; Activate UART bootloader#define SP_LOAD_SPI 101b ; Activate SPI bootloader (invalid on 2000)#define SP_RESERVED 111b ; Reserved value...call initializeJTAG ; Set up port pins for JTAGcall testLogicReset ; Reset JTAG port (ending state: Run-Test-Idle)move Acc, #IR_SYSTEM_PROGcall shiftIR3 ; Load the System Programming instruction into IRmove Acc, #SP_LOAD_JTAGcall shiftDR3 ; Enable the bootloader in JTAG interface modemove RST, #1 ; Drive nRESET lowmove Acc, #100 ; Delay for 100mscall delayMScall clock0 ; Remain in Run-Test-Idlemove RST, #0 ; Release nRESETmove Acc, #100 ; Delay for 100mscall delayMSmove Acc, #IR_DEBUGcall shiftIR3 ; Enable access to the 10-bit debug shift register;;;; Bootloader commands may now be shifted through the DR registercall waitForPrompt ; Verify that the bootloader is responding...
與加載程序通信
一旦啟動加載程序運行,程序ROM中的啟動加載程序代碼讀取內部寄存器的命令代碼,命令代碼由DR移位寄存器裝入。程序ROM還把結果數(shù)據(jù)寫入另一內部寄存器,由JTAG主機通過DR寄存器移出。通過這種方式,啟動加載程序代碼和JTAG主機交換信息。然而,啟動加載程序代碼和JTAG主機并不同步。只要JTAG時鐘保持低于MAXQ系統(tǒng)時鐘1/8的最大值,由于JTAG是同步接口,因此,兩路時鐘的確切值并不影響通信。但是,MAXQ系統(tǒng)時鐘速率以及接收到的啟動加載程序命令特性將決定啟動加載程序接收命令和發(fā)送回應之間的延時。例如,1MHz運行的MAXQ2000響應某一啟動加載程序命令的時間要比10MHz的MAXQ2000時間長,即使兩個微控制器都可以采用100kHz的JTAG時鐘進行通信。只是讀并返回信息的命令,例如返回ROM標志ID的命令以及從程序存儲器讀取的命令,花費的時間也要少于編程閃存操作等命令。
通過JTAG接口傳送的數(shù)據(jù)沒有被緩沖。如果在前一命令被讀取之前,發(fā)送了另一10位命令,前一命令的結果丟失。ROM代碼和TAP控制器保證前一數(shù)據(jù)被JTAG主機卸載前,啟動加載程序不會發(fā)送其他數(shù)據(jù),但反方向還是需要同步。JTAG主機需要通過某種方式知道移入DR的前一字節(jié)是否已經(jīng)被啟動加載程序讀取了。這樣,JTAG主機能夠知道什么時候發(fā)送下一字節(jié)。采用的方法是利用TAP控制器發(fā)送的其他兩個狀態(tài)位,以及啟動加載程序輸出的每個8位字節(jié)。

圖4. 通過DR的移位數(shù)據(jù)和狀態(tài)位
2x5 如上面的圖4所示,在TAP調試模式下,移入和移出DR的數(shù)據(jù)包括8個數(shù)據(jù)位(第2位到第9位)和兩個狀態(tài)位(第0位和第1位)。當JTAG主機移入數(shù)據(jù)時,只使用8個數(shù)據(jù)位。TAP控制器沒有使用的兩個狀態(tài)位(也必須被移入),可以被設置為零,或者任何其他值。
在TAP控制器移出的10位數(shù)值中,兩個狀態(tài)位提供啟動加載程序或者調試引擎的狀態(tài)信息。當啟動加載程序運行時,一般只能達到最后兩個狀態(tài)(調試忙或者調試有效),這是因為其他兩個狀態(tài)值不會出現(xiàn)在啟動加載程序模式中。(參見圖4中的狀態(tài)/條件)
- 如果狀態(tài)位被設置為調試忙(10b),啟動加載程序還沒有讀取被JTAG主機移入到DR中的前一數(shù)值。這也表明,移出的8位數(shù)據(jù)沒有意義,因為啟動加載程序還沒有執(zhí)行完命令。接收到該數(shù)值后,JTAG主機必須以前一發(fā)送的字節(jié)值重新裝入DR,這樣,啟動加載程序可以訪問它。正確執(zhí)行這一操作的狀態(tài)順序如下。
- 在Shift-DR狀態(tài),將最后一個比特移入到DR中,轉換到Exit1-DR之后,JTAG主機應檢查兩個狀態(tài)位。
- 如果接收到調試忙值,轉換到Pause-DR狀態(tài),從這里到Exit2-DR,然后再次返回Shift-DR。重新裝入前一DR值(這次不是移位的數(shù)值),然后通過Exit1-DR和Update-DR,忽略第二次通過的狀態(tài)位值。
- 延遲較短的一段時間(取決于所執(zhí)行的命令),重試字節(jié)傳送。
- 如果狀態(tài)位被設置為調試有效(11b)值,表明啟動加載程序讀取了移入的最后字節(jié),已經(jīng)裝入了應答字節(jié)。移出的8位數(shù)值含有有效數(shù)據(jù)。
;==============================================================================;=;= sendCommand;=;= Transmits a loader command by shifting bytes through DR.;=;= Inputs : DP[0] - Points to area of RAM which stores input bytes;= for command and which will be filled with output.;= LC[1] - Number of bytes to transmit/receive;= Outputs : C - Set on JTAG communication error;= Destroys : AP, APC, A[0], A[1], A[2], A[15], PSW, LC[0];=sendCommand:move APC, #80h ; Acc => A[0], turn off auto inc/decpush LC[1]call waitForPromptpop LC[1]jump C, sendCommand_failmove Acc, @DP[0] ; Read first byte to transmitcall shiftDRpush Accmove Acc, A[1]cmp #3 ; Should be valid status since we had a promptpop Accjump NE, sendCommand_failmove @DP[0], Acc ; Store first received bytemove NUL, @DP[0]++ ; Increment data pointerdjnz LC[1], sendCommand_loopjump sendCommand_passsendCommand_loop:move A[2], #10 ; Number of retries allowedsendCommand_retry:move Acc, @DP[0] ; Get next byte to transmitcall shiftDR_nextpush Accmove Acc, A[1]cmp #3pop Accjump NE, sendCommand_stallmove @DP[0], Acc ; Store received bytemove NUL, @DP[0]++ ; Increment data pointerdjnz LC[1], sendCommand_loopjump sendCommand_passsendCommand_stall:move LC[0], #8000 ; About a milliseconddjnz LC[0], $move Acc, A[2]sub #1jump NZ, sendCommand_retryjump sendCommand_fail
評論