Forum: Mikrocontroller und Digitale Elektronik Frage: 328p und Timer2/GPIO in assembler


von Andreas (Firma: Self education) (andreas_bujok)


Angehängte Dateien:

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

von Peter D. (peda)


Lesenswert?

So und jetzt poste den Code nochmal, aber ohne sämtlichen toten Code.
Und er muß ohne Fehlermeldungen assemblieren!

von Andreas (Firma: Self education) (andreas_bujok)


Lesenswert?

Ups, dann hatte ich wohl kompiliert ohne jeweils immer zu speichern :-O
Sorry, wird so schnell wie möglich nachgeliefert.

Danke

von Andreas (Firma: Self education) (andreas_bujok)


Angehängte Dateien:

Lesenswert?

Hallo Peter

Hier nun die "Bereinigte" source Datei und das SALEAE logfile.

Danke

Gruß Andreas

von Sherlock 🕵🏽‍♂️ (rubbel-die-katz)


Lesenswert?

Hast du einen Debugger? Wenn nicht, benutze den Simulator, um die ISR 
durch zu steppen.

: Bearbeitet durch User
von Andreas (Firma: Self education) (andreas_bujok)


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

von Björn W. (bwieck)


Lesenswert?

Die Samplerate in LOGIC zu klein eingestellt?

von Sherlock 🕵🏽‍♂️ (rubbel-die-katz)


Lesenswert?

Björn W. schrieb:
> Die Samplerate in LOGIC zu klein eingestellt?

Wollte ich auch gerade fragen.

Vielleicht mal die NOPs verdreifachen.

: Bearbeitet durch User
von Andreas (Firma: Self education) (andreas_bujok)


Lesenswert?

Guter Hinweis!

Ich werde das nachher einmal gegenprüfen.
Welche Rate müsste den mindestens eingestellt werden?

von Sherlock 🕵🏽‍♂️ (rubbel-die-katz)


Lesenswert?

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
von Matthias S. (Firma: matzetronics) (mschoeldgen)


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

von Sherlock 🕵🏽‍♂️ (rubbel-die-katz)


Lesenswert?

Sherlock 🕵🏽‍♂️ schrieb:
> 32Hz würde ich mal sagen.

Sorry, ich wollte 32 MHz schreiben.

: Bearbeitet durch User
von Norbert (der_norbert)


Lesenswert?

Einfach mal aus den einfachen NOPs zum Testen jeweils 10 NOPs machen.
Dann klappt's auch mit nem gemütlichen LA.

von Andreas (Firma: Self education) (andreas_bujok)


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

von Sherlock 🕵🏽‍♂️ (rubbel-die-katz)


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.

von Andreas (Firma: Self education) (andreas_bujok)


Lesenswert?

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.
von Arduino F. (Firma: Gast) (arduinof)


Lesenswert?

Andreas schrieb:
> Nächste überlegung war PortD einlesen, bit7 togglen, PortD wieder

Warum nicht einfach eine (toggle)Maske in PINB rein schreiben?

von Matthias S. (Firma: matzetronics) (mschoeldgen)


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.

von Peter D. (peda)


Lesenswert?

Wenn Du schon Zyklen zählst, der Einsprung in einen Interrupt kostet 6/7 
Zyklen + 1..5 Zyklen Delay für den laufenden Befehl.

von Matthias S. (Firma: matzetronics) (mschoeldgen)


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'

: Bearbeitet durch User
von Peter D. (peda)


Lesenswert?

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.

von Andreas (Firma: Self education) (andreas_bujok)


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

von Johannes F. (jofe)


Lesenswert?

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
von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

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.

von Johannes F. (jofe)


Lesenswert?

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
von Arduino F. (Firma: Gast) (arduinof)


Lesenswert?

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>

von Sherlock 🕵🏽‍♂️ (rubbel-die-katz)


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.

: 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
Noch kein Account? Hier anmelden.