Arduino als JTAG Programmer

Ich würde gerne meine Honeywell Heizkörperregler HR-20 Rondostat zeitgesteuert nicht nur passiv auslesen (das geht auch schon mit der nativen Firmware), sondern auch über einen ESP8266 steuern. Das wurde schon von schlauen Leuten vorgedacht, und daher gibt es mit OpenHR20 auch eine neue Firmware, welche man mittels JTAG-Interface auf das HR20 flashen kann.

Ich habe nur kein JTAG-Programmierer zur Hand, aber dafür einen Arduino Uno. Ich habe den Ansatz eines JTAGduino gefunden. Die notwendigen Lötarbeiten waren schnell erledigt, ich habe die nachfolgende Steckerbelegung (Quelle) berücksichtigt, um den JTAGduino zu versorgen. Um eine durchgehende Stiftleiste am Arduino Uno verwenden zu können, habe ich die gesamte Kommunikation auf die Analogen Ports A0 bis A4 gelegt.

Die ersten Tests mit den von JTAGduino mitgelieferten Skripten verliefen erfolgreich, wenn ich das JTAG-Interface vom Arduino an den HR20 angeschlossen habe und mein Arduino an meinen Linux-Rechner per USB verbunden ist, kommt folgende Ausgabe:

user@host:~/work/JTAGduino$ ./host_test.py 
if_ver_major = 0; if_ver_minor = 1
fw_ver_major = 0; fw_ver_minor = 1
set_serial_speed(115200) = 0
clear pin TDI rsp = 1
set pin TDI rsp = 0
get pin TDO rsp = 0; val = 0
jtag_clock(1,1): rsp = 1; tdo = 0
jtag_clock(1,0): rsp = 0; tdo = 1
jtag_sequence([1,1,1,1], [1, 1, 0, 1]), rsp = 0; tdo_seq = [1, 0, 0, 0]
jtag_sequence([1] * 255, [1] * 255), rsp = 0; tdo_seq = [1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
device.set_jtag_speed(1) = 255
jtag_sequence([1] * 255, [1] * 255), rsp = 127; tdo_seq = []
user@host:~/work/JTAGduino$ ./readid.py 
Traceback (most recent call last):
  File "./readid.py", line 81, in 
    if rsp != 0: raise Exception('error: set_jtag_speed returned %d' % rsp)
Exception: error: set_jtag_speed returned 191
user@host:~/work/JTAGduino$ ./readid.py 
#Taps = 1
Device identifier registers (beginning from closest to TDO):
0x6940503F

Die Fehlermeldung habe ich absichtlich drin gelassen, damit man auch andere den Grund für den Fehler finden können. Man muss vor JEDEM Ansprechen des JTAGduino diesen manuell auf durch einen Druck auf den Reset-Button am Arduino zurücksetzen.

Die ID 0x6940503F ist bereits die vom HR20, wir können also grundsätzlich per JTAG bereits mit ihm kommunizieren.

Als nächstes muss ich noch herausfinden, wie avrdude mit dem so gebauten „Programmer“ sprechen kann, bisher habe ich nur ermitteln können, dass es eine mögliche Liste von Programmern in avrdude vordefiniert gibt: (Der Pfad zur Arduino-Installation muss natürlich angepasst werden)

user@host:~/work/JTAGduino$ PATH=$PATH:/arduino-1.8.1/hardware/tools/avr/bin avrdude -c dslfkj -C /arduino-1.8.1/hardware/tools/avr/etc/avrdude.conf 2<&1 | grep -i jtag
  atmelice         = Atmel-ICE (ARM/AVR) in JTAG mode (avrdude: jtag3_open_common(): JTAGICE3/EDBG port names must start with "usb")
  dragon_jtag      = Atmel AVR Dragon in JTAG mode
  jtag1            = Atmel JTAG ICE (mkI)
  jtag1slow        = Atmel JTAG ICE (mkI)
  jtag2            = Atmel JTAG ICE mkII
  jtag2avr32       = Atmel JTAG ICE mkII im AVR32 mode
  jtag2dw          = Atmel JTAG ICE mkII in debugWire mode
  jtag2fast        = Atmel JTAG ICE mkII
  jtag2isp         = Atmel JTAG ICE mkII in ISP mode
  jtag2pdi         = Atmel JTAG ICE mkII PDI mode
  jtag2slow        = Atmel JTAG ICE mkII
  jtag3            = Atmel AVR JTAGICE3 in JTAG mode
  jtag3dw          = Atmel AVR JTAGICE3 in debugWIRE mode
  jtag3isp         = Atmel AVR JTAGICE3 in ISP mode
  jtag3pdi         = Atmel AVR JTAGICE3 in PDI mode
  jtagkey          = Amontec JTAGKey, JTAGKey-Tiny and JTAGKey2
  jtagmkI          = Atmel JTAG ICE (mkI)
  jtagmkII         = Atmel JTAG ICE mkII
  jtagmkII_avr32   = Atmel JTAG ICE mkII im AVR32 mode
  o-link           = O-Link, OpenJTAG from www.100ask.net (avrdude: Error: no libftdi or libusb support. Install libftdi1/libusb-1.0 or libftdi/libusb and run configure/make again.)
  xil              = Xilinx JTAG cable (tested - avrdude: can't claim device "/dev/ttyACM0": Inappropriate ioctl for device)
  xplainedpro      = Atmel AVR XplainedPro in JTAG mode

Den nachfolgenden Befehl nutze ich zum Test, ob der jeweilige Programmer-Typ funktioniert, er sollte bei erfolgreicher Kommunikation nur Backups von fuses anlegen, also führt noch keine schreibenden Operationen aus:

user@host:~/work/JTAGduino$ PATH=$PATH:/arduino-1.8.1/hardware/tools/avr/bin avrdude -p m169 -c xil -P /dev/ttyACM0 -C /arduino-1.8.1/hardware/tools/avr/etc/avrdude.conf -U lfuse:r:backup/unknown/`date  "+%F_%T"`/lfuse.hex:h -U hfuse:r:backup/unknown/`date  "+%F_%T"`/hfuse.hex:h -U efuse:r:backup/unknown/`date  "+%F_%T"`/efuse.hex:h

So wie es aussieht, ist die Library nicht komplett, und für meinen Anwendungszweck vielleicht gar nicht geeignet. Ich bin dadurch über eine JTAG-Library gestoßen, welche man direkt über die Arduino-IDE nachinstallieren kann: https://github.com/mrjimenez/JTAG

Nach dem Upload des JTAGTest-Programms (wird als Beispiel in der ArduinoIDE bereitgestellt, wenn man die Bibliothek installiert hat) auf dem Arduino kann man das python-Programm „xsvf“ nutzen, um erste Tests durchzuführen:

user@host:~/work/JTAG/extras/python$ ./xsvf ../xsvf/all/idcode_simpler.xsvf
File: /work/JTAG/extras/xsvf/all/idcode_simpler.xsvf
Ready to send 18 bytes.
Sent:       18 bytes,        0 remaining
IMPORTANT: ********
IMPORTANT: Success!
IMPORTANT: ********
IMPORTANT: Last TDO: FF FF FF FF/32 bits
IMPORTANT: Processed 5 instructions.
IMPORTANT: Checksum:  0xC2/18.
IMPORTANT: Sum: 0x0000003E/18.
Quit: No error (0).
  Expected checksum:  0xC2/18.
  Expected sum: 0x0000003E/18.
Elapsed time: 0.02 seconds.

Mit der neuen JTAG-Library alle möglichen Programmiermodi des avrdude durchgegangen:

atmelice         = Atmel-ICE (ARM/AVR) in JTAG mode (avrdude: jtag3_open_common(): JTAGICE3/EDBG port names must start with "usb")
  dragon_jtag      = Atmel AVR Dragon in JTAG mode (no response)
  jtag1            = Atmel JTAG ICE (mkI) (avrdude: jtagmkI_open(): failed to synchronize to ICE)
  jtag1slow        = Atmel JTAG ICE (mkI) (avrdude: jtagmkI_open(): failed to synchronize to ICE)
  jtag2            = Atmel JTAG ICE mkII (no response)
  jtag2avr32       = Atmel JTAG ICE mkII im AVR32 mode (avrdude: jtagmkII_recv_frame(): timeout     avrdude: jtagmkII_getsync(): sign-on command: status -1)
  jtag2dw          = Atmel JTAG ICE mkII in debugWire mode
  jtag2fast        = Atmel JTAG ICE mkII
  jtag2isp         = Atmel JTAG ICE mkII in ISP mode
  jtag2pdi         = Atmel JTAG ICE mkII PDI mode
  jtag2slow        = Atmel JTAG ICE mkII
  jtag3            = Atmel AVR JTAGICE3 in JTAG mode
  jtag3dw          = Atmel AVR JTAGICE3 in debugWIRE mode
  jtag3isp         = Atmel AVR JTAGICE3 in ISP mode
  jtag3pdi         = Atmel AVR JTAGICE3 in PDI mode
  jtagkey          = Amontec JTAGKey, JTAGKey-Tiny and JTAGKey2
  jtagmkI          = Atmel JTAG ICE (mkI)
  jtagmkII         = Atmel JTAG ICE mkII
  jtagmkII_avr32   = Atmel JTAG ICE mkII im AVR32 mode
  o-link           = O-Link, OpenJTAG from www.100ask.net (avrdude: Error: no libftdi or libusb support. Install libftdi1/libusb-1.0 or libftdi/libusb and run configure/make again.)
  xil              = Xilinx JTAG cable (avrdude: can't claim device "/dev/ttyACM0": Inappropriate ioctl for device)
  xplainedpro      = Atmel AVR XplainedPro in JTAG mode (avrdude: jtag3_open_common(): JTAGICE3/EDBG port names must start with "usb")

 

Schreibe einen Kommentar