Hallo, der Atmega328P hat einen "Internal SRAM"-Bereich von 2k, der von 0x0100 bis 0x08FF reicht (2048 Bytes lang). Das ist auch in der entsprechenden Include-Datei unter RAMEND = 0x08FF genau so definiert. Wenn ich mir nun im Datenblatt unter "Register Summary" das SPH- (und das SPL-) Register ansehe, dann haben die zusammen eine Breite von 11 Bit. Das bedeutet, dass die höchste Adresse (bzw. nur das High-Byte betrachtet), die SPH aufnehmen kann, eine 0x07 ist. Also die höchste Adresse ist die 0x07FF. Nochmal in Kurzform: SPH ist 3 Bit breit: Höchste darstellbare Zahl: 0x07. Wenn ich jetzt aber den Stackpointer auch auf das RAM-Ende setzen kann, dann brauche ich in SPH noch ein viertes Bit, d.h. das Datenblatt ist fehlerhaft. Oder übersehe ich etwas? Gruß, Thomas
:
Gesperrt durch Moderator
Thomas T. schrieb: > d.h. das Datenblatt ist fehlerhaft. Jau. Guckst Du in 7.5.1, da steht die relevante Inforation.
der sram beginnt bei 100hex plus 7ff ist 8ff siehe db seite 19 da ist es eindeutig erklärt
Thomas T. schrieb: > Nochmal in Kurzform: SPH ist 3 Bit breit: Höchste darstellbare Zahl: > 0x07. > > Wenn ich jetzt aber den Stackpointer auch auf das RAM-Ende setzen kann, > dann brauche ich in SPH noch ein viertes Bit, d.h. das Datenblatt ist > fehlerhaft. Nun, der Stackpointer ist groß genug, um den gesamten RAM addressieren zu können, das genügt prinzipiell. Der Rest wird sicher per wrap-around-Mathematik erledigt. Die Frage ist nur, ob der Programmierer sich darum kümmern muß oder ob es die Hardware tut. Ich würde mal auf letzteres tippen, sonst hätte in der Anmerkung zum SPH-Register sicher etwas dazu gestanden. Mit minimaler Eigeninitiative läßt sich das allerdings auch sehr einfach selbst herausfinden: cbi TESTPORT,TESTBIT ;für TEST-LED zwischen Pin und GND sbi TESTDDR,TESTBIT ldi R16,Low(RAMEND) ldi R17,High(RAMEND) out SPL,R16 out SPH,R17 push R17 push R16 lds R16,RAMEND-1 pop R17 sub R16,R17 lds R16,RAMEND pop R17 sbc R16,R17 brne stop sbi TESTPORT,TESTBIT stop: rjmp stop Wenn die LED leuchtet, kümmert sich mit sehr hoher Wahrscheinlichkeit die Hardware darum...
c-hater schrieb: > Nun, der Stackpointer ist groß genug, um den gesamten RAM addressieren > zu können, das genügt prinzipiell. > > Der Rest wird sicher per wrap-around-Mathematik erledigt. Dein erster Satz ist definitiv falsch, wenn man sich nur auf das "Register Summary" bezieht: Dort hat der Stack 11 Bit und das reicht nicht aus! Es wird auch nichts per irgendwelcher wrap-around-Mathematik gerechnet. Vielmehr scheint es wohl wirklich so zu sein, dass SPH mehr Bits hat, als im "Register Summary" vermerkt. Ich habe mal auf die schnelle Folgendes probiert: LDI r16,$xx OUT SPH,r16 NOP IN r16, SPH OUT Port,r16 Also nacheinander SPH mit 0x01, 0x02, 0x04, 0x08, 0x10 und 0x20 geladen, den Wert in SPH wieder ausgelesen und auf einen Port ausgegeben. Dabei ist im unteren Nibble alles in Ordnung, es werden alle vier unteren Bits korrekt ausgegeben, ab 0x10 ist der Port durchweg 0x00. Das beweist wohl deutlich, dass im "Register Summery" auf Seite 624 das unbelegte Bit 3 vom SPH falsch markiert ist und eigentlich SP11 heißen sollte. Damit wären 12 Bits verfügbar und dann ist die Welt auch wieder in Ordnung... Gruß, Thomas
:
Bearbeitet durch User
Im Text findet man The AVR Stack Pointer is implemented as two 8-bit registers in the I/O space. The number of bits actually used is implementation dependent. Note that the data space in some implementations of the AVR architecture is so small that only SPL is needed. In this case, the SPH Register will not be present. Herrlich mehrdeutig alles. Es gilt wie so oft: Sobald man weiß, wie es funktioniert, interpretiert man auch das Datenblatt richtig.
:
Bearbeitet durch User
Georg G. schrieb: > Herrlich mehrdeutig alles. Manche Softwerker sagen, die beste Dokumentation sei immer der Quellcode. Das darf man wohl auch für Hardware sagen: Egal was im Datasheet steht, als eigentliche relevante Dokumentation taugt nur der VHDL/Verilog Quellcode, ersatzweise die reale Hardware. Spannend wärs jetzt, das bei verschiedenen Typen einer Familie mal zu testen. Also die Mega48/88/168/328 mit 0,5/1/2 KB RAM. Ob da jede RAM Grösse genau ihre spezifischen SPH Bits hat, oder ob welche mit mehr Bits als RAM dabei sind.
:
Bearbeitet durch User
Thomas T. schrieb: > Dein erster Satz ist definitiv falsch, wenn man sich nur auf das > "Register Summary" bezieht: Dort hat der Stack 11 Bit und das reicht > nicht aus! Natürlich reicht das aus. 11 Bit können 2^11 Adressen ansprechen. Wenn du das mal in irgendeinen vergurkten Taschenrechner eingibst, dann kommt was raus? ...2048 Und wie groß ist das SRAM eines Mega328P? 2048 Bytes. Was für ein Zufall... > Es wird auch nichts per irgendwelcher wrap-around-Mathematik gerechnet. Du bist definitiv ein Nixwisser/Nixkönner. Das allein ist noch nix Schlimmes, denn schließlich hat absolut jeder mal so angefangen. Auch ich übrigens. Aber Unwissend/Unfähig und dann noch stolz darauf, das geht garnicht...
c-hater schrieb: > Du bist definitiv ein Nixwisser/Nixkönner. Es würde dir sicherlich etwas helfen, nicht nur schreiben, sondern auch lesen zu lernen. Die Oberkante des RAMs liegt bei AVRs bekanntlich oberhalb der 2K Grenze des Datenadressraums, weil darunter die Register und der I/O Bereich liegen. Was hier im Thread auch anfangs klar geschrieben steht.
:
Bearbeitet durch User
Thomas T. schrieb: > Dein erster Satz ist definitiv falsch, wenn man sich nur auf das > "Register Summary" bezieht: Dort hat der Stack 11 Bit und das reicht > nicht aus! doch das reicht dicke denn du vergisst die verdammte 0, sp0-sp10 sind und bleiben 11 bit. 0-9 = 10 Ziffern unter 8.3 findest du ein simples bild welches es nochmal verdeutlicht wo der Ram anfängt und aufhört.
c-hater schrieb: > Thomas T. schrieb: > >> Dein erster Satz ist definitiv falsch, wenn man sich nur auf das >> "Register Summary" bezieht: Dort hat der Stack 11 Bit und das reicht >> nicht aus! > > Natürlich reicht das aus. 11 Bit können 2^11 Adressen ansprechen. Wenn > du das mal in irgendeinen vergurkten Taschenrechner eingibst, dann kommt > was raus? > > ...2048 > > Und wie groß ist das SRAM eines Mega328P? 2048 Bytes. Was für ein > Zufall... > >> Es wird auch nichts per irgendwelcher wrap-around-Mathematik gerechnet. > > Du bist definitiv ein Nixwisser/Nixkönner. Das allein ist noch nix > Schlimmes, denn schließlich hat absolut jeder mal so angefangen. Auch > ich übrigens. > > Aber Unwissend/Unfähig und dann noch stolz darauf, das geht garnicht... Passendes Beispiel eines Dunning-Kruger-Effekts ... Diskussion ist bei diesem Niveau sinnlos. Kein weiterer Text, Thomas
chris schrieb: > doch das reicht dicke denn du vergisst die verdammte 0, sp0-sp10 sind > und bleiben 11 bit. SP adressiert den Datenspeicher, nicht direkt das RAM-Array und wird deshalb qua Datasheet auf RAMEND initialisiert. RAMEND = 0x08FF = 0000.1000.1111.1111 xxxx xxxx xxxx = 12 Bits
A. K. schrieb: > SP adressiert den Datenspeicher, nicht direkt das RAM-Array und wird > deshalb qua Datasheet auf RAMEND initialisiert. > > RAMEND = 0x08FF = 0000.1000.1111.1111 > xxxx xxxx xxxx = 12 Bits das ist ja richtig. die frage war aber warum der stack bei 8ff aufhört und nicht bei 7ff und wenn man sich das bild nur bezogen auf das sram anschaut und mal kurz durchrechnet kommt man auf die 7ff und somit brauch sph auch nur bis 0x07 "zählen".
Eben nicht. Der SP kann auch den I/O-Bereich und die Register adressieren. Sinnvoll ist das eher nicht, aber es ist so (zumindest war es bei den frühen AVRs so, und ich denke nicht, dass da was geändert wurde). Lustige Sachen, wenn der stack in den Bereich wächst :-)
chris schrieb: > brauch sph auch nur bis 0x07 "zählen". Herrje. SP adressiert den Datenadressraum, ohne Adder, Offset oder irgendwelche Tricks. Nicht das SRAM Array. Deshalb steht anfangs 0x8FF drin und nicht 0x7FF. Und nun erzähl mir bitte, wie du den Wert 0x8FF in ein Register kriegst, das nur die unteren 11 Bits implementiert. Klar liesse sich das anders machen. Atmel hätte zum SP jedes Mal 0x100 dazu addieren können, bevor damit das RAM angesprochen wird. Machen sie aber nicht.
H.Joachim Seifert schrieb: > Eben nicht. Der SP kann auch den I/O-Bereich und die Register > adressieren. Hat das eigentlich mal jemand ausprobiert? Also SP=0x000F beispielsweise, und dann zusehen, wie der Stack in R15 abwärts schreibt.
ich seh es grade im simulator, dass das sph 4bit breit ist, war zu sehr auf den sp fixiert und die untere adressieung ausser acht gelassen. soll i ma probiern?
Ein Simulator simuliert nominelles, nicht reales Verhalten. Es ist also nicht gewährleistet, dass sich der Simulator dabei wie die Hardware verhält.
zumindest macht er es so wie du es beschrieben hast, fehlt halt vielleicht ne anwendung wo man dieses gebrauchen kann bzw mir fällt gerade nix ein 0.o
Um auch etwas zu dieser ulkigen Diskussion beizutragen:
> jemand ausprobiert?
Also meinen einzigen 328P reisse ich nicht aus seiner Umgebung, aber mit
einem alten 168 geht es nicht, nachfolgendes Programm liefert an D 00.
.include "m168def.inc"
.def tmp0 = r16
.org 0
ldi tmp0,$FF
out DDRD,tmp0
ldi tmp0,0
out SPH,tmp0
ldi tmp0,15
out SPL,tmp0
ldi tmp0,$A5
push tmp0
out PORTD,r15
rjmp pc
chris schrieb: > zumindest macht er es so wie du es beschrieben hast, fehlt halt > vielleicht ne anwendung wo man dieses gebrauchen kann bzw mir fällt > gerade nix ein 0.o "Wir haben die Lösung! Jetzt suchen wir noch nach dem zugehörigen Problem." :-) Es gibt tatsächlich Fälle, da will man den SP in einem Adressbereich haben, in dem er das RAM nicht beschreiben kann: man benötigt das komplette RAM für Variablen oder als Puffer und man verwendet Interrupts. Das ist aber schon arg speziell und wirklich selten.
Markus Weber schrieb: > Es gibt tatsächlich Fälle, da will man den SP in einem Adressbereich > haben, in dem er das RAM nicht beschreiben kann: > man benötigt das komplette RAM für Variablen oder als Puffer und man > verwendet Interrupts. Dann lege ich mir den Stackpointer auf die unteren (hoffentlich nicht benutzten) Register und kann weiterhin Unterprogramme oder Interrupts benutzen... Das könnte tatsächlich funktionieren. Ist aber etwas bizarr... Gruß, Thomas
Thomas T. schrieb: > Das könnte tatsächlich funktionieren. Ist aber etwas bizarr... Könnte wohl, tuts aber nicht, siehe grad eben 20:09. Ist eine Frage der internen Busse bzw. Muxer. Wenn SP per Muxer direkt an den Adressen vom RAM hängt, dann geht das nicht. Dann wärs sogar denkbar, dass die geschriebenen 0xA5 an der Adresse 0x80F gelandet sind. Im Simulator hingegen gehts. Siehe 19:41. Soviel zum Verhalten von Simulatoren ausserhalb ihres vorgesehenen Einsatzzwecks.
:
Bearbeitet durch User
Wohingegen dieses: ldi tmp0,$FF out DDRD,tmp0 ldi tmp0,$00 out SPH,tmp0 ldi tmp0,15 out SPL,tmp0 ldi tmp0,$A5 clr r15 push tmp0 pop r15 out PORTD,r15 das $A5 auf D bringt; wo, bitte, wurde der Wert gespeichert? (Oder liegt es am 168, date-code 0452?)
Thomas T. schrieb: > Markus Weber schrieb: > Dann lege ich mir den Stackpointer auf die unteren (hoffentlich nicht > benutzten) Register und kann weiterhin Unterprogramme oder Interrupts > benutzen... > > Das könnte tatsächlich funktionieren. Ist aber etwas bizarr... Ja, schon etwas arg speziell. :-) Die in den Adressbereich gemappten Register sind per SP übrigens nicht beschreibbar. Das ist allerdings nur durch praktische Versuche nachgewiesen, das Datenblatt schweigt sich dazu aus. Also vor dem Verwenden besser selber prüfen, es gibt keine Garantie dafür, dass es auf bei zukünftigen AVR so sein wird. Interrupts lassen sich zwar verwenden, aber man sollte dann besser kein Hauptprogramm haben, das an der Unterbrechungsstelle fortgesetzt werden muss, diese Adresse geht nämlich verloren. Meine Anwendung war damals allein ereignisgesteuert und bestand nur aus Interrupt-Routinen (einschließlich Timer-Interrupts). Unterprogrammaufrufe gehen, aber halt ohne Stack. Das heißt, man muss die Rücksprungadresse in ein Register legen. -> Makros zcall und zret. Reicht für eine Unterprogrammebene, Verschachtelungen müssen manuell behandelt werden. Wie gesagt, schon arg speziell und eher von wissenschaftlicher als von praktischer Bedeutung.
der alte Hanns schrieb: > das $A5 auf D bringt; wo, bitte, wurde der Wert gespeichert? Guck mal ins RAM. An Adresse 0x80F, oder 0x40F bei 1KB RAM. Wenn SP direkt am Adressmuxer vom RAM hängt und nicht dekodiert wird, weil bei den Typen ohne Support für externes RAM unnötig, dann landet das Byte genau dort.
:
Bearbeitet durch User
Nein, auf Ihren Hinweis hin hatte ich schon unter $80F nachgeschaut, dort steht $00, ebenso $40F.
Dann käme noch ein floatender Datenbus in Frage, dessen Kapazität den Wert hält. Mach zwischen PUSH und POP mal was mit RAM, an einer existierenden Adresse und einem anderen Wert.
Treffer! Nachfolgendes bringt $00: ldi tmp0,$FF out DDRD,tmp0 ldi tmp0,$00 out SPH,tmp0 ldi tmp0,15 out SPL,tmp0 ldi tmp0,$A5 clr r15 push tmp0 ldi tmp0,$66 sts $400,tmp0 clr ZH sbiw ZL,1 brne pc-1 pop r15 out PORTD,r15 rjmp pc Jetzt allerdings verabschiede ich mich, zumal mein alter 168 von vor 10 Jahren sicher keine Rückschlüsse auf heutige Versionen erlaubt.
Da hatte ich Sie wohl falsch verstanden, also Nachtrag: nur ldi tmp0,$66 sts $400,tmp0 also ohne diese Zeitschleife bringt tatsächlich $66. Treffer - versenkt !
der alte Hanns schrieb: > zumal mein alter 168 von vor 10 > Jahren sicher keine Rückschlüsse auf heutige Versionen erlaubt. Weshalb sollte sich da viel verändert haben? AVR hat seither zwar ein A und ein P dran gehängt, was mit Herstellungsprozess und Stromverbrauch zu tun hat, aber am Core hat sich m.W. nichts geändert. Das sind keine x86er. Danke für die Bemühungen!
:
Bearbeitet durch User
Da scheinen Sie der Fachmann zu sein, zu meinem Gebiet gehört dies nicht. Aber ein wirklich merkwürdiges Verhalten. Und wenn mir wieder einmal etwas spanisch vorkommt, werde ich mit doppeltem Eifer den Fehler in meinem Programm suchen - insofern konnte ich doch noch Nutzen aus dieser ulkigen Diskussion ziehen.
> zumal mein alter 168 von vor 10 > Jahren sicher keine Rückschlüsse auf heutige Versionen erlaubt. Doch, das ist ja das schlimme.
Ich grabe morgen mal paar Schätzchen aus der 90er Serie aus, da liegt noch irgendwo was rum. Ich bin mir ziemlich sicher, dass man den unteren Bereich damit schreiben und lesen kann.
H.Joachim Seifert schrieb: > Ich grabe morgen mal paar Schätzchen aus der 90er Serie aus, da liegt > noch irgendwo was rum. Ich bin mir ziemlich sicher, dass man den unteren > Bereich damit schreiben und lesen kann. Per SP die Register lesen? Das wär interessant! Vielleicht geh ich auch mal suchen.
Ich habe noch einen 4414 von 1997 gefunden... Aber mit dem neuen AVR-Studio 6.2 gibts den beim STK500 gar nicht mehr.
Ähm, habe ich das richtig verstanden, dass man per push/pop mit SP < 0x100 nicht in die Register schreibt, sondern in einen sozusagen im Schatten dahinterliegenden Datenbereich? Und das das nicht bei allen Typen gleich ist? Wäre vielleicht jemand so nett, das mal zusammenfassend darzustellen? Das würde mich freuen.
Bitflüsterer schrieb: > Ähm, habe ich das richtig verstanden, dass man per push/pop mit SP < > 0x100 nicht in die Register schreibt, sondern in einen sozusagen im > Schatten dahinterliegenden Datenbereich? Richtig, damit schreibst du ins Controller-eigene WOM (Write-Only-Memory). :-) > Und das das nicht bei allen > Typen gleich ist? Ich kenne nur AVR, bei denen das so ist. Da sich das Datenblatt aber nicht darüber auslässt, ist es natürlich nicht ganz auszuschließen, dass es auch AVR gibt, bei denen man über diesen Weg die Register beschreiben kann.
Bitflüsterer schrieb: > Ähm, habe ich das richtig verstanden, dass man per push/pop mit SP < > 0x100 nicht in die Register schreibt, sondern in einen sozusagen im > Schatten dahinterliegenden Datenbereich? Nein. PUSH schreibt auf einen Bus, auf dem niemand hört. Das RAM nicht, weil ausserhalb seines Adressraums. Und die Register nicht, vielleicht weil es nicht ihr Bus ist und sie das überhaupt nicht mitbekommen. Wenn darauf der POP Befehl folgt, dann findet er ebenso keinen Ansprechpartner. Der Bus bleibt offen, tri-stated. Wenn zwischendrin sonst nichts auf dem Bus los war, dann liegt noch ein Weilchen der alte Wert drauf. Kurzzeitig in den Leitungs- und Gatekapazitäten gespeichert. Und das ist es, was der POP Befehl liest. Wenn dazwischen viel Zeit vergeht, dann ist diese Ladung abgebaut und es kommt nichts sinnvolles an. Wenn ein anderer Befehl des Bus unmittelbar vor dem POP nutzte (STS oben), dann steht der Wert davon drauf und POP kriegt die 0x66. Wer Lust am Experimentieren hat, der kann diese These mal ausprobieren, indem er die Wartezeit zwischendrin sukzessive erhöht bis sich der Wert ändert. Dieser Code darf natürlich den Bus nicht verwenden, da muss man ggf. etwas experimentieren. NOPs dürften sicher sein.
:
Bearbeitet durch User
Markus Weber schrieb: > Richtig, damit schreibst du ins Controller-eigene WOM > (Write-Only-Memory). :-) Danke für die Antwort. Der Scherz verunsichert mich ein wenig. Ist es so, das ein Wert der in Adressen < 0x100 per PUSH geschrieben wird, zwar nicht in einem Register landet, aber auch nicht per POP wieder hervorgeholt werden kann?
Hm, ich bekomme die alten Teile nicht mehr programmiert. Weder über STK500, Dragon oder ISP MKII.
Bitflüsterer schrieb: > Der Scherz verunsichert mich ein wenig. Ist es so, das ein Wert der in > Adressen < 0x100 per PUSH geschrieben wird, zwar nicht in einem Register > landet, aber auch nicht per POP wieder hervorgeholt werden kann? Doch, unmittelbar darauf eben schon. Das hatte ja Hanns irritiert: Beitrag "Re: ATmega328P: Höchste mögliche Adresse vom Stackpointer?" Das ist sozusagen wie DRAM, gespeichert in Kapazitäten. Nach einer Weile isser weg, der Inhalt. Jedes DRAM wird auf Dauer zum WOM, nur kann das u.U. Sekunden oder gar Minuten dauern.
:
Bearbeitet durch User
an crazyhorse Ein AT90S4433-8PI von 0045 zeigt dasselbe Verhalten, d.h. .include "4433def.inc" .def tmp0 = r16 .org 0 ldi tmp0,$FF out DDRD,tmp0 ldi tmp0,15 out SP,tmp0 ldi tmp0,$A5 clr r15 push tmp0 out PORTD,r15 rjmp pc bringt $00, wird jedoch zwischen push und out ein pop r15 zwischengeschaltet, so erscheint $A5. Gleiches Verhalten mit angepasstem Programm bei einem AT90S8515-8PI von 9825. an prx Mit diesem pop r15 kann ich beliebig viele nops vorschalten, es kommt immer $A5; Randbedingung: mega168, 5.0 V, 1 MHz: 8000 nops --> der Bus hält die Information mindestens 8 ms.
Ich finde es übrigens sinnvoll, daß PUSH und POP nicht den gesamten Datenadreßbereich ansprechen können, sondern nur den Teil, der mit RAM hinterlegt ist. Sonst würden Amok laufende Programme (Stacküberlauf) unkontrolliert I/Os überschreiben. Die indirekten Ladebefehle LD ... mit der Adresse in X, Y oder Z haben diese Einschränkung nicht. Mit denen kann man ohne Unterschied Register, I/O Register und RAM lesen und schreiben. Bei manchen Typen sogar das Flash lesen. XL
Geil, der ATmega hat ein DRAM :-)) Vielleicht kann man ja damit so eine Art "Recht auf Vergessen" im Firmwarebereich (Google light) einbauen ... Gruß, Stefan
> "Recht auf Vergessen"
Das haben wir ja bereits, "Data retention: 20 years at 85°C/ 100 years
at 25°C".
der alte Hanns schrieb: > Mit diesem pop r15 kann ich beliebig viele nops vorschalten, es kommt > immer $A5; Randbedingung: mega168, 5.0 V, 1 MHz: > 8000 nops --> der Bus hält die Information mindestens 8 ms. Also doch kein DRAM. Schade. ;-) Diesem Effekt war ich allerdings schon vor Jahrzehnten bei anderen Rechnern begegnet, also eine solche kapazitive Speicherung gibt es. Es sind auch andere Modelle für das Verhalten vorstellbar.
Beitrag #6629753 wurde von einem Moderator gelöscht.
Beitrag #6629881 wurde von einem Moderator gelöscht.
Dieser Beitrag ist gesperrt und kann nicht beantwortet werden.