MAXQ2000 마이크로컨트롤러를 위한 JTAG 부트로더 (Bootloader) 마스터 구현
개요: MAXQ® 마이크로컨트롤러에 의해 제공되는 JTAG 부트로더는 일련의 표준 명령을 사용하여 외부 JTAG 마스터가 모든 MAXQ 마이크로컨트롤러를 쉽게 인식하고 프로그래밍할 수 있게 한다. 본 애플리케이션 노트에 포함된 코드를 길잡이로 이용하면 완전한 기능의 JTAG 부트로더 마스터 애플리케이션을 구성할 수 있을 것이다. 마스터 애플리케이션은 표준화된 부트로더 명령 세트를 지원하는 모든 MAXQ 마이크로컨트롤러의 코드와 데이터 메모리 내용을 식별, 초기화, 로드 및 검사할 수 있다.
개요
재기록 가능한 프로그램 메모리가 내장된 MAXQ 마이크로컨트롤러에는 보통 ROM 기반 부트로더가 탑재되어 있으며, 이러한 부트로더는 마이크로컨트롤러의 JTAG 호환 디버그 포트를 통해 프로그램 메모리를 로드할 수 있게 한다. JTAG 부트로더가 제공하는 정확한 기능은 소자마다 다르지만, 일반적으로 프로그램과 데이터 메모리를 읽고, 쓰고, 검사하고, 삭제할 수 있는 명령이 포함되어 있다. 일부 소자는 부트로더에 직렬 포트나 SPI™ 인터페이스와 같이 다른 인터페이스를 제공하기도 하지만, 보통 JTAG 인터페이스가 가장 많이 이용된다. 그 이유는 첫째, 인서킷 디버깅 기능 지원을 위해 JTAG 인터페이스가 미리 설치되어야 한다. 둘째, JTAG 인터페이스는 직렬 포트와 달리 일반적으로 최종 사용자 애플리케이션에서는 사용되지 않는다. 패스워드 메커니즘 옵션을 이용하면 프로그램 코드가 로드된 후에 부트로더 또는 인서킷 디버깅 기능에 대한 액세스를 제한할 수 있다. 각 MAXQ 소자가 지원하는 여러 기능에 대한 세부 정보는 데이터 시트와 사용자 가이드를 포함하여 구체적인 제품별 정보를 참조한다.
이 애플리케이션 노트에서는 MAXQ2000을 위한 JTAG 부트로더 마스터를 구현하는 데 필요한 기본 단계를 설명한다. 이러한 단계에는 JTAG 포트에 인터페이싱, 테스트 액세스 포트 (TAP) 컨트롤러와의 통신, 부트로더 모드 활성화, ROM 기반 부트로더에 명령 전송 등이 있다. 일반적으로 JTAG 포트는 모든 MAXQ 소자에서 동일한 동작을 수행하며, MAXQ 부트로더는 공통적인 명령 세트를 사용하여 동작하므로, 예제 코드를 포함하여 이 애플리케이션 노트에서 설명되는 대부분의 주제는 어느 MAXQ 마이크로컨트롤러의 JTAG 부트로더 마스터를 구현하든 관계 없이 적용할 수 있을 것이다.
직렬 포트를 제외하면 이러한 구현에 MAXQ2000의 다른 특별한 기능은 사용되지 않았다. 즉, 여기에 나온 예제 코드는 충분한 프로그램 메모리를 갖고 있는 어느 MAXQ20 소자에서나 실행할 수 있다는 뜻이다. 코드는 MAXQ 어셈블리로 작성되었고 MAX-IDE 개발 환경을 사용하여 컴파일되었다. 코드는 다운로드하여 이용할 수 있다.
하드웨어 셋업
이 애플리케이션 노트의 예제 코드는 한 쌍의 MAXQ2000 EV 킷(EV kit)을 사용하여 개발되었다. 여기에 설명된 소프트웨어를 실행하려면 2개의 MAXQ2000 EV 킷이 필요하다. 하나의 MAXQ2000(JTAG 마스터)은 예제 코드를 실행하고, 두 번째 MAXQ2000은 마스터에 의해 재프로그래밍되어 JTAG 슬레이브로 동작한다. 두 MAXQ2000 마이크로컨트롤러에는 모두 표준 8.00MHz 크리스털이 사용되었다.
마스터 MAXQ2000 EV 킷은 프로토타이핑 영역에 2 x 5 핀 헤더를 설치함으로써 JTAG 케이블 연결의 마스터 측을 제공한다. 헤더의 핀은 표준 MAXQ JTAG 헤더 레이아웃을 따랐으며, 표 1과 같이 연결하였다.
표 1. MAXQ2000 JTAG 연결
JTAG Header Pin
JTAG Cable Function
MAXQ2000 JTAG Master Connection
MAXQ2000 JTAG Slave Connection
1
TCK (Test Clock)
P0.0 (Output)
P4.0 (Input)
2
GND
GND
GND
3
TDO (Test Data Out)
P0.1 (Input)
P4.3 (Output)
4
VREF
–
–
5
TMS (Test Mode Select)
P0.2 (Output)
P4.2 (Input)
6
nRESET
P0.4 (Open Drain)
nRESET (Input)
7
Keyed pin
–
–
8
+5V
–
–
9
TDI (Test Data In)
P0.3 (Output)
P4.1 (Input)
10
GND
GND
GND
슬레이브 MAXQ2000 EV 킷에는 수정이 필요 없다. 앞에서 설명했듯이 마스터 MAXQ2000 EV 킷의 프로토타이핑 영역에 2 x 5 JTAG 헤더를 설치하고 연결했다. 그런 다음 두 개의 EV 킷을 연결하였다. 즉, 직렬-JTAG 보드를 MAXQ EV 킷에 연결하는 데 일반적으로 사용되는 표준 2 x 5 JTAG 케이블을 마스터 EV 킷의 프로토타이핑 영역에 있는 2 x 5 JTAG 헤더와 슬레이브 EV 킷의 표준 JTAG 헤더 (J4) 사이에 연결한 것이다. 이 JTAG 2 x 5 커넥터는 MAXQ2000 EV 킷에 포함되어 있다.
작업을 간소화하기 위해 JTAG 케이블을 통해 마스터 EV 킷으로부터 슬레이브 EV 킷까지 전원 또는 기준전압을 연결하는 시도는 하지 않았다. 대신, 두 EV 킷은 모두 동일한 VDDIO 전압(약 3.6V)으로 동작하도록 설정하였다. 이러한 설정은 마스터 및 슬레이브 MAXQ2000이 공통 I/O 레일 레벨로 동작하도록 한다.
슬레이브 EV 킷에는 또한 헤더 J3에 LCD 도터보드(MAXQ2000-K01)가 탑재되어 있다. 직렬-JTAG 보드와 함께 두 보드에 대한 점퍼와 DIP 스위치 설정은 표 2에 나와 있다. 주의: 이 표에 나열되지 않은 모든 점퍼는 분리되어야 한다. 그림 1은 최종 구성을 보여준다.
표 2. 보드의 스위치 및 점퍼 설정
Board
Switch or Jumper
Setting
Notes
Serial-to-JTAG Board
JH1
Connected
JH2
Connected
JH3
Connected
Supplies 5V power over JTAG cable
Master MAXQ2000 EV Kit
JU1
Pins 1 and 2 connected
Powers VDD from 2.5V supply
JU2
Pins 1 and 2 connected
Powers VDDIO from 3.6V supply
JU3
Pins 1 and 2 connected
Powers VLCD from 3.6V supply
JU11
Connected
Powers kit board from JTAG 5V supply
DIP SW1
Switches #4 and #8 ON; all other switches OFF
Enables serial port 0 output to J5
DIP SW3
All switches OFF
DIP SW6
All switches OFF
Slave MAXQ2000 EV Kit
JU1
Pins 1 and 2 connected
Powers VDD from 2.5V supply
JU2
Pins 1 and 2 connected
Powers VDDIO from 3.6V supply
JU3
Pins 1 and 2 connected
Powers VLCD from 3.6V supply
DIP SW1
All switches OFF
DIP SW3
All switches OFF
DIP SW6
All switches OFF
그림 1. JTAG 데모 셋업
MAXQ JTAG 인터페이스
MAXQ 마이크로컨트롤러의 JTAG 인터페이스는 TAP (Test Access Port) 컨트롤러에 정보를 전달하고 가져오는 데 사용되는 4개의 신호 라인으로 구성된다. 이 TAP 컨트롤러는 MAXQ의 부트로더와 인서킷 디버깅 기능에 대한 액세스를 제공한다. (디버그 마스터에 대한 구현은 부트로더 마스터 구현과 유사하지만 본 애플리케이션 노트의 범위를 넘어선다.) 4개의 JTAG 신호 라인은 표 3과 같다.
표 3. JTAG 인터페이스 신호
JTAG Signal
Signal Name
Direction (Master)
Direction (Slave)
Signal Description
TMS
Test Mode Select
Output
Input
이 신호 라인은 TCK 라인과 함께 하나의 동작 상태에서 다음 동작으로 TAP 컨트롤러를 시프트하는 데 사용된다.
TCK
Test Clock
Output
Input
이 신호는 JTAG 인터페이스를 위한 클록을 제공한다. JTAG 클록은 슬레이브 클록 주파수를 8로 나눈 최대값으로 제한된다. 예를 들어, 슬레이브가 8MHz 클록 주파수로 동작하면 TCK의 JTAG 클록은 1MHz보다 더 빠른 속도로 실행할 수 없다.
TDI
Test Data In
Output
Input
이 신호는 마스터에서 슬레이브로 전송되는 데이터를 전달한다.
TDO
Test Data Out
Input
Output
이 신호는 슬레이브에서 다시 마스터로 전송되는 데이터를 전달한다.
nRESET 핀은 기술적으로 말하면 JTAG 인터페이스의 일부가 아니다. nRESET 핀은 JTAG 케이블에 포함되어 JTAG 마스터가 슬레이브 마이크로컨트롤러를 리셋할 수 있게 한다. 슬레이브 마이크로컨트롤러의 리셋은 부트로더 모드로 들어가기 위해 필요한 단계이며, 또 JTAG 통신이 갑자기 중단될 경우 유용할 수 있다.
JTAG 인터페이스는 풀 듀플렉스이므로, 데이터는 TDI 라인에서 마스터로부터 슬레이브로 시프트 인되는 동시에 TDO 라인에서는 슬레이브로부터 마스터로 시프트 아웃된다. 슬레이브는 TCK의 상승 에지에서 입력 데이터를 (TDI와 TMS에서 모두) 샘플링하고 TCK의 하강 에지에서 TDO의 마스터로 출력 데이터를 구동한다. 입/출력 데이터는 모두 먼저 최하위 비트부터 값이 전송된다.
이 애플리케이션 노트는 예제 코드의 동작을 중점적으로 설명하므로 JTAG 인터페이스와 TAP 컨트롤러에 대한 간단한 설명만 제공된다. 이러한 기능에 대한 세부 내용은 Maxim 웹 사이트의 MAXQ 제품군 사용자 가이드에서 테스트 액세스 포트(TAP), 인서킷 디버그 모드 및 인시스템 프로그래밍 단원을 참조한다.
TAP 컨트롤러와의 통신
TAP 컨트롤러는 아래의 그림 2와 같이 스테이트 머신을 중심으로 구성된다. TAP 스테이트 머신에는 16개의 개별 상태가 있다. 하나의 상태에서 다음 상태로의 천이는 TMS 신호 값을 바탕으로 한 TCK의 상승 에지에서 발생한다. 예컨대 TAP 컨트롤러가 Select-DR-Scan 상태에 있으면, TCK의 상승 에지에서는 다음과 같이 천이가 발생한다.
TMS = 1이면, TAP 컨트롤러는 Select-IR-Scan 상태로 천이된다.
TMS = 0이면, TAP 컨트롤러는 Capture-DR 상태로 천이된다.
이런 방식으로 원하는 상태까지 TAP 컨트롤러에 클로킹할 수 있다. 상태 다이어그램(그림 2)에 대한 다음 두 가지 사항을 유의한다.
5번의 '1' 천이(TMS를 하이로 유지하면서 TCK를 5회 풀 사이클로 클로킹하는 것)는 시작 상태와 상관 없이 언제나 스테이트 머신을 Test-Logic-Reset으로 되돌려 놓는다. 이는 TAP 컨트롤러의 현재 상태를 알 수 없거나 JTAG 마스터와 슬레이브 간 통신이 어떤 식으로든 중단되는 경우 '1' 천이를 5번 클로킹하여 TAP 컨트롤러를 알려진 상태로 되돌릴 수 있다는 뜻이다.
TCK 클록이 계속 동작하는 경우에도 JTAG 통신을 일시 중지하고 TAP 컨트롤러의 상태에 영향을 미치지 않으면서 Run-Test-Idle, Pause-DR 또는 Pause-IR 상태를 무한 유지할 수 있다.
그림 2. 테스트 액세스 포트 (TAP) 스테이트 머신
TAP 컨트롤러의 스테이트 머신은 2개의 제어 레지스터에 대한 액세스를 제공하며, 이 제어 레지스터들은 부트로더, 디버그 인터페이스 및 기타 기능에 인터페이스를 제공한다.
명령 레지스터(IR)는 언제나 3비트 폭이다. 이 레지스터는 인덱스 레지스터의 역할을 하며, DR의 기능을 제어한다(아래 참조).
데이터 레지스터(DR)는 TAP 컨트롤러에 있는 여러 개의 레지스터 중 하나를 가리키는 액세스 포인트이다. 비트가 DR에 시프트 인 또는 아웃될 때 액세스되는 실제 레지스터는 IR의 현재 값에 의해 결정된다.
그림 3. TAP 컨트롤러의 레지스터 액세스
그림 3에서 보듯이 DR은 IR의 값에 따라 3개의 내부 레지스터 중 하나를 가리킨다.
IR = 011b이면, TAP 컨트롤러는 바이패스(Bypass) 모드가 된다. 이 모드(TAP 컨트롤러의 디폴트 모드)에서 TDI를 통해 DR로 시프트 인되는 데이터는 TDO를 통해 간단히 다시 시프트 아웃된다. 내부 레지스터는 TAP 컨트롤러를 통해 시프트되는 데이터에 의해 변경되지 않는다.
IR = 100b로 설정하면 TAP 컨트롤러는 시스템 프로그래밍(System Programming) 모드에 놓인다. 이 모드에서 DR에 시프트 인된 데이터는 3비트 시스템 프로그래밍 레지스터에 시프트 인된다. 이 레지스터(MAXQ 마이크로컨트롤러에 의해 ICDF 레지스터의 비트 [3:1]로도 액세스 가능)는 리셋 후 MAXQ가 일반 프로그램 실행 모드에 들어갈지 또는 부트로더 모드에 들어갈지를 제어한다. 부트로더 모드가 인에이블되면 부트로더에서 사용되는 인터페이스도 제어한다(JTAG, 직렬 또는 SPI).
IR = 010b로 설정하면, TAP 컨트롤러는 디버그(Debug) 모드가 된다. 이 모드에서 DR로 시프트 인된 데이터는 내부 10비트 디버깅 레지스터에 시프트 인되며, 이 레지스터는 부트로더로 읽혀진다. 또한 부트로더에 의한 데이터 출력은 이 레지스터를 통해 그리고 TDO를 통해 이 레지스터로부터 (2상태 비트와 함께) 다시 시프트 아웃된다. 이 레지스터는 부트로더와 인서킷 디버깅 모드에서 모두 데이터를 전송하는 데 사용된다.
위에서 설명한 3개 모드 중 바이패스 모드는 "무동작" 모드이다. 즉, 우리가 관심을 갖는 부트로더 기능에 대한 액세스를 제공하지 않는다. 시스템 프로그래밍 모드는 이름과는 달리 실제로 부트로더와 통신하는 데는 사용되지 않으며, 부트로더로의 액세스만 가능하게 할 뿐이다. 일단 부트로더가 동작하고 통신하면, 이 TAP 모드는 더 이상 사용되지 않는다. 디버그 모드는 10비트 입/출력 레지스터에 액세스할 수 있으며 부트로더와의 모든 통신을 수행하는 데 사용된다. 부트로더가 인에이블된 다음에는 로더 세션이 완료될 때까지 디버그 모드만 사용된다.
JTAG 포트와 리셋 라인 제어
슬레이브 MAXQ2000에 있는 JTAG/TAP 포트의 4개 라인(TMS, TCK, TDO, TDI)과 nRESET 라인은 각각 마스터 MAXQ2000에 있는 하나의 포트 핀에 연결된다. JTAG 인터페이스를 제어하는 첫 번째 단계는 이 라인들을 적절히 구성하는 것이다.
#define TCK PO0.0 ; Test Clock - Master output
#define TDO PI0.1 ; Test Data Out - Slave output, master input
#define TMS PO0.2 ; Test Mode Sel - Master output
#define TDI PO0.3 ; Test Data In - Master output
#define RST PD0.4 ; Reset - Master open-drain output (on 1)
4개의 JTAG 라인은 표준 드라이브 모드로 동작한다. 마스터의 관점에서 TMS, TCK 및 TDI는 언제나 출력으로 구동되는 반면, 슬레이브에 의해 구동되는 TDO는 언제나 입력이 된다. JTAG 라인의 방향은 고정적이며 양방향이 아니다. nRESET 라인은 특수한 경우로, 마스터 측에서 오픈 드레인 출력으로 구성된다. 일반적으로 슬레이브는 자체적인 nRESET 라인을 하이로 구동하기 때문에 마스터는 (슬레이브를 리셋할 때) 이 라인을 풀 다운하거나 (그 외 모든 경우에는) 라인을 완전히 해제할 수 있을 뿐이다. 마스터가 슬레이브의 nRESET 라인을 하이로 구동할 이유는 전혀 없다.
;==============================================================================
;=
;= initializeJTAG
;=
;= Sets up the port pins for the JTAG interface.
;=
;= Inputs : None
;= Outputs : None
;= Destroys : None
;=
initializeJTAG:
move PD0.0, #1 ; TCK - master output
move PO0.0, #1 ; Drive high
move PD0.1, #0 ; TDO - master input
move PO0.1, #1 ; Weak pullup on
move PD0.2, #1 ; TMS - master output
move PO0.2, #1 ; Drive low
move PD0.3, #1 ; TDI - master output
move PO0.3, #1 ; Drive high
move PD0.4, #0 ; RST - open drain when 1, tristate when 0
move PO0.4, #0 ; Weak pullup off
ret
포트 핀을 초기화한 후에는 clock0과 clock1 루틴을 사용하여 TMS 라인의 스태틱 0과 1을 클로킹하여 TAP 컨트롤러를 한 상태에서 다음 상태로 이동시킨다. JTAG 클록 레이트가 슬레이브 마이크로컨트롤러의 시스템 클록 레이트의 최대 1/8 미만으로 유지되는 한 JTAG 클록은 어느 주파수에서나 구동할 수 있다. 마스터의 시스템 클록 레이트는 슬레이브의 클록 레이트와 일치시킬 필요가 없기 때문에 여기서 고려할 필요가 없다. 마스터는 JTAG 통신 문제 없이 슬레이브보다 더 빠르거나 느리게 동작할 수 있다.
이 예에서 슬레이브 MAXQ2000에는 8MHz 클록 크리스털이 설치되어 있으므로, 마스터는 문제 없이 최대 1MHz에서 JTAG 클록을 구동할 수 있다. 여기서 JTAG 클록 레이트는 100kHz면 충분하다.
이 두 루틴을 적절히 구성한 다음, 루틴을 추가하여 TAP 컨트롤러를 Test-Logic-Reset 상태로 되돌려 초기화할 수 있다. Test-Logic-Reset 상태는 이름에서 알 수 있듯이 부트로더의 인에이블 여부, 부트로더에 의해 사용되는 인터페이스를 결정하는 비트(SPE 및 PSS[1:0])를 포함하여 TAP 로직에 대한 완벽한 리셋을 수행한다. 따라서 부트로더 모드에 들어간 후 TAP 컨트롤러를 Test-Logic-Reset으로 설정하면 소자가 리셋되고 부트로더 모드가 종료된다. 데모 애플리케이션에 사용되는 JTAG 루틴은 testLogicReset itself) 자체는 제외) 모두 루틴 시작 시 TAP 컨트롤러가 Run-Test-Idle 상태에 있다고 가정한다. JTAG 통신 루틴 동안 TAP 컨트롤러는 다양한 상태를 통해 시프트되며, 루틴의 마지막에 TAP 컨트롤러는 언제나 Run-Test-Idle로 다시 돌아간다.
;==============================================================================
;=
;= testLogicReset
;= clock0, clock1
;=
;= Resets the JTAG/TAP controller to its starting state.
;=
;= Inputs : None
;= Outputs : None
;= Destroys : LC[0]
;=
testLogicReset:
call clock1
call clock1
call clock1
call clock1
call clock1
call clock1
call clock1
call clock0 ; Brings us to Run-Test-Idle
ret
TAP 명령 레지스터에 쓰기
TAP 컨트롤러의 IR에 값을 로드하려면 TAP 스테이트 머신을 Shift-IR 상태가 될 때까지 이동시킨 다음 새로운 3비트 값으로 클로킹한다. 이 값은 Update-IR 상태에 들어갈 때까지는 실제로 시프트 레지스터에서 명령 레지스터로 복사되지 않는다.
모든 JTAG 시프트 레지스터 동작과 마찬가지로 새로운 값이 시프트 인되면 레지스터의 현재 내용은 TDO에 의해 시프트 아웃된다. 그러나 시프트 아웃된 값은 JTAG 인터페이스의 기능을 테스트하는 데 사용할 수 있도록 JTAG 표준에 의해 규정된 대로 언제나 고정된다(001b).
어느 하나의 시프트 레지스터(IR 또는 DR)에 비트를 시프트 인/아웃하는 절차는 동일하다. TAP 스테이트 머신은 각각 Shift-IR 또는 Shift-DR 상태에 있어야 한다. (TDI에서) 입력 비트는 각 TCK 사이클의 상승 에지에서 TAP 컨트롤러에 의해 샘플링되고, (TDO에서) 출력 비트는 TCK 사이클의 하강 에지에서 구동된다.
;==============================================================================
;=
;= shift
;=
;= In a shift register state, clocks in a TDI bit and clocks out a TDO bit.
;=
;= Inputs : C - Bit to shift in to TDI.
;= Outputs : C - Bit shifted out from TDO.
;= Destroys : PSW, LC[0]
;=
shift:
jump C, shift_bit1
shift_bit0:
move TDI, #0 ; Shift in zero bit
jump shift_bitEnd
shift_bit1:
move TDI, #1 ; Shift in one bit
jump shift_bitEnd
shift_bitEnd:
move LC[0], #JCLOCK
djnz LC[0], $
move TCK, #1 ; Rising edge, TDI is sampled
move LC[0], #JCLOCK
djnz LC[0], $
move TCK, #0 ; Falling edge, TDO is driven out
move LC[0], #JCLOCK
djnz LC[0], $
move C, TDO ; Latch TDO value
ret
TMS는 전송 시 각 비트에서 최종 비트만 제외하고 로우(low)를 유지해야 한다. 이것은 매우 중요한데, 각 비트가 시프트 인/시프트 아웃됨에 따라 스테이트 머신이 Shift-IR 또는 Shift-DR 상태를 유지하기 때문이다. 최종 비트 사이클에서는 최종 비트가 클록 인/아웃됨에 따라 TAP 컨트롤러가 Exit1-DR 또는 Exit1-IR 상태가 되기 때문에 TMS는 하이(high)로 구동되어야 한다.
예를 들어, 표 4에서 값 100b(시스템 프로그래밍 모드)는 JTAG 마스터에 의해 IR 레지스터에 시프트 인되고 있다. IR 레지스터는 바이패스 값 011b로 프로그래밍되기 시작하며, TAP 컨트롤러는 Run-Test-Idle 상태로 들어가기 시작한다. 아래의 그림 4에서 보듯이 최하위 비트로 시작하고 최상위 비트로 끝나는 TAP 컨트롤러에 비트가 시프트 인되고 아웃된다. 따라서, 첫 번째 시프트 사이클에서 새로운 값의 비트 0이 시프트 인되고, 이전 값의 비트 0은 시프트 아웃된다.
표 4. 명령 레지스터 시프트 예
TCK
TMS
TDI
TDO
TAP State
Shift Register
Instruction Register
bit 2
bit 1
bit 0
bit 2
bit 1
bit 0
0
1
x
x
Run-Test-Idle
x
x
x
0
1
1
1
1
x
x
Select-DR-Scan
x
x
x
0
1
1
0
1
x
x
Select-DR-Scan
x
x
x
0
1
1
1
1
x
x
Select-IR-Scan
x
x
x
0
1
1
0
0
x
x
Select-IR-Scan
x
x
x
0
1
1
1
0
x
x
Capture-IR
0
0
1
0
1
1
0
0
x
x
Capture-IR
0
0
1
0
1
1
1
0
x
x
Shift-IR
0
0
1
0
1
1
0
0
0
x
Shift-IR
0
0
1
0
1
1
1
0
0
x
Shift-IR
0
0
1
0
1
1
0
0
0
1
Shift-IR
0
0
0
0
1
1
1
0
0
1
Shift-IR
0
0
0
0
1
1
0
1
1
0
Shift-IR
0
0
0
0
1
1
1
1
1
0
Exit1-IR
0
0
0
0
1
1
0
1
x
0
Exit1-IR
1
0
0
0
1
1
1
1
x
0
Update-IR
1
0
0
1
0
0
0
0
x
x
Update-IR
1
0
0
1
0
0
1
0
x
x
Run-Test-Idle
x
x
x
1
0
0
이러한 동작, shiftIR3을 수행하기 위해 사용되는 루틴은 다음과 같다.
;==============================================================================
;=
;= shiftIR3
;= clock0, clock1, shift
;=
;= Shifts a 3-bit value into the IR register.
;=
;= Inputs : A[0] - Low three bits contain value to shift into IR
;= Outputs : None
;= Destroys : AP, APC, A[0], PSW, LC[0]
;=
shiftIR3:
move APC, #80h ; Acc => A[0], turn off auto inc/dec
call clock1 ; (Select DR Scan)
call clock1 ; (Select IR Scan)
call clock0 ; (Capture IR - loads 001b to shift register)
call clock0 ; (Shift IR)
move TMS, #0 ; Drive TMS low
move C, TDO ; xxxxx210 c = s
rrc ; sxxxxx21 c = 0
call shift ; Shift in IR bit 0
rrc ; ssxxxxx2 c = 1
call shift ; Shift in IR bit 1
rrc ; sssxxxxx c = 2
move TMS, #1 ; Drive TMS high for last bit
call shift ; Shift in IR bit 2 (Exit1 IR)
call clock1 ; (Update IR)
call clock0 ; (Run Test Idle)
ret
TAP 데이터 레지스터에 쓰기
TAP 컨트롤러의 DR에 값을 시프트 인/아웃하는 것은 IR의 로드/언로드와 유사한 방식으로 이루어진다. 일반적으로 이것은 IR이 100b(TAP 컨트롤러가 시스템 프로그래밍 모드) 또는 010b(TAP 컨트롤러가 디버그 모드)의 두 값 중 하나로 설정된 경우에만 수행된다.
시스템 프로그래밍 모드에 있을 때, DR 레지스터의 로딩과 언로딩은 다음과 같이 수행된다.
DR 레지스터의 시프트 인/아웃은 3비트 폭이다. 모든 3비트는 유효 데이터를 나타낸다.
DR 레지스터로 입력되는 값은 Update-DR 상태에 도달하면 슬레이브 마이크로컨트롤러의 내부 시스템 프로그래밍 레지스터로 복사된다. 이 세 개의 비트는 다음과 같이 사용된다.
비트 0은 슬레이브 마이크로컨트롤러에 의해 레지스터 비트 ICDF.1(SPE)로 액세스 (읽기/쓰기) 가능하며, 시스템 프로그램 인에이블 비트라고도 한다. 이 비트는 리셋 후 부트로더 모드(SPE = 1) 또는 일반 프로그램 실행 모드(SPE = 0)를 실행해야 할지 결정하기 위해 Utility ROM에서 검사를 거친다.
비트 1과 2는 슬레이브 마이크로컨트롤러에 의해 레지스터 비트 ICDF.2-3(PSS0-PSS1)로 액세스 (읽기/쓰기) 가능하며, 프로그래밍 소스 선택 비트라고도 한다. MAXQ2000과 같이 부트로더에 하나 이상의 인터페이스를 지원하는 마이크로컨트롤러에서 이 비트들은 SPE = 1일 때 어떤 부트로더 인터페이스를 사용할지 선택하는 데 사용된다. SPE = 0(일반 프로그램 실행 모드)일 때 이 비트를 설정하면 무시된다.
DR 레지스터에서 출력되는 값은 시스템 프로그래밍 레지스터의 이전 값(Capture-DR 상태에 들어갈 때 시프트 레지스터로 래치)이다.
디버그 모드에 있을 때, DR 레지스터의 로딩과 언로딩은 다음과 같이 수행된다.
DR 레지스터의 시프트 인/아웃은 10비트 폭이다. 시프트 아웃되는 데이터의 경우, 모든 10비트는 유효 데이터(8개의 데이터 비트와 2개의 상태 비트)를 나타낸다. 시프트 인되는 데이터의 경우, 8개의 데이터 비트 값만 사용되고 두 개의 상태 비트는 사용되지 않는다.
DR 레지스터에 시프트 인되는 값의 상위 8비트는 언로드되어 (유틸리티 ROM에서 실행되는) 부트로더에 의해 부트로더 명령의 일부로 읽혀진다.
DR 레지스터에서 시프트 아웃되는 10비트 값은 부트로더에 의해 (명령 출력의 일부로) 로드되는 8비트 값과 TAP 컨트롤러에 의해 설정되는 2비트의 상태 정보로 구성된다.
;==============================================================================
;=
;= shiftDR3
;=
;= Shifts a 3-bit value into the DR register. This operation should only be
;= performed when IR =100b (System Programming Mode).
;=
;= Inputs : A[0] - Low 3 bits contain value to shift into SPB (PSS1:PSS0:SPE)
;= Outputs : None
;= Destroys : AP, APC, A[0], PSW, LC[0]
shiftDR3:
move APC, #80h ; Acc => A[0], turn off auto inc/dec
call clock1 ; (Select DR Scan)
call clock0 ; (Capture DR)
call clock0 ; (Shift DR)
move TMS, #0 ; Drive TMS low
move C, TDO ; xxxxx210 c = s
rrc ; sxxxxx21 c = 0
call shift ; Shift in DR bit 0
rrc ; ssxxxxx2 c = 1
call shift ; Shift in DR bit 1
rrc ; sssxxxxx c = 2
move TMS, #1 ; Drive TMS high for last bit
call shift ; Shift in DR bit 2 (Exit1 DR)
call clock1 ; (Update DR)
call clock0 ; (Run Test Idle)
ret
;==============================================================================
;=
;= shiftDR
;= clock0, clock1, shift
;=
;= Shifts a 10-bit value into and out of the DR register. This operation
;= should only be performed when IR = 010b (Debug/Loader Mode).
;=
;= Inputs : A[0] - Byte value (input) to shift into DR
;= Outputs : A[0] - Byte value (output) shifted out of DR
;= A[1] - Low two bits are status bits 1:0 shifted out of DR
;= A[15] - Byte value shifted in, cached for use by shiftDR_next
;= Destroys : AP, APC, PSW, LC[0]
shiftDR:
move APC, #80h ; Acc => A[0], turn off auto inc/dec
move A[15], A[0] ; Cache input byte value for use by shiftDR_next
sla2 ; Add two empty bits (for status)
call clock1 ; (Select DR Scan)
call clock0 ; (Capture DR)
call clock0 ; (Shift DR)
move TMS, #0 ; Drive TMS low
move C, TDO ; xxxxxxxx76543210 c = s
rrc
call shift ; Shift in DR bit 0
rrc
call shift ; Shift in DR bit 1
rrc
call shift ; Shift in DR bit 2
rrc
call shift ; Shift in DR bit 3
rrc
call shift ; Shift in DR bit 4
rrc
call shift ; Shift in DR bit 5
rrc
call shift ; Shift in DR bit 6
rrc
call shift ; Shift in DR bit 7
rrc
call shift ; Shift in DR bit 8
rrc
move TMS, #1 ; Drive TMS high for last bit
call shift ; Shift in DR bit 9 (Exit1 DR)
call clock1 ; (Update DR)
call clock0 ; (Run Test Idle)
push Acc ; sddd dddd 10xx xxxx
sra4 ; ssss sddd dddd 10xx
sra2 ; ssss sssd dddd dd10
and #0003h ; ---- ---- ---- --10
move A[1], Acc ; Return status bits only in A[1]
pop Acc
and #0FF00h
xch ; Return data bits only in A[0]
ret
JTAG 부트로더 모드에 들어가기
MAXQ2000이 JTAG 부트로더 모드에 들어가기 위해서는 다음 단계가 필요하다.
TAP 컨트롤러를 Test-Logic-Reset 상태로 리셋하여 TAP 컨트롤러를 초기화한다.
명령 레지스터(IR)를 100b로 설정하여 시스템 프로그래밍 모드를 인에이블한다.
데이터 레지스터(DR)를 001b로 설정한다. 이렇게 하면 SPE (System Programming Enable) 비트가 1로 설정되어 부트로더를 인에이블하고, PSS[1:0] (Programming Source Select) 비트가 00b로 설정되어 JTAG 인터페이스가 선택된다.
nRESET을 로우로 유지하여 MAXQ2000을 리셋한다.
nRESET을 해제한다. 이렇게 하면 MAXQ2000은 유틸리티 ROM(8000h)의 표준 리셋 포인트로 이동한다. 유틸리티 ROM 코드는 SPE와 PSS 비트 값을 검사하여 그에 따라 JTAG 부트로더를 동작시킨다. 이 시점에서 부트로더가 실행되고 JTAG 명령을 받아들일 준비가 된다.
명령 레지스터(IR)를 010b로 설정하여 디버그 모드를 인에이블한다. 디버그 모드는 JTAG 부트로더 또는 디버그 엔진과 통신하는 데 사용된다. 우리의 경우도 디버그 모드를 사용하여 부트로더와 통신할 것이다.
DR을 통해 10비트 값을 시프트하여 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 JTAG
call testLogicReset ; Reset JTAG port (ending state: Run-Test-Idle)
move Acc, #IR_SYSTEM_PROG
call shiftIR3 ; Load the System Programming instruction into IR
move Acc, #SP_LOAD_JTAG
call shiftDR3 ; Enable the bootloader in JTAG interface mode
move RST, #1 ; Drive nRESET low
move Acc, #100 ; Delay for 100ms
call delayMS
call clock0 ; Remain in Run-Test-Idle
move RST, #0 ; Release nRESET
move Acc, #100 ; Delay for 100ms
call delayMS
move Acc, #IR_DEBUG
call shiftIR3 ; Enable access to the 10-bit debug shift register
;;;; Bootloader commands may now be shifted through the DR register
call waitForPrompt ; Verify that the bootloader is responding
...
부트로더와의 통신
일단 부트로더가 실행되면 유틸리티 ROM에 있는 부트로더 코드가 DR 시프트 레지스터에서 로드되는 내부 레지스터로부터 명령 코드를 읽는다. 유틸리티 ROM은 또한 JTAG 마스터로 DR 레지스터를 통해 시프트 아웃할 수 있는 또 다른 내부 레지스터에 결과 데이터를 쓴다. 이러한 방식으로 부트로더 코드와 JTAG 마스터는 정보를 교환할 수 있다.
그러나 부트로더 코드와 JTAG 마스터는 동기화되지 않는다. JTAG는 동기 인터페이스이므로 JTAG 클록 레이트가 최대 MAXQ 시스템 클록의 1/8 미만으로 유지되는 한, 두 클록의 정확한 값은 통신에 문제가 되지 않는다. 그러나 MAXQ 시스템 클록 레이트와 수신된 부트로더 명령의 속성은 부트로더가 명령을 수신하고 응답을 전송하는 사이에 발생되는 지연 시간 길이를 결정한다. 예를 들어, 1MHz로 동작하는 MAXQ2000은 10MHz에서 실행하는 MAXQ2000보다 주어진 부트로더 명령에 응답하는 데 더 오래 걸린다. 두 마이크로컨트롤러가 모두 100kHz의 JTAG 클록을 사용하여 통신할 수 있더라도 마찬가지이다. ROM 배너 ID를 리턴하거나 프로그램 메모리로부터 읽는 명령과 같이 단순히 정보를 읽고 리턴하는 명령 역시 플래시 메모리 프로그래밍과 같은 동작을 포함하는 명령보다 시간이 덜 소요된다.
JTAG 인터페이스를 통해 전송되는 데이터는 버퍼링되지 않는다. 만약 이전 명령이 읽혀지기 전에 다른 10비트 명령이 전송되면 이전 명령의 결과는 손실된다. ROM 코드와 TAP 컨트롤러는 이전 데이터가 JTAG 마스터에 의해 언로드되기 전에 부트로더에 의해 추가 데이터가 전송되지 못하도록 보장하지만, 역 방향의 동기화 또한 필요하다. JTAG 마스터는 DR로 시프트 인된 이전 바이트가 부트로더에 의해 읽혀졌는지 알 수 있는 방법이 필요하다. 다음과 같은 방법으로 JTAG 마스터는 언제 다음 바이트를 전송할지 알 수 있다. 이러한 정보는 부트로더의 각 8비트 바이트 출력과 함께 TAP 컨트롤러에 의해 전송되는 2개의 추가 상태 비트로부터 알 수 있다.
그림 4. DR를 통한 데이터와 상태 비트 시프트
그림 4에서 보듯이 TAP 디버그 모드에서 DR에 시프트 인/아웃되는 데이터는 8개의 데이터 비트(비트 2에서 9까지)와 2개의 상태 비트(비트 0과 1)로 구성된다. JTAG 마스터가 데이터를 시프트 인할 때에는 8개의 데이트 비트만 사용된다. 여전히 시프트 인되어야 하는 2개의 상태 비트는 TAP 컨트롤러에 의해 사용되지 않으며, 제로 또는 다른 임의 값으로 설정할 수 있다.
TAP 컨트롤러에서 시프트 아웃되는 10비트 값에서 2개의 상태 비트는 부트로더 또는 디버그 엔진의 상태에 대한 정보를 제공한다. 부트로더가 실행될 때, 일반적으로 마지막 2개의 상태(Debug Busy 또는 Debug Valid)만 발생되며, 다른 2개의 상태 값은 부트로더 모드에서는 발생되지 않는다. (그림 4의 Status/Condition 참조)
상태 비트가 Debug Busy (10b) 값으로 설정된 경우는 JTAG 마스터에 의해 DR에 시프트 인된 이전 값을 부트로더가 아직 읽지 않았음을 의미한다. 이것은 또한 부트로더가 명령을 아직 완료하지 않았기 때문에 시프트 아웃된 8비트 데이터 값이 의미가 없음을 뜻한다. 이 값을 수신하면, JTAG 마스터는 이전에 전송된 바이트 값으로 DR을 재전송하여 부트로더가 액세스할 수 있게 해야 한다. 이러한 동작을 정확히 수행하기 위한 상태 시퀀스는 다음과 같다.
Shift-DR 상태에서 DR에 마지막 비트를 시프트 인하여 Exit1-DR로 천이한 후, 2개의 상태 비트는 JTAG 마스터에 의해 검사되어야 한다.
Debug Busy 값이 수신되면 Pause-DR 상태로 천이하고, 여기에서 Exit2-DR로 천이한 다음, 다시 Shift-DR로 천이한다. 이전 DR 값(이번에는 시프트 인된 값이 아님)을 재로드한 다음, 두 번째 통과한 상태 비트의 값과 상관 없이 Exit1-DR과 Update-DR 상태를 통과한다.
짧은 지연 시간(실행되는 명령에 따라)을 거쳐 바이트 전송을 재시도한다.
상태 비트가 Debug Valid (11b) 값으로 설정되면, 부트로더가 시프트 인된 마지막 바이트를 읽고 응답 바이트를 로드했음을 의미한다. 시프트 아웃된 8비트 값은 유효 데이터를 포함한다.
부트로더 명령 시퀀스를 실행할 때, shiftDR과 shiftDR_next 루틴은 자동으로 이러한 동기화를 수행한다. 시퀀스에서 첫 번째 바이트에는 shiftDR 루틴이 호출되고 shiftDR_next는 이어지는 바이트에서 호출된다. shiftDR_next 루틴은 앞에서 설명했듯이 필요 시 2개의 상태 비트를 검사하고 이전 DR 바이트를 재전송한다는 점만 제외하면 shiftDR과 동일한 동작을 수행한다. sendCommand 루틴은 이러한 모든 동작을 결합하여, 명령이 완료될 때까지 필요하면 지연하고 바이트를 재전송하면서 shiftDR과 shiftDR_next를 호출하여 명령 시퀀스를 전송한다.
;==============================================================================
;=
;= 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/dec
push LC[1]
call waitForPrompt
pop LC[1]
jump C, sendCommand_fail
move Acc, @DP[0] ; Read first byte to transmit
call shiftDR
push Acc
move Acc, A[1]
cmp #3 ; Should be valid status since we had a prompt
pop Acc
jump NE, sendCommand_fail
move @DP[0], Acc ; Store first received byte
move NUL, @DP[0]++ ; Increment data pointer
djnz LC[1], sendCommand_loop
jump sendCommand_pass
sendCommand_loop:
move A[2], #10 ; Number of retries allowed
sendCommand_retry:
move Acc, @DP[0] ; Get next byte to transmit
call shiftDR_next
push Acc
move Acc, A[1]
cmp #3
pop Acc
jump NE, sendCommand_stall
move @DP[0], Acc ; Store received byte
move NUL, @DP[0]++ ; Increment data pointer
djnz LC[1], sendCommand_loop
jump sendCommand_pass
sendCommand_stall:
move LC[0], #8000 ; About a millisecond
djnz LC[0], $
move Acc, A[2]
sub #1
jump NZ, sendCommand_retry
jump sendCommand_fail
부트로더에 의해 제공되는 기능
MAXQ 마이크로컨트롤러의 부트로더 기능은 일반적으로 공유된 패턴을 따르고 있는데, 이는 곧 소자 간에 많은 명령과 상태 코드가 동일하다는 것을 의미한다. 다른 소자들은 내부 프로그램 메모리와 다른 요구사항에 따라 부트로더 명령 세트의 다른 서브세트를 구현할 수 있다. 보다 자세한 내용은 사용하는 MAXQ 마이크로컨트롤러 사용자 가이드 부록을 참조한다. 이 경우에는 MAXQ2000 사용자 가이드 부록의 "In-System Programming" 단원에 있는 부트로더 명령을 참고하면 된다.
다른 MAXQ 부트로더와 마찬가지로 MAXQ2000 부트로더에 의해 제공되는 명령은 0에서 15까지의 명령군으로 나누어진다. 표 5에서 보듯이 각 명령은 명령군(상위 4비트)과 명령에 대한 특정 번호(하위 4비트)의 조합으로 구성되는 명령 바이트로 시작된다. 일반적으로 명령군 0은 모든 소자에 의해 구현되는 기본 정보를 담고 있는 반면, 다른 명령군은 옵션이다. 특정 MAXQ 소자에 의해 지원되는 명령군을 결정하려면 소자의 문서를 참조한다. 명령군 0의 명령 05h(Get Supported Commands)는 해당 부트로더에 의해 어떤 다른 명령군이 지원되는지를 나타내는 비트마스크를 리턴한다.
MAXQ2000에 의해 지원되는 부트로더 명령군은 다음과 같다.
명령군 0 — 정보 및 상태. MAXQ 소자에 관한 기본 정보를 얻는 데 사용할 수 있다. 여기에는 ROM/부트로더의 식별 정보와 버전, 가장 최근 명령으로부터의 결과 (상태 코드) 및 프로그램과 데이터 메모리 크기가 포함된다. 이 명령군에는 소자의 모든 프로그램과 데이터 메모리를 삭제하는 Master Erase 명령도 포함되어 있다.
명령군 1 — 가변 길이 로드. 프로그램 (플래시) 또는 데이터 (RAM) 메모리를 로드하는 데 사용할 수 있다.
명령군 2 — 가변 길이 덤프. 프로그램 또는 데이터 메모리의 내용을 읽는 데 사용할 수 있다.
명령군 3 — CRC 가변 길이. 프로그램 또는 데이터 메모리의 지정된 범위에 대해 계산된 CRC-16 값을 얻는 데 사용할 수 있다.
명령군 4 — 가변 길이 검사. 프로그램 또는 데이터 메모리의 지정된 범위가 JTAG 마스터에 의해 제공되는 데이터와 일치하는지 여부를 검사하는 데 사용할 수 있다.
명령군 5 — 가변 길이 로드 및 검사. 로드 및 검사 명령 기능을 하나의 명령으로 결합한다.
명령군 6 — 가변 길이 삭제. MAXQ2000에서 이 명령은 데이터 RAM의 지정된 영역을 제로(0)로 소거하는 데 사용할 수 있다.
명령군 7 — 고정 길이 삭제. MAXQ2000에서 이 명령은 Master Erase 명령으로 한번에 모든 플래시 메모리를 지우는 대신 플래시 프로그램 메모리의 개별 페이지를 삭제하는 데 사용할 수 있다.
MAXQ 마이크로컨트롤러의 TAP 컨트롤러를 사용하여 마이크로컨트롤러를 JTAG 로더 모드에 둔 다음(이 프로세스는 모든 MAXQ 마이크로컨트롤러에 동일함), 첫 번째 단계는 로더의 응답 여부를 결정하는 것이다. 이를 수행하는 가장 빠른 방법은 부트로더 명령 코드 00h(No Operation)를 반복적으로 전송하는 것이다. 각 부트로더 명령이 완료되면, 부트로더는 프롬프트 ('>' 또는 3Eh) 바이트로 응답한다. 00h를 전송하여 3Eh 응답을 수신하면, 부트로더가 실행되고 명령을 받아들일 준비가 된다.
표 5. 범용 MAXQ 부트로더 명령군
Bit 7
Bit 6
Bit 5
Bit 4
Bit 3
Bit 2
Bit 1
Bit 0
Code
Family/Command
0
0
0
0
x
x
x
x
0 x h
Family 0—Informational Commands
0
0
0
0
0
0
0
0
00h
No Operation
0
0
0
1
01h
Exit Loader
0
0
1
0
02h
Master Erase
0
0
1
1
03h
Password Match
0
1
0
0
04h
Get Status
0
1
0
1
05h
Get Supported Commands
0
1
1
0
06h
Get Code Memory Size
0
1
1
1
07h
Get Data Memory Size
1
0
0
0
08h
Get Loader Version
1
0
0
1
09h
Get Utility ROM Version
1
0
1
0
0Ah
Set Word/Byte Access Mode
1
1
0
1
0Dh
Get ID Information
0
0
0
1
x
x
x
x
1 x h
Family 1—Variable-Length Load
0
0
0
1
0
0
0
0
10h
Load Code Variable Length
0
0
0
1
0
0
0
1
11h
Load Data Variable Length
0
0
1
0
x
x
x
x
2 x h
Family 2—Variable-Length Dump
0
0
1
0
0
0
0
0
20h
Dump Code Variable Length
0
0
1
0
0
0
0
1
21h
Dump Data Variable Length
0
0
1
1
x
x
x
x
3 x h
Family 3—Variable-Length CRC
0
0
1
1
0
0
0
0
30h
CRC Code Variable Length
0
0
1
1
0
0
0
1
31h
CRC Data Variable Length
0
1
0
0
x
x
x
x
4 x h
Family 4—Variable-Length Verify
0
1
0
0
0
0
0
0
40h
Verify Code Variable Length
0
1
0
0
0
0
0
1
41h
Verify Data Variable Length
0
1
0
1
x
x
x
x
5 x h
Family 5—Variable-Length Load and Verify
0
1
0
1
0
0
0
0
50h
Load/Verify Code Variable Length
0
1
0
1
0
0
0
1
51h
Load/Verify Data Variable Length
0
1
1
0
x
x
x
x
6 x h
Family 6—Variable-Length Erase
0
1
1
0
0
0
0
0
60h
Erase Code Variable Length
0
1
1
0
0
0
0
1
61h
Erase Data Variable Length
0
1
1
1
x
x
x
x
7 x h
Family 7—Reserved (for expansion)
1
0
0
0
x
x
x
x
8 x h
Family 8—Reserved (for expansion)
1
0
0
1
x
x
x
x
9 x h
Family 9—Fixed-Length Load
1
0
0
1
0
0
0
0
90h
Load Code Fixed Length
1
0
0
1
0
0
0
1
91h
Load Data Fixed Length
1
0
1
0
x
x
x
x
A x h
Family A —Fixed-Length Dump
1
0
1
0
0
0
0
0
A0h
Dump Code Fixed Length
1
0
1
0
0
0
0
1
A1h
Dump Data Fixed Length
1
0
1
1
x
x
x
x
B x h
Family B—Fixed-Length CRC
1
0
1
1
0
0
0
0
B0h
CRC Code Fixed Length
1
0
1
1
0
0
0
1
B1h
CRC Data Fixed Length
1
1
0
0
x
x
x
x
C x h
Family C—Fixed-Length Verify
1
1
0
0
0
0
0
0
C0h
Verify Code Fixed Length
1
1
0
0
0
0
0
1
C1h
Verify Data Fixed Length
1
1
0
1
x
x
x
x
D x h
Family D—Fixed-Length Load and Verify
1
1
0
1
0
0
0
0
D0h
Load/Verify Code Fixed Length
1
1
0
1
0
0
0
1
D1h
Load/Verify Data Fixed Length
1
1
1
0
x
x
x
x
E x h
Family E —Fixed-Length Erase
1
1
1
0
0
0
0
0
E0h
Erase Code Fixed Length
1
1
1
0
0
0
0
1
E1h
Erase Data Fixed Length
1
1
1
1
x
x
x
x
F x h
Family F—Reserved (device specific)
JTAG 슬레이브 마이크로컨트롤러의 식별
부트로더를 올리고 실행하면, 다음 단계는 슬레이브 MAXQ 마이크로컨트롤러를 식별하는 것이다. 명령군 0의 명령 0Dh(Get ID Information)는 소자와 유틸리티 ROM 버전을 식별하는 가변 길이 ASCII 스트링(제로로 종료)을 리턴한다.
우리의 예제 프로그램은 이러한 정보를 얻은 다음, 이 정보를 데모의 일부로 직렬 포트로 출력한다. 이를 수행하는 데 사용되는 루틴은 getBanner이다.
;==============================================================================
;=
;= getBanner
;= waitForPrompt
;= shiftDR
;= clock0, clock1, shift
;=
;= Executes command 0Dh to retrieve the ROM (device ID) banner and prints
;= the banner text out over the serial port.
;=
;= Inputs : None
;= Outputs : C - Set on JTAG communication error
;= Destroys : AP, APC, Acc, PSW, LC[0]
;=
getBanner:
call waitForPrompt
jump C, getBanner_fail
move Acc, #CMD_GET_ROM_BANNER
call shiftDR
move Acc, #00h
call shiftDR
getBanner_loop:
move Acc, #00h
call shiftDR
cmp #0FFh ; The banner is ASCII, so receiving this character
; most likely indicates that the JTAG lines are
; floating high and that no device is connected
jump E, getBanner_fail
jump Z, getBanner_done
call txChar
jump getBanner_loop
getBanner_done:
call txNewline
jump getBanner_pass
getBanner_fail:
move C, #1
ret
getBanner_pass:
move C, #0
ret
프로그램 메모리 삭제
MAXQ2000에 포함된 플래시 프로그램 메모리는 프로그래밍하기 전에 삭제해야 한다(0FFFFh로 설정). JTAG 데모 애플리케이션은 02h (Master Erase) 부트로더 명령을 전송하여 부트로더에게 모든 프로그램과 데이터 메모리를 삭제하도록 명령함으로써 플래시 메모리를 삭제한다. 이 명령은 또한 패스워드 록 (lock) 비트를 삭제하므로, 지원되는 모든 명령군은 인에이블된다.
MAXQ 소자에 따라 이 02h (Master Erase) 명령은 완료하는 데 몇 초가 걸릴 수 있다. 이 명령은 단일 바이트 명령이므로 언제 완료되는지 결정하는 가장 쉬운 방법은 부트로더가 3Eh를 리턴하여 명령이 완료되었다는 것을 나타낼 때까지 No Operation (00h) 명령과 1밀리초 지연을 연속해서 전송하는 것이다. 이 방법은 아래의 masterErase 루틴에서 볼 수 있다.
;==============================================================================
;=
;= masterErase
;=
;= Executes command 02h (Master Erase) to clear all program and data memory.
;=
;= Inputs : None
;= Outputs : C - Set on JTAG communication error
;= Destroys : Acc, PSW, LC[0], LC[1]
;=
masterErase:
call waitForPrompt
jump C, masterErase_fail
move Acc, #CMD_MASTER_ERASE
call shiftDR
move Acc, #00h
call shiftDR
move LC[1], #5000 ; Number of retries before returning an error
masterErase_loop:
move Acc, #CMD_NOP
call shiftDR
cmp #3Eh
jump E, masterErase_pass
move LC[0], #8000 ; Delay for about a millisecond
djnz LC[0], $
djnz LC[1], masterErase_loop
masterErase_pass:
move C, #0
ret
masterErase_fail:
move C, #1
ret
상태 정보 가져오기
MasterErase(또는 거의 모든 다른 부트로더 명령)이 완료되면, 04h (Get Status) 명령을 사용하여 명령이 성공적으로 완료되었는지 결정할 수 있다. Get Status 명령은 2바이트의 데이터를 리턴한다. 첫 번째 바이트는 상태 플래그(패스워드 록 설정/해제, 워드/바이트 모드 액티브 및 기타 정보를 나타냄)를 포함하고 있으며, 두 번째 바이트는 단일 바이트 상태 코드이다.
마지막 명령이 성공적으로 완료되면 상태 코드는 언제나 00h(No Error)이다. 제로 이외의 모든 상태 코드는 에러를 나타낸다. 상태 코드의 완전한 리스트는 MAXQ2000 사용자 가이드 부록에 나와 있다. 몇 가지 공통 에러 코드는 다음과 같다.
01h/02h — Family Not Supported/Invalid Command. 이 에러 코드는 대개 JTAG 마스터의 통신 글리치 또는 정렬 에러를 나타낸다. JTAG 마스터가 주어진 명령 코드에 대해 부트로더가 예상하는 바이트보다 더 많은 (또는 더 적은) 바이트를 전송하면, 부트로더는 데이터 바이트 중 하나를 새로운 명령의 시작으로 해석한다.
03h — No Password Match. 이 에러 코드는 JTAG 마스터가 먼저 패스워드 록을 삭제하지 않고 패스워드로 보호되는 (보통 명령군 0에 없는 명령을 포함) 명령을 사용했음을 나타낸다. JTAG 마스터가 이미 워드 어드레스 0010h - 001Fh로 로드된 코드를 갖는 부분에 액세스하는 경우 이 에러는 발생한다. 이 경우, 해당 부분을 Master Erased하거나 Password Match 명령(03h)을 사용하여 해당 부분의 록을 해제해야 한다.
05h — Verify Failed. 검사 단계가 Load/Verify 또는 Verify 명령에서 실패했음을 나타낸다. 통신 글리치 후 또는 이전에 프로그래밍된 플래시 메모리를 먼저 삭제하지 않고 재프로그래밍을 시도 한 경우 이 에러가 발생할 수 있다.
프로그램 메모리에 코드 로드
JTAG 부트로더의 기능을 시연하려면 데모 애플리케이션은 JTAG 연결을 통해 코드를 슬레이브 MAXQ2000으로 로드해야 한다. 이 예에서, 로드된 코드는 LCD 컨트롤러를 시작하고 LCD 디스플레이에 4디지트 숫자를 보여주는 간단한 루틴이다.
슬레이브 MAXQ2000에 로드된 코드는 다음과 같은 간단한 데모 프로젝트를 기반으로 한다.
그러나 우리는 하드 코드화된 헥사 파일 대신 데모 애플리케이션으로부터 코드 바이트를 로드할 것이므로(MTK 또는 MAX-IDE로 코드를 로드하는 경우와 같이), 데모 애플리케이션은 사용자 입력에 따라 로드된 애플리케이션을 수정할 것이다.
코드를 로드하기 전에 JTAG 통신 데모 애플리케이션은 먼저 사용자에게 4디지트 십진수를 입력하도록 요청한 후, 다음과 같이 로드되는 애플리케이션을 수정한다.
LCD에 표시되는 숫자는 사용자가 입력한 4디지트 수이다.
패스워드 영역(워드 어드레스 010h에서 시작)의 처음 4바이트는 사용자가 입력한 4개 문자의 ASCII 값으로 프로그래밍된다.
애플리케이션 코드는 세 번의 호출을 통해 데모에 의해 부트로더 명령 10h(Load Code, Variable Length)으로 로드된다. 이 명령에 대한 파라미터는 다음을 포함한다. 로드할 바이트 수(워드 정렬을 위해 코드 메모리 로드 시 짝수여야 함), 시작 어드레스, 그리고 데이터 자체이다. MAXQ 메모리는 little-endian이므로, 애플리케이션은 먼저 각 프로그램 워드의 최하위 바이트를 전송해야 한다.
Load Code Variable Length 명령(10h)을 사용하는 대신 Load and Verify Code Variable Length 명령(50h)을 사용한다. 후자의 명령은 코드 로드 동작과 검사 단계를 결합한 것이다.
또 다른 방법으로 Verify Code Variable Length 명령(40h)을 호출하여 개별적으로 검사를 수행할 수 있다.
부트로더에서 로드된 코드를 검사하도록 하는 대신, Dump Code Variable Length(20h)를 사용하여 JTAG 호스트가 로드된 값을 직접 검사할 수 있어 로드된 코드가 전송된 데이터와 일치하는지 검사할 수 있다.
프로그램 메모리로부터 코드 덤프
모든 코드가 로드된 후, JTAG 데모의 마지막 단계는 단일 블록으로 모든 코드를 다시 읽는 것이다. 이 읽기는 Dump Code Variable Length (20h) 명령을 부트로더에 전송함으로써 수행된다. 이 명령에 대한 파라미터는 덤프(읽기)를 시작할 어드레스와 덤프할 바이트 수이다. 모든 JTAG 부트로더 명령과 마찬가지로 다시 읽혀진 모든 바이트에 대해 한 바이트씩 전송되어야 함에 유의한다. 따라서 이 명령에는 프로그램 메모리로부터 읽혀질 각 바이트에 대해 하나씩, 많은 수의 제로 패드 바이트가 필요하다.
MAX-IDE가 설치되어 있지 않은 경우, MAXQ2000 EV 킷에 포함된 문서를 참조하여 다운로드하고 설치한다.
MTK가 설치되어 있지 않은 경우, MAXQ2000 EV 킷에 포함된 문서를 참조하여 다운로드하고 설치한다.
위의 그림 1과 같이 LCD 도터보드를 슬레이브 MAXQ2000 킷의 헤더 J3에 연결한다. LCD 도터보드는 MAXQ2000 킷 보드의 상단에 닿지 않아야 한다.
MAXQ2000 EV 킷 보드에 모두 (Y1에) 8.00MHz 크리스털을 설치한다.
표 1에 나와 있는 것과 같이 핀을 마스터 MAXQ2000 핀에 연결하여 마스터 MAXQ2000 킷의 프로토타이핑 영역에 2 x 5 JTAG 헤더를 설치한다.
표 2에 나와 있는 것과 같이 직렬-JTAG 보드와 2개의 MAXQ2000 EV 킷 보드에서 점퍼와 DIP 스위치를 구성한다.
DB9 직렬 케이블을 PC의 COM1 포트에서 직렬-JTAG 보드의 J1로 연결한다.
첫 번째 5V 전원을 직렬-JTAG 보드의 J2에 연결한다.
두 번째 5V 전원을 슬레이브 MAXQ2000 EV 킷 보드의 J1에 연결한다.
첫 번째 JTAG 케이블을 직렬-JTAG 보드의 P2에서 마스터 MAXQ2000 킷의 J4로 연결한다. 두 JTAG 헤더에서 적색 와이어는 핀 1로 가야 한다.
두 번째 JTAG 케이블을 마스터 MAXQ2000 킷의 프로토타이핑 영역 JTAG 헤더에서 슬레이브 MAXQ2000 킷의 J4로 연결한다. 두 JTAG 헤더에서 적색 와이어는 핀 1로 가야 한다.
JTAG 데모 컴파일링 및 로드
JTAG 데모 소프트웨어 패키지를 다운로드하여 작업 디렉토리에 압축을 푼다.
MAX-IDE를 시작한다.
두 5V 전원을 모두 켠다.
메뉴에서 Project Open Project를 선택하고, maxqjtag.prj project 파일을 선택하여 연다.
메뉴에서 Debug Make를 선택한다. "Build Successful" 메시지가 표시된다.
메뉴에서 Debug Run을 선택한다. 일련의 "Loading" 메시지가 표시되면서 "Done"이 나타난다.
메뉴에서 Debug Stop을 선택한다.
MAX-IDE를 닫는다.
전원을 끈다.
JTAG 데모 실행
전원을 끈 상태에서 직렬-JTAG 보드에서 DB9 직렬 케이블을 분리한다.
DB9 케이블을 마스터 MAXQ2000 킷 보드의 J5에 연결한다.
MTK를 시작한다. 시작 대화 상자에서 "Dumb Terminal"을 선택한다.
메뉴에서 Options Configure Serial Port를 선택한다. 대화 상자에서 포트를 COM1로, 속도를 9600 baud로 설정한다.
메뉴에서 Target Open COM1 at 9600 baud를 선택한다.
전원을 켠다.
애플리케이션이 로드되고 모든 것이 올바르게 연결되었다면, 직렬 포트를 통해 다음과 같은 텍스트가 (그림 5) 출력될 것이다.
그림 5. 데모 애플리케이션, 직렬 포트 프롬프트
이제 4디지트 십진수를 입력한다. 다음에 ENTER 키를 누를 필요는 없다. 데모 애플리케이션에서 나머지 동작(마스터 삭제, 코드 로드, 코드 덤프)을 완료하고, 프로그램 메모리에서 덤프되는 바이트 헥사 값과 함께 결과를 출력할 것이다(그림 6).
그림 6. 데모 애플리케이션, 직렬 포트 출력
결론
MAXQ 마이크로컨트롤러에 의해 제공되는 JTAG 부트로더는 표준 명령 세트를 사용하여 외부 JTAG 마스터가 모든 MAXQ 마이크로컨트롤러를 쉽게 식별하고 프로그래밍할 수 있게 한다. 본 애플리케이션 노트에 포함된 코드를 길잡이로 사용하여 표준 부트로더 명령 세트를 지원하는 모든 MAXQ 마이크로컨트롤러의 코드와 데이터 메모리 내용을 식별하고, 초기화하고, 로드 및 검사할 수 있는 완전한 기능의 JTAG 부트로더 마스터 애플리케이션을 구현할 수 있을 것이다.