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...
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
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
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)
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.
"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
@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
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
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.
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.
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.
@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
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 ?
(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
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
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.
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.
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?
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.