实现MAXQ2000微控制器的JTAG加载主机
进入JTAG程序加载模式
需要按照以下步骤使MAXQ2000进入JTAG启动加载程序模式。- 初始化TAP控制器,重新设置它,进入Test-Logic-Reset状态。
- 设置指令寄存器(IR)为100b,使能系统编程模式。
- 设置数据寄存器(DR)为001b。这使得SPE(系统编程使能)位为1,使能启动加载程序,设置PSS[1:0] (编程源选择)位为00b,选择JTAG接口。
- 保持nRESET低电平,复位MAXQ2000。
- 释放nRESET。这导致MAXQ2000指向程序ROM (8000h)中的标准复位点。程序ROM代码将检查SPE和PSS位值,相应地激活JTAG启动加载程序。在这一点,启动加载程序运行,准备接收JTAG命令。
- 设置指令寄存器(IR)为010b,使能调试模式。该模式用于和JTAG启动加载程序或者调试引擎进行通信;在这一例子中,我们将使用该模式和启动加载程序进行通信。
- 10位数据移位通过DR,开始向JTAG启动加载程序发送命令。
#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还把结果数据写入另一内部寄存器,由JTAG主机通过DR寄存器移出。通过这种方式,启动加载程序代码和JTAG主机交换信息。然而,启动加载程序代码和JTAG主机并不同步。只要JTAG时钟保持低于MAXQ系统时钟1/8的最大值,由于JTAG是同步接口,因此,两路时钟的确切值并不影响通信。但是,MAXQ系统时钟速率以及接收到的启动加载程序命令特性将决定启动加载程序接收命令和发送回应之间的延时。例如,1MHz运行的MAXQ2000响应某一启动加载程序命令的时间要比10MHz的MAXQ2000时间长,即使两个微控制器都可以采用100kHz的JTAG时钟进行通信。只是读并返回信息的命令,例如返回ROM标志ID的命令以及从程序存储器读取的命令,花费的时间也要少于编程闪存操作等命令。
通过JTAG接口传送的数据没有被缓冲。如果在前一命令被读取之前,发送了另一10位命令,前一命令的结果丢失。ROM代码和TAP控制器保证前一数据被JTAG主机卸载前,启动加载程序不会发送其他数据,但反方向还是需要同步。JTAG主机需要通过某种方式知道移入DR的前一字节是否已经被启动加载程序读取了。这样,JTAG主机能够知道什么时候发送下一字节。采用的方法是利用TAP控制器发送的其他两个状态位,以及启动加载程序输出的每个8位字节。

图4. 通过DR的移位数据和状态位
2x5 如上面的图4所示,在TAP调试模式下,移入和移出DR的数据包括8个数据位(第2位到第9位)和两个状态位(第0位和第1位)。当JTAG主机移入数据时,只使用8个数据位。TAP控制器没有使用的两个状态位(也必须被移入),可以被设置为零,或者任何其他值。
在TAP控制器移出的10位数值中,两个状态位提供启动加载程序或者调试引擎的状态信息。当启动加载程序运行时,一般只能达到最后两个状态(调试忙或者调试有效),这是因为其他两个状态值不会出现在启动加载程序模式中。(参见图4中的状态/条件)
- 如果状态位被设置为调试忙(10b),启动加载程序还没有读取被JTAG主机移入到DR中的前一数值。这也表明,移出的8位数据没有意义,因为启动加载程序还没有执行完命令。接收到该数值后,JTAG主机必须以前一发送的字节值重新装入DR,这样,启动加载程序可以访问它。正确执行这一操作的状态顺序如下。
- 在Shift-DR状态,将最后一个比特移入到DR中,转换到Exit1-DR之后,JTAG主机应检查两个状态位。
- 如果接收到调试忙值,转换到Pause-DR状态,从这里到Exit2-DR,然后再次返回Shift-DR。重新装入前一DR值(这次不是移位的数值),然后通过Exit1-DR和Update-DR,忽略第二次通过的状态位值。
- 延迟较短的一段时间(取决于所执行的命令),重试字节传送。
- 如果状态位被设置为调试有效(11b)值,表明启动加载程序读取了移入的最后字节,已经装入了应答字节。移出的8位数值含有有效数据。
;==============================================================================;=;= 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
评论