Hallo Ich tauche gerade in das Thema Assembler und 328P ein. Ich lasse den Timer2 ohne prescaler als freerunning im Mode0 laufen. Das passt auch, alle 16us ändert sich der Ausgang von PB3 (OC2A). Next step ist, zwei rechecksignale über PD7 innerhalb des Timer2OverFlow Interrupts auszugeben. Daran cheitere ichanscheinend (oder die Test HW ist zu schwach). Ich bekomme einmal ein Recht oder manchmal die gewünschten zwei Rechtecke auf D7, allerdings nicht konstant immer. Habe ich etwas übersehen?!? Danke für die Hilfe Gruß Andreas
So und jetzt poste den Code nochmal, aber ohne sämtlichen toten Code. Und er muß ohne Fehlermeldungen assemblieren!
Ups, dann hatte ich wohl kompiliert ohne jeweils immer zu speichern :-O Sorry, wird so schnell wie möglich nachgeliefert. Danke
Hallo Peter Hier nun die "Bereinigte" source Datei und das SALEAE logfile. Danke Gruß Andreas
Hast du einen Debugger? Wenn nicht, benutze den Simulator, um die ISR durch zu steppen.
:
Bearbeitet durch User
Hallo Sherlock Debugger ist vorhanden. Ich kann das ganze ja nocheinmal im Emulator durchlaufen lassen, nur scheint mir die Realität in diesem Fall von dem Debugger abzuweichen. GPIO/Timer und die entsprechenden realen "verhaltensweisen" lassen sich nicht einfach emulieren. Egal, ich spiele das noch einmal durch und liefere dann die "Erkentnisse" ;-) Gruß Andreas
Björn W. schrieb: > Die Samplerate in LOGIC zu klein eingestellt? Wollte ich auch gerade fragen. Vielleicht mal die NOPs verdreifachen.
:
Bearbeitet durch User
Guter Hinweis! Ich werde das nachher einmal gegenprüfen. Welche Rate müsste den mindestens eingestellt werden?
Andreas schrieb: > Welche Rate müsste den mindestens eingestellt werden? 32Hz würde ich mal sagen. Mein logic Analyzer geht bis 25 MHz, aber unzuverlässig (mit Aussetzer). Zuverlässig kann er nur 10 MHz.
:
Bearbeitet durch User
Die Interrupts immer erst freigeben, wenn die Quelle konfiguriert ist, sonst kann es zu Fehlzündungen kommen. In der ISR solltest du als erstes immer das SFR retten und am Ende zurückschreiben. Jetzt noch nicht so wichtig, aber führt in Zukunft zu unerwünschten Seiteneffekten. >.EQU takt = 16000000 ; Systemtakt 16 MHz intern => 1 CPU clk = 62,5ns Sicher? 16Mhz gibts eigentlich nur mit externem Quarz oder Oszillator. Intern sind max. 8Mhz drin. > out DDRD,dummy ; 1 cycl, set portd > sbi portd,7 ; 2 cycl, enable pullup D7 Nö. Wenn PD7 ein Ausgang ist, setzt das Statement PD7 auf high. Pullup schaltest du nur ein, wenn PD7 ein Eingang wäre. > ldi dummy,(COM2A<<6)|(COM2B<<4)|(0<<WGM21)|(0<<WGM20) ; 1 cycl Tippfehler? COM2A z.B. setzt du mit (1 << COM2A) und COM2B mit (1 << COM2B). Nullen schieben bringt übrigens keine Wirkung. Hier genauso: > ldi dummy,(0<<WGM22)|(CS2) ; 1 cycl > sts TCCR2B,dummy ; 2 cycl, SFR B1
Sherlock 🕵🏽♂️ schrieb: > 32Hz würde ich mal sagen. Sorry, ich wollte 32 MHz schreiben.
:
Bearbeitet durch User
Einfach mal aus den einfachen NOPs zum Testen jeweils 10 NOPs machen. Dann klappt's auch mit nem gemütlichen LA.
Matthias S. schrieb: > Die Interrupts immer erst freigeben, wenn die Quelle konfiguriert ist, > sonst kann es zu Fehlzündungen kommen. In der ISR solltest du als erstes > immer das SFR retten und am Ende zurückschreiben. Jetzt noch nicht so > wichtig, aber führt in Zukunft zu unerwünschten Seiteneffekten. Ja, Danke. >>.EQU takt = 16000000 ; Systemtakt 16 MHz intern => 1 CPU clk = 62,5ns > Sicher? 16Mhz gibts eigentlich nur mit externem Quarz oder Oszillator. > Intern sind max. 8Mhz drin. Mhm, soweit ich das Datenblatt korrekt gelesen habe, wird der 16mHz Quarz direkt 1:1 übernommen. Das Bedeutet 1/16mHz = 62,5ns. Bitte um korrektur, falls ich Falsch liege :-O >> out DDRD,dummy ; 1 cycl, set portd >> sbi portd,7 ; 2 cycl, enable pullup D7 > Nö. Wenn PD7 ein Ausgang ist, setzt das Statement PD7 auf high. Pullup > schaltest du nur ein, wenn PD7 ein Eingang wäre. Aber um einen gesetzten Eingang wieder einzulesen, brauche ich doch den Pullup, oder? Sonnst hätte ich doch einen OpenCollector System? Bitte um Korrektur. >> ldi dummy,(COM2A<<6)|(COM2B<<4)|(0<<WGM21)|(0<<WGM20) ; 1 cycl > Tippfehler? COM2A z.B. setzt du mit (1 << COM2A) und COM2B mit (1 << > COM2B). > Nullen schieben bringt übrigens keine Wirkung. Hier genauso: >> ldi dummy,(0<<WGM22)|(CS2) ; 1 cycl >> sts TCCR2B,dummy ; 2 cycl, SFR B1 Ich dachte das die "Null" x-mal verschieben wird. Somit kann ich einzelne bits im Byte Ein/Ausschalten. Doch nicht ?!? :-O Auf jedenfall herzlichen Dank für die Hinweise. Werden gerne aufgenommen :-)
Andreas schrieb: > Mhm, soweit ich das Datenblatt korrekt gelesen habe, wird der 16mHz > Quarz direkt 1:1 übernommen. Es gibt keinen internen Quarz. Intern gibt es nur einen R/C Oszillator mit max. 8 MHz. Andreas schrieb: > Aber um einen gesetzten Eingang wieder einzulesen, brauche ich doch den > Pullup, oder? Mag sein, je nach Schaltung, die wir nicht kennen. In diesem Programm konfigurierst du den Pin aber als Ausgang. Deine Überlegungen zu Eingängen passen nicht dazu.
Nächste überlegung war PortD einlesen, bit7 togglen, PortD wieder ausgeben. Am Pin D7 hängt ledidglich nur der SALEAE Clone. Gruß
Beitrag #7859892 wurde vom Autor gelöscht.
Andreas schrieb: > Nächste überlegung war PortD einlesen, bit7 togglen, PortD wieder Warum nicht einfach eine (toggle)Maske in PINB rein schreiben?
Andreas schrieb: > Ich dachte das die "Null" x-mal verschieben wird. Somit kann ich > einzelne bits im Byte Ein/Ausschalten. Doch nicht ?!? :-O Ich habe dir es doch geschrieben: Wenn du z.B. COM2A und COM2B im TCCR2A setzen willst, benutzt du
1 | ldi dummy, (1 << COM2A) | (1 << COM2B) |
2 | sts TCCR2A, dummy |
Die 1 wird so oft geschoben, wie das define für das betreffende Bit vorschreibt. Mehrere Bits kannst du verodern und dann in einem Schwupps schreiben.
Wenn Du schon Zyklen zählst, der Einsprung in einen Interrupt kostet 6/7 Zyklen + 1..5 Zyklen Delay für den laufenden Befehl.
Andreas schrieb: > Ich dachte das die "Null" x-mal verschieben wird. Somit kann ich > einzelne bits im Byte Ein/Ausschalten. Doch nicht ?!? :-O Bits löschen ist ein wenig komplizierter:
1 | lds dummy, TCCR2A ; derzeitigen Inhalt des Registers laden |
2 | andi dummy, ~(1 << COM2A) ; nun mit dem Kehrwert des zu löschenden Bits verUNDen |
3 | sts dummy, TCCR2A ; und wieder ins Register schreiben. |
4 | ; zum gezielten Setzen im Register, ohne den restlichen Inhalt zu zermanschen |
5 | lds dummy, TCCR2A ; derzeitigen Inhalt des Registers laden |
6 | ori dummy, (1 << COM2B) ; verodern mit dem Bit |
7 | sts dummy, TCCR2A |
Hier gibts umfangreiche Infos zur Bitmanipulation in Assembler und C: https://www.mikrocontroller.net/articles/Bitmanipulation Wenn man im Register 16 bis 31 Bits setzen will, geht auch 'sbr'
:
Bearbeitet durch User
Andreas schrieb: > Ich dachte das die "Null" x-mal verschieben wird. Wird sie auch, nur hat das keinen Effekt. Der Ausdruck bleibt immer 0, egal wie weit Du schiebst. Mathematisch bewirkt nur (1<<n) etwas.
Jepp, das war's. Für alle newbees nach mir: - Mein "Testsystem" ist hier ein Arduino Uno mit modifiziertem "RESET-EN". [Darum auch die 16mHz] - Achtet auf die Abtastfrequenz des LogicAnalyzer. [Ist die Frequenz zu gering, können Signale ggf. nicht erfasst werden. Eingestellt waren bei mir 2 oder 4 MS/s. Mit 25 MS/s bekomme endlich meine beiden Rechtecke :-)] Die errechneten Zeiten für jeweils High/Low stimmen (in etwa), aber irgendwo muss der Preisunterschied zwischen Original und Clone SALEAE berechtigt sein ;-) Auf jedenfall Herlichen Dank für die vielen Hinweise und das schubsen in die richtige Richtung. Man(n) zweifelt ja sofort am eigenem Unvermögen ;-) ---------------- @Arduino F Wie würde so eine "Toggle Maske" aussehen? @Matthias S Danke, so ein HowTo hatte ich schon immer gesucht und es gibt wieder etwas Lesestoff ;-) @Peter D Merci für den Hinweis der zusätzlichen cyclen beim Interrupt. LG Andreas
Andreas schrieb: > @Arduino F > Wie würde so eine "Toggle Maske" aussehen? Schreiben einer '1' in PINx (das ja dem Sinn nach eigentlich zum Lesen bestimmt ist) bewirkt ein Toggeln (Umschalten) des entsprechenden Bits in PORTx. Z.B. PD7 kannst du also mittels einer einzelnen Anweisung umschalten:
1 | sbi PIND, 7 ; toggle PORTD.7 |
:
Bearbeitet durch User
Johannes F. schrieb: > sbi PIND, 7 ; toggle PORTD.7 Das klappt bei allen nicht 'uralten' AVR, hat nur den Haken, das man schon wissen sollte, wie der Pin vorher stand :-) Wenn man vorher auslesen muss, lohnt sich das nicht.
Matthias S. schrieb: > Das klappt bei allen nicht 'uralten' AVR, hat nur den Haken, das man > schon wissen sollte, wie der Pin vorher stand :-) Naja, es ging ja explizit ums Toggeln. Wenn man ein einzelnes Bit direkt setzen oder löschen will, nimmt man halt 'SBI PORTx, b' bzw. 'CBI PORTx, b', damit geht es auch in einem Takt.
:
Bearbeitet durch User
Andreas schrieb: > @Arduino F > Wie würde so eine "Toggle Maske" aussehen? Rudimentärer Arduino C++ Code:
1 | constexpr byte maske = 1 << PD7; // toggle maske |
2 | |
3 | int main() |
4 | {
|
5 | DDRD = maske; // auf Output |
6 | for(;;) |
7 | {
|
8 | PIND = maske; // toggel |
9 | }
|
10 | }
|
Generierter ASM Code(relevanter Ausschnitt):
1 | 00000080 <main>: |
2 | 80: 80 e8 ldi r24, 0x80 ; 128 |
3 | 82: 8a b9 out 0x0a, r24 ; 10 |
4 | |
5 | 00000084 <.L2>: |
6 | 84: 89 b9 out 0x09, r24 ; 9 |
7 | 86: fe cf rjmp .-4 ; 0x84 <.L2> |
Andreas schrieb: > irgendwo muss der Preisunterschied zwischen Original und Clone > SALEAE berechtigt sein Generell halte ich es für hilfreich, seine Werkzeuge kennen zu lernen, bevor man sie ernsthaft benutzt. Alles hat irgendwo seine Grenzen, die sollte man kennen, dann ist es kein Problem. Ich würde z.B. bei Netzteilen auf jeden Fall mal testen, wie sie sich beim ein/aus Schalten mit unterschiedlichen Lasten (keine, klein, mittel, groß, , ohmsch, kapazitiv, induktiv, Akkus) verhalten. Da gibt es oft Überraschungen, bis hin zur Zerstörung der Zielschaltung oder des Netzteils.
:
Bearbeitet durch User
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.