Hi!
OP DELIVERS!
Ich möchte der Vollständigkeit halber nochmal eine kurze Zusammenfassung
geben für Leute, die vor dem gleichen Problem stehen wie ich.
In der Tat finden sich alle nötigen Informationen im Datenblatt. Beim
ATTiny84 auf Seite 163, Kapitel 19.5: Serial Programming.
Der (bei mir) 8KB große Flash Speicher ist linear angelegt. Die
Adressierung erfolgt in WORD Schritten, die nächst größere "Einheit" ist
eine Page. Adresse 0 ist das erste Wort, Adresse 1 das zweite. Auf eine
Page passen (beim ATTiny44 und ATTiny84) 32 Words.
Der Speciher wird folgendermaßen beschrieben: Die Reset Leitung wird auf
GND gezogen und das Kommando "Programming Enable" per SPI geschickt.
Kommandos haben immer 4 Byte, die übertragen werden müssen, hier sind es
die Bytes
Wenn es geklappt hat, wird mit dem 3. gesendeten Byte das 2. Byte 0x53
zurückgesendet. Dies hat bei mir erst lange nicht funktioniert. Man muss
GENAU darauf achten, wie die Clock eingestellt ist: Die gesendeten Daten
werden auf Rising Edge übernommen. Ich habe es mit einem Oszi und Trial
and Error eingestellt. Irgendwann war auf dem Rückkanal dann die Antwort
0x53 zu sehen.
Tabelle 19-12 des Datenblattes beschreibt alle möglichen Commands.
Wichtig hier ist, dass man für die Commands immer im Programming Mode
sein muss! Auch für's Auslesen, beispielsweise!
Nun sendet man erstmal einen Chip Erase.
Dieser löscht das ganze Flash, selektiv Adressen löschen ist, soweit ich
weiß, nicht möglich. Als nächstes kann man eine Adresse beschreiben. Zum
Testen kann irgendein WORD genommen werden ( 0xAA55 ). Der Controller
hat eine ganze Page als Buffer. Diesen Buffer lädt man voll und schreibt
ihn dann mit einem Schreibbefehl auf den Controller. Wie oben
beschrieben , ist das Flash Word adressiert. Trotzdem gibt es zwei
Befehle zum Buffer laden, nämlich High Byte und Low Byte einer Adresse.
Es muss erst das Low Byte geladen werden! Ablauf:
Lade Low Byte -> Lade High Byte (bis zu 32 mal, dann Page Buffer voll)
-> Schreibe Page.
Die Befehle dazu sind in der Tabelle zu finden. Als abschließendes
Beispiel hier noch ein Bisschen Pseudo Code zum Schreiben von 0xAA55 an
Adresse 0:
1 | // Lade low byte an Puffer Adresse 0
|
2 | spisend( 0x40 ) //OP Code
|
3 | response = spiread();
|
4 | spisend( 0x00 ) //Adresse MSB
|
5 | response = spiread();
|
6 | spisend( 0x00 ) //Adresse LSB
|
7 | response = spiread();
|
8 | spisend( 0x55 ) //Daten
|
9 | response = spiread();
|
10 |
|
11 | // Lade high byte an Puffer Adresse 0
|
12 | spisend( 0x48 ) //OP Code
|
13 | response = spiread();
|
14 | spisend( 0x00 ) //Adresse MSB
|
15 | response = spiread();
|
16 | spisend( 0x00 ) //Adresse LSB
|
17 | response = spiread();
|
18 | spisend( 0xAA ) //Daten
|
19 | response = spiread();
|
20 |
|
21 |
|
22 | // Schreibe Page, beginnend bei Adresse 0
|
23 | spisend( 0x4C ) //OP Code
|
24 | response = spiread();
|
25 | spisend( 0x00 ) //Adresse MSB
|
26 | response = spiread();
|
27 | spisend( 0x00 ) //Adresse LSB
|
28 | response = spiread();
|
29 | spisend( 0x00 )
|
30 | response = spiread();
|
Nach dem Schreiben muss man die Reset Leitung wieder auf High setzen, um
die Programmiermodus zu verlassen.
Auch wichtig: Wenn man die zweite Page schreiben möchte, ist die Adresse
nicht 0x02, sondern 0x20, da man die Anfangsadresse, nicht die Page
Nummer angeben muss!
Das ist ein grober Überblick. Timing muss man kaum beachten, es gibt ein
Busy Flag, das man pollen kann, wenn man eine Page schreibt. Auch sehr
einfach, wenn man die Command Sets erst mal geblickt hat.
Hoffe, dass ich jemandem helfen konnte.
Grüße!