Frage: 328p und Timer2/GPIO in assembler

(Firma: Self education) #7859645
Lesenswert?

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

Angehängte Dateien:
(Firma: Self education) #7859809
Lesenswert?

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

(Firma: matzetronics) #7859823
Lesenswert?

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

(Firma: Self education) #7859885
Lesenswert?

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 :-)

Gast #7859888
Lesenswert?

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.

Beitrag #7859892 wurde von einem Moderator gelöscht.
(Firma: matzetronics) #7859902
Lesenswert?

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.

(Firma: matzetronics) #7860038
Lesenswert?

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'

(Firma: Self education) #7860057
Lesenswert?

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

(Firma: Gast) #7860173
Lesenswert?

Andreas schrieb:

@Arduino F Wie würde so eine "Toggle Maske" aussehen?

Rudimentärer Arduino C++ Code: [c] constexpr byte maske = 1 << PD7; // toggle maske

int main() { DDRD = maske; // auf Output for(;;) { PIND = maske; // toggel } } [/C]

Generierter ASM Code(relevanter Ausschnitt): [c]

00000080 <main>: 80: 80 e8 ldi r24, 0x80 ; 128 82: 8a b9 out 0x0a, r24 ; 10

00000084 <.L2>: 84: 89 b9 out 0x09, r24 ; 9 86: fe cf rjmp .-4 ; 0x84 <.L2>

[/C]

Gast #7860291
Lesenswert?

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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren