Hallo,
ich bin irgendwie am Ende. Ich verstehe es einfach nicht.
Ich habe einen USB-Programmer (ISP) mit einem ATMega8 gebaut, um meine
kleineren Geräte mit ATtiny13 bequem zu flashen über den PC (Programm
starten, lädt FW Datei runter flashed es dann).
Jetzt wollte ich den Programmer mal um den ATMega168 erweitern, weil ich
ihn brauche.
Über USB wird je eine Hex-Line gesendet (also das Teil mit
:100xxxxxxxx).
Die wird dann im Programmer geparsed und sollte geflashed werden. Das
parsen klappt, Fuses lesen/schreiben und EEPROM lesen/schreiben ist
alles kein Problem.
Beim Flash ist es komisch: Flashe ich nur die ersten 20 Zeilen stimmen
die.
Flashe ich die nächsten 20, stimmen diese, aber die ersten 20 werden
"verfuscht". Interessanterweise ist es auch so, dass dies ein der Tat
noch so halb richtig bleiben (siehe Dokumente).
Hier die Routine, die das Flashen übernimmt:
1
if(write_to_buffer)
2
{
3
//fill buffer (adress here only from 0 to WordsPerPage-1
spi_data((((*adress)%(BytesPerWord*WordsPerPage))/BytesPerWord)+i);//low byte adr for word offset
10
spi_data(DATA_LSB_MSB[(i*2)]);
11
12
//msb data
13
spi_data(0x48);
14
spi_data(0x00);
15
spi_data((((*adress)%(BytesPerWord*WordsPerPage))/BytesPerWord)+i);//high byte adr for word offset
16
spi_data(DATA_LSB_MSB[((i*2)+1)]);
17
}
18
}
19
else
20
{
21
//calc the page adr.
22
*adress/=(AdressBytesMax/(BytesPerWord*WordsPerPage));//divide through max. of pages
23
24
25
//Now write the data to page
26
spi_data(0x4C);
27
spi_data((*adress)>>ShiftAmountOffset);
28
spi_data((*adress)<<ShiftAmountOffset);
29
spi_data(0x00);
30
31
_delay_ms(10);
32
}
Dabei ist ShiftAmountOffset beim ATMEga168 6.
AdressByteMax ist 1024 * 16 = 16kb
BytesPerWord = 2
BytesPerIntelHex = 16
WordsPerPage ist beim ATMega168 64
Ich denke es liegt an den Adressen, aber ehrlich gesagt, ich verstehe es
einfach nicht mehr. Ich finde/sehe das Problem nicht.
Da er die Lines an sich korrekt flashed, sollte die For-Schleife (also
Buffer füllen) korrekt sein, denke ich.
Also müsste es an der Fkt. Buffer to Flash liegen, sprich den Bereich im
"Else"-Teil. Commando 4C passt auch. Entweder berechne ich die Adresse
falsch, oder das mit dem Schieben (6 bit) habe ich falsch verstanden.
Mich wundert das, dass es beim Attiny13 funktioniert. Vll einfach glück
gehabt. Dort schiebe ich übrigends um 4.
Ich bin der Meinung, dass bei 4C "Write program memory page" die
Wortadresse übergeben werden muss, genauer eine Wortadresse, die
innerhalb der zu schreibenden Seite liegt, und da eben das MSB in Byte2
sowie das LSB in Byte3.
Ich habe nochmal was herausgefunden.
Wenn ich eine Schleife mache die einfach immer als MSB und LSB den Wert
der aktuellen Position einträgt (0,1,2,3...), dann habe ich einfach mal
fix auf page 0 und fix auf page 1 programmiert.
Dabei kommt das raus (siehe Anhang). Soweit ok mit der Page. Ein Fehler
gefunden: Das LSbit von der Page ist das MSbit des LSB der Page adresse.
Komisch aber ist so, muss man um einen mehr nach unten schieben (7) und
dann um 1 nach oben schieben.
Das Problem ist jetzt tatsächlich der Buffer. 16kb/128 = 128.
Das passt auch, wenn man das Dokument anschaut, aber irgendwie bekomme
ich nur den halben Buffer, also eine halbe Page immer beschreiben.
Was muss ich hier anders machen?! Muss man da im Buffer noch springen
oder wie? Das ist mir jetzt unklar. Normalerweise müssten 2 Pages mit
der Testschleife komplett gefüllt sein, es ist aber nur jeweils die
halbe befüllt.
S. Landolt schrieb:> Eine, wie ich finde, besser lesbare Tabelle als beim ATmega168 finden> Sie beim ATmega8515.
Jap, das war eine gute Idee. Habe mir die vom ATMega16 geschnappt (hat
ja auch 16kb), dort steht nämlich drin, dass die Page 2 bit im LSB hat
und nicht 1 Bit wie ich es erraten hatte. Die neuen Tabellen kann man
echt vergessen, bei den alten mit der Bitangabe klappt es sofort.
Vielen Dank dafür!
Ihre Beschreibung von 18:26 verstehe ich nicht. Hier vereinfacht mein
Vorgehen (Assembler):
Das MSB der Wortadresse kommt nach Byte2, das LSB nach Byte3, ohne
irgendetwas auszumaskieren. Auf diese Weise fülle ich die Seite
aufsteigend mit den Befehlen 40 und 48; ist die Seite voll, so steht ja
noch die letzte Adresse der Seite in den beiden Bytes, und genau damit
setze ich Befehl 4C ab, wieder ohne Maskierung.
S. Landolt schrieb:> Ihre Beschreibung von 18:26 verstehe ich nicht. Hier vereinfacht mein> Vorgehen (Assembler):> Das MSB der Wortadresse kommt nach Byte2, das LSB nach Byte3, ohne> irgendetwas auszumaskieren. Auf diese Weise fülle ich die Seite> aufsteigend mit den Befehlen 40 und 48; ist die Seite voll, so steht ja> noch die letzte Adresse der Seite in den beiden Bytes, und genau damit> setze ich Befehl 4C ab, wieder ohne Maskierung.
Buffer füllen ist klar, dass funktioniert.
Das Problem ist so ein bisschen die richtige Page-Auswahl.
Ich glaube das kann man so einfach nicht machen:
Tiny13: Page wird so gesendet:
MSB LSB
0000 000a aaaa xxxx
ATMega16(8): Page wird so gesendet:
MSB LSB
000a aaaa aa00 0000
Durch meine berechnung der neuen adresse (*adress /= (AdressBytesMax /
(BytesPerWord * WordsPerPage));) bekomme ich die passende Adresse (PAGE)
direkt raus. Also 0-x, ich habe also keine 16-bit mehr, deswegen muss
ich hoch bzw. runterschieben, um die Adresse mittig um die 2 Bytes zu
platzieren.
Das haben die aber auch dermaßen bescheuert gelöst, anstelle LSB bei Bit
0 anzufangen und dann einfach je nach MCU einfach mehr bits nach oben zu
nutzen.
Ich habe es jetzt gelöst bekommen. Ob das so kompatibel ist für andere
CPUs muss ich aber erst noch abchecken, für den Tiny13 und Mega16(8)
geht es.
Programm kann bleiben wie oben, nur aus:
spi_data((*adress) >> ShiftAmountOffset);
spi_data((*adress) << ShiftAmountOffset);
wird
spi_data((*adress) >> (8 - ShiftAmountOffset));
spi_data((*adress) << ShiftAmountOffset);
S. Landolt schrieb:> Zum ATtiny13 kann ich nichts sagen, den hatte ich nie. Aber mit den> folgenden funktioniert das beschriebene Verfahren:
Danke schön. Ich habe es jetzt erstmal auf meine maskierende Art gelöst.
Ich werde jetzt mal die Datenblätter der anderen CPUs testen, ob das so
geht.
Ihr Verfahren funktioniert zwar, ist aber für mich in der Anwendung
nicht zu gebrauchen, da ich im Vorfeld die Adresse schon anders
handhabe.
Ich könnte mir aber vorstellen, dass das vll. sogar für die Tinys geht,
dann wäre das schon die bessere Lösung. Das muss ich jetzt erstmal
vergleichen und testen.
Zwar bin ich der Meinung, dass man ohne dies 'ShiftAmountOffset'
auskommt, deshalb auch die geänderte Tabelle in den neueren
Datenblättern, ist aber letztlich egal, Hauptsache, es läuft bei Ihnen.
S. Landolt schrieb:> Zwar bin ich der Meinung, dass man ohne dies 'ShiftAmountOffset'> auskommt, deshalb auch die geänderte Tabelle in den neueren> Datenblättern, ist aber letztlich egal, Hauptsache, es läuft bei Ihnen.
Ja das ist erstmal richtig. Ich habe das mal getestet: Wenn ich direkt
MSB und LSB der Adresse sende (ohne den ganzen Klatsch vorher mit
adresse einzeln berechnen, schieben usw), dann wird nur jede 2. Page
gefüllt, beginnend mit Page 2.
Edit: Ich habe gerade gemerkt, dann programmiert der auch wieder
irgendeinen quatsch da rein.
So ganz grün werde ich damit nicht. Das mit dem schieben ist auf jeden
Fall keine besonders gute Lösung. Bei anderen CPUs (Tiny 2313/4313) wird
das Probleme machen.
S. Landolt schrieb:>> dann wird nur jede 2. Page gefüllt> Wann zählen Sie die Adresse hoch, oder anders gefragt, mit welcher> Adresse setzen Sie jeweils den Befehl 4C ab?
Mit der letzten Adresse die ich nutze um den Buffer zu füllen.
Ich gehe her, fülle den Buffer und parse mir die Adresse vom
Intel-Hex-Format direkt. Wenn eine Page voll ist (WordsPerPage *
BytesPerWord) dann schreibe ich den Buffer auf den Chip.
Dann sollte es doch funktionieren.
Beispiel, welches ich gerade zur Hand habe: ATmega88 mit 32 words per
page, da lautet das erste page-write:
$4C $00 $1F $00
das zweite:
$4C $00 $3F $00
das dritte:
$4C $00 $5F $00
usw.
Genaugenommen steht im 4. Byte irgendein übriggebliebener Rest, das wird
offenbar völlig ignoriert.
S. Landolt schrieb:> Dann sollte es doch funktionieren.> Beispiel, welches ich gerade zur Hand habe: ATmega88 mit 32 words per> page, da lautet das erste page-write:> $4C $00 $1F $00> das zweite:> $4C $00 $3F $00> das dritte:> $4C $00 $5F $00> usw.>> Genaugenommen steht im 4. Byte irgendein übriggebliebener Rest, das wird> offenbar völlig ignoriert.
Das 4. Byte ist egal, da bekommt man als Kontrolle wohl ein Byte wieder
zurück wie ich die Anleitung verstehe.
Ich hatte mich vorhin beim Nachrechnen vertippt. Meine Version mit dem
Schieben funktioniert bei allen CPUs. Man muss nur den ShiftAmoutOffset
angeben. Der ist einfach die Anzahl der Bits die für PCWORD genutzt
werden.
Das mit den 2 Byte senden will bei mir nicht, da ich jetzt 2 Tage
gebraucht habe, um zu finden, warum das nicht geht (und im Endeffekt nur
2 Zeilen zu tauschen), reicht es mir jetzt. Klappt jetzt. Nach meinen
Berechnungen (Atmega16, Atmega8, Attiny13, 25, 45, 85, 261, 461, 861)
sollte es demnach auch bei allen anderen CPUs klappen. Sind ja so
ziemlich alle wichtigen Flashgrößen.
Bspw. wenn es beim Attiny85 klappt auch beim Mega88 etc...
> Klappt jetzt ... sollte es demnach auch bei allen anderen CPUs klappen
Prima.
Dann bedanke ich mich für den angenehmen Gedankenaustausch und wünsche
noch einen schönen Abend.
S. Landolt schrieb:>> Klappt jetzt ... sollte es demnach auch bei allen anderen CPUs klappen> Prima.> Dann bedanke ich mich für den angenehmen Gedankenaustausch und wünsche> noch einen schönen Abend.
Ebenso! Schönen Abend noch!