jtag:tutorials:start

Dies ist eine alte Version des Dokuments!


JTAG lernen - für ungeduldige

Warum bist Du hier gelandet? Warum willst Du JTAG verstehen, ohne es aber gleich monatelang studieren zu wollen? Vielleicht aus dem gleichen Grund wie ich: „Nur mal eben schnell nen Firmwaredump von nem Flash einer Steuerung lesen oder neu programmieren“ - irgendsowas in der Art. Und dann findet man im Netz massig Infos die einen aber nur tagelang mit Grundlagen oder abgedrehtem Zeugs beschäftigen ohne das man wirklich voran kommt. Seitenweise dämliche Posts in irgendwelchen Foren und immer wenns ins Detail geht, also in die Praxis ist plötzlich schluß und man ist genauso weit wie vorher.

Wenn es Dir genauso ging bist Du HIER genau richtig! :-) Nachfolgend will ich Dir mit wenig Worten und viel Praxis die Funktion von JTAG näher bringen. Alles mit Standard-Mitteln, also kauf nicht gleich irgendwelche JTAG-Debugger Hardware für hunderte von Euros, zum lernen brauchts' das nicht.

Ich will mich nachfolgend so kurz wie möglich halten. Wer etwas nicht versteht oder doch genauer wissen will was dahinter steckt, für den hab ich immer mal einen Zusatz „Nerd-Wissen“ reingepackt. Der leitet auf eine separate Seite mit detaillierteren Infos zum jeweiligen Thema.

Genug geschwafelt - LOS GEHTS!

Geeignetes Gerät für die Experimente finden

Wo und wie anfangen? Am besten nicht mit dem eigentlichen Probanten. Such Dir aus der Bastelkiste oder auf kleinanzeigen ein billiges Gerät, z.B. wie ich einen alten Linksys WRT54 Router, von dem Du genau weißt das der eine JTAG-Schnittstelle besitzt. Das bekommst Du mit ein paar Google-Suchen leicht raus.

Nimm ein Gerät von dem die JTAG-Schnittstelle bekannt und bereits dokumentiert ist. Google einfach danach: „<GERÄTENAME> JTAG Signale Header“. Später lernen wir noch, wie man die Schnittstelle eines nicht bekannten Systems ermittelt. Für den Anfang wäre das aber der falsche Weg, glaub mir. Sobald Du also weißt wo auf Deinem Test-Board die JTAG-Anschlüsse TCK, TMS, TDI, TDO (und natürlich GND) liegen kann es schon losgehen.

Womit und wie kann ich Daten über die JTAG-Schnittstelle senden und lesen?

Dafür sind die „Test-Adapter“ da. Die machen die Kommunikation vom PC aus möglich und kommen meist auch mit einer Steuersoftware daher. Anstelle jetzt aber hunderte von Euros dafür auszugeben, verwenden wir erstmal einen billigen 5,- € Arduino Nano (oder Uno) und kommunizieren direkt bzw. per Serial-Terminal mit dem JTAG-Chip.

Damit uns der nicht wegen unterschiedlicher Betriebs- und IO-Signalspannung hopps geht, schalten wir noch einen Pegelwandler zwischen ihm und der JTAG-Schnittstelle vom Gerät. Ich verwende hier einen 8-Kanaligen mit nem „TXS0108“ IC drauf. Der kostet auf Ebay auch nur ein paar Euro.

UND HEY, DAS IST WICHTIG nicht einfach auf den Pegelwandler verzichten, sonst grillst Du womöglich gleich Dein Testgerät. (Nerd-Wissen: Was macht ein Pegelwandler und wozu braucht man das?)

Prinzipschaltbild
[PC]<---USB---> [Arduino]<--->[Pegelwandler]<--->[JTAG-Schnittstelle vom Testgerät]
Schaltplan und physikalischer Aufbau

<SCHALTPLAN>

<FOTO VOM AUFBAU>

Arduino Pegelwandler HS Pegelwandler LS JTAG-Signal Kabelfarbe
D7 H1 L1 TCK Gelb
D8 H2 L2 TMS Grau
D9 H3 L3 TDI Grün
D10 H4 L4 TDO Lila
Software-Grundgerüst für den Arduino

Zunächst definieren wird die Signale mit Namen um sie einfach verwenden zu können:

#define TCK 7
#define TMS 8
#define TDI 9
#define TDO 10

Im setup() Teil des Codes konfigurieren wir damit die Signalports und stellen ihren Grundzustand ein:

void initPins()
{
  pinMode(TCK, OUTPUT);
  pinMode(TMS, OUTPUT);
  pinMode(TDO, OUTPUT);
  pinMode(TDI, INPUT);
 
  digitalWrite(TCK, HIGH);
  digitalWrite(TMS, HIGH);
  digitalWrite(TDO, HIGH);
}
 
void setup()
{
  initPins();
  ...
}
Grundlegende Kommunikation

Diese ist seriell, sowohl für die Daten als auch für die Befehle. Die Daten werden an den TDI und TDO-Pins gesendet bzw. empfangen, die Befehle über den TMS-Pin. Wann die jeweilige Information an den Pins stabil ist und übernommen wird, regelt die Taktleitung TCK. Hierbei sind die Übergänge von 0 nach 1 bzw. 1 nach 0 entscheident.

Intern liegt zwischen TDI und TDO ein Schieberegister. Die Breite dieses und die Verwendung der darin befindlichen Daten bestimmt der Betriebsmodus des Chips, der über JTAG-Befehle gesteuert wird.

Sind mehrere JTAG-fähige Chips auf einem Board vorhanden, werden deren Datenleitungen in Reihe geschaltet. Also TDO des einen an TDI des nächsten Chips. Dadurch ergibt sich eine Kette, „JTAG-Chain“ genannt, der einzelnen Schieberegister:

TAP Chip 1 Chip 2

TDO ---->| TDI [010100011] TDO |---->| TDI [11111] TDO |---.
TDI <------------------------------------------------------'                                                   

Die Befehls- und Taktleitung (TMS, TCK) liegt an allen Chips parallel an, was bedeutet das immer alle den gleichen Betriebszustand einnehmen werden.

Daten an TDI einlesen

Die Norm definiert das der Logikpegel (Bit) von TDI bei der steigenden Flanke von TCK in das Schieberegister übernommen wird. Solange TCK also '0' ist, kann TDI von aussen anglegt werden. In Arduino-Code säh das so aus:

digitalWrite(TCK, LOW); // wer auch immer vor uns TDI einstellt, kann dies nun nach herzenslust tun...
digitalWrite(TCK, HIGH); // Hier ist der Spaß vorbei, nun ist der Signalpegel an TDI bindend und darf nicht mehr verändert werden!
bit = digitalRead(TDI); // Wir können das Bit einlesen und in unser "Schieberegister" stellen.
data = (data << 1) & bit;
Daten auf TDO senden

Bei der fallenden Flanke von TCK wird das nächste Bit vom Schieberegister an TDO ausgegeben.

digitalWrite(TCK, HIGH); // Ausgangszustand
bit = data & 1;
digitalWrite(TDO, bit);
digitalWrite(TCK, LOW);
data >> 1;
Daten auf TMS senden

TMS ist unidirektional, also eine reine Sendeleitung aus sicht des Test-Adapters und eine reine Empfangsleitung aus Sicht der JTAG-Controller (Chips). Das Bit am TMS-Pin wird bei der steigenden Flanke von TCK von den JTAG-Controllern aller in der Chain befindlichen Chips übernommen und der Zustand der internen Statemachine entsprechend geändert.

bit = x; // 0 oder 1
digitalWrite(TCK, LOW);
digitalWrite(TMS, bit);
digitalWrite(TCK, HIGH);
Welche Betriebszustände kennt der JTAG-Controller und wozu dienen diese?

Nach dem einschalten befindet sich der JTAG-Controller im Betriebszustand „Test-Logic-Reset“. Solange am TMS-Pin ein HIGH-Pegel anliegt wird dieser Zustand nicht verlassen, egal wieviele Takte an TCK passieren. Man nennt diesen Zustand einen „stabilen Zustand“. Stabil, weil man so an TDI Daten hineintakten kann, ohne das sich dadurch der Zustand ändert.

In diesem Zustand passiert JTAG-mäßig einfach nichts. Der Chip macht was er will oder soll ohne das wir darauf Einfluß nehmen. Eine Statemachine beschreibt die stabilen Zustände und den Übergang dort hin. (Nerd-Wissen …)

Für uns ist wichtig, das man über TMS den Controller dazu veranlassen kann, entweder das Datenregister (DR) zwischen TDI und TDO zu verbinden, oder das Befehlsregister (IR). Sobald man das getan hat, gehen die an TDI eingetakteten Bits in das jeweilige Register. Hat man alle Bits so eingetaktet, weist man den Controller über TMS an die Daten zu übernehmen. Im Falle vom Befehlsregister wird dann ein bestimmter Betriebszustand angenommen.

Die JTAG-Norm definiert hier nur wenige:

  • BYPASS - Dieser Befehl veranlasst den Chip ein 1-Bit Register zwischen TDI und TDO zu legen. Die darin befindlichen Daten irgnoriert der Chip. Bei jedem Takt wird also das zuletzt darin befindliche Bit auf TDO gelegt und das an TDI in das Register übernommen.
  • EXTTEST - Zwischen TDI und TDO wird das sog. „Boundary Scan Register“ (BSR) geschaltet. Damit können die IO-Pins des Chips abgefragt oder gesetzt werden.
  • SAMPLE/PRELOAD

Darüber hinaus unterstützen manche Chips auch noch diese:

  • IDCODE - Es wird ein spezielles register zwiscneh TDI und TDO geschaltet, welches einen 32-Bit breiten Identifizierungscode des Chips enthält.
  • INTEST - Wie EXTTEST, jedoch werden nicht die physikalischen Pins gelesen oder beschrieben, sondern die Signale der Core-Logic.

Will man also nur die Daten eines bestimmten Chips lesen oder schreiben, muss man wissen an welcher Stelle der Chain sich dieser befindet.

Mit JTAG kann man mehr als einen Chip verbinden. Diese sind dabei datentechnisch in Reihe geschaltet und man nennt das eine „JTAG-Chain“. Man kann sich das wie eine Verkettung von Schieberegistern vorstellen:

Die Kommunikation vom Testadapter (unserem Arduino) mit der Chain erfolgt also seriell. Jeder Chip enthält seinen eigenen JTAG-Controller. Sein Betriebsmodus bestimmt, was mit den einfließenden Daten an TDI zu tun ist und welche Daten an TDO anliegen. Dieser Modus wird über die separate TMS-Leitung eingestellt, ebenfalls seriell.

Zur Synchronisation dient das Clocksignal TCK. Bei der steigenden, bzw. fallenden Flanke des Signals werden bestimmte Ein-, Ausgangssignale verarbeitet. Man muss wissen das TCK und TMS im Gegensatz zu TDI und TDO bei allen JTAG-Chips einer Chain parallel anliegen. Man steuert also über TMS nicht nur einen Chip sondern alle und der Betriebszustand ist immer für alle gleich.

Es gilt als erstes herauszufinden wieviele Chips in einer Chain verkettet sind. Das ist die Basis für alle weiteren Untersuchungen. Später wirst Du das verstehen!

Nach dem einschalten des Chips befindet sich der Controller im Zustand „Test-Logic Reset“. Im Modus „Shift IR“ verbindet der Controller das Befehlsregister an TDI+TDO. Dann kann man einen JTAG-Befehl senden. Oder im Modus „Shift DR“ die Scandaten des Chips auslesen oder einschreiben. Dazu später mehr.

Wie finde ich heraus wieviele Chips in einer JTAG-Chain sind?

Das Verfahren ist im groben so: Man versetzt den JTAG-Controller im Chip in den Bypass-Modus. Dabei verbindet er ein 1-Bit Schieberegister zwischen TDI und TDO. Der Inhalt interessiert den Chip nicht. Jetzt besteht die Chain aus Anschließend schiebt man erstmal ne große Menge an '1'en durch die Chain.

  • jtag/tutorials/start.1520862193.txt.gz
  • Zuletzt geändert: Mon. 12.03.2018 14:43
  • von wikiadmin