Forum: Mikrocontroller und Digitale Elektronik ISP Programmer ATMega168 IPS Protokoll Adressen fehlerhaft?!


von MOBA 2. (Gast)


Angehängte Dateien:

Lesenswert?

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
4
      for (uint8_t i = NULL; i < (BytesPerIntelHex / BytesPerWord); i++)
5
      {
6
        //lsb data
7
        spi_data(0x40);
8
        spi_data(0x00);
9
        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.

von S. Landolt (Gast)


Lesenswert?

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.

von S. Landolt (Gast)


Angehängte Dateien:

Lesenswert?

Eine, wie ich finde, besser lesbare Tabelle als beim ATmega168 finden 
Sie beim ATmega8515.

von MOBA 2. (Gast)


Angehängte Dateien:

Lesenswert?

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.

von MOBA 2. (Gast)


Lesenswert?

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!

von S. Landolt (Gast)


Lesenswert?

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.

von MOBA 2. (Gast)


Lesenswert?

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.

von S. Landolt (Gast)


Lesenswert?

Zum ATtiny13 kann ich nichts sagen, den hatte ich nie. Aber mit den 
folgenden funktioniert das beschriebene Verfahren:
.db $91,$01,c2313   ," c2313",0
.db $91,$03,c2343   ," c2343",0
.db $92,$03,c4433   ," c4433",0
.db $93,$01,c8515   ," c8515",0
.db $90,$05,t12     ,"  t12 ",0
;           paging 16   flash  32B  (eep  4B)
.db $91,$09,t26     ,"  t26 ",16
.db $91,$0A,t2313   ," t2313",16
;           paging 32   flash  64B  (eep  4B)
.db $92,$05,m48     ,"  m48 ",32
.db $93,$0A,m88     ,"  m88 ",32
.db $92,$08,t461    ," t461 ",32
.db $93,$0B,t85     ,"  t85 ",32
.db $93,$06,m8515   ," m8515",32
.db $93,$0C,t84     ,"  t84 ",32
.db $93,$0D,t861    ," t861 ",32
;           paging 64   flash 128B  (eep  4B)
.db $94,$06,m168    ," m168 ",64
.db $94,$03,m16     ,"  m16 ",64
.db $94,$04,m162    ," m162 ",64
.db $95,$0F,m328P   ," m328P",64
;           paging 128  flash 256B  (eep  8B)
.db $96,$09,m644    ," m644 ",128
.db $96,$0A,m644P   ," m644P",128
.db $97,$05,m1284P  ,"m1284P",128

von MOBA 2. (Gast)


Lesenswert?

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);

von MOBA 2. (Gast)


Lesenswert?

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.

von S. Landolt (Gast)


Lesenswert?

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.

von MOBA 2. (Gast)


Lesenswert?

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.

von S. Landolt (Gast)


Lesenswert?

> 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?

von MOBA 2. (Gast)


Lesenswert?

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.

von S. Landolt (Gast)


Lesenswert?

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.

von MOBA 2. (Gast)


Lesenswert?

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...

von S. Landolt (Gast)


Lesenswert?

> 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.

von MOBA 2. (Gast)


Lesenswert?

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!

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.