Forum: Mikrocontroller und Digitale Elektronik Stack beim AVR


von Benedikt (Gast)


Lesenswert?

In welcher Reihenfolge speichert der der AVR die Adresse des PC bei
einem Interrupt in den Stack ?
Ich synchronisiere den AVR auf ein externes Ereignis. Sobald der
Interrupt auftritt, muss er an eine bestimmte Stelle springen. Dazu
ersetze ich die Rücksprungadresse durch meine eigenen Werte:

Interrupt:
pop temp
pop temp
ldi temp, low(Adresse)
push temp
ldi temp, high(Adresse)
push temp
reti

Oder muss high und low vertauscht werden ?
Im Datenblatt und einigen AppNotes habe ich nichts dazu gefunden. Es
steht nur "The stack pointer uses a post-decrement scheme" bei der
Beschreibung...

von Henning (Gast)


Lesenswert?

rcall

macht das selbe wie

push low(PC)
push high(PC)
rjmp

von Tobi (Gast)


Lesenswert?

hab gerad mal nachgeschaut: die grossen avr's scheinen einen 22bit pc
zu haben der dann in 3 byte auf dem stack landet. musst du mal schaun
ob das für dich relevant ist

von Stefan Kleinwort (Gast)


Lesenswert?

Interrupt:
pop temp
pop temp
;;pop temp   ;drittes pop nur bei 22-Bit-Adressen!
sei
jmp Adresse

sollte funktionieren.

Aber was zum Grauen willst Du damit denn machen? Einen Kopierschutz?
Eine Arbeitsplatz-Erhaltungsmassnahme?

Stefan

von Henning (Gast)


Lesenswert?

eine stackmanipulation.

die rücksprung adresse erst löschen (durch pop auslesen) dann mit neuen
werten wieder belegen (ldi und push) und dann kann mittls reti die
gespeicherte adresse erreicht werden. dadurch wird der prozessor aber
natürlich den weg zu seiner eigentlichen stelle finden, an der er
unterbrochen wurde (deswegen ja auch manipulation)

von Jörg Wunsch (Gast)


Lesenswert?

Hab's mal kurz ausprobiert.  Interessanterweise ist der AVR an dieser
Stelle "big-endian", d. h. die unteren 8 Bit der Rücksprungadresse
stehen auf der höheren Adresse.  Zu beachten ist, daß die
Rücksprungadresse eine (16-bit-)Wortadresse ist.

von Peter D. (peda)


Lesenswert?

"Aber was zum Grauen willst Du damit denn machen? Einen Kopierschutz?
Eine Arbeitsplatz-Erhaltungsmassnahme?"


Er will ein Minenfeld anlegen, in das er zu 99,9% selber reintappt.

Ein Interrupt kann ja überall reinhauen. Und wenn man überall erst
nachdenken muß, ob das gut geht, dann kommt man nicht mehr zum
eigentlichen Programmieren.


Im günstigsten Fall riskiert man einen nicht ausbalancierten Stack, in
der Regel aber weit schlimmeres.


Peter

von Stefan Kleinwort (Gast)


Lesenswert?

@Henning:
Was der Code macht, das ist natürlich klar. Aber wozu kann man so etwas
-vernünftig- einsetzen?
Das Hauptprogramm ist ja verloren, und damit auch die Info über dessen
Stackaufbau. Wenn man so etwas häufiger in dieser Form macht, kann es
sogar einen Stack-Overflow geben.

Stefan

von Hagen (Gast)


Lesenswert?

Jo, zB. das der IRQ in einer mit RCALL aufgerufenen Funktion erfolgte.
Diese Funktion hat zusätzlich noch einige lokale Variablen auf dem
Stack gesichert usw. usw. Durch die Manipulation der Rücksprungadresse
der ISR wird nun erreicht das 1. alle RET's in den Unterfunktonen nun
falsch zürckspringen, sogar an Adressen die durch lokale
stckgespeicherte Variablen bestimmt werden, und 2. alle lokalen
Variablen nicht vom Stack genommen werden, und 3. somit ein
Stacküberlauf eintritt.

Bei diesem Trick müsste man schon eine extrem kleine Hauptschleife im
Program haben. Nur diese Schleife steht zwischen einem SEI/CLI Block.
Somit ist sichergestellt das IRQ's nur in ganz kontrollierten
Bedingungen auftreten können. Allerdings durch solche Bedingungen
zerstört man sich ja gerade die Vorteile der asynchronen Interrupts.

Gruß Hagen

von Benedikt (Gast)


Lesenswert?

Stackoverflow ?
Wie denn ? Ich verringere den Stack um 2 Bytes und lade zwei neue Bytes
auf den Stack -> die Größe bleibt gleich.

Dies ist eine Displayansteuerung mit externem Sync Signal.
Kommt das Signal, unterbricht der AVR seine Arbeit und beginnt damit
ein neues Bild auszugeben. Leider reicht es nicht den Adresszähler auf
0 zu setzen, sondern der uC muss sofort nach dem Sync Signal das neue
Bild gesendet werden.

von Henning (Gast)


Lesenswert?

für den fall, in dem er interrupt auftaucht, nachdem zB ein wert gepusht
wurde aber noch nicht wieder gepopt wurde hast du das chaos sicher.

von crazy horse (Gast)


Lesenswert?

wenn das sowieso höchste Priorität hat, was spricht denn dann dagegen,
das Bild während der ISR aufzubauen?
Ich würde auch auf jeden Fall versuchen, die Finger von derartigen
Experimenten zu lassen.

von Stefan Kleinwort (Gast)


Lesenswert?

@Benedikt:
Wenn Du nur den IR betrachtest, ist das schon richtig. Was aber das
Hauptprogramm vorher mit dem Stack angestellt hat, geht verloren. Dazu
2 Beispiele:

void test(void){
}

void main(void){ -> Stack 80hex
  while(1){
    test();      -> Stack innerhalb test = 7Ehex
  }
  -> hier tritt Interrupt auf und springt zu bild_malen (Stack = 80h)
}


Beispiel 2:
-----------

void test(void){
  -> hier tritt IR auf und springt zu bild_malen (Stack = 7Eh)
}

main(){        -> Stack 80hex
  while(1){
    test();    -> Stack 7Ehex
  }
}


Warum gibst Du Dein Bild nicht komplett im IR aus? Und springst ganz
normal mit reti wieder in Dein Hauptprogramm zurück?

Stefan

von Benedikt (Gast)


Lesenswert?

Das Bild wird im Hauptprogramm ausgegeben. Ist das Bild zuende wartet
das Programm in einer Endlosschleife.
Tritt irgendwann (egal ob in der Endlosschleife oder schon vorher) der
Interrupt auf, wird das Hauptprogramm neu gestartet.
Normalerweise würde ich in der IR nur ein Bit setzen, das vom
Hauptprogramm abgefragt wird und dann einen Sprung macht, aber da alles
sehr Zeitkritisch ist, dauert es zu lange.

Ich habe das beim 8051 schon problemlos eingesetzt und hatte noch nie
Probleme.

Andere Frage:
Ich setze vor das Hauptprogramm ein .org 0400
Wiso ist es nachher auf 0x0200, wenn ich die Datei in einem Hexeditor
betrachte ?
Was muss ich nun in den PC schreiben, damit ich da lande ?
0x0100,0x200 oder 0x400
Ich würde 0x200 sagen, denn der PC zählt Words, also 400/2 ?

von Henning (Gast)


Lesenswert?

(AVRStudio)
das org als hexzahl angeben, dann landest du auch an der hex adresse

wenn du nach $400 willst geht bei mir .ORG 0x400 oder .ORG $400

von Tobi (Gast)


Lesenswert?

ich kann hier allen nur zustimmen. der ansatz ist einfach für diese
aufgabe nicht wirklich gut und nötig. es spricht doch nichts dagagen
das bild im interrupt auszugeben oder kann es auch passieren, dass ein
zweites bild ausgegeben werden soll während das erste noch dran ist?
aber selbst das liesse sich besser erledigen.
was spricht dagegen dass ganze mit einem flag zu lösen, das würde nur
maximal 3 takte länger dauern als deine lösung und du hättest nich so
eine fehlerquelle drin. erweiterbarkeit errreichst du dadurch auch
nicht wirklich weil eine neue zeile code auf einmal alles schrotten
kann...

ich hab sowas früher mal bei x86 assembler gemacht und das hat viele
schlaflose nächte gekostet bis es lief, und da hat man nicht ganz so
probleme mit begrenzten ressourcen

von Christof Krüger (Gast)


Lesenswert?

Sinnvoll kann man solche Stackmanipulationen anwenden, wenn man eine Art
Scheduler benutzt. Allerdings sollte dann auch jeder Task seinen eigenen
Stack haben, sonst ist das Chaos vorprogrammiert.

von Benedikt (Gast)


Angehängte Dateien:

Lesenswert?

OK, ihr habt mich überredet, ich habs jetzt ohne Externen Interrupt
gemacht (u.a. deshalb, weil das andere nicht so ging wie ich wollte...)
Sobald ein Bild fertig übertragen ist, hängt der uC in einer
Endlosschleife in der er nur wartet bis das VSync Signal kommt und
springt dann an die Initialisierung fürs nächste Bild.
Funktioniert problemlos solange die Sync Signale einigermaßen passen.
Da ich nur 128kByte Speicher (für 512x256 Pixel) verwende, ein TV
Halbbild aber 312,5 Zeilen hat, ist der uC eher fertig.
Damit ihr wisst, worum es eigentlich geht, hier mal die ganze
Beschreibung:
Ich habe mal ein Testbild angehängt, wie es auf dem TV erscheint. Da
ich leider im Moment keine Digitalkmera habe, nur ein Screenshot von
der TV Karte.
Bisher lief anstelle des pinkompatiblen AVRs AT90S8515 ein AT89S51 mit
1,8432MHz CPU Takt (also 22,1184MHz Quarz). Dieser war zu etwa 90%
ausgelastet, ich hab mal den Pixeltakt von 10MHz auf 12MHz erhöht und
da haben schon ein paar gefehlt.
Der AVR ist mit 7,3728MHz und dank den Registern (bei gleichem Takt
etwa 50% schneller als der 8051) ausreichend schnell, um zusätzlich zur
Bildausgabe noch Befehle per UART empfangen zu können.
Anfangs wollte ich SPI nehmen, aber ich brauche die 9bit um mir eine
primitive Grafikkarte mit TVOut zu basteln.
Es wird nur wenige Befehle geben, die aber ausreichen:
- Farbpalette ändern
- Maske schreiben (um anstelle der 256 Farben auch 2 Bilder mit 16
Farben, 4 Bilder mit 4 Farben oder 8 Bilder mit 2 Farben für
Animationen speichern zu können)
- Adresse setzen
- Daten schreiben (mit Autoinkrement)
Das neunte Bit entscheidet zwischen Daten und Befehl so wie die RS
Leitung beim HD44780 oder C/D Leitung beim T6963.

von Christof Krüger (Gast)


Lesenswert?

Wie erstellst du denn das Video-Signal mit einem AVR? Finde ich
interessant, hab aber keine Ahnung von. Ein PAL-Signal ist doch ein
analoges Signal, oder?

von Benedikt (Gast)


Lesenswert?

Der AVR dient als Grafikcontroller, steuert einen VRAM, der mit 10MHz
8bit Daten an den RAMDAC liefert. Dieser schaut im internen RAM nach,
welche RGB Werte die entsprechende Farbe hat und erzeugt dann die drei
analogen Signale.
Ein zweiter AVR (AT90S1200) mit 12MHz erzeugt ein Standart PAL
Composite Sync Signal. Beides geht entweder in die Scartbuchse oder
wird über einen Videoenkoder (z.B. AD722) in ein PAL Signal
umgewandelt.
Die Schaltung besteht im Moment aus 4 Spezial ICs (2x AVR, VRAM,
RAMDAC), drei Quarzen (12MHz, 10MHz und 7,3728MHz) und drei HCMOS IC
(fürs Sync Timing und um dementsprechend den Pixel Takt während des
Zeilenrücklaufs abzuschalten, so dass alle 512x256 Pixel sichtbar
sind.)

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.