Forum: Mikrocontroller und Digitale Elektronik Assembler-Verständnisproblem beim attiny13a


von Stephan E. (loetzinn02)


Angehängte Dateien:

Lesenswert?

Grüß Gott zusammen,

es geht um einen attiny13a und den CTC-Mode (Assembler).
Ziel ist es, den Port PB0 bzw. OC0A kurz ein- und dann wieder 
auszuschalten.
Dazu wird der timer0 im CTC-Mode verwendet. Das funktioniert auch im 
Simulator, aber nicht auf einem echten Chip, wenn ich das über COM0A0=1 
und COM0A1=1 mache.
Anbei zwei Codes - der eine mit, der andere ohne gesetztes COM0A0 bzw. 
-1.

Aus dem Datenblatt:
Compare output mode, non-PWM Mode:
WGM01=1, COM0A0=1 und COM0A1=1 => CTC-Mode mit "Set OC0A on Compare 
Match"

Wenn ich nur WGM01=1 setze und den Pin PB0 über die Interrupts der
compare-matches oc0a und oc0b setze, läuft alles wie erwartet, sowohl im 
Simulator als auch auf echter Hardware. Im anderen Fall bleibt der Pegel 
auf einem echten Chip am Port PB0 permanent high, im Simulator zeigt das 
Oszilloskop jedoch in beiden Fällen genau das gleiche.

Beide Codes sollten vom Ergebnis her genau das gleiche liefern, oder? 
Beim einen setze ich den Port manuell, beim anderen sollte das 
automatisch gemacht werden.
Die Frage ist - was mache ich beim Code "funktioniert nicht" falsch?

von Jobst M. (jobstens-de)


Lesenswert?

Du kannst entweder auf den Port schreiben (SBI/CBI), dann sind  COM0A0=0 
und COM0A1=0 -> "Normal port operation, OC0A disconnected."

ODER

Der Timer hat Kontrolle über den Pin und kann ihn mit COM0A0=1 und 
COM0A1=1 nur setzen. Dann haben aber SBI/CBI auf den Portpin keinen 
Einfluss mehr.

Siehe im DaBla auch Kapitel: Alternate Port Functions - vor allem das 
Signal PVOExn


Wenn ich das richtig sehe, schaltest Du den Portpin immer an und aus.
Wäre dann nicht ein PWM-Mode die richtige Wahl?
Dann geht es auch ohne IRQ.
Allerdings muss ich zugeben, dass ich nicht so ganz begriffen habe, was 
Du möchtest, da Du nicht Dein Problem, sondern das Problem Deiner Lösung 
beschrieben hast.


Gruß
Jobst

von Gregor J. (Firma: Jasinski) (gregor_jasinski)


Lesenswert?

Jobst M. schrieb:
> Allerdings muss ich zugeben, dass ich nicht so ganz begriffen habe, was
> Du möchtest

Ich auch nicht.

von Stephan E. (loetzinn02)


Lesenswert?

Jobst M. schrieb:
> Du kannst entweder auf den Port schreiben (SBI/CBI), dann sind  COM0A0=0
> und COM0A1=0 -> "Normal port operation, OC0A disconnected."
>
> ODER
>
> Der Timer hat Kontrolle über den Pin und kann ihn mit COM0A0=1 und
> COM0A1=1 nur setzen. Dann haben aber SBI/CBI auf den Portpin keinen
> Einfluss mehr.

Vielen Dank für die sehr erhellende Antwort. Dann scheint der Simulator 
das schlicht falsch wiederzugeben, denn dort funktioniert das.


> Allerdings muss ich zugeben, dass ich nicht so ganz begriffen habe, was
> Du möchtest, da Du nicht Dein Problem, sondern das Problem Deiner Lösung
> beschrieben hast.

Ich verfolge derzeit keine konkreten Ziele, ist nur ein reines Hobby. 
Ich möchte nur im Detail nachvollziehen können, was genau da im 
Controller wie warum passiert und nebenbei mein bißchen Assembler 
vertiefen. Deine Antwort hat mich weiter gebracht, danke dafür.

von Gregor J. (Firma: Jasinski) (gregor_jasinski)


Angehängte Dateien:

Lesenswert?

Stephan E. schrieb:
> (...) und nebenbei mein bißchen Assembler vertiefen.

Stapel richtig benutzen, das Retten der Register über Register macht man 
nur in Ausnahmefällen und 64 Bytes SRAM sollten laut Datenblatt bei 
diesem Baby-µC vorhanden sein, sonst wird man bald schnell in Teufels 
Küche kommen. Hier ist es sogar so, dass man in den beiden 
Interruptroutinen gar nichts retten müsste, weil SBI und CBI weder Flags 
noch Arbeitsregister beeinflussen – man sollte es sich aber von Anfang 
an angewöhnen, es richtig mit Stapel zu machen, denn dabei lernt man die 
richtige Schreibweise des Pro- und Epilogs, die ja – wie bei einem 
Kartenstapel – in umgekehrter Reihenfolge vollführt werden muss, damit 
am Ende alles wieder an seinem Platz ist. Ferner macht man sich mit 
µControllern mit so kleinen Ressourcen in der Regel das Leben selbst 
unnötig schwer – in PDIP8 gibt es z.B. auch den ATTINY85, mit dem man 
weniger komische Akrobatik wegen Ressourcenmangel vollführen muss.

: Bearbeitet durch User
von Stephan E. (loetzinn02)


Lesenswert?

Gregor J. schrieb:
> Ferner macht man sich mit
> µControllern mit so kleinen Ressourcen in der Regel das Leben selbst
> unnötig schwer – in PDIP8 gibt es z.B. auch den ATTINY85, mit dem man
> weniger komische Akrobatik wegen Ressourcenmangel vollführen muss.


Nicht zuletzt macht gerade das für mich den Reiz aus. Ich bin immer 
wieder fasziniert, was mit diesem Minimalisten so alles möglich ist. 
Damit habe ich beispielsweise schon ein Bewässerungssystem mit 
kapazitivem Feuchtigkeitssensor gebastelt und dabei recht viel gelernt 
(minimaler Stromverbrauch, Watchdog, ADC). Oder diese 
billigst-Lichterketten mit einigen Blinkmustern (inklusive 
Morsebotschaft und z.B. auto-save des letzten Programms) versehen.
Der Weg ist das Ziel, und nach oben geht's immer.

Wenn man erst mal die Grundlagen kennt ist es ein leichtes, auch einen 
größeren der AVR-Familie zu verwenden (dann aber in C). Und wie gesagt - 
ich mache das nur als reines Hobby und bin sehr, sehr weit vom 
Profientwickler weg.

von Gregor J. (Firma: Jasinski) (gregor_jasinski)



Lesenswert?

Stephan E. schrieb:
> Nicht zuletzt macht gerade das für mich den Reiz aus. Ich bin immer
> wieder fasziniert, was mit diesem Minimalisten so alles möglich ist.

Ein sehr kleiner µController ist oft – zwar auf eine andere Art – aber 
dennoch genauso schwierig zu handhaben wie ein großer, vor allem in 
Assembler, wo alles sehr knapp bemessen ist, man für alles selbst sorgen 
muss und die Pinanzahl zusätzlich noch extrem begrenzt ist. Wie man gut 
sehen kann, bist Du hier schon einfach an einem Portpin eines Timers 
gescheitert, weil Dir die Grundlagen zu den Betriebsmodi fehlen, obwohl 
das alles sehr gut im Datenblatt erklärt und sogar mit Beispielen, 
Bildern und Zeitdiagrammen unterstützt wird. Normalerweise nimmt man am 
Anfang etwas Moderates aus der Mitte der Produktpalette, nichts Extremes 
– also weder zu klein noch zu groß – arbeitet sich dann nach und nach 
durch die Themen mit Oszilloskop und Voltmeter ausgestattet durch und 
kann dann bei Bedarf in der Regel auf etwas sowohl Kleineres als auch 
Größeres übergehen. Die ausgewogene Mitte bildet hier oft der ATMEGA328P 
– wenn man den vollständig durchgearbeitet und begriffen hat, kann man 
praktisch alle ATMEGAs und die älteren ATTINYs. Es gibt genügend 
Speicher, Portpins etc. – die ganzen besonderen, schwierigen Umstände 
für einen Assembler-Einstieg hat man hier nicht, man kann sich auf das 
Wesentliche konzentrieren. Und die hier in diesem Forum oft Verwendete 
Redewendung „ich hatte es gerade in der Bastelkiste” ist in so einem 
Zusammenhang völliger Unfug, denn man kann sich heutzutage für 2 Euro 
etwas Passenderes besorgen.

____________
> Wenn man erst mal die Grundlagen kennt (...)

Das mit dem richtigen Gebrauch des Stapelspeichers sind Grundlagen, die 
man sich unbedingt zuerst aneignen sollte, und Du hast einfach nur 
Glück, dass es bei den AVRs per default keine verschachtelten Interrupts 
gibt, also wo innerhalb eines Interrupts ein weiterer ausgeführt werden 
kann, denn dann wärst Du mit dieser Methode Register zu retten bereits 
geliefert. Wenn man nicht weiß, wie es geht, kann man sich auch das vom 
Compiler generierte anschauen (im Anhang ein Beispiel), es gibt auch 
genügend Beispiele im Netz. Leider auch falsche – irgendein Guru macht 
etwas vor und alle ahmen und vervielfältigen seinen Blödsinn kritiklos 
nach – das Forum ist leider auch damit verseucht bzw. davon betroffen.

____________
> Und wie gesagt - ich mache das nur als reines Hobby und bin sehr, sehr
> weit vom Profientwickler weg.

Ob Hobby oder Professionell – Assembler und die Grundlagen dazu sind auf 
allen Ebenen gleich, auch die Fehler, die man damit machen kann, sind 
gleich, insofern kann das niemals eine Rechtfertigung für schlechte 
Angewohnheiten oder nicht durchgearbeitete Themen sein – es ist einfach 
eine Ausrede, ein Ausweichen.

Viel Erfolg auf dem langen und steinigen Weg wünsche ich trotzdem.

: Bearbeitet durch User
von Gregor J. (Firma: Jasinski) (gregor_jasinski)


Angehängte Dateien:

Lesenswert?

Hier noch ein Beispiel wie ein Mensch es schreiben würde, weil ein 
Compiler in der Regel immer einen unnötigen Überhang mit Null-Register 
etc. generiert – wenn man es selbst in Assembler schreibt, rettet man 
nur das, was auch wirklich in der Interruptroutine angefasst wird (und 
das ist ja bekannt, weil man es selbst schreibt), in der Regel also das 
Statusregister und die Register, die man verwenden möchte – je weniger 
man braucht, desto besser für die Performance und den Speichergebrauch, 
denn es wird alles auf dem Stapel abgelegt und später in umgekehrter 
Reihenfolge wieder dort abgeholt – nach dem Verlassen der ISR muss alles 
wieder so hergestellt worden sein, wie es vor dem Einsprung der Fall 
war. Da es bei diesen AVRs keine expliziten PUSH/POP-Befehle für das 
Statusregister gibt, muss das über ein Hilfsregister erledigt werden – 
dieses Hilfsregister muss dementsprechend vorher gerettet werden und 
beim Epilog muss das entsprechend wieder alles umgekehrt gemacht werden. 
Und wie ich bereits sagte, bei CBI und SBI bräuchte man eigentlich gar 
nichts retten, denn es sind sehr besondere Befehle, obendrein ist der 
Zugriff auch noch atomic (unteilbar), also extrem wichtig und nützlich.

: Bearbeitet durch User
von Stephan E. (loetzinn02)


Lesenswert?

Gregor J. schrieb:
> Stephan E. schrieb:
>> Nicht zuletzt macht gerade das für mich den Reiz aus. Ich bin immer
>> wieder fasziniert, was mit diesem Minimalisten so alles möglich ist.
>
> Ein sehr kleiner µController ist oft – zwar auf eine andere Art – aber
> dennoch genauso schwierig zu handhaben wie ein großer, vor allem in
> Assembler, wo alles sehr knapp bemessen ist, man für alles selbst sorgen
> muss und die Pinanzahl zusätzlich noch extrem begrenzt ist. Wie man gut
> sehen kann, bist Du hier schon einfach an einem Portpin eines Timers
> gescheitert, weil Dir die Grundlagen zu den Betriebsmodi fehlen, obwohl
> das alles sehr gut im Datenblatt erklärt und sogar mit Beispielen,
> Bildern und Zeitdiagrammen unterstützt wird.

Ja, stimmt. Mir hat einfach das "ODER" gefehlt, welches Du in Deinem 
Posting weiter oben genannt hast. Ich bin halt davon ausgegangen, daß 
ich den Pin per sbi/cbi auch im genannten ctc-Mode setzen oder löschen 
kann. Ich habe mich wohl geirrt, aber jetzt weiß ich's.


> Das mit dem richtigen Gebrauch des Stapelspeichers sind Grundlagen, die
> man sich unbedingt zuerst aneignen sollte

Auch das ist richtig. Und ja, ich bin schon über einen nicht 
initialisierten Stackpointer oder ein vergessenes "pop" am Ende der 
Routine geflogen.


> Viel Erfolg auf dem langen und steinigen Weg wünsche ich trotzdem.

Danke, und das nicht zuletzt auch nochmal für Deine hilfreichen 
Antworten.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Gregor J. schrieb:

> Wenn man nicht weiß, wie es geht, kann man sich auch das vom
> Compiler generierte anschauen (im Anhang ein Beispiel)

Wobei das Beispiel offenbar mit einem total veralteten Compiler (v7 oder 
älter) erstellt wurde und viele unnötige Instruktionen enthält. Ab v8 
(Release 2018) ist das nicht mehr der Fall.

von S. L. (sldt)


Angehängte Dateien:

Lesenswert?

> Mir hat einfach das "ODER" gefehlt, welches Du in Deinem
> Posting weiter oben genannt hast.

Na, wir wollen festhalten: Gregor J. mag zwar sehr viel geschrieben 
haben, aber das "ODER", bzw. der entscheidende Hinweis, kam gleich zu 
Beginn und kurz gehalten von Jobst M.!
  Allenfalls könnte man noch den Abschnitt aus 'Compare Match Output 
Unit' ergänzen.

von Gregor J. (Firma: Jasinski) (gregor_jasinski)


Lesenswert?

Johann L. schrieb:
> Wobei das Beispiel offenbar mit einem total veralteten Compiler (v7 oder
> älter) erstellt wurde und viele unnötige Instruktionen enthält. Ab v8
> (Release 2018) ist das nicht mehr der Fall.

Das spielt keine Rolle, denn es geht darum zu zeigen, wie und was der 
Compiler macht, dass er die Register über den Stapelspeicher rettet, und 
richtig/konsistent ist es trotzdem, was der Compiler gemacht hat, egal 
wie viele unnötige Instruktionen hinzugefügt werden, was ich übrigens 
auch erwähnt habe, dass er das macht. Die Menge des Überhangs hängt auch 
immer davon ab, welche Optimierungsstufe man gewählt hat, was genau man 
in der ISR macht und wie umfangreich das ganze Programm selbst ist. Fürs 
Verständnis und zum Lernen ist das zweite Beispiel angefügt, wo gezeigt 
wird, wie ich es mit dem Statusregister und zwei Registern gemacht habe, 
weil ich auch nur zwei Register in der ISR benutze – man macht es in der 
Regel so, dass die Register immer wieder für verschiedene Aufgaben 
benutzt werden, um deren Anzahl insgesamt zu minimieren, denn dann wird 
es performant und man geht nicht so in die Tiefe mit dem Stapelspeicher, 
denn auch jede Subroutine bewirkt das, und wenn die Subroutinen auch 
noch verschachtelt werden, addiert sich alles zu einem Gesamtgebrauch, 
der bei einem kleinen SRAM, wo auch noch von unten nach oben Variablen 
platziert werden, zu Problemen führen kann, wo es dann bei zu großer 
Stack-Tiefe unglücklich zusammenlaufen kann.

: Bearbeitet durch User
von Gregor J. (Firma: Jasinski) (gregor_jasinski)


Angehängte Dateien:

Lesenswert?

Stephan E. schrieb:
> Auch das ist richtig. Und ja, ich bin schon über einen nicht
> initialisierten Stackpointer oder ein vergessenes "pop" am Ende der
> Routine geflogen.

Der Stackpointer muss immer als erstes initialisiert werden (Beispiel 
von mir mit einem 16-Bit langen Pointer als Screenshot), das ist quasi 
der Startschuss im Programm, die Anzahl der PUSHs und POPs muss immer 
gleich sein und die Reihenfolge (wie bei einem Kartenstapel) in der ISR 
auch immer umgekehrt gemacht werden, damit alles am Ende passt, weil 
jeder Fehler sofort zum Absturz oder einer Fehlfunktion führen wird – 
das macht man aber mit dem Stapelspeicher seit mindestens 50 Jahren bei 
quasi allen Mikroprozessoren so, denn genau dafür wurde er von den 
Ingenieuren entwickelt und genau deswegen gibt es bei µControllern in 
der Neuzeit auch die entsprechenden Instruktionen im Befehlssatz und 
genau deswegen macht auch der Compiler davon Gebrauch. Wenn man es 
einmal richtig verstanden hat, ist es im Grunde genommen relativ einfach 
und man kann auch das schon einmal richtig Geschriebene in den eigenen, 
neuen Assemblerprojekten immer wiederverwenden, ggfs. auch leicht 
erweitern – das Muster ist immer gleich und man muss das Rad nicht immer 
wieder neu erfinden. Den Stapelspeicher kann man übrigens auch lokal und 
temporär als Zwischenspeicher benutzen, wenn es mit den Registern eng 
wird oder man Parameter an Subroutinen übertragen möchte; auch innerhalb 
von Subroutinen, um die Registerinhalte nicht zu zerstören – nach dem 
Gebrauch muss aber auch hier alles wieder konsistent in puncto Stack 
sein.

______
> Danke, und das nicht zuletzt auch nochmal für Deine hilfreichen
> Antworten.

Sehr gerne.

: Bearbeitet durch User
von Peter D. (peda)


Angehängte Dateien:

Lesenswert?

Gregor J. schrieb:
> Der Stackpointer muss immer als erstes initialisiert werden

Nö, das war ganz früher mal 1997 bei den allerersten AT90Sxxx nötig.
Selbst beim alten ATtiny13 zeigt er schon richtig auf 0x9F.

von Peter D. (peda)


Lesenswert?

Jobst M. schrieb:
> Der Timer hat Kontrolle über den Pin und kann ihn mit COM0A0=1 und
> COM0A1=1 nur setzen. Dann haben aber SBI/CBI auf den Portpin keinen
> Einfluss mehr.

Dafür gibt es auch die Bits FOC0A, FOC0B. Damit kann man ein sofortiges 
Compare Match erzwingen und so die Ausgänge setzen. "The OC0A output is
changed according to its COM0A1:0 bits setting."

von S. L. (sldt)


Lesenswert?

>> Der Stackpointer muss immer als erstes initialisiert werden
> Nö, das war ganz früher mal 1997 bei den allerersten AT90Sxxx nötig.

Aber auch z.B. noch beim ATmega16 und dessen Geschwistern (ATmega32, 
ATmega8).

von Gregor J. (Firma: Jasinski) (gregor_jasinski)


Angehängte Dateien:

Lesenswert?

Peter D. schrieb:
> Nö, das war ganz früher mal 1997 bei den allerersten AT90Sxxx nötig.
> Selbst beim alten ATtiny13 zeigt er schon richtig auf 0x9F.

Darauf sollte man sich nicht verlassen, denn eines Tages erwischt es 
einen doch, d.h. man sollte das auch von Anfang an richtig lernen, 
selbst der Compiler macht das, er löscht sogar noch das Statusregister 
beim Start. Aber ich habe noch ein andere, wichtigere Nachricht für Dich 
& Co: wir sind hier nicht bei C und auch nicht beim Compiler, sondern 
beim Assembler, wo man alles selbst schreibt und auch alles selbst 
bestimmen darf, d.h. je nach Konzept möchte man den Stapel auch mal 
woanders im SRAM haben, nicht unbedingt an seinem Ende. Auch die eigenen 
Variablen darf man dort platzieren, wo es einem am besten passt – und 
das muss nicht immer der Anfang vom SRAM sein.

von Peter D. (peda)


Lesenswert?

Gregor J. schrieb:
> wir sind hier nicht bei C und auch nicht beim Compiler, sondern
> beim Assembler, wo man alles selbst schreibt

Besser gesagt: "... wo man den ganzen lästigen Verwaltungskram selber 
schreiben und überprüfen muß".
Das war für mich einer der Hauptgründe, nicht länger Zeit mit Assembler 
zu vertrödeln.

von Gregor J. (Firma: Jasinski) (gregor_jasinski)


Lesenswert?

Peter D. schrieb:
> Das war für mich einer der Hauptgründe, nicht länger Zeit mit Assembler
> zu vertrödeln.

Für mich auch, ich war einfach müde davon und wollte mich auf das 
Wesentliche beim Programmieren konzentrieren. Hinzu kommt noch, dass man 
für komplexe Berechungen etc. einen enormen Zeitaufwand benötigt, um es 
zu schreiben – in C schreibt man die Berechnung einfach so hin in einer 
Zeile und der Compiler kümmert sich dann um den üblen Rest und der kann 
wirklich manchmal übel lang und kryptisch aussehen, wenn man sich das 
mal in der Assemblerdatei anschaut. Beim STM32 empfehle ich niemandem, 
irgendetwas in Assembler zu schreiben – wenn man es doch macht, was ja 
nicht verboten ist, wird man schon sehen (manchmal sehr selten sehen :), 
was man da angerichtet hat. Der Compiler kennt die Ausnahmen im Code und 
verwendet bestimmte Codeausdrücke bzw. Codekombinationen nicht, weil er 
mit den nötigen Informationen gefüttert wurde.

: Bearbeitet durch User
von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Gregor J. schrieb:

> selbst der Compiler macht das [...] beim Start.

Nitpick: Der Startup Code der AVR-LibC setzt SP nicht ans Ende des 
internen RAMs, sondern auf den Wert des Symbols __stack (welches 
wiederum den default Wert auf das Ende des internen RAMs hat).

Das ist der Grund, warum SP auch auf solchen Devices initialisiert wird, 
deren Hardware den SP nach einem Reset aufs RAM-Ende initialisieren: Der 
Anwender behält die Möglichkeit, __stack passend zu setzen.

: Bearbeitet durch User
von Peter D. (peda)


Lesenswert?

Da es keinen perfekten Programmierer gibt, ist es auch nicht unklug, den 
Stack auf einen gültigen Wert zu setzen und die Interrupts zu disablen, 
falls z.B. ein wilder Pointer über den Resetvektor läuft.
Dann kann man z.B. eine Debugmessage versenden oder im EEPROM speichern, 
daß noch dringend nachgearbeitet werden muß.

von Gregor J. (Firma: Jasinski) (gregor_jasinski)


Lesenswert?

Johann L. schrieb:
> Nitpick: Der Startup Code der AVR-LibC setzt SP nicht ans Ende des
> internen RAMs, sondern auf den Wert des Symbols __stack (welches
> wiederum den default Wert auf das Ende des internen RAMs hat).
> Das ist der Grund, warum SP auch auf solchen Devices initialisiert wird,
> deren Hardware den SP nach einem Reset aufs RAM-Ende initialisieren: Der
> Anwender behält die Möglichkeit, __stack passend zu setzen.

Wenn der Wert default bleibt, was ja bekannt ist, bräuchte er das nicht 
machen, könnte das überspringen, was aber offensichtlich nicht so ist. 
Dann musst Du jetzt nur noch erklären, warum er das Statusregister 
nullt.

: Bearbeitet durch User
von Gregor J. (Firma: Jasinski) (gregor_jasinski)


Lesenswert?

Peter D. schrieb:
> Da es keinen perfekten Programmierer gibt, ist es auch nicht unklug, den
> Stack auf einen gültigen Wert zu setzen und die Interrupts zu disablen,
> falls z.B. ein wilder Pointer über den Resetvektor läuft.

Abstürze geschehen nicht nur aufgrund von Programmierfehlern, sondern 
auch durch falsche Arbeitsbedingungen, die unerwartet (oder auch durch 
Unwissen und/oder Fahrlässigkeit des Entwicklers) eintreten können – 
z.B. das temporäre Absinken der Versorgungsspannung bei ungünstigen 
Umgebungstemperaturen, wo es dann bei zu hoher Arbeitsfrequenz zu 
Flashlesefehlern und dementsprechend unkontrolliertem Lauf über den 
ganzen Programmspeicher kommen kann. Nicht richtig oder ordnungsgemäß 
angeschlossene Quarze können auch scheinbar magische oder unerklärliche 
Taten diesbezüglich vollbringen.

: Bearbeitet durch User
von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Gregor J. schrieb:
> Johann L. schrieb:
>> Nitpick: Der Startup Code der AVR-LibC setzt SP nicht ans Ende des
>> internen RAMs, sondern auf den Wert des Symbols __stack (welches
>> wiederum den default Wert auf das Ende des internen RAMs hat).
>> Das ist der Grund, warum SP auch auf solchen Devices initialisiert wird,
>> deren Hardware den SP nach einem Reset aufs RAM-Ende initialisieren: Der
>> Anwender behält die Möglichkeit, __stack passend zu setzen.
>
> Wenn der Wert default bleibt, was ja bekannt ist, bräuchte er das nicht
> machen, könnte das überspringen, was aber offensichtlich nicht so ist.

Ich kenne kein Feature / keine Assembler- oder Linkerdirektive, die es 
ermöglicht, abhängig von einem bestimmten Symbol bestimmte Codesequenzen 
zu linken (oder eben nicht).

Oder wie sollte der Startup Code der AVR-LibC umgeschrieben werden, um 
dies zu erreichen?

von Ob S. (Firma: 1984now) (observer)


Lesenswert?

Johann L. schrieb:

> Ich kenne kein Feature / keine Assembler- oder Linkerdirektive, die es
> ermöglicht, abhängig von einem bestimmten Symbol bestimmte Codesequenzen
> zu linken (oder eben nicht).

Also ich schon. Beim Atmel-Assembler ist das überhaupt kein Problem. 
Schon deshalb, weil es da keinen Linker gibt und auch keinen braucht.

Es gibt da nur einen (hoffentlich) kompetenten Programmierer. Und wenn 
es den gibt, dann kontrolliert er mit den Sprachfeatures des Assemblers 
die gesamte Codegenerierung. Natürlich u.A. auch, ob ein bestimmter 
Programmteil abhängig vom Wert oder der Existenz eines Symbols übersetzt 
wird oder nicht.

Und das genügt. Der unnütze Schritt des "Linkens" entfällt hier ja 
komplett.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Und wie hilft das jetzt weiter?

von Spess53 .. (hardygroeger)


Lesenswert?

Hi

Weil es deine Aussage

>Ich kenne kein Feature / keine Assembler- oder Linkerdirektive, die es
>ermöglicht, abhängig von einem bestimmten Symbol bestimmte Codesequenzen

ad absurdum führt.

MfG Spess

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Im GNU Assembler ist das auch kein Problem, sofern das Symbol zur 
Assembler Zeit bekannt ist. Es ist aber erst zur Link Zeit bekannt, ein 
Konzept, das nicht mal existiert im Atmel Assembler. Von daher sehe ich 
nicht, wie Nennung des Atmel Assemblers weiter helfen könnte wie so ein 
Feature (bedingte Codeerzeugung abhängig von einem erst zur Linkzeit 
bekannten Symbol) mit den GNU Tools zu realisieren ist.

: Bearbeitet durch User
von Carl D. (jcw2)


Lesenswert?

Gregor J. schrieb:
> Peter D. schrieb:
>> Da es keinen perfekten Programmierer gibt, ist es auch nicht unklug, den
>> Stack auf einen gültigen Wert zu setzen und die Interrupts zu disablen,
>> falls z.B. ein wilder Pointer über den Resetvektor läuft.
>
> Abstürze geschehen nicht nur aufgrund von Programmierfehlern, sondern
> auch durch falsche Arbeitsbedingungen, die unerwartet (oder auch durch
> Unwissen und/oder Fahrlässigkeit des Entwicklers) eintreten können –
> z.B. das temporäre Absinken der Versorgungsspannung bei ungünstigen
> Umgebungstemperaturen, wo es dann bei zu hoher Arbeitsfrequenz zu
> Flashlesefehlern und dementsprechend unkontrolliertem Lauf über den
> ganzen Programmspeicher kommen kann. Nicht richtig oder ordnungsgemäß
> angeschlossene Quarze können auch scheinbar magische oder unerklärliche
> Taten diesbezüglich vollbringen.

Solange Fehler nur außerhalb der von Dir geschriebenen Software 
passieren können, wünsche ich Dir schon mal viel Spaß bei der 
Zielerreichung.

Ich finde auch nach 40J programmieren die Fehler zu 99.999% in meinem 
Code und nicht im Compiler/Betriebssystem/Hardware.

von Gregor J. (Firma: Jasinski) (gregor_jasinski)


Lesenswert?

Carl D. schrieb:
> Solange Fehler nur außerhalb der von Dir geschriebenen Software
> passieren können, wünsche ich Dir schon mal viel Spaß bei der
> Zielerreichung.
> Ich finde auch nach 40J programmieren die Fehler zu 99.999% in meinem
> Code und nicht im Compiler/Betriebssystem/Hardware.

Die Textinhalte zu verdrehen ist einfach, sie aber richtig zu deuten und 
zu verstehen, erfordert schon etwas Anstrengung – vielleicht solltest Du 
da erstmal ansetzen und mit der Fehlerfindung dort beginnen.

von Rbx (rcx)


Lesenswert?

Das ein oder andere Grundlagenbuch kann schon hilfreich sein. Oft haben 
die auch einen didaktischen Aufbau und andere Goodies, so dass man 
gewisse Schritte gut verdauen kann und am Ende schneller lernt und mehr 
gelernt hat.

von Chris S. (Firma: hier&da) (keiningenieur)


Angehängte Dateien:

Lesenswert?

Stephan E. schrieb:
> Grüß Gott zusammen,
>
> es geht um einen attiny13a und den CTC-Mode (Assembler).
> Ziel ist es, den Port PB0 bzw. OC0A kurz ein- und dann wieder
> auszuschalten.
> Dazu wird der timer0 im CTC-Mode verwendet. Das funktioniert auch im
> Simulator, aber nicht auf einem echten Chip, wenn ich das über COM0A0=1
> und COM0A1=1 mache.
> Anbei zwei Codes - der eine mit, der andere ohne gesetztes COM0A0 bzw.
> -1.
>
> Aus dem Datenblatt:
> Compare output mode, non-PWM Mode:
> WGM01=1, COM0A0=1 und COM0A1=1 => CTC-Mode mit "Set OC0A on Compare
> Match"
>
> Wenn ich nur WGM01=1 setze und den Pin PB0 über die Interrupts der
> compare-matches oc0a und oc0b setze, läuft alles wie erwartet, sowohl im
> Simulator als auch auf echter Hardware. Im anderen Fall bleibt der Pegel
> auf einem echten Chip am Port PB0 permanent high, im Simulator zeigt das
> Oszilloskop jedoch in beiden Fällen genau das gleiche.
>
> Beide Codes sollten vom Ergebnis her genau das gleiche liefern, oder?
> Beim einen setze ich den Port manuell, beim anderen sollte das
> automatisch gemacht werden.
> Die Frage ist - was mache ich beim Code "funktioniert nicht" falsch?

ALso:
CTC MODE werden die COMBits nur zum setzen genutzt heißt aktiver Zustand 
bleibt bis Manuell die Bits irgendwann negiert. im CTC Modus ist ein 
toggeln nicht vorgesehen

oder

PWM Mode denn ein Spike ist nichts weiter als Tastverhältnis togglen ist 
vorgesehen

oder

Timer MODE 0!!
Timer läuft immer durch und toggelt bei erreichen von OCRx das jeweilige 
Bit.

https://ww1.microchip.com/downloads/aemDocuments/documents/MCU08/ProductDocuments/DataSheets/ATtiny13A-Data-Sheet-DS40002307A.pdf
ab Seite 76-79

able 11-8. Waveform Generation Mode Bit Description
0  0 0 0 Normal 0xFF Immediate MAX
1  0 0 1 PWM
(Phase Correct) 0xFF TOP BOTTOM
2  0 1 0 CTC OCRA Immediate MAX
3  0 1 1 Fast PWM 0xFF TOP MAX
4  1 0 0 Reserved – – –
5  1 0 1 PWM
(Phase Correct) OCRA TOP BOTTOM
6  1 1 0 Reserved – – –
7  1 1 1 Fast PWM OCRA TOP TOP

Table 11-2. Compare Output Mode, non-PWM Mode
COM0A1 COM0A0 Description
0 0 Normal port operation, OC0A disconnected.
0 1 Toggle OC0A on Compare Match !!!!!!!!!!
1 0 Clear OC0A on Compare Match
1 1 Set OC0A on Compare Match

Hinweis
https://www.roboternetz.de/community/threads/67800-Tiny-2313-Bibliothek
hier mal einfach die Struktur anschauen
denn in deinem CODE ist OCRB gesetzt obwohl das DDR dazu nicht genutzt 
wird ebenso die COM0By:x... Absicht?

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.