IPAQ AVR Hacking

Aus Ethersex_Wiki
Wechseln zu: Navigation, Suche

5358S09TA eht gnireenigne esrever

{maketoc}

jippie, wie unter IpaqRfmFunkmod näher dargelegt, habe ich mich dazu entschieden, die Firmware des auf dem iPAQ verbauten AT90S8535 etwas näher unter die Lupe zu nehmen. Meine Fortschritte in Punkto Programmcode kannst Du unter http://git.brokenpipe.de/cgi-bin/gitweb.cgi?r=stesie;p=h3600_micro;a=summary begutachten.

Der Controller AT90S8535 ...

  • läuft mit maximal 8 MHz, verbaut ist ein Quarz mit 3,68 MHz
  • hat 8 kB Flashspeicher für Programmcode
  • 512 Byte RAM
  • 512 Byte EEPROM

Die Außenbeschaltung des Controllers

ist unter http://handhelds.org/Compaq/iPAQH3600/iPAQ_H3600.html#pgpio ausführlichst beschrieben.

Protokoll

Der AVR ist mittels UART an den Strong-ARM des iPAQ angebunden. Dabei scheint der iPAQ zu entscheiden, wann der AVR sprechen darf und wann nicht. Von sich aus sagt der AVR scheinbar nichts, er macht sich nur mittels Interrupt beim ARM bemerkbar und wird dann von diesem ausgefragt.

Der Befehlssatz

Version 0
Keyboard 2
Touchpanel 3
EEPROM Read 4
EEPROM Write 5
Thermal Sensor 6
Notify LED 8
Battery 9
SPI Read 11
SPI Write 12
Backlight 13
Codec Control 14

Paketaufbau AVR -> ARM

SOF ID + Len Data Chksum
immer 0x02 Die Befehls-ID wird im oberen Nibble,

die Länge im unteren Nibble übermittelt

zu übertragende Daten (max. 15 Byte) Prüfsumme = Summe der ASCII-Werte der Bytes

ID/Len und der Datenbytes

Das heißt es werden immer mindestens drei Bytes übertragen, maximal 18.

Als Default Ack wird die Reaktion des AVR bezeichnet, wenn keine Daten zurück gegeben werden, sondern nur der Befehl als solches bestätigt wird. Die Original-Firmware kennt vier Befehle, die immer ein Default-Ack zurück geben:

  • EEPROM Write
  • Notify LED
  • SPI Write
  • Codec Control

Im Falle von EEPROM Write (ID 5) würde also 0x02, 0x05, 0x05 zurück übertragen.

Version Ack

0x02 0x09 1.07 x.xx yy Chksum
SOF ID = 0, Len = 0 Host Version

bei mir 1.07, wird als ASCII-String übertragen

Pack Version

ebenfalls ASCII String aus RAM 0x00BC ff.

Boot Type

RAM 0x00BF

-

Der Inhalt von 0x00BF wird nach dem Lesen auf 0x00 zurück gesetzt.

Keyboard Ack

0x02 0x21 RAM 0x006B Chksum

Im RAM werden in 0x0068 die Bits 3 und 6 gelöscht (AND 0xB7).

Paketaufbau ARM -> AVR

TODO

Registerbelegung

Register 7 6 5 4 3 2 1 0
r0 SREG carry (zum Zwischenspeichern während Interrupts)
r1,r2 temp??
r3..r6 unused
r7 temp??
r8 Counter, counting from 3 down in TOV0
r9 some state (what??)
r10..15 temporary? state? ?? (usage handling r9 register)
r16..r21 temporary registers
r22 Batt. Temp. related ??? Thermal Sensor Ack Send SPI Read Ack
r23 Default Ack

zurückgeben

Battery Ack Backlight Ack

Light sensor status from 0x008F

Version Ack

zurückgeben

EEprom Read Ack

sendet Bytes ab 0x00D5

Keyboard Ack

zurückgeben sendet Byte 0x006B

Touchpanel Read Ack

sendet Bytes 0x0060..63

CPU IRQ Reply

Code nicht ausführen

r24 Skip ADC Block Sotre ADC

Batt. temp. sensor

Store ADC

light sensor

Store ADC

charger current

Store ADC

main batt. 2/3 voltage

store ADC

key signal input

r25 7 Trigger ADC for

Batt. temp. sensor

Trigger ADC for

light sensor

Trigger ADC for

charger current

Trigger ADC for

main batt. 2/3 voltage

Trigger ADC for

key signal input

Trigger ADC for

TP X coord

ADC start over

Trigger for TP Y coord.

r26:r27 X Pointer
r28:r29 Y Pointer
r30:r31 Z Pointer

Speicherbelegung

Speicherzelle 7 6 5 4 3 2 1 0
0x0000..0x005F MCU Register
0x0060..0x0063 Touchpanel Read Buffer
0x0064 Touchpanel related (whatever?)
0x0065 RX buf busy

(Packet zu verarbeiten)

0x0066 Bytes left to receive / Packet length
0x0067 Default Ack: SPI Write

(vgl. r23, bit 7)

Default Ack: EEPROM Write

(vgl. r23, bit 7)

Default Ack: Notify LED

(vgl. r23, bit 7)

Default Ack: Codec Control

(vgl. r23, bit 7)

0x006B Keyboard "Read" Buffer (wird beim Keyboard Ack zurückgegeben)
0x006D Notify LED nicht ändern Notify LED abschalten
0x0075 Battery Dead Thermal related ??
0x007B Battery Voltage MSB
0x007C Battery Voltage LSB
0x007D Battery Voltage MSB (raw value)
0x007E Battery Voltage LSB (raw value)
0x007F Battery Voltage Iteration Counter (0..) ??
0x0080 Countdown triggering batt. voltage sense (from TOV2)
0x0081 Battery Voltage MSB (latest measurement)
0x0082 Battery Voltage LSB (latest measurement)
0x0083 Charge Current LSB
0x0084 Charge Current MSB
0x0087 Thermal Batt. Status LSB
0x0088 Thermal Batt. Status MSB
0x008C charging (1. Batt) charging (1. Batt) charging (1. Batt)
0x008D Timer/Counter Charger
0x008E Light sensor ??
0x008F Light sensor status (??); value returned on backlight ack
0x0090..0x00A0 SPI (send??) buffer
0x00A1 Zeiger auf nächstes zu sendendes Byte (SPI)
0x00A2 Zeiger auf das letzte zu sendende Byte (SPI)
0x00A3 Zeiger wo nächstes gelesenes Byte gespeichert werden soll (SPI)
0x00A4 dto. ??
0x00A5.. SPI buffer ??
0x00B6 Second Battery Chemistry
0x00B7 Akkustand 2. Batt. (Prozent)
0x00B8 2. Batt. nicht vorh. 2. Batt. voll 2. Batt not inst. 1. Batt charging 2. Batt charging 2. Batt critical 2. Batt status low 2. Batt Status high
0x00B9 Countdown 5..0, SPI related, Sleeve/2nd Batt. detection related ??
0x00BA Counter Charge/Battery Temperature related ??
0x00BB Battery Temp. related ??
0x00BC Vorkommastelle der Pack-Version
0x00BD 1. Nachkommastelle Pack-Version
0x00BE 2. Nachkommastelle Pack-Version
0x00BF Boot Type (0x01 = Power-on Reset, 0x02 = External Reset, 0x03 = Watchdog Reset)

Der Wert wird nach einmaliger Abfrage der Version (Befehl 0x00) gelöscht

0x00C0..0x00CF Send buffer
0x00D1 Zeiger auf nächstes zu sendendes Datenbyte (UART)
0x00D2 Zeiger auf das letzte zu sendende Datenbyte (UART)
0x00D3 EEprom Read REQ Addr
0x00D4 EEprom Read REQ Len
0x00D5 Länge der EEprom-Read-Buffer
0x00D6.. EEprom-Read-Buffer (nur 8 Byte??)
0x00DE..0x00EE Incoming Message Buffer; an 00DE liegt der Befehl, ab 00DF kommen die Daten
0x00EF Pointer auf Incoming Message Buffer; wenn 0xDE -> dann Puffer leer; beim Empfang Zeiger auf Stelle, an die das nächste Byte zu speichern ist
0x00F1 Light sensor ??
0x00F3 Skip SPI Block SPI ?? read ext. batt state (??) SPI Read/Write Complete read ext. batt state (??) SPI Datenrichtung

(1 = Writing)

0x00F4 SPI write active SPI read active
0x00F5 SPI ?? SPI ?? SPI busy ??
0x00F6 SPI related ??
0x00F7 Anzahl der noch zu empfangenden Bytes (SPI)
0x00F8 SPI Read Buffer len
0x00FF
0x0100..0x010F SPI Read Buffer (Data out over UART)
0x0113.. SPI (Send?) Buffer

Bytes 00B6, 00B7, 00B8 and 00FF cleared after every power down.

Modifikationskonzept für den RFM12

Alter SPI Code raus? ... nein! bloß nicht!

... Zunächst war angedacht den alten SPI-Code von Bord zu werfen. Aber wir können auf den originalen SPI-Code nicht verzichten, da damit EEPROMs in der Sleeve abgefragt werden. Auf diese Art und Weise wird unter anderem abgefragt, welcher Akku verbaut ist, Ladezustand, Gerätetyp, Seriennummer, etc.

Wohl oder übel haben wir dann beschlossen, dass unser RFM12 einen eigenen Chip Select zur Verfügung bekommt. Nachdem der AVR keine freien I/O-Ports hat, muss eine andere Funktion leiden. Das kleinste Übel ist da wohl die Notify LED -- bislang haben wir mit der ohnehin nichts angestellt. Ist auch die Frage, warum die LED "Notify" heißt, ein Dialogfenster am Bildschirm fällt doch tausendmal mehr auf ...

Interrupt

Auf Grund akutem Pinmangel muss sich der RFM12 den Interrupt mit dem Touchscreen teilen, ... der Pin ist active-low, kann also ohne größere Probleme vom RFM12 angesteuert werden. Auf der Leitung sind auch nicht all zu viele Interrupts aktiv, sodass ein Abfragen des RFM12, ob er denn der Schuldige ist, nicht erheblich ins Gewicht fällt (Interrupts treten immer dann auf, wenn der Anwender auf's Display klopft) ...

Der andere Interrupt-Pin ist übrigens nicht ohne weiteres verwendbar. Es hängt eine ganze Reihe von Logikgattern davor, die alle angesteuert werden möchten. Da ist der Pin fürs Touchscreen doch wesentlich leichter zu handlen ...

Neues Protokollbackend für RFM2

Natürlich brauchen wir einen neuen Befehl, Befehls-ID nehmen wir die 10. Mit der Fünf-/Dreiundzwanzig-Logik kommen wir diesmal nicht weiter. Die 5 ist unmittelbar belegt, die 8 zwar eigentlich unbesetzt, aber da hätten wir ein Problem wenn der ARM von dem RFM12 nichts weiß und wirklich die Notify-LED steuern möchte.

Gesendet werden an den AVR immer mindestens zwei Byte, egal welche Richtung, d.h. der Identifier ist fix 0xA2 bis 0xAF.

Die Initialisierung des RFM12 erfolgt zunächst vom ARM, d.h. der ARM sendet die typischen Initialisierungsbefehle an den AVR, der diese schlicht weiterleitet. Das hat den Vorteil, dass man die Baudrate, Modulation, etc. relativ leicht abändern kann.

Spezielle Befehle ARM->AVR:

0xF000 Internen Status abfragen (liefert Inhalt von r5 und r6)
0xF100 Enable RX
0XF20n Trigger TX, letzter zu sendender Puffer ist n (wahlweise 3 bis F)
0xF3 TX einleiten, Puffer 3 (= erster Datenpuffer) schreiben, max. 14 Bytes können folgen
0xFn TX-Puffer n schreiben (4 bis F), max. 14 Bytes können folgen
0x0000 Status vom RFM12 abfragen

Alle anderen Befehle werden direkt an den RFM12 gesendet. Zurück gegeben wird nicht die Antwort des RFM12, sondern der interne Status!!

Antwortpakete AVR->ARM

A0 TX-mode, FIFO fill phase (triggered by 0xF3...)
A1 xx RX-mode, Datenbyte xx empfangen
A2 xx yy Statusbytes (abhängig vom vorher gesendeten Befehl)

Aufbau des RFM12-Statusregisters

r3 Wait-Byte 0 Wait-Byte 1 unused unused unused bit10 bit9 bit8
r4 (RX) bytes left to receive (bits 7..0)
r5 FIFO overrun reset request FIFO busy (RX) FIFO notification request Ack Internal Status Ack Rfm Status RX active TX active
r6 (RX) fifo byte

Speicherbelegung durch RFM12-Codeteil

0x0130..0x01ff TX-Puffer
0x0200 Frequency Config Byte 0xa6nn
0x0201 Bandwidth Config Byte 0x94nn
0x0202 Baudrate Config Byte 0xc6nn
0x0203 Power Config Byte 0x98nn