Forum: Mikrocontroller und Digitale Elektronik Höchstmögliche Schaltfrequenz an einem normalen AVR Ausgangs-Pin


You were forwarded to this site from EmbDev.net. Back to EmbDev.net
von Marvin K. (m_marvin)


Lesenswert?

Was ist die höchste mögliche Schaltfrequenz bei einem AVR 
Microcontroller wie z.B. dem ATmega328P ?
Ich brauche 6 verschiedene 0-200kHz Signale (einstellbare Frequenz) weis 
aber nicht genau ob das mit einem AVR möglich ist, im Datenblatt steht 
dazu nichts (oder ich kann es nicht finden).

Bei einer CPU Frequenz von 20MHz sollte das doch gehen oder ?

von Achim M. (minifloat)


Lesenswert?

Marvin K. schrieb:
> Ich brauche 6 verschiedene 0-200kHz Signale (einstellbare Frequenz

Alle voneinander unabhängig nur soviele Timer, wie der μC hat. 
Voneinander abhängig soviele OCx-Pins, wie du findest.

mfg mf

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Marvin K. schrieb:
> Bei einer CPU Frequenz von 20MHz sollte das doch gehen oder ?
Welchen Jitter kannst du tolerieren?

von Εrnst B. (ernst)


Lesenswert?

Willst du nur die Frequenz ausgeben, oder soll da noch PWM drüber. Oder 
garnicht periodisch, sondern ein Datensignal mit der Frequenz erzeugt 
werden?

Ersteres ginge über die Timer, beim Datensignal müsste man vielleicht 
Tricksen, z.B. das SPI-Modul zweckentfremden. Davon hat der AVR aber nur 
eins.

Direkt in der CPU per PORTx=... geht evtl. auch noch, je nachdem wie 
komplex die Daten vorzubereiten sind, und wie lange die zu erzeugende 
Sequenz ist.

von Marvin K. (m_marvin)


Lesenswert?

Achim M. schrieb:
> Alle voneinander unabhängig nur soviele Timer, wie der μC hat.
> Voneinander abhängig soviele OCx-Pins, wie du findest.

Was meinst du mit "unabhängig" ?
Ich meine ich will 6 Signale die unterschiedliche Frequenzen im Bereich 
von 0-200kHz haben können (bzw. 0 oder ~1-200kHz, niedrigere Frequenzen 
als 1kHz werden es nicht sein).

Lothar M. schrieb:
> Welchen Jitter kannst du tolerieren?

Das weis ich nicht genau, ich habe 6 DM542 Schrittmotortreiber die ich 
ansteuern will (Pulse-Eingang).
Dazu steht nichts im Datenblatt.
Aber ein unsauberes Signal von einem übertakteten Raspberry Pi hat er 
genommen.

von Lukas K. (kugelblitz)


Lesenswert?

Hallo,
ich weiß nicht genau was für Signale du ausgeben willst. PWM kann der 
Atmega328 auf pin:
 5 und 6 max 62,5kHz
3, 9, 10 und 11 max 31372.55 Hz rund 31kHz

Ohne pwm braucht er ca 1µs um ein und aus zu schalten, aber wenn ich das 
messe ist das keine saubere Rechteckkurve.

von Marvin K. (m_marvin)


Lesenswert?

Keine Daten, nur ein 1-200kHz Signal, egal ob Rechteck, Sägezahn usw.

von c-hater (Gast)


Lesenswert?

Marvin K. schrieb:
> Was ist die höchste mögliche Schaltfrequenz bei einem AVR
> Microcontroller wie z.B. dem ATmega328P ?

1/2 Systemtakt, also bei 20MHz Systemtakte 10MHz.

> Ich brauche 6 verschiedene 0-200kHz Signale (einstellbare Frequenz) weis
> aber nicht genau ob das mit einem AVR möglich ist

6 wird schwierig, weil auch die besten klassischen AVR8 nur höchstens 
vier Timer haben. Die restlichen zwei Kanäle müssten per Software 
generiert werden. Das ist nicht so ganz trivial.

Aber es gibt neuere AVR8, die deutlich mehr Timer besitzen, z.b. die 
AVR128D(A,B,D).

Generell gilt aber: "einstellbar" ist relativ. Je höher die erzeugte 
Frequenz, desto größer werden auch die Schritte, in denen sie 
einstellbar ist. Ein-Herz-Schritte in der Nähe von 200kHz kannst du 
vergessen. Das kann man für einen Kanal in Software noch gut 
hinbekommen, aber nicht für 6, die parallel laufen müssen.

von Marvin K. (m_marvin)


Lesenswert?

Das einzige Kriterium (neben der Tatsache dass der Treiber es als 
"Pulse" erkennen kann) ist eigentlich, dass ich eine Möglichkeit haben 
muss die "Impulse" zu zählen (entweder durch festlegen oder messen der 
Zeit die das Signal aktiv ist, oder durch direktes ausgeben der 
einzelnen Impulse).

von Εrnst B. (ernst)


Lesenswert?

Marvin K. schrieb:
> DM542 Schrittmotortreiber

Marvin K. schrieb:
> nur ein 1-200kHz Signal

Das willst du auf den "Pulse"-Eingang des Treibers geben?
Welcher Schrittmotor macht denn 200000 Schritte/Sekunde?

von Marvin K. (m_marvin)


Lesenswert?

Der AVR hätte nur 2 Aufgaben, über I2C Frequenz, Pulsanzahl 
entgegennehmen, und diese dann ausgeben.
Der Frequenzbereich liegt wie gesagt bei 1-200 kHz, und kHz Schritt 
reichen aus (also 1 - 200 währe der gesamte Bereich den man einstellen 
könnte).

Ich könnte den DM542 auch anders Konfigurieren, um weniger Impulse pro 
Umdrehung zu nutzen, dann hätte ich aber eine geringere Genauigkeit.
Ob das geht müsste ich testen wenn der 1-200kHz Bereich nicht möglich 
ist.

von Wolfgang (Gast)


Lesenswert?

Lukas K. schrieb:
> Ohne pwm braucht er ca 1µs um ein und aus zu schalten, aber wenn ich das
> messe ist das keine saubere Rechteckkurve.

Es gibt verschiedene Dinge, die ein Signal unsauber erscheinen lassen. 
Letztendlich liegt das immer im Auge des Betrachters. Wie er das, was er 
sieht, bewertet, sollte von den Anforderungen abhängen. Einer guckt auf 
die Flankensteilheit, jemand anderes vielleicht auf die 
Amplitudenverteilung und wieder ein anderer guckt auf das Tastverhältnis 
oder den Jitter. Natürlich hat auch die Art der Programmierung einen 
entscheidenden Einfluss.

von Marvin K. (m_marvin)


Lesenswert?

Εrnst B. schrieb:
> Das willst du auf den "Pulse"-Eingang des Treibers geben?
> Welcher Schrittmotor macht denn 200000 Schritte/Sekunde?

Es ist ein Microstepp-Treiber, er erzeugt auch Zwischenschritte indem er 
einen Sinusverlauf auf die Motor-Wicklungen gibt.

Mit einem Frequenzgenerator hab ich das alles getestet, daher kenne ich 
den Frequenzbereich den ich für meine gewünschten Geschwindigkeiten 
benötige.

von Yalu X. (yalu) (Moderator)


Lesenswert?

Marvin K. schrieb:
> Der Frequenzbereich liegt wie gesagt bei 1-200 kHz, und kHz Schritt
> reichen aus

200 kHz -> 5,000 µs
199 kHz -> 5,025 µs
Differenz: 25 ns

So fein löst ein 20 MHz-AVR nicht auf.

von Εrnst B. (ernst)


Lesenswert?

Marvin K. schrieb:
> Es ist ein Microstepp-Treiber, er erzeugt auch Zwischenschritte indem er
> einen Sinusverlauf auf die Motor-Wicklungen gibt.

Ah, klar.

Überlegt dir, ob du wirklich zwischen 200 und 199 kHz unterscheiden 
musst, oder ob das auch gröber abgestuft reicht.

von Marvin K. (m_marvin)


Lesenswert?

Ich denke ich teste einfachmal was ich hinbekomme (mit einem AVR), zur 
not kann ich wie gesagt die Schritt-Auflösung am Treiber runtersetzen, 
ich muss dann halt schauen ob das dann noch von der Genauigkeit 
ausreicht (mechanisch am Motor).

von Εrnst B. (ernst)


Lesenswert?

Marvin K. schrieb:
> Ich denke ich teste einfachmal was ich hinbekomme (mit einem AVR),
> zur
> not kann ich wie gesagt die Schritt-Auflösung am Treiber runtersetzen,
> ich muss dann halt schauen ob das dann noch von der Genauigkeit
> ausreicht (mechanisch am Motor).

Timer mit 20MHz bis 100 Laufen lassen -> 200kHz
bis 101 -> 198 kHz
196 kHz
usw.

(Positions-) Genauigkeit geht dir dabei nicht verloren, wenn du keine 
199kHz hast. Du hast nur eben weniger verschiedene 
Umdrehungsgeschwindigkeiten zur Auswahl.

Ansonsten: Manche neuere (naja, inzwischen nicht mehr ganz so neue) AVRs 
haben eine PLL integriert, die geht auf 64MHz hoch und kann den Timer 
befeuern.

: Bearbeitet durch User
von Yalu X. (yalu) (Moderator)


Lesenswert?

Du könntest dein Vorhaben auch zum Anlass nehmen, von AVR auf ARM
umzusteigen. Die haben meist mehr Timer und mehr Megahertz.

von Marvin K. (m_marvin)


Lesenswert?

Ich hab jetzt mal einen ATmega328P auf mein STK500 gesteckt und ein 
Oszilloskop an den Pin PB1 angeschlossen, meinen Tests nach ist die 
Signalqualität selbst bei 250 kHz noch super, ein sehr schönes 
Rechteck-Signal mit sehr wenig rauschen und steiler Flanke, ich denke 
das kann ich so ohne Probleme machen.

Für diesen simplen Test hab ich einfach folgenden sehr einfachen Code 
genutzt, weshalb die Frequenz etwas abweicht, aber ich denke wenn ich 
das mit Timern mache, sollte das funktionieren.
1
    DDRB = (1 << 1);
2
  
3
    while (1) 
4
    {
5
        PORTB |= (1 << 1);
6
        _delay_us(2);
7
        PORTB &= ~(1 << 1);
8
        _delay_us(2);
9
    }

von PiffPoff (Gast)


Lesenswert?

Mit einem pin hast du ja auch noch keinerlei overhead.
Weder zaehlen, noch mehrfachausgabe (vor allem unabhaengig)
Und das interruptverhalten ist auch noch nicht relevant. :/

Mach den test lieber mal mit 6 unabhaengigen kanaelen.

(Ich will nicht behaupten, dass es so nicht geht.
Nur zur vorsicht raten, von diesem versuch aus zu schliessen,
dass es dann auch im realanwendungsfall problemlos so funktioniert)

von DANIEL D. (Gast)


Lesenswert?

Also wenn es nur um ein oder zwei Ausgänge geht, welche diese Frequenz 
erreichen sollen. Dann würde mir nur so eine Lösung einfallen, wo ein 
kompletter Port abgefragt wird als dateneingabe sozusagen parallel. Wo 
man dann ein oder zwei Pins wackeln lassen könnte.

Aber das ist natürlich Betriebswirtschaftlich ungünstig wie wir hier 
immer zu sagen pflegen.

von Wühlhase (Gast)


Lesenswert?

Bei sechs Kanälen würde ich lieber über einen STM32 nachdenken. Die 
haben weitaus mehr Timer. 200kHz bei sechs Kanälen wären eine gute 
Gelegenheit, sich mit mal mit den High-Resolution-Timern zu befassen.

von Marvin K. (m_marvin)


Lesenswert?

Die Frequenz muss gar nicht so genau sein, nur die Einstellbarkeit im 
Bereich von 1-200 kHz muss gegeben sein und weitestgehend linear sein.
Ob der Schrittmotor jetzt bei 150 oder bei 148 kHz dreht, ist egal (kann 
man ja nachstellen/kallibrieren)

Ich hatte gerade eine Idee, weis aber nicht ob das sinnvoll ist das so 
zu machen.

Das Problem ist ja das ich bei einem ATmega nicht genug Timer habe.
Und mit der delay Funktion kann ich (ohne größeren aufwand) nur einen 
Pin ansteuern.

Ich hätte jetzt die idee, für jeden Kanal eine Variable anzulegen die 
durch einen Timer Overflow Interupt hochgezählt werden, und die wenn sie 
einen (einstellbaren) wert erreicht werden ebenfalls ein (halt als 
Funktion implementieren) Interrupt auslösen.
So könnte ich ja 6 Kanäle bekommen deren Timer ich getrennt einstellen 
kann.

Hier ein kurzer Pseudocode wie ich das meine:
1
long chanel1 = 0;
2
long chanel2 = 0;
3
...
4
5
ISR_Timer0_Interrupt {
6
  chanel1++;
7
  if (chanel1 > *einstellbar*) chanel1 = 0 und Chanel1_Interrupt()
8
  chanel2++;
9
  if (chanel1 > *einstellbar*) chanel2 = 0 und Chanel2_Interrupt()
10
  ...
11
}
12
13
Chanel1_Interrupt {
14
  //Toggel Pin
15
}
16
17
Chanel2_Interrupt {
18
  //Toggel Pin
19
}
20
21
...

: Bearbeitet durch User
von Marvin K. (m_marvin)


Lesenswert?

Man könnte auch die Variablen direkt hochzählen, ich probiere das jetzt 
einfach mal aus.

von Wolfgang (Gast)


Lesenswert?

Εrnst B. schrieb:
> Timer mit 20MHz bis 100 Laufen lassen -> 200kHz

wohl eher 100kHz, oder bis 50 laufen lassen.

von DANIEL D. (Gast)


Lesenswert?

Marvin K. schrieb:
> Man könnte auch die Variablen direkt hochzählen, ich probiere das
> jetzt einfach mal aus.

Was auch noch eine Idee wäre, dass du dir eine Art latch programmierst. 
Also ein kompletter Port für die Eingabe, und mit bestimmten pins 
entscheidest du für welchen Ausgang die Variable gesetzt wird. Dann 
müsstest du mit Bit Masken arbeiten. Aber das würde dann vermutlich auch 
immer zur Frequenz Abweichungen führen, jedes mal wenn du eine 
Einstellung der Bitmasken vornimmst. Hmm ich bin da nicht tief genug in 
der Materie.

von Oliver S. (oliverso)


Lesenswert?

c-hater schrieb:
> 6 wird schwierig, weil auch die besten klassischen AVR8 nur höchstens
> vier Timer haben.

Atmega2560 z.B. hat schon 6 Timer mit PWM, aber 2 davon halt nur mit 8 
Bit. Da gibst dann halt nur 255 Stufen.

Oliver

von Marvin K. (m_marvin)


Lesenswert?

Ich hab jetzt einen Timer konfiguriert, aber egal auf welchen wert ich 
den Vergleichswert setze, er scheint den Compare-Match-Interrupt immer 
zur selben Zeit auszulösen, was kann da die Ursache sein ?

von Marvin K. (m_marvin)


Lesenswert?

Hab den Fehler gefunden, kleiner Tipfehler bei einem der Register, hatte 
den Timer im falschen Modus.

von Marvin K. (m_marvin)


Lesenswert?

Also mit Variablen klappt das nicht, schon allein das "counter++;" lässt 
die Aufruffrequenz von dem CTC Interrupt von 200kHz auf 10kHz absinken.

Ich werde es entweder so machen, dass immer nur 3 von 6 Kanälen 
Zeitgleich genutzt werden können (und jeder der 3 dann über einen der 
Timer läuft) oder ich schaue nach einem AVR mit 6 Timern.

von Thomas F. (igel)


Lesenswert?

Marvin K. schrieb:
> long chanel1 = 0;

> ISR_Timer0_Interrupt {
>   chanel1++;

Das long wird dir viel zu viel Rechenleistung fressen um 200kHz zu 
erreichen.
Selbst uint16 wird für 6 Variablen vermutlich viel zu langsam werden.

Ein AtXmega128 könnte das vermutlich mit Hardware-Timern.

von Falk B. (falk)


Lesenswert?

Marvin K. schrieb:
> Also mit Variablen klappt das nicht, schon allein das "counter++;" lässt
> die Aufruffrequenz von dem CTC Interrupt von 200kHz auf 10kHz absinken.

Dann machst du was falsch.

Beitrag "Re: "Burst" mit atmega328 erzeugen"

> Ich werde es entweder so machen, dass immer nur 3 von 6 Kanälen
> Zeitgleich genutzt werden können (und jeder der 3 dann über einen der
> Timer läuft) oder ich schaue nach einem AVR mit 6 Timern.

Du solltest mal 2 Schritte zurück machen und bissel Ruhe reinbringen und 
dein Konzept hinterfragen. Ich hab da meine Zweifel, ob das alles so 
sinnvoll ist. Auch nicht mit einem leistungsfähigeren Prozessor.

von m.n. (Gast)


Lesenswert?

Yalu X. schrieb:
> Du könntest dein Vorhaben auch zum Anlass nehmen, von AVR auf ARM
> umzusteigen. Die haben meist mehr Timer und mehr Megahertz.

Da gibt es allerdings erhebliche Probleme bei der Beschaffbarkeit.

Nicht unbedingt mein Lieblingsteil aber für 4 Euro selbst bei Reicheilt 
beschaffbar ist ein RP2040 Pico-Board. Es hat zwei ARM M0+ Kerne, von 
denen der eine einfach schlafen kann.
Die acht PWM-Kanäle können nicht viel sind aber für Deine Anwendung wohl 
perfekt: Vorteiler auf die max. sinnvolle Schrittfrequenz einstellen und 
dann per TOP-Wert der Timer die Ausgangsfrequenz wählen.

Ein AVR ist für Deine Aufgabe hoffnungslos überfordert. Mit delay_us() 
läßt sich so etwas nicht programmieren. Du wirst Rampen brauchen und 
diese brauchen exaktes Timing.

von neuer PIC Freund (Gast)


Lesenswert?

Was soll das eigentlich werden?

Geht das in Richtung Ventilator oder was mit CNC?

>Keine Daten, nur ein 1-200kHz Signal, egal ob Rechteck, Sägezahn usw.

Naja. Am Eingang des Treibers liegen Optokoppler. Da wäre Rechteck schon 
schön.

von Yalu X. (yalu) (Moderator)


Lesenswert?

m.n. schrieb:
> Yalu X. schrieb:
>> Du könntest dein Vorhaben auch zum Anlass nehmen, von AVR auf ARM
>> umzusteigen. Die haben meist mehr Timer und mehr Megahertz.
>
> Da gibt es allerdings erhebliche Probleme bei der Beschaffbarkeit.

Einzelne Chips sind Mangelware, komplette Boards sind aber noch ganz gut
beschaffbar, wenn man nicht auf einen ganz bestimmten Controllertyp
festgelegt ist. Den RP2040 hast du ja schon genannt, es gibt aber auch
noch etliche von anderen Herstellern.

@Marvin: Wenn du unbedingt bei den AVRs bleiben möchtest:

Statt nur eines ATmega328P könntest du auch zwei davon einsetzen, um
sechs 16-Bit-Timer zur Verfügung zu haben. Da die sechs Kanäle ja
unabhängig voneinander sind, sollte diese Aufteilung keine Probleme
bereiten.

Evtl. reichen auch weniger Timer, wenn man die Output-Compares geschickt
nutzt. Der Ansatz: Sechs OCs werden jeweils mit einem Ausgang verbunden.
Immer, wenn der Zählerstand einen der OCs erreicht hat, wird das
OC-Register um die Periodendauer erhöht. Das muss natürlich innerhalb
der Periodendauer geschehen, damit keine Impulse verloren gehen. Ich
habe die dafür erforderliche Rechenzeit mal grob überschlagen mit dem
Ergebnis, dass es sehr eng wird, zumal ja auch noch Rechenzeit für das
Einlesen der Periodenwerte benötigt wird. Trotzdem sehe ich eine gute
Chance, dass die Rechenzeit für die gewünschten sechs Kanäle mit 200 kHz
und die SPI-Kommunikation gerade so ausreichen könnte, geschickte
Programmierung vorausgesetzt.

Jetzt musst du nur noch einen AVR mit mindestens sechs OC-Ausgängen
finden. Der ATmega328P hat zwar drei 16-Bit-Timer mit jeweils zwei OCs,
aber dummerweise teilen sich zwei davon (OC3B und OC4B) einen Ausgang,
so dass leider nur fünf Kanäle möglich sind.

Ein ATmega640/1280/1281/2560/2561 hätte genügend OC-Ausgänge. Vielleicht
gibt es auch kleinere Typen, die ebenfalls passen würden, da fehlt mir
im Moment aber der Überblick über die aktuelle AVR-Produktpalette.

von m.n. (Gast)


Lesenswert?

Yalu X. schrieb:
> @Marvin: Wenn du unbedingt bei den AVRs bleiben möchtest:
>
> Statt nur eines ATmega328P könntest du auch zwei davon einsetzen, um
> sechs 16-Bit-Timer zur Verfügung zu haben.

Caesar folgend - parte et divide - kann man dann auch gleich sechs 
ATmega328 nehmen. Es hängt aber von der Aufgabe ab, inwieweit die 
einzelnen Stepper synchron zueinander arbeiten müssen. Wenn sie einfach 
nur drehen sollen, ist das kein Problem.

Als Anregung ein Beispiel für einen Taktgeber für Schrittmotore hier mit 
ATtiny25, wo in der Timer-ISR noch ein paar Berechnungen stattfinden. 
Bei 20 MHz Taktfrequenz des µC werden 100 kHz Schrittfrequenz erzeugt. 
Für 200 kHz müßte abgespeckt bzw. optimiert werden.
http://mino-elektronik.de/Generator/takte_impulse.htm#bsp5

von Marvin K. (m_marvin)


Angehängte Dateien:

Lesenswert?

Ich habe eben gerade gemerkt, mein ATmega328P hat 6 OC Ausgänge, 
unabhängig voneinander.
Das Problem ist nur, was wenn ich an 2 OT Ausgängen des selben Zählers 
unterschiedliche Frequenzen haben möchte?
Im CTC Modus kann ich den dann ja nicht nutzen.

Und ich habe gerade nochmal rumgerechnet, mit 100kHz komme ich auch noch 
hin, wenn ich ein par Sachen weglasse die ich ursprünglich geplant 
hatte.

Aktuell will ich das für einen selbstgebauten Roboterarm nutzen, da 
müssen die Motoren recht langsam drehen, 100kHz reichen aus.

Aber für den 3D Drucker, für den ich ihn dann auch nehmen wollte, werde 
ich mir dann wohl was anderes überlegen, bzw da reichen auch weniger 
Kanäle, also mache ich mir da dann was anderes.

: Bearbeitet durch User
von m.n. (Gast)


Lesenswert?

Marvin K. schrieb:
> Aktuell will ich das für einen selbstgebauten Roboterarm nutzen, da
> müssen die Motoren recht langsam drehen, 100kHz reichen aus.

Und wenn es schneller sein soll, werden es dann 10 MHz?
Reduziere mal die Mikroschritte auf ein sinnvolles Maß, dann wird das 
alles realistischer.

von Marvin K. (m_marvin)


Lesenswert?

Ich denke es würde auch ausreichen, wenn ich immer 2 OCs mit der selben 
Frequenz betreibe, also Gruppen aus je 2 Kanälen bilde, die zwar jeweils 
einzeln ein/aus geschaltet werden können, aber immer mit dem gleichen 
Takt laufen.
Das würde aber beim verfahren des Arms stark auffallen, es währe nicht 
möglich ihn ohne irgend welche Kurven zu einer Zielposition zu fahren, 
weil die Motoren nicht gleich lange drehen würden, sondern gleich 
schnell.

von Εrnst B. (ernst)


Lesenswert?

Du willst das doch über I²C ansteuern?
Ich würde da einen AVR (Tiny reicht vmtl.) pro Schrittmotortreiber 
vorschlagen, alle am selben I²C-Bus, alle mit identischer Software, ein 
paar IOs zum Festlegen der Adresse.
Das wäre dann eine relativ generische Lösung, und du kannst dein 
Gesamtsystem  leicht auf mehr oder weniger Schrittmotoren anpassen.

Klar, die Hardware kostet so etwas mehr, aber je nachdem wie teuer du 
deine Arbeitszeit zum Entwickeln einschätzt relativiert sich das 
schnell.

von Marvin K. (m_marvin)


Lesenswert?

m.n. schrieb:
> Und wenn es schneller sein soll, werden es dann 10 MHz?
> Reduziere mal die Mikroschritte auf ein sinnvolles Maß, dann wird das
> alles realistischer.

Nein, das sind dann die genannten 200kHz ...

Für den Arm reichen aber 100kHz aus.
Und zum reduzieren der Schritte:
Ich hab das auch versucht, aber aus irgend einem Grund fangen die 
Motoren dann an laut zu Rattern, es wird sogar im Dauerbetrieb so 
schlimm das der Arm anfängt zu vibrieren, und die Motoren heiß werden.
Ich weis nicht genau woran das liegt, ich vermute das Problem ist das 
die Schrittweite dann zu groß wird und die Motoren nach jedem Schritt 
wieder abbremsen müssen.

von Marvin K. (m_marvin)


Lesenswert?

Εrnst B. schrieb:
> Du willst das doch über I²C ansteuern?
> Ich würde da einen AVR (Tiny reicht vmtl.) pro Schrittmotortreiber
> vorschlagen, alle am selben I²C-Bus, alle mit identischer Software, ein
> paar IOs zum Festlegen der Adresse.
> Das wäre dann eine relativ generische Lösung, und du kannst dein
> Gesamtsystem  leicht auf mehr oder weniger Schrittmotoren anpassen.
>
> Klar, die Hardware kostet so etwas mehr, aber je nachdem wie teuer du
> deine Arbeitszeit zum Entwickeln einschätzt relativiert sich das
> schnell.

Hm, darüber hab ich auch nachgedacht, ich hab hier eine Box voller AVRs 
die ich von Projekten übrig hab, ich wollte auch wenn das hier nichts 
wird, da mal reinschauen ob ich genug identische ATtiny finde, um das so 
zu machen.
Aber ich denke ich werde wohl erst welche bestellen müssen.

Aber eine Frage hätte ich da jetzt noch:
Gibt es nicht eventuell doch eine Möglichkeit, 2 OCs des selben Timers 
mit unterschiedlichen Frequenzen zu belegen ?
Wenn ja, würde das mein Problem lösen, wenn nicht (was ich leider 
glaube) werde ich diesen Ansatz ausprobieren.

von Walter T. (nicolas)


Lesenswert?

Die DM542 sind mit Schrittsignalen im niedrigen zweistelligen 
Kilohertzbereich sehr glücklich. Es gibt keinen sinnvollen Grund, die 
hohen Mikroschrittfaktoren (über Achtelschritt) an einem µC zu nutzen. 
Man bekommt ohnehin keine höhere mechanische Auflösung als Halbschritt.

Die hohen Mikroschritt-Faktoren waren eigentlich eher dafür gedacht, 
kleine Servos durch Hybrid-Schrittmotoren ersetzen zu können.

: Bearbeitet durch User
von m.n. (Gast)


Lesenswert?

Marvin K. schrieb:
> Und zum reduzieren der Schritte:
> Ich hab das auch versucht, aber aus irgend einem Grund fangen die
> Motoren dann an laut zu Rattern, es wird sogar im Dauerbetrieb so
> schlimm das der Arm anfängt zu vibrieren, und die Motoren heiß werden.
> Ich weis nicht genau woran das liegt, ich vermute das Problem ist das
> die Schrittweite dann zu groß wird und die Motoren nach jedem Schritt
> wieder abbremsen müssen.

Wieviel Mikroschritte sind es denn aktuell?
Wenn etwas vibriert, liegt es u.U. am Spiel der Mechanik. Vielleicht 
hast Du den Motorstrom zu hoch eingestellt.
Für einen Schwingungsdämpfer hast Du vermutlich keine 2. Achse am Motor 
oder noch woanders Platz?

> Gibt es nicht eventuell doch eine Möglichkeit, 2 OCs des selben Timers
> mit unterschiedlichen Frequenzen zu belegen ?

Die gibt es: http://mino-elektronik.de/Generator/takte_impulse.htm#bsp3a
Die max. Schrittfrequenz sinkt dann natürlich.

von Walter T. (nicolas)


Lesenswert?

Marvin K. schrieb:
> Ich hab das auch versucht, aber aus irgend einem Grund fangen die
> Motoren dann an laut zu Rattern, es wird sogar im Dauerbetrieb so
> schlimm das der Arm anfängt zu vibrieren, und die Motoren heiß werden.
> Ich weis nicht genau woran das liegt, ich vermute das Problem ist das
> die Schrittweite dann zu groß wird und die Motoren nach jedem Schritt
> wieder abbremsen müssen.

In diesem Fall sind Deine Rampen kaputt - zuviel Jitter. Die Motoren 
müssen nicht bei jedem Schritt abbremsen. Sauber angesteuerte 
Schrittmotoren an einer DM542 schnurren wie ein Kätzchen.

Nachtrag: Instabile Versorgungsspannung könnte auch zum Fehlerbild 
passen. Insbesondere Netzteil mit Hiccup-Kurzschlußschutz.

: Bearbeitet durch User
von Marvin K. (m_marvin)


Lesenswert?

Walter T. schrieb:
> In diesem Fall sind Deine Rampen kaputt - zuviel Jitter. Die Motoren
> müssen nicht bei jedem Schritt abbremsen.

Der Frequenzgenerator liefert aber eigentlich ein sauberes 
Rechtecksignal.
Aber wenn ich mit der Microstep-Auflösung unter 20.000 Impulse die 
Umdrehung gehe, fangen die Motoren bei bestimmten Frequenzen an extrem 
laut zu rattern, und man schmal drehen sie sich auch gar nicht (Rattern 
aber trozdem).

von Marvin K. (m_marvin)


Lesenswert?

Ich glaub ich hab die Ursache, wenn ich die Frequenz am Generator 
erhöhe, macht dieser eine Kurze pause von einigen ms in der kein Signal 
kommt, ich denke das verursacht dann ein Kuren stopp im Motor und wenn 
dann direkt das höhere Signal kommt ist das ja wie ein von stillstand zu 
voller Drehzahl, was den Motor aus dem Takt kommen lässt.

von Yalu X. (yalu) (Moderator)


Lesenswert?

Marvin K. schrieb:
> Ich habe eben gerade gemerkt, mein ATmega328P hat 6 OC Ausgänge,
> unabhängig voneinander.

Die sind aber nicht alle an die 16-Bit-Timer angeschlossen, und mit den
8-Bit-Zählern reicht vermutlich die Auflösung nicht.

> Das Problem ist nur, was wenn ich an 2 OT Ausgängen des selben Zählers
> unterschiedliche Frequenzen haben möchte?

Bei meinem Ansatz von oben würde man die drei Zähler mit der maximalen
Frequenz (20 MHz) über den vollen Wertebereich (0..0xFFFF) zählen
lassen. Die Frequenz bzw. Periodendauer wird über die fortlaufende
Aktualisierung der OC-Register festgelegt.

Um bspw. an OC1A eine Frequenz von 200 kHz auszugeben, setzt man das
Register OCR1A erst auf 100. Sobald dieser Werte erreicht ist, wird er
auf 200 erhöht, dann auf 300 usw.

von Walter T. (nicolas)


Lesenswert?

Marvin K. schrieb:
> Ich glaub ich hab die Ursache, wenn ich die Frequenz am Generator
> erhöhe, macht dieser eine Kurze pause von einigen ms in der kein Signal
> kommt

Das klingt plausibel.

Deswegen der wichtigste Tipp für jede selbstprogrammierte Steuerung: 
achte darauf, dass Du jederzeit einen Soll-Ist-Vergleich zwischen der 
internen Zählerposition und der realen Ist-Position anstellen kannst.

Yalu X. schrieb:
> Bei meinem Ansatz von oben würde man die drei Zähler mit der maximalen
> Frequenz (20 MHz) über den vollen Wertebereich (0..0xFFFF) zählen
> lassen. Die Frequenz bzw. Periodendauer wird über die fortlaufende
> Aktualisierung der OC-Register festgelegt.

Macht das Spaß? Bei beliebigen Frequenzen können so doch zwei bis n 
Überläufe beliebig dicht zusammen erfolgen, also auch kürzer als die 
Ausführungsdauer der ISR.

Marvin K. schrieb:
> Aber wenn ich mit der Microstep-Auflösung unter 20.000 Impulse die
> Umdrehung gehe, fangen die Motoren bei bestimmten Frequenzen an extrem
> laut zu rattern, und man schmal drehen sie sich auch gar nicht (Rattern
> aber trozdem).


Noch ein Nachtrag (ich hatte den Post übersehen): Ich nutze am liebsten 
1600 Schritte/Umdrehung. Da dreht alles butterweich, aber es kostet auch 
nicht so viel Rechenleistung.

: Bearbeitet durch User
von Yalu X. (yalu) (Moderator)


Lesenswert?

Walter T. schrieb:
> Macht das Spaß?

Geschmackssache :)

> Bei beliebigen Frequenzen können so doch zwei bis n
> Überläufe beliebig dicht zusammen erfolgen,

Das macht nichts, solange die Bearbeitung aller n OC-Register
abgeschlossen ist bevor der nächste Impuls fällig ist.

> also auch kürzer als die Ausführungsdauer der ISR.

Mit Interrupts geht es nicht, da der Interrupt-Overhead schon die
gesamte zur Verfügung stehende Bearbeitungszeit verschlingt. Ich
würde die OC-Interruptflags in einer Schleife abfragen und immer, wenn
eines oder mehrere davon gesetzt sind, entsprechend darauf reagieren.

: Bearbeitet durch Moderator
von Walter T. (nicolas)


Lesenswert?

Yalu X. schrieb:
> Das macht nichts, solange die Bearbeitung aller n OC-Register
> abgeschlossen ist, bevor der nächste Impuls fällig ist.

Genau das meine ich. Wie stellst Du das sicher? Würdest Du ein Fenster 
festlegen, um mehrere Impulse, die zu dicht zusammen sind, gemeinsam 
auszugeben?

von Yalu X. (yalu) (Moderator)


Lesenswert?

Walter T. schrieb:
> Würdest Du ein Fenster
> festlegen, um mehrere Impulse, die zu dicht zusammen sind, gemeinsam
> auszugeben?

Die Ausgabe erfolgt durch die Timer-Hardware und damit jitterfrei mund
ggf. auch gleichzeitig. Die Software aktualisiert nur die OC-Register.
Das kann aber zu einem beliebigen Zeitpunkt innerhalb der Periodendauer
erfolgen.

: Bearbeitet durch Moderator
von Walter T. (nicolas)


Lesenswert?

Lass mich mal paraphrasieren, ob ich das richtig verstanden habe:

Der Timer läuft durch. Bei jedem Timerdurchlauf können Null oder ein 
Taktsignal ausgegeben werden.

Dafür muss eine schnelle ISR zweimal in jedem Timerdurchlauf die 
OCx-Register updaten. Soll keine Taktflanke erzeugt werden, stellt die 
erste OCx den Überlauf auf "kommt am Ende" und die zweite auf "ist schon 
am Anfang geschehen" und es wird kein echter Überlauf erzeugt. Soll ein 
Taktflanke erzeugt werden, stellt die letzte vor dem echten Takt den 
richtigen Zeitpunkt ein und zählt den Taktzähler hoch.

So?

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

m.n. schrieb:
> Reduziere mal die Mikroschritte auf ein sinnvolles Maß, dann wird das
> alles realistischer.
Ich glaube, du hast das eigentlich Problem genannt. Und wenn man das 
eigentliche (bislang unbekannte) Problem genau anschaut, dann könnte man 
vermutlich den Motor auch mit Vollschritten fahren...

Marvin K. schrieb:
> Der Frequenzgenerator liefert aber eigentlich ein sauberes
> Rechtecksignal.
> Aber wenn ich mit der Microstep-Auflösung unter 20.000 Impulse die
> Umdrehung gehe, fangen die Motoren bei bestimmten Frequenzen an extrem
> laut zu rattern, und man schmal drehen sie sich auch gar nicht (Rattern
> aber trozdem).
Du willst da offenbar ein mechanisches Problem mit Raktentechnik lösen. 
Welche Last hast du da dran?

Yalu X. schrieb:
> Das kann aber zu einem beliebigen Zeitpunkt innerhalb der Periodendauer
> erfolgen.
Muss das "kann" nicht eher "muss" heißen? ;-)

Denn der Comparewert muss rechtzeitig geschrieben sein, sonst stolpert 
das Ding böse.

: Bearbeitet durch Moderator
von Marvin K. (m_marvin)


Lesenswert?

Ich hab jetzt einen Timer so konfiguriert, dass er bei dem Compare Match 
A den Ausgang OC0A toggeln soll, genau so auch Compare Match B.
Ansonsten macht das Programm absolut nichts.

Komischerweise liegten an OC0B kein Signal an (immer low) und an OC0A 
~800 Hz.
Beide OCR sind auf 128 gesetzt, also ungefähr die hälfte des 
Timer-Bereiches.
Warum verhält sich das so ?
Die Frequenz für den Timer ist die CPU Frequenz von 16MHz (hatte gerade 
keinen 20MHz Quartz.

von Marvin K. (m_marvin)


Lesenswert?

Lothar M. schrieb:
> Du willst da offenbar ein mechanisches Problem mit Raktentechnik lösen.
> Welche Last hast du da dran?

Keine ...
Einfach ein Motor im Leerlauf ohne etwas daran.

von Marvin K. (m_marvin)


Lesenswert?

Hier ist noch mein aktueller Code für den Timer.
1
TCCR0A = (1 << COM0A0) | (1 << COM0B0);
2
TCCR0B = (1 << CS00);
3
TIMSK0 = (1 << OCIE0B) | (1 << OCIE0A);
4
  
5
OCR0A = 128;
6
OCR0B = 128;
Eigentlich sollte doch sowohl an OC0A als auch an OC0B ~62kHz anliegen 
(bei 16MHz CPU Takt) oder ?

von Walter T. (nicolas)


Lesenswert?

Marvin K. schrieb:
> Einfach ein Motor im Leerlauf ohne etwas daran.

Etwas Off-Topic, aber: Gibt dem Motor etwas Last. Schwungmasse oder 
etwas Dämpfendes (ein Getriebe oder so).

von Marvin K. (m_marvin)


Lesenswert?

Korrektur, ~32 kHz.
62kHz ist ja nur die Frequenz mit der getoggelt wird.

von Yalu X. (yalu) (Moderator)


Lesenswert?

Walter T. schrieb:
> Lass mich mal paraphrasieren, ob ich das richtig verstanden habe:
>
> Der Timer läuft durch. Bei jedem Timerdurchlauf können Null oder ein
> Taktsignal ausgegeben werden.

Nicht wenn der Timer durchgelaufen ist, sondern jedesmal, wenn der Wert
des OC-Registers erreicht wird. Soll die Ausgabefrequenz 200 kHz sein,
geschieht dies alle 100 Taktzyklen, also 655- bis 656-mal pro
Timerdurchlauf.

Lothar M. schrieb:
> Yalu X. schrieb:
>> Das kann aber zu einem beliebigen Zeitpunkt innerhalb der Periodendauer
>> erfolgen.
> Muss das "kann" nicht eher "muss" heißen? ;-)

Vielleicht habe ich den Satz missverständlich formuliert: Es muss
innerhalb der gewünschten Periodendauer des Ausgabesignals erfolgen,
innerhalb dieser Zeitspanne ist der genaue Zeitpunkt aber beliebig.

von Marvin K. (m_marvin)


Lesenswert?

Interesant, ich hab einfach mal den ganzen Code gelöscht der noch die 
PORTS als Ein/Aushänge definiert (die DDRs schreibt) jetzt haben beide 
OCs 31,2 kHz.
Die OCs hab ich weiterhin als Ausgang in die DDRs geschrieben, aber ich 
verstehe nicht warum das entfernen der anderen DDR-Schreib-Befehle die 
Frequenzen an den OCs beeinflusst.

von Marvin K. (m_marvin)


Lesenswert?

Ich versuche jetzt einfach mal mit diesem Timer 2 verschiedene 
Frequenzen an den OCs zu erzeugen, egal welche.
Dazu muss ich jetzt das Compare Match Interrupt abfangen und den OCR 
updaten.
Wie geht das jetzt am schnellsten, mit einer Schleife die das Flag im 
Register abfragt, oder durch ein ISR?
Ich hab jetzt schon 2 Meinungen mitbekommen.

von MaWin (Gast)


Lesenswert?

Marvin K. schrieb:
> Was ist die höchste mögliche Schaltfrequenz

Egal.

Marvin K. schrieb:
> ich habe 6 DM542 Schrittmotortreiber die ich ansteuern will

Das kann ein ATmega328, er kann GRBL laufen lassen und der macht 3 
Achsen. Zwar taktet er nur mit 30-40kHz, aber Mikroschritte sind bei 
hohem Tempo sowieso irrelevant, der Strom steigt durch die Induktivität 
des Motors gar nicht mehr so schnell wie der Chopper haben müsste damit 
er mal zum choppen käme (meist 100kHz).

Wenn man möchte und programmieren kann und die 6 STEP Ausgänge auf 1 
Port legt, muss man nur zu jedem Zeitintervall (das kann der ATmega mit 
einem einzelnen Timer auf 0.1us genau) ein vorausberechnet neues Byte 
auf den Ausgang schreiben und die Pulszeit bis zum nächsten Schritt ins 
Compare-Register übertragen. Das geht in Assembler in ca. 1us, könnte 
also 1MHz auf bis zu 8 Schrittmotoren erzielen.
1
uint8_t calculated_steos[256];
2
uint16_t ticks_to_next_event[256];
3
uint8_t n;
4
ISR (TIMER1_COMPA_vect)
5
{
6
   PORTB=calculated_step[n];
7
   OCR1A=ticks_to_next_event[n++];
8
}
Das Hauptprogramm berechnet die Tabellen immer ausreichend im Voraus, 
die werden vom zeitvariablen Interupt  im Ringpuffer abgearbeitet.

von m.n. (Gast)


Lesenswert?

Marvin K. schrieb:
> Lothar M. schrieb:
>> Du willst da offenbar ein mechanisches Problem mit Raktentechnik lösen.
>> Welche Last hast du da dran?
>
> Keine ...
> Einfach ein Motor im Leerlauf ohne etwas daran.

Und vorhin war es noch ein Roboterarm.

Yalu X. schrieb:
> Ich
> würde die OC-Interruptflags in einer Schleife abfragen und immer, wenn
> eines oder mehrere davon gesetzt sind, entsprechend darauf reagieren.

Is ja nett, aber wie soll der Motor an neue Daten kommen?
;-)

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Marvin K. schrieb:
> Lothar M. schrieb:
>> Du willst da offenbar ein mechanisches Problem mit Raktentechnik lösen.
>> Welche Last hast du da dran?
> Keine ...
> Einfach ein Motor im Leerlauf ohne etwas daran.
Dann vergiss die Spielereien.
Du musst einen Schrittmotor mit einer Last und zwar am besten mit 
einer dämpfenden Last betreiben. Was du da grad erlebst, nennt sich 
"Eigenresonanz" und die dafür nötigen Grundlagen stehen in jedem 
halbwegs brauchbaren Lehrbuch zum Thema Schrittmotorantriebe ganz weit 
vorne.

Sowas: https://www.google.com/search?q=schrittmotr+resonanz

Findet dann sowas: 
http://www.schrittmotor-blog.de/resonanzen-bei-schrittmotoren/

: Bearbeitet durch Moderator
von Walter T. (nicolas)


Lesenswert?

Yalu X. schrieb:
> Soll die Ausgabefrequenz 200 kHz sein,
> geschieht dies alle 100 Taktzyklen, also 655- bis 656-mal pro
> Timerdurchlauf.

Nehmen wir an, Du hättest vier Ausgangssignale. Dann bringst Du 
innerhalb jeder Periode dieser vier Ausgangssignale das Überlaufregister 
mindestens einmal auf Stand (und für sehr niedrige Frequenzen zusätzlich 
zweimal bei jedem Timer-Durchlauf). Indem Du den Update-Zeitraum immer 
frühestmöglich nach dem letzten Überlauf machst, stellst Du sicher, dass 
es keinen Update-Stau gibt, wenn mehrere Überlaufregister direkt 
hintereinander dran sind.

Habe ich das jetzt richtig verstanden?

(Entschuldige die Penetranz, aber mich interessiert jeder Kniff, wie man 
race conditions bei Timern verhindert.)

: Bearbeitet durch User
von Yalu X. (yalu) (Moderator)


Lesenswert?

m.n. schrieb:
> Yalu X. schrieb:
>> Ich
>> würde die OC-Interruptflags in einer Schleife abfragen und immer, wenn
>> eines oder mehrere davon gesetzt sind, entsprechend darauf reagieren.
>
> Is ja nett, aber wie soll der Motor an neue Daten kommen?
> ;-)

Der Schrittmotor bekommt seine Signale vom Treiber (DM542), dieser
bekommt vom Mikrocontroller ein Rechtecksignal, wobei jeder Impuls einem
Mikroschritt entspricht. Das Rechtecksignal kommt bspw. aus dem
OC1A-Ausgang de ATmega328P und durch den Timer1 erzeugt. Die Software
schreibt hierzu periodisch den Zeitpunkt des jeweils nächsten Impulses
in das OCR1A-Register. Entsprechendes gilt für die Ausgänge OC1B, OC3A,
OC3B, OC4A und OC4B, wobei – wie ich oben schon schrieb – OC3B und OC4B
beim ATmega328P leider auf demselben Pin herausgeführt sind, so dass man
nicht beide gleichzeitig nutzen kann.

Walter T. schrieb:
> Nehmen wir an, Du hättest vier Ausgangssignale.

Pro Timer des ATmega328P sind nur zwei Signale möglich, da jeder Timer
nur zwei Outout-Compare-Units hat.

> Dann bringst Du
> innerhalb jeder Periode dieser vier Ausgangssignale das Überlaufregister

Meinst du mit Überlaufregister die Output-Compare-Register
(OCR[134][AB])?

> mindestens einmal auf Stand (und für sehr niedrige Frequenzen zusätzlich
> zweimal bei jedem Timer-Durchlauf).

Diesen Teil des Satzes habe ich nicht verstanden und kann deswegen auch
nicht sagen, ob du das richtig verstanden hast ;-)

> Indem Du den Update-Zeitraum immer frühestmöglich nach dem letzten
> Überlauf machst, stellst Du sicher, dass es keinen Update-Stau gibt,
> wenn mehrere Überlaufregister direkt hintereinander dran sind.

Genau.

Wenn mir heute Abend langweilig ist, werde ich das mal ausprobieren und
– falls es so funktioniert, wie ich mir das vorstelle – den Code
veröffentlichen. Vielleicht wird dann einiges klarer.

Vielleicht stellt sich dabei ja auch heraus, dass ich auf dem Holzweg
bin, dann werde ich dies ebenfalls kundtun ;-)

von Marvin K. (m_marvin)


Lesenswert?

m.n. schrieb:
> Und vorhin war es noch ein Roboterarm.

Zum Test hab ich den Motor ausgebaut, ich will ja nicht das durch ein 
Programmierfehler der Roboterarm sich selbst kaputt Schlägt ...

von Marvin K. (m_marvin)


Lesenswert?

Ich hab es jetzt mal mit dem Ring-Buffer versucht, indem ich im voraus 
werte berechne, die dann im ISR nur noch dem Port zugewiesen werden.
Das funktioniert ganz gut, so hätte ich 8 Kanäle zu verfügung.
Das einzige Problem das ich habe sind so "krumme" Frequenzen wie z.B: 
1kHz.
Da gibt es dann an den Überlaufstellen im Ringbuffer (also der Punkt wo 
es wieder bei 0 losgeht) Probleme, was zu einem "Bruch" (ka wie ich das 
beschreiben soll) kommt, und es neu beginnt.

Ich denke das liegt daran das ich es noch nicht richtig programmiert 
habe, ich denke aber das das eine gut Lösung ist.

Wenn das dann funktioniert, währe es nur noch gut, wenn ich diese 
Oberwellen an dem Port rausbekäme, aktuell sind da in unregelmäßigen 
abständen Spitzen die bis z 9V reichen.

von Walter T. (nicolas)


Lesenswert?

Yalu X. schrieb:
> Diesen Teil des Satzes habe ich nicht verstanden

Vielleicht kann man den Sonderfall "ausgegebene Taktfrequenz ist 
niedriger als eine Flanke pro Timer-Überlauf" auch einfach weglassen und 
in den Verantwortungsbereich einer übergeordneten Regelschleife 
verlagern. Dann spielt das keine Rolle mehr.

von m.n. (Gast)


Lesenswert?

Yalu X. schrieb:
>> Is ja nett, aber wie soll der Motor an neue Daten kommen?
>> ;-)
>
> Der Schrittmotor bekommt seine Signale vom Treiber (DM542), dieser
> bekommt vom Mikrocontroller ein Rechtecksignal, wobei jeder Impuls einem
> Mikroschritt entspricht.

Tut mit Leid, ich hatte zu schnell und ungenau formuliert. Wie kommen 
Daten in den ATmega, damit er den Motor passend ansteuern kann? Wo 
werden die Rampen erzeugt?
In der Dauerschleife zur OCR-Abfrage ist ja keine Luft mehr, noch 
irgendetwas anderes zu tun. Der AVR sollte auch noch die Position 
erfassen und Zielfahrten ausführen können; das erwarte zumindest ich von 
einer sinnvollen Steuerung.

Selbst, wenn man das irgendwie - meinetwegen auch in Assembler - in den 
µC gepackt bekommt, bei jeder Änderung hat man wieder etliche Risiken 
und Nebenwirkungen. Meine Meinung: Keine gute Lösung!

Da jetzt auch 9V auftauchen, halte ich mich lieber zurück ;-)

von Marvin K. (m_marvin)


Lesenswert?

Es funktioniert jetzt, ich kann auf 8 Kanälen unabhängig voneinander 
Frequenzen von 0-16MHz ausgeben (die Qualität der Signale ist aber nur 
bis ~150-200kHz brauchbar, was aber ja vollkommen ausreicht).

Jetzt fehlt nur noch die Möglichkeit die Anzahl an Perioden zu 
begrenzen, und die I2C Schnittstelle.

von Marvin K. (m_marvin)


Lesenswert?

Und zur Ansteuerung:
Das mit den Zielfahrten macht ein Rasperry Pi.
Der ATmega bekommt per I2C nur gesagt, welche Richtung, Welche Frequenz 
und wie viele Perioden (Impulse).

Zusätzlich werde ich noch irgend eine Form von direkter 
Positionsermittlung einbauen, z.B. durch ein Potentiometer oder so, das 
den Winkel der Gelenke erfassen kann.
Damit kann ich dann auch die Position ermitteln wenn der Strom 
abgeschaltet wird und der Arm dann "herunterfällt", da ja der Haltestrom 
weg ist.
Ansonsten müsste ich ihn ja immer manuell in Grundstellung fahren.

: Bearbeitet durch User
von Carsten-Peter C. (carsten-p)


Lesenswert?

Hallo, ich habe mal ein Plotter- Programm geschrieben (in Assembler). 
Dabei habe ich das OCR-Register genutzt im CTC Mode, um die 
Geschwindigkeit festzulegen. Immer der schnellere der beiden Motoren 
bestimmte die Rampenlänge, indem ich das OCR- Register nach jedem 
Schritt angepasst habe. In der ISR (Timer/Counter1 Compare Match A) habe 
ich die Impulse auf die entsprechenden Ports gegeben. Genutzt habe ich 
den ATmega 1284P, weil der reichlich SRAM für den Datenpuffer hatte. Mit 
1/8 Mikroschritt lief der Motor am ruhigsten. So brauchst Du nur einen 
Timer für alle Motore. Deine 200KHz- Signale empfind ich als sehr hoch. 
Meine Schrittmotore machen das nicht annähernd mit.
Vielleicht ist das ja ein Weg für Dich. Viel Erfolg:
Gruß Carsten

von Marvin K. (m_marvin)


Lesenswert?

Mit der Ringpuffer-Methode nutze ich auch nur einen Timer.

Ich habe jetzt einmal den Vorteiler Wert für den Timer im CTC Betrieb.
Mit diesem kann ich den Grundlegenden Frequenzbereich wählen.

Dann hab ich für jeden der Acht Kanäle noch einen weiteren Teiler, mit 
dem ich recht genau auf die beliebigen Frequenzen komme.

Funktioniert auch gut, nur die Angabe der Periodenzahl hab ich noch 
nicht hinbekommen.

Den Frequenzbereich passe ich dann nochmal an wenn die Mechanik komplett 
fertig gestellt ist.

: Bearbeitet durch User
von Yalu X. (yalu) (Moderator)


Lesenswert?

Marvin K. schrieb:
> Ich hab es jetzt mal mit dem Ring-Buffer versucht, indem ich im voraus
> werte berechne, die dann im ISR nur noch dem Port zugewiesen werden.
> Das funktioniert ganz gut, so hätte ich 8 Kanäle zu verfügung.

Das bedeutet aber, dass du die Geschwindigkeit nicht dynamisch erhöhen
kannst (für eine beschleunigte Bewegung), weil ja mit jeder Änderung
einer der 8 Geschwindigkeiten der Inhalt des Ringpuffers neu berechnet
werden muss und dabei der Motor kurzzeitig zum Stillstand kommt.

Und wie ist das mit der Größe des Ringpuffers? Wird der bei krummen
Frequenzverhältnissen zwischen den 8 Kanälen nicht sehr groß? Die Größe
müsste ja das kleinste gemeinsame Vielfache der einzelnen Periodendauern
sein.

Oder habe ich deine Methode falsch verstanden?

Marvin K. schrieb:
> Es funktioniert jetzt, ich kann auf 8 Kanälen unabhängig voneinander
> Frequenzen von 0-16MHz ausgeben

Sicher? Die 16 MHz sind ja schon fast die CPU-Frequenz.

von Marvin K. (m_marvin)


Lesenswert?

Nein, der Ringpuffer wird im Hauptprogramm dauerhaft neu berechnet, und 
im ISR dann nur ausgelesen.
Es ist wie eine Endlosschleife und scheint auch gut zu funktionieren.
Wenn man jetzt mal annimmt das der Puffer 10 Stellen/Einträge hat, und 
das ISR gerade beim 5. ist, dann wird im nächsten durchlauf des 
Hauptprogramms von der 6. stelle über den überlauf bis hin zur 5. stelle 
neu berechnet.
Ich denke das es in bestimmten Frequenzbereichen durchaus zu kleinen 
"Brüchen" kommen kann, wo ein Periode mal länger oder kürzer ist, aber 
das sollte bei so hohen Frequenzen nicht auffallen.

Und ja, es erreicht 16MHz, was der CPU Frequenz entspricht.
Das liegt daran das ich kein Rechteck-Signal sondern Impulse mit immer 
gleicher länge erzeuge (oder fast gleich, die länge wird vom genannten 
"Vorteiler" bestimmt).
Dadurch wird bei jedem Takt der Timers eine neue Periode begonnen, 
anstatt nur die Flanke umzuschalten.
Das funktioniert ganz gut, die Motoren haben sich jedenfalls sauber 
gedreht und hatten kein rattern.

Eigentlich müsste des dadurch nur fast an die CPU grenze heranreichen, 
aber wenn ich den Teiler (also den wert im OCR auf 0) setze, bekomme ich 
16MHz raus, halt sehr unsauber, aber es sind 16MHz.
Ich hab keine Ahnung wie das sein kann, aber da ich es sowieso 
allerhöchstens auf 200kHz bringe, stört mich das nicht weiter.

von Marvin K. (m_marvin)


Lesenswert?

Und doch, ich kann die Werte dauerhaft ändern und so die Frequenz 
Rampenartig hochfahren um einen sanfteren Anlauf zu bekommen.
Der Ringpuffer wird ja konstant neu berechnet, eine gewisse Verzögerung 
hat es, aber das liegt im ms Bereich, das kann man ja ignorieren.

Ich muss nur noch einen weg finden, die Perioden zu zählen, bzw. bei der 
Berechnung des Puffers nur eine begrenzte Anzahl an Perioden zu 
erlauben.
Bisher hat das nicht funktioniert.
Eventuell mache ich auch gar keine Impulszählung, und alles über die 
direkte Positionsermittlung.

: Bearbeitet durch User
von Marvin K. (m_marvin)


Lesenswert?

Ich hab jetzt auch die Impulszählung hinbekommen, morgen beschäftige ich 
mich dann mit dem I2C und einer Funktion für einen sanften Anlauf.

Wenn ich fertig bin, werde ich den Code eventuell hier hochladen, ist 
bisher recht übersichtlich.

von Michael S. (Gast)


Lesenswert?

Hallo,

auch auf die Gefahr, dass ich das Thema "AVR" verfehle, mir fällt zum 
Problem spontan der bereits genannte PI PICO ein.
Und zwar mit seinen 8 Statemachines, programmiert in asm-pio.
Die laufen unabhängig von main() und mit bis zu 125 MHz.
Ein Signal vom 1KHz bis 200KHz stemmen die mit links.

Überschlag:
1
Bei einem Takt von 120MHz und 3 Takten für jedes Decrementieren, Vergleichen und Jumpen verbleiben effektiv 40MHz.
2
Bei einem Preload von 4000 (2 * 2000) erhalten wir   1.000Hz,
3
bei einem Preload vom 200  (2 * 100)  erhalten wir 200.000Hz.
4
Bei einem Preload von 202  (2 * 101)  erhalten wir 198.020Hz

Programmablauf der Statemachines:
1
Der Statemachine wird von main() ein Preload in das Input-Register geladen.
2
1.) Die Statemachine schaltet den Output-Pin auf high
3
2.) Sie holt sich den Preload in das X-Register
4
    und decremntiert X bis auf 0
5
3.) Die Statemachine schalten den Output-Pin auf low
6
4.) Die Staetmeachine holt sich den Preload in das X-Register
7
    und decrementiert X bis auf 0
8
5.) weiter bei 1).
Immer, wenn main() einen neuen Preload in die Statemachine schreibt,
wird der beim nächsten (Halb-)Takt verwendet.

Wie gesagt, die Statemachines sind unabhängig voneinander und unabhängig 
vom main()

In main() kann nach Herzenlust am I2C-Bus rumgebummelt werden oder es 
können
aufwändige Neuberechnungen der Preloads ausgeführt werden ...

Das ist in C und vermutlich sogar in Python möglich.

Michael S.

von m.n. (Gast)


Lesenswert?

Michael S. schrieb:
> Und zwar mit seinen 8 Statemachines, programmiert in asm-pio.
> Die laufen unabhängig von main() und mit bis zu 125 MHz.

Die PWM-Timer laufen auch unabhängig vom Kern, lassen sich aber viel 
transparenter programmieren.

Yalu X. schrieb:
> Sicher? Die 16 MHz sind ja schon fast die CPU-Frequenz.

Das funktioniert wegen der 9 V :-(

von Jobst M. (jobstens-de)


Angehängte Dateien:

Lesenswert?

Moin!

Ich habe hier einen ATmega168 (sollte aber auch auf dem 48 aber 
natürlich auch 328 laufen).
Steppertreiber DRV8825.
Systemtakt 18,432MHz
Max. Steptakt 192kHz - könnte aber noch nach oben geschoben werden, gibt 
dann nur Einschränkungen an anderer Stelle.
Takt wird mit dem DDS-Prinzip erzeugt. Jittert also. Funktioniert aber 
problemlos.
Board bietet RS485 Interface mit 8 einstellbaren Adressen. (+ Broadcast)
Kommunikation ist ASCII.
Geschwindigkeit und Rampe lassen sich einstellen.
Position kann innerhalb int32 (+/-2G) angegeben werden.
Position wird gesendet und der Motor fährt dort hin.
Kommunikation auch während der Bewegung möglich.

Im Timer IRQ (192kHz) wird die DDS-Routine aufgerufen. Wird ein neuer 
Puls generiert (beide Flanken!), muss aufgrund der neuen Position die 
Geschwindigkeit neu berechnet werden. Virtuell werden 192000 32-Bit 
Wurzeln in der Sekunde gezogen. Ist bereits eine Wurzelberechnung im 
Gange, wird keine neue gestartet.
Der Timer IRQ unterbricht sich selber, um zwischendurch einen neuen Takt 
zu berechnen.

Das Ganze ist recht kompakt und verschachtelt in ASM geschrieben. Und es 
ist kaum Zeit über. Wenn der Motor mit voller Drehzahl läuft, lässt sich 
die Kommunikation merklich Zeit mit der Antwort.

6 Kanäle mit 200kHz in das Ding zu quetschen halte ich für unmöglich.
Mit Timern wirst Du nicht hinterher kommen die Positionen aktuell zu 
halten.
Dazu die ganzen Rampenberechnungen.
Nebenbei noch Kommunikation.
 - unmöglich.

Entweder benutzt Du 6 Chips oder eine fette CPU.

Gruß
Jobst

von Walter T. (nicolas)


Lesenswert?

Jobst M. schrieb:
> Ich habe hier ...

Hast Du da ein sehr interessantes Objektiv oder einen sehr interessanten 
Motor?

von Jobst M. (jobstens-de)


Lesenswert?

Walter T. schrieb:
> Hast Du da ein sehr interessantes Objektiv oder einen sehr interessanten
> Motor?

Kamera: Panasonic DMC-SZ8

Motor: ACT 11HS5406

Gruß
Jobst

von PittyJ (Gast)


Lesenswert?

Ich habe ein ähnliches Problem, wo ich mehrere exakte Timings brauche.
Dafür nehme ich jetzt immer ein FPGA. Die CPU stellt einmal die Frequenz 
ein. Der FPGA hält das Timing ein, und die CPU ist frei für andere 
Aufgaben.
Dafür reichen FPGAs mit wenig LUTs.
Und wenn man noch eine weitere Frequenz braucht, dann instanziert man 
eine weitere Einheit im FPGA.

von Walter T. (nicolas)


Lesenswert?

Jobst M. schrieb:
> Motor: ACT 11HS5406

Danke! Nema 11 Bauhöhe 50 mm - so etwas langes, dünnes hatte ich noch 
nicht gesehen.

PittyJ schrieb:
> Dafür nehme ich jetzt immer ein FPGA.

Das wird jetzt so langsam Overkill. Die genannten Endstufen arbeiten 
optimal bei 0...30kHz:

Die meisten Schrittmotoren haben ab 1000 U/min nur noch weniger als 2/3 
des Drehmoments, 200 Schritte/U, Achtelschrittmodus sind 26 kHz.

: Bearbeitet durch User
von PittyJ (Gast)


Lesenswert?

Walter T. schrieb:

> PittyJ schrieb:
>> Dafür nehme ich jetzt immer ein FPGA.
>
> Das wird jetzt so langsam Overkill. Die genannten Endstufen arbeiten
> optimal bei 0...30kHz:

Nö, wieso Overkill?
Ein Lattice ICE40 mit 1200 Luts kostet bei Mouser 5€. Die sind sogar 
verfügbar.
Also habe ich für 5€ ein genaues Timing und erspare mir diese ganzen 
fehlerträchtigen Interrupts.

von MaWin (Gast)


Lesenswert?

PittyJ schrieb:
> Also habe ich für 5€ ein genaues Timing

Normalerweise ist Timing die einfachste Sache, die Berechnung wie man da 
hin kommt die aufwändige und die muss glitch-frei das Timing mehrerer 
Kanäle simultan beinflussen können - da stört jede Zweiteilung mehr als 
sie hilft.
Siehe Vorschlag von oben, Impulse in Software zu machen statt 
Hardware-Timer, davon nur einen als Zeitraster nutzen. Ist schneller.

Z.B. G-Code: bisher Lauf zu Punkt x1,y1 bekannt. Bremsrampe berechnet. 
Nun kommt Kommando von x1,y1 nach x2,y2 d.h. man muss wissen wie weit 
der Motor schon gebremst hat, neue Beschleunigungsrampe berechnen und 
stattdessen einsetzen, und Kommandos bis x2,y2 einspeichern.

von m.n. (Gast)


Lesenswert?

PittyJ schrieb:
> Ein Lattice ICE40 mit 1200 Luts kostet bei Mouser 5€.

1200 luts sind 5 Euro? Welches Land hat denn die Währung? Oder etwas zum 
Lutschen?

> Also habe ich für 5€ ein genaues Timing und erspare mir diese ganzen
> fehlerträchtigen Interrupts.

Einfach alle delay_ms(500) aus der ISR rauswerfen, dann läuft das auch 
;-)


Jobst M. schrieb:
> Geschwindigkeit und Rampe lassen sich einstellen.

Wird die Rampe zuvor berechnet oder während der Fahrt?

von Jobst M. (jobstens-de)


Lesenswert?

m.n. schrieb:
> Wird die Rampe zuvor berechnet oder während der Fahrt?

Während der Fahrt. Nach jedem Schritt - solange die Schritte zeitlich 
nicht zu dicht zusammen liegen. Sonst macht er auch nur eine Berechnung 
für 3 Schritte. Viel Änderung der Geschwindigkeit ist in der Zeit nicht.

Gruß
Jobst

von m.n. (Gast)


Lesenswert?

Jobst M. schrieb:
> m.n. schrieb:
>> Wird die Rampe zuvor berechnet oder während der Fahrt?
>
> Während der Fahrt. Nach jedem Schritt - solange die Schritte zeitlich
> nicht zu dicht zusammen liegen. Sonst macht er auch nur eine Berechnung
> für 3 Schritte.

Das gefällt mir!

von PittyJ (Gast)


Lesenswert?

m.n. schrieb:
> PittyJ schrieb:
>> Ein Lattice ICE40 mit 1200 Luts kostet bei Mouser 5€.
>
> 1200 luts sind 5 Euro? Welches Land hat denn die Währung? Oder etwas zum
> Lutschen?


Wenn du nicht einmal weisst, was eine LUT bei einem FPGA ist, dann 
wirdst du wohl auch ein Leben lang immer beim AtMega bleiben.

von Walter T. (nicolas)


Lesenswert?

PittyJ schrieb:
> Wenn du nicht einmal weisst, was eine LUT bei einem FPGA ist, dann
> wirdst du wohl auch ein Leben lang immer beim AtMega bleiben.

Wenn Du nicht einmal weißt, dass die Anschaffungskosten des ICs bei 
allem, was programmierbar ist, nur einen Bruchteil des Aufwands 
darstellen, wird man Dich niemals Ernst nehmen.

von Marvin K. (m_marvin)


Lesenswert?

Also ich hab meinen ATmega jetzt soweit dass er auf dem Port D alle Pins 
als einen Kanal nutzt.
Jeder Kanal gibt nun mit der in einer Variable angegebenen Frequenz eine 
bestimmte Anzahl von Pulsen aus, womit ich einen Motor auch ganz gut 
ansteuern kann (Funktioniert ganz gut mit den DM542).

Problematisch ist nur dass er durch das Zählen der Impulse in einer 
Variable (geschrieben in c++) etwas Zeit verliert, nicht viel, aber 
etwas was man auf dem Oszilloskop merkt.

Ich bin nun zufällig nochmal über die "General Purpose Register" der AVR 
gestolpert, und hab folgendes im Datenblatt gefunden:

"Most of the instructions operating on the register file have direct 
access to all registers, and most of them are single cycle
instructions."

Meine Frage ist daher, macht es sinn als Impuls-Zähler einen solchen 
Register zu nutzen, oder ist eine Variable im RAM ausreichend ?
Ich verstehe das so, dass der Zugriff auf Register besonders schnell 
ist, aber vielleicht verstehe ich den Satz auch falsch.

: Bearbeitet durch User
von Gerald M. (gerald_m17)


Lesenswert?

Ram lesen und schreiben sind ebenfalls Single Cycle Instructions.

Ich weiß nicht wie genau du die die Pins togglest. Aber das Zähler 
hochzählen an sich brauch kaum Zeit, das Einspringen in die ISR hingegen 
schon.

Hier würde ich, wie der ein oder andere bisher, noch einmal einen Blick 
auf die STM32 empfehlen, hier kannst du zwei Counter koppeln, so dass 
bei einem Pin-Change der Zähler hoch zählt, und zwar alles in Hardware 
ohne dass die CPU davon etwas mitbekommt.
Wenn du CubeMX zur Konfiguration nutzt, sind das, was du bisher 
geschrieben hast, etwa 10 - 20 Zeilen Code (PWM und I2C Ansteuerung, 
inkl. kopieren der Werte), der Rest wird automatisch generiert.

von c-hater (Gast)


Lesenswert?

Marvin K. schrieb:

> Meine Frage ist daher, macht es sinn als Impuls-Zähler einen solchen
> Register zu nutzen, oder ist eine Variable im RAM ausreichend ?

Seltsame Frage.

Fakt ist jedenfalls, dass man auf die GPIO-Register schneller zugreifen 
kann als auf RAM. Einfaches Lesen oder Schreiben geht in einem Takt 
statt in zwei, einzelne Bits setzen oder löschen geht in zwei Takten 
statt in fünf.

Ob das aber in deiner Anwendung irgendeine Relevanz besitzt, kannst 
bestenfalls nur du wissen, weil nur du diese kennst. Es könnte nämlich 
genausogut sein, dass die Sache sogar langsamer wird. Nämlich dann, wenn 
die Variablen in Wirklichkeit garnicht im RAM liegen, sondern in 
MCU-Registern gehalten werden. Mit C ist man halt am Raten oder muss 
sich das Listfile anschauen.

Schreibt man's gleich in Assembler, hat man die volle Kontrolle. Bei 
timngkritischen Sachen immer die beste Lösung, denn C garantiert kein 
bestimmtes Timing.

von Jobst M. (jobstens-de)


Lesenswert?

Gerald M. schrieb:
> Ram lesen und schreiben sind ebenfalls Single Cycle Instructions.

Nein.

Gruß
Jobst

von piffpoff (Gast)


Lesenswert?

c-hater schrieb:
> Schreibt man's gleich in Assembler, hat man die volle Kontrolle. Bei
> timngkritischen Sachen immer die beste Lösung, denn C garantiert kein
> bestimmtes Timing.

Exaktes timing durch benutzung von assembly funktioniert auch nur 
solange du keinen einzigen interrupt im programm hast...

von Asm Profi (Gast)


Lesenswert?

@ c-hater:
Hier geht es nicht um Assembler. Lass die sinnlosen Anspielungen.

von m.n. (Gast)


Lesenswert?

c-hater schrieb:
> Schreibt man's gleich in Assembler, hat man die volle Kontrolle. Bei
> timngkritischen Sachen immer die beste Lösung, denn C garantiert kein
> bestimmtes Timing.

Genaues Timing bietet das Setzen/Rücksetzen eines Ausgangs in Verbindung 
mit OCRx. Und das programmiert man ganz entspannt in C.

von MaWin (Gast)


Lesenswert?

Marvin K. schrieb:
> Problematisch ist nur dass er durch das Zählen der Impulse in einer
> Variable (geschrieben in c++) etwas Zeit verliert, nicht viel, aber
> etwas was man auf dem Oszilloskop merkt

Die Pulserzeugung sollte in einem Timer-Compare-Interrupt stattfinden.

In diesem Interrupt wird genau ein 8 bit Zahler incrementiert. Ob man 
dazuein dediziertes Tegister nutzt damit man keines pushen muss oder 
eine volatile Variable im RAM kannst du dir aussuchen, letztetes kostet 
mehr Instruktionen.


Alles andere der Impulserzeugung sollte im Hauptprogramm stattfinden, 
das sicherstellen muss, dass der Puffer mit den Interrupt-Timet-Aktionen 
nie leerläuft. Es ist für die Impulserzeugen vollig egal, was das 
Hauptprogramm dabei zeitverzögerndes macht. Der Interrupt ist immer in 
der Lage, das Hauptprogramm zu unterbrechen. Da die Instruktionen 
maximal 2 Takte Lang sind, liegt der Jitter bei 0.1us.
Ausnahme wäre, wenn du noch andere Interrupt-Routinen hast.

von Marvin K. (m_marvin)


Lesenswert?

Also, ich hab jetzt nach langem Rumprobieren folgendes herausgefunden:
Das erzeugen von hohen Frequenzen von bis zu 400kHz auf 8 unabhängigen 
Kanälen, mit SPI Interface zur Ansteuerung ist problemlos auf einem 
ATmega328P möglich, die Signalqualität ist gut und die 
Schrittmotortreiber verstehen es.

Das Problem was ich gerade bemerkt habe ist das Zählen der Impulse im 
Interrupt.

Der Rechenaufwand für das hochzählen von 8 Registern/Variablen (beides 
hatte das gleich Ergebnis) ist zu hoch.
Mit dem Zählen der Impulse von 1 Kanal hat es noch 100% seiner Frequenz
Mit 2 Kanälen ~90%
Mit 4 dann nur noch 50%

Ich brauche also wenn ich die Pulse Zählen will, doch eine 
leistungsfähigere CPU/eine MCU mit mehr Countern.
(Es sei denn jemand weis noch eine bessere Lösung)

Weis jemand einen AVR mit min. 6 16-Bit-Timern ?
Ich habe auf Reichelt jetzt z.B. den ATXMEGA 128A3UAU gefunden, mit 7 
leider nur 8-Bit-Timern.

Er hat eine Taktfrequenz von bis zu 32 Mhz, was dem doppelten des 
ATmegas328P entspricht.
Eventuell kann ich dann auch die Ringpuffermethode nutzen wie jetzt, nur 
mit einer schnelleren CPU.

Lieber währe mir aber nach dem ganzen rumprobieren ein AVR mit 6 16-Bit 
Timern.
Da weis ich dann das es funktioniert, weil das alles in der Hardware 
abläuft.

: Bearbeitet durch User
von Marvin K. (m_marvin)


Lesenswert?

Ich hab gerade noch ein par andere ATxmega gefunden, die teilweise bis 
zu 8 16-Bit Timer haben, das sollte ausreichen.
Die sind leider fast alle im SMD Format, was mir nichts ausmachen würde, 
währe da nicht das Problem das ich damit nichts auf einem Steckbrett 
testen kann.

Generell ist das ein großes Problem, was mich schon oft davon abgehalten 
hat solche "neueren" MCUs zu kaufen, wie soll man damit was Testen, ohne 
gleich eine fertige Leiterplatte anzufertigen ...
Man müsste ja für jede neue Pinzahl erst ein Adapter kaufen.

: Bearbeitet durch User
von Wilhelm M. (wimalopaan)


Lesenswert?

Marvin K. schrieb:
> Ich hab gerade noch ein par andere ATxmega gefunden, die teilweise bis
> zu 8 16-Bit Timer haben, das sollte ausreichen.
> Die sind leider fast alle im SMD Format, was mir nichts ausmachen würde,
> währe da nicht das Problem das ich damit nichts auf einem Steckbrett
> testen kann.
>
> Generell ist das ein großes Problem, was mich schon oft davon abgehalten
> hat solche "neueren" MCUs zu kaufen, wie soll man damit was Testen, ohne
> gleich eine fertige Leiterplatte anzufertigen ...
> Man müsste ja für jede neue Pinzahl erst ein Adapter kaufen.

In Deinem anderen Thread hatte ich Dir schonmal den Wechsel auf einen 
anderen µC vorgeschlagen, als Dich mit diesen alten AtMegas herum zu 
schlagen. Dort war es für Dich nicht möglich, jetzt schon?

Die Adapter von TQFP32/48/64 bekommst Du bei ebay problemlos für ein 
paar Cent. Macht Dein Hobby auch nicht exorbitant teuerer.

von Marvin K. (m_marvin)


Lesenswert?

Ich hab nicht gesagt das es nicht möglich ist, ich hab nur gesagt dass 
ich es nicht mache solange es auch mit einem ATmega geht.
Ich wollte es halt erstmal mit dem versuchen das ich hier habe, anstatt 
gleich was zu bestellen.
Und wie gesagt, bis auf das Zählen geht das auch alles mit einem ATmega.

von Ron T. (rontem)


Lesenswert?

Wilhelm M. schrieb:
> den Wechsel auf einen anderen µC vorgeschlagen, als Dich mit diesen
> alten AtMegas herum zu schlagen

Das "Herumschlagen" geht ohne jede Vorkenntnis dann erst richtig los.

von Marvin K. (m_marvin)


Lesenswert?

Ich ab jetzt einen ATxmega192A3 bestellt, war der einzige der nicht 
mehrere Wochen Lieferzeit hat, und einen TQFP Adapter.
Kann ich den jetzt auch mit einem STK500 per SPI programmieren?
Im Datenblatt steht er kann über JTAG oder PID programmiert werden, aber 
er hat auch SPI, nur steht da nicht ob er auch über SPI programmiert 
werden kann.

von S. Landolt (Gast)


Lesenswert?

an Marvin K.:
Mich würde der aktuelle Stand des Programms interessieren.

> bis zu 400kHz ... ist problemlos auf einem ATmega328P möglich
Das gilt für die 16 MHz?

(übrigens, am Rande: "währe" ist nicht das Wahre)

von Wilhelm M. (wimalopaan)


Lesenswert?

Marvin K. schrieb:
> Im Datenblatt steht er kann über JTAG oder PID programmiert werden, aber
> er hat auch SPI, nur steht da nicht ob er auch über SPI programmiert
> werden kann.

Nochmal: ISP und SPI sind unterschiedliche Dinge!

Im übrigen hat das Datenblatt in diesem Aspekt Recht ;-)

von Marvin K. (m_marvin)


Lesenswert?

S. Landolt schrieb:
>> bis zu 400kHz ... ist problemlos auf einem ATmega328P möglich
> Das gilt für die 16 MHz?

Ja, das höchste was ich rausbekommen hab waren 16MHz, brauchbar war es 
aber nur bis 400kHz.
Es ist aber halt nur das Signal, ich kann die Pulszahl nicht steuern, 
dafür ist die CPU dann nicht leistungsfähig genug.

Wilhelm M. schrieb:
> Nochmal: ISP und SPI sind unterschiedliche Dinge!
>
> Im übrigen hat das Datenblatt in diesem Aspekt Recht ;-)

Warum sagt jeder dauernd das IPS und SPI nicht das gleiche sind, das 
weis ich doch.
Und was bedeutet das das Datenblatt recht hat?
Da wird erwähnt dass der AVR das Programmieren über JTAG oder PID 
ermöglicht, und dass er UART und SPI Schnittstellen (und diverse andere) 
besitzt.

Aber es wird nicht erwähnt ob man auch diese anderen Schnittstellen 
(z.B. SPI) zum Programmieren nutzen kann.
Generell ist das Datenblatt der neueren AVRs ziemlich ungenau.
Es gibt kaum nähere Informationen zu den verschiedenen Funktionen, nicht 
mal die Register der Schnittstellen werden aufgelistet (zumindest nicht 
immer).

von Wilhelm M. (wimalopaan)


Lesenswert?

Marvin K. schrieb:
> Warum sagt jeder dauernd das IPS und SPI nicht das gleiche sind, das
> weis ich doch.

Weil Dein Text es nahelegt, dass Du den Unterschied nicht kennst. Die 
ISP-Schnittstelle ist zum flashen des µC, SPI ist eine simples serielles 
Interface, was Du aus Deinem Code heraus benutzen kannst.

Marvin K. schrieb:
> Aber es wird nicht erwähnt ob man auch diese anderen Schnittstellen
> (z.B. SPI) zum Programmieren nutzen kann.

Du kannst weder SPI noch UART noch I2C noch einen Timer noch ... 
irgendetwas der internen Peripherie zum flashen des µC benutzen. Es sei 
denn, Du hast da einen Bootloader drauf, der diese Schnittstelle 
verwendet.
(Hier hast Du wieder ISP und SPI verwechselt: Du bist verwirrt, weil 
physisch ISP die SPI verwendet).

von Wilhelm M. (wimalopaan)


Lesenswert?

Marvin K. schrieb:
> Es gibt kaum nähere Informationen zu den verschiedenen Funktionen, nicht
> mal die Register der Schnittstellen werden aufgelistet (zumindest nicht
> immer).

Dann schaust Du ins falsche Datenblatt ...

von Marvin K. (m_marvin)


Lesenswert?

Also so wie ich das Verstanden habe ist ISP "In System Programming" und 
bezeichnet das Programmieren des AVR ohne diesen auszubauen, unabhängig 
von der Schnittstelle.
Und SPI ist eine Schnittstelle.

Meine frage ist ob der ATxmega es erlaubt über die SPI Schnittstelle den 
Flash zu beschreiben.
Wenn jemand ein Datenblatt hat das diese Informationen hat, würde ich 
dafür gerne einen Link haben, das Datenblatt was ich habe hat nur die 
Info dass es möglich ist über JTAG und PID zu programmieren, und auch 
das wird nur nebensächlich erwähnt.

Ich verstehe nicht warum ich angeblich ISP und SPI verwechsle.
Ich weis dass das über einen Bootloader funktioniert, und ich weis auch 
das ISP nicht gleich SPI ist.
Meine Frage bezieht sich spezifisch auf die SPI Schnittstelle, da das 
STK500 das ich habe SPI hat.

von Wilhelm M. (wimalopaan)


Lesenswert?

Marvin K. schrieb:
> Meine frage ist ob der ATxmega es erlaubt über die SPI Schnittstelle den
> Flash zu beschreiben.

Nein

von Wilhelm M. (wimalopaan)


Lesenswert?

Marvin K. schrieb:
> Wenn jemand ein Datenblatt hat das diese Informationen hat, würde ich
> dafür gerne einen Link haben, das Datenblatt was ich habe hat nur die
> Info dass es möglich ist über JTAG und PID zu programmieren, und auch
> das wird nur nebensächlich erwähnt.

Findest Du selbst bei MicroChip auf der Seite.

Es geht nur PDI (nicht PID ;-) ) und JTAG, wie ich oen schon gesagt 
habe.

von Marvin K. (m_marvin)


Lesenswert?

Das hier ist alles was ich zum Thema "Prgramming" gefunden habe:

The program and debug interface (PDI), a fast, two-pin interface for 
programming and debugging, is available. The
devices also have an IEEE std. 1149.1 compliant JTAG interface, and this 
can also be used for boundary scan, on-chip
debug and programming.

Steht so in der "Overview" Kategorie.

Dort stehen aber generell nur besonderheiten drin.
Daher ist meine Frage (und so ist sie auch Wörtlich gemeint, nein ich 
habe nicht ISP und SPI vertauscht):
Gibt es eine Möglichkeit den ATxmega über SPI zu programmieren, so dass 
ich nicht noch einen neuen JTAG oder PID Programmer brauche.
Ich weis das das vom Bootloader abhängt, aber dazu steht wie gesagt 
nichts im Datenblatt.

von S. Landolt (Gast)


Lesenswert?

> über JTAG und PID zu programmieren
Dann wird das wohl oder übel alles sein - warum sollte der Hersteller 
noch eine dritte Möglichkeit integrieren.

Eigentlich hatte ich auf den aktuellen Sourcecode für den ATmega328P 
gehofft.

von Marvin K. (m_marvin)


Lesenswert?

Wilhelm M. schrieb:
> Es geht nur PDI (nicht PID ;-) ) und JTAG, wie ich oen schon gesagt
> habe.

Danke, das reicht mir als Antwort, oben hast du nur gesagt das das 
Datenblatt recht hat, aber ich nur den Text gefunden den ich eben 
nochmal hier rein kopiert habe, welche nur beiläufig das Programmieren 
über PID und JTAG erwähnt.

Aber ich habe gerade noch was zum STK gefunden, angeblich unterstützt es 
auch JTAG, nur nicht in den DPI-Sockeln, was ja auch nicht nötig ist.

Stimmt das, oder hab ich das falsch verstanden, bisher hab ich nur ein 
Bild mit Jumper-Kabeln auf den Expension-Slots gesehen.

von Marvin K. (m_marvin)


Lesenswert?

S. Landolt schrieb:
> Eigentlich hatte ich auf den aktuellen Sourcecode für den ATmega328P
> gehofft.

Denn kannst du haben: https://pastebin.com/Agxs5WQ4

Beachte das dass jetzt nur der Code für das erzeugen der Frequenzen ist, 
ich habe eben schnell alles entfernt was ich  gerade so ausprobiert habe 
um die Impulse zu zählen (was wie gesagt die CPU überfordert).
Ich hab es danach jetzt nicht nochmal getestet, aber wenn ich nichts 
übersehen hab, ist es in der Lage Frequenzen bis hin zur CPU Frequenz zu 
erzeugen (was ich selbst nicht ganz verstehe, aber das sagt mein 
Oszilloskop).

von m.n. (Gast)


Lesenswert?

S. Landolt schrieb:
> Eigentlich hatte ich auf den aktuellen Sourcecode für den ATmega328P
> gehofft.

Lass mich raten: Du möchtest testen, wie sich die erzeugte Frequenz von 
13 MHz auf 13,5 MHz erhöhen läßt?

Marvin K. schrieb:
> Ich ab jetzt einen ATxmega192A3 bestellt, war der einzige der nicht
> mehrere Wochen Lieferzeit hat, und einen TQFP Adapter.

Als ob dieser irgendetwas verbessern würde :-(
Wenn Du die vielen, ernstgemeinten Vorschläge verstanden hättest, wären 
es 6 x ATmegaxxx oder ein STM32 oder RP2040 oder ... gewesen.

von Marvin K. (m_marvin)


Lesenswert?

Ich hab hier im mikrocontroller.net noch was anderes zu ISP (ja ISP 
nicht SPI) gefunden.

Laut dieser Seite 
https://www.mikrocontroller.net/articles/AVR_In_System_Programmer?msclkid=395a3bc2cd2611eca7e7533b57100329
Teilen sich ISP und SPI die Pins nur, bedeutet das jetzt ISP kann auch 
eine Schnittstelle sein, oder wie soll ich das jetzt verstehen?

Bis eben dachte ich noch ISP bedeutet nur das man den Chip Programmieren 
kann während er verbaut ist.

von Marvin K. (m_marvin)


Lesenswert?

m.n. schrieb:
> Als ob dieser irgendetwas verbessern würde :-(
> Wenn Du die vielen, ernstgemeinten Vorschläge verstanden hättest, wären
> es 6 x ATmegaxxx oder ein STM32 oder RP2040 oder ... gewesen

Der hat jetzt aber 7 16-Bit Timer, heißt ich kann es einfach von der 
Hardware machen lassen, und brauch keine CPU Leistung dafür.

Und ich würde generell gerne bei AVR bleiben, damit kenne ich mich aus 
und bisher hatte ich damit auch keine Probleme.

von m.n. (Gast)


Lesenswert?

Marvin K. schrieb:
> Der hat jetzt aber 7 16-Bit Timer, heißt ich kann es einfach von der
> Hardware machen lassen, und brauch keine CPU Leistung dafür.

Marvin K. schrieb:
> Es ist aber halt nur das Signal, ich kann die Pulszahl nicht steuern,
> dafür ist die CPU dann nicht leistungsfähig genug.

Und daran wird sich auch nichts ändern.

von Stefan F. (Gast)


Lesenswert?

MaWin schrieb:
> Der Interrupt ist immer in
> der Lage, das Hauptprogramm zu unterbrechen. Da die Instruktionen
> maximal 2 Takte Lang sind, liegt der Jitter bei 0.1us.

Sicher? Man abgesehen von cli() meine ich, das Interrupt-Routinen nicht 
immer sofort angesprungen werden, sobald das Signal kommt.

Das hat mal jemand untersucht: 
http://nerdralph.blogspot.com/2020/04/measuring-avr-interrupt-latency.html

von Stefan F. (Gast)


Lesenswert?

MaWin schrieb:
> Der Interrupt ist immer in
> der Lage, das Hauptprogramm zu unterbrechen. Da die Instruktionen
> maximal 2 Takte Lang sind, liegt der Jitter bei 0.1us.

Sicher? Man abgesehen von cli() meine ich, das Interrupt-Routinen nicht 
immer sofort angesprungen werden, sobald das Signal kommt.

Das hat mal jemand untersucht: 
http://nerdralph.blogspot.com/2020/04/measuring-avr-interrupt-latency.html

"Results
As expected INT0 latency is 4 clock cycles from the end of the currently 
executing instruction.  This means that if the interrupt occurs during 
the first cycle of a call instruction which takes 3 cycles, the 
interrupt response time will be 6 cycles.  For pin change interrupts, 
the latency is 6 cycles, indicating the synchronizer circuit adds 2 
cycles of latency.  In idle sleep mode, both INT0 and PCINT latency is 8 
cycles, indicating pin change interrupts operate asynchronously when the 
CPU clock is not running."

von Wilhelm M. (wimalopaan)


Lesenswert?

Marvin K. schrieb:
> Denn kannst du haben: https://pastebin.com/Agxs5WQ4

Mmh, was ich sehe ist der Zugriff auf eine Datenstruktur aus einer ISR 
die non-volatile ist, die auch von main() permanent modifiziert wird, 
und das ohne jegliche Synchronisation ...

von Marvin K. (m_marvin)


Lesenswert?

m.n. schrieb:
> Marvin K. schrieb:
>> Es ist aber halt nur das Signal, ich kann die Pulszahl nicht steuern,
>> dafür ist die CPU dann nicht leistungsfähig genug.
>
> Und daran wird sich auch nichts ändern.

Durch die 7 Timer kann ich ja aber jetzt die gesamte Pulserzeugung auf 
die Hardwere verschieben.
Ich muss nur noch mit einem ISR oder durch Abfrage der Interrupt Flags 
einen Register oder eine Variable hochzählen.
Wenn dann auch noch die CPU auf 32 MHz läuft, sollte das ja kein Problem 
sein.
Beim ATmega funktioniert das ja auch, nur hab ich da halt nur 2 8-Bit 
und einen 16-Bitt Timer.

Ich könnte sogar soweit gehen, das ich auch das Zählen von einem Timer 
übernehmen lasse, in dem ich sage das der Timer über einen externen Pin 
seinen Takt bekommt, und dann einfach den Compare Match des Puls-Timers 
mit dem Takt Pinn des Counter Timers verbinde.

Sollte die Auflösung des Counters nicht ausreichen, kann ich einfach ein 
überlauf ISR nehmen und damit dann eine Variable hochzählen, das würde 
die Aufruffrequenz deutlich verringern.

von Stefan F. (Gast)


Lesenswert?

Marvin K. schrieb:
> Ich verstehe das so, dass der Zugriff auf Register besonders schnell

Ja ist so. Auf die meisten Register kann die CPU schneller zugreifen, 
als auf RAM. Deswegen benutzt der C Compiler Register, um mehrfache 
Zugriffe aus Variablen zu optimieren. Beispiel:
1
int variable=0;
2
3
void tuwas()
4
{
5
  while (wasauchimmer) 
6
  {
7
    variable++;
8
    machwas();
9
  }
10
}

Hier wird die Variable am Anfang der Funktion in ein Register kopiert, 
dann das Register mehrfach inkrementiert, und erst bei Verlassen der 
Funktion zurück ins RAM übertragen.

Mit dem Prefix "volatile" kannst du das verhindern.

von Marvin K. (m_marvin)


Lesenswert?

In meinem fall, wäre es ja aber sinnvoller die variable nur in den 
Registern zu speichern oder ?
Ich werde das bei dem neuen ATxmega sowieso ganz anders machen, aber 
mich interessiert jetzt mal was besser gewesen währe.

Ich habe ja den ISR der prinzipiell dauerhaft mit hoher Frequenz auf die 
Variable zugreift, und die main-loop die es auch tut, nur etwas 
inkonsistenter (nicht immer mit der gleichen Frequenz).

Ist es da dann Sinnvoller einen von den GPIO-Registern zu nehmen ?

von m.n. (Gast)


Lesenswert?

S. Landolt schrieb:
> (übrigens, am Rande: "währe" ist nicht das Wahre)

Ja, wenn es nur das wäre ;-)

von Wilhelm M. (wimalopaan)


Lesenswert?

Marvin K. schrieb:
> Ich bin nun zufällig nochmal über die "General Purpose Register" der AVR
> gestolpert, und hab folgendes im Datenblatt gefunden:
>
> "Most of the instructions operating on the register file have direct
> access to all registers, and most of them are single cycle
> instructions."
>
> Meine Frage ist daher, macht es sinn als Impuls-Zähler einen solchen
> Register zu nutzen, oder ist eine Variable im RAM ausreichend ?
> Ich verstehe das so, dass der Zugriff auf Register besonders schnell
> ist, aber vielleicht verstehe ich den Satz auch falsch.

Diese GPIOR liegen im Bereich <= 0x1f. Damit sind sie für 
sbi/cbi/sbic/sbis-Befehle nutzbar, die besonders schnell sind. Als 
Register-Definition sind sie natürlich volatile-qualifiziert. Der 
avr-gcc kennt diesen Spezialfall.

Wenn Du nun also irgendwelche eigenen Status-Flags benötigst, die 
zwischen einer ISR und non-ISR geteilt werden, so kannst Du damit eine 
paar CPU-Zyklen sparen gegenüber einer volatile-bool-Variablen im RAM.
Bei Code ohne ISR ist es etwas fraglicher, ob Du damit wirklich besser 
dran bist, denn es ist immer noch volatile und kann deswegen nicht 
optimiert werden (merke: volatile verhindert re-order und erzwingt 
mem-access). Hier kann es sein, dass Du mit einer normalen Variablen 
(lokal oder TU-lokal) besser dran bist, weil der Compiler sie einfach 
dauerhaft in Register packt. Je größer die Code-Abdeckung ist, in der Du 
diese Variable benutzt, desto geringer ist allerdings die Chance dazu.

von Walter T. (nicolas)


Lesenswert?

Marvin K. schrieb:
> sinnvoller

Marvin K. schrieb:
> Sinnvoller

Jetzt habe ich den Faden verloren. Geht es jetzt um sinnvolles Vorgehen 
oder um möglichst hohen Takt? Sinnvoll wären 15...30 kHz Maximaltakt.

von S. Landolt (Gast)


Lesenswert?

> Diese GPIOR liegen im Bereich <= 0x1f. Damit sind sie für
> sbi/cbi/sbic/sbis-Befehle nutzbar

Das ist nicht der entscheidende Punkt - beim ATmega328P zum Beispiel 
liegen die drei im Bereich <= 3F, und erlauben damit einen Zugriff, 
sowohl lesend als auch schreibend, in einem Takt, wohingegen SRAM zwei 
Takte benötigt.

von PittyJ (Gast)


Lesenswert?

Walter T. schrieb:
> Jetzt habe ich den Faden verloren. Geht es jetzt um sinnvolles Vorgehen
> oder um möglichst hohen Takt? Sinnvoll wären 15...30 kHz Maximaltakt.

Es geht hier nicht um sinnvoll. Es geht nur darum, etwas unbedingt auf 
einem AtMega328 zu machen, weil man sonst was neues machen/lernen müßte.

von Wilhelm M. (wimalopaan)


Lesenswert?

S. Landolt schrieb:
>> Diese GPIOR liegen im Bereich <= 0x1f. Damit sind sie für
>> sbi/cbi/sbic/sbis-Befehle nutzbar
>
> Das ist nicht der entscheidende Punkt - beim ATmega328P zum Beispiel
> liegen die drei im Bereich <= 3F, und erlauben damit einen Zugriff,
> sowohl lesend als auch schreibend, in einem Takt, wohingegen SRAM zwei
> Takte benötigt.

S. Landolt schrieb:
> Das ist nicht der entscheidende Punkt

Doch.
Wie Du selbst ist genau das (Lage im IO-Adressbereich) der entscheidende 
Punkt.

von S. Landolt (Gast)


Lesenswert?

Aber nicht die Einzelbit-Funktionen.

von Wilhelm M. (wimalopaan)


Lesenswert?

S. Landolt schrieb:
> Aber nicht die Einzelbit-Funktionen.

Ok, in und out natürlich auch.
Wenn es aber um Flags geht wie ich oben sagte, dann die Einzelbitbefehle 
für IO-Bereich.

von uwe (Gast)


Lesenswert?

PSOC 6 hat 32 Timer
8x 32Bit
24x 16Bit

Oder PSOC 5 mit UDBs selber machen

von Yalu X. (yalu) (Moderator)


Lesenswert?

Marvin K. schrieb:
> Denn kannst du haben: https://pastebin.com/Agxs5WQ4

Nein, das wird so nichts.

So, wie du den Timer konfigurierst, generiert er alle 161 Taktzyklen
einen Interrupt, d.h. die Interruptfrequenz ist etwa 99,4 kHz.
Wahrscheinlich wolltest du ja 100 kHz, dazu musst du aber OCR1A mit 159
statt 160 laden.

Da in jedem Interrupt maximal 1 Pegelwechsel pro Kanal stattfindet, ist
die maximale Frequenz an den Pins die Hälfte der Interruptfrequenz, also
50 kHz.

Der Behandlung des Interrupts dauert vom Auslösen des Interrupts durch
den Timer bis zum Rücksprung aus der Interruptroutine 42 bis 45 Zyklen,
abhängig davon, wieviele Restzyklen die beim Auslösen des Interrupts
aktive Instruktion im Hauptprogramm noch andauert.

Wenn das Hauptprogramm nichts tun müsste, so dass zu jedem Zeitpunkt die
Interruptroutine aktiv sein könnte, könnte man die Interrupts mit einer
Frequenz von 16MHz/42 ≈ 381kHz auslösen, was etwa den von dir genannten
400kHz entspricht. Die maximale Frequenz an den Pins wäre dann etwa
190kHz.

Diese 190kHz sind aber theoretischer Natur, denn für jeden Interrupt
muss das Hauptprogramm ja mindestens einen Eintrag im Ringpuffer
aktualisieren. Jeder Eintrag in den Ringpuffer benötigt einen Durchlauf
der For-Schleife im Hauptprogramm und dauert (wenn ich mich nicht
verzählt habe) mindestens 1663¹ Zyklen. Damit ist die maximal sinnvolle
Interruptfrequenz 16MHz/(42+1663) ≈ 0,938kHz und die maximale Frequenz
an den Pins entsprechend 0,469kHz.

Alles, was über diese 0,469kHz hinausgeht, wird zu Unregelmäßigkeiten in
den Ausgangssignalen führen. Zum Teil werden diese zwar durch die
Trägheit des Motors weggebügelt, es kann aber nicht ausgeschlossen
werden, dass der zeitliche Abstand zweier Impulse sporadisch soviel
kleiner oder größer als der Sollabstand wird, dass entweder Schritte
verschluckt werden oder der Motor kurz stottert, was beides vermieden
werden sollte.

Dein neuer Ansatz mit den sechs Hardware-Timern ist deswegen der einzig
richtige, und das nicht nur, weil die CPU dadurch mehr Zeit hat, die
Impulse zu zählen.

PS: Die While-Schleife in deinem Programm ist übrigens überflüssig, weil
die For-Schleife bereits endlos läuft. Mit -Wextra gibt dies auch der
Compiler zu bedenken:
1
test.c:50:31: warning: comparison is always true due to limited range of data type [-Wtype-limits]
2
   50 |         for (uint8_t i = 0; i < 256; i++) {
3
      |                               ^

Er ist aber intelligent genug, die While-Schleife einfach
wegzuoptimieren.

──────────────
¹) Diese Zahl gilt für den Fall, dass die Inhalte von portFrequency,
   variabel, d.h. zur Compilezeit noch nicht bekannt sind. Da du sechs
   der acht Werte vor Beginn der Schleife mit konstanten Werten belegst,
   kann der Compiler den Code in der Schleife stark optimieren. Aber
   konstante Frequenzwerte entsprechen ja nicht der späteren Realität.

: Bearbeitet durch Moderator
von Wilhelm M. (wimalopaan)


Lesenswert?

Yalu X. schrieb:
> Diese 190kHz sind aber theoretischer Natur, denn für jeden Interrupt
> muss da Hauptprogramm ja mindestens einen Eintrag im Ringpuffer
> aktualisieren.

Da keine Synchronisation zwischen Leser und Schreiber stattfindet, ist 
das eh nichts mit dem vermeintlichen Ring-Puffer. Zudem fehlte volatile 
für die gemeinsamen Datenstrukturen (allerdings hat er "Glück" gehabt, 
weil die external-linkage haben ...).

von Yalu X. (yalu) (Moderator)


Lesenswert?

Wilhelm M. schrieb:
> Da keine Synchronisation zwischen Leser und Schreiber stattfindet, ist
> das eh nichts mit dem vermeintlichen Ring-Puffer.

Ja, das komm noch hinzu. Allerdings ist dies ein lösbares Problem,
während das Zeitproblem bei den angestrebten 200kHz (oder auch nur
100kHz) für den ATmega328P nicht lösbar ist.

von Yalu X. (yalu) (Moderator)


Lesenswert?

Wilhelm M. schrieb:
> Marvin K. schrieb:
>> Ich bin nun zufällig nochmal über die "General Purpose Register" der AVR
>> gestolpert, und hab folgendes im Datenblatt gefunden:
>>
>> "Most of the instructions operating on the register file have direct
>> access to all registers, and most of them are single cycle
>> instructions."
>>
>> ...
>
> Diese GPIOR liegen im Bereich <= 0x1f.

General Purpose Register ≠ GPIOR = General Purpose I/O Register.

von Wilhelm M. (wimalopaan)


Lesenswert?

Yalu X. schrieb:
> Wilhelm M. schrieb:
>> Marvin K. schrieb:
>>> Ich bin nun zufällig nochmal über die "General Purpose Register" der AVR
>>> gestolpert, und hab folgendes im Datenblatt gefunden:
>>>
>>> "Most of the instructions operating on the register file have direct
>>> access to all registers, and most of them are single cycle
>>> instructions."
>>>
>>> ...
>>
>> Diese GPIOR liegen im Bereich <= 0x1f.
>
> General Purpose Register ≠ GPIOR = General Purpose I/O Register.

Oh ja, da war der Wunsch Vater des Gedanken ... sorry for the noise!

von S. Landolt (Gast)


Lesenswert?

Aber verständliches Missverständnis: normalerweise heißt es ja 'General 
Purpose Working Registers'.

von Marvin K. (m_marvin)


Lesenswert?

PittyJ schrieb:
> Es geht hier nicht um sinnvoll. Es geht nur darum, etwas unbedingt auf
> einem AtMega328 zu machen, weil man sonst was neues machen/lernen müßte.

Ich habe mich jetzt doch entschieden einen anderen AVR zu nutzen, es 
ging darum es damit zu probieren, weil ich davon noch welche hier hatte.

Und zu dem Code über den gerade Diskutiert wurde:
Ich weis das der unsauber ist, es war mehr oder weniger nur ein Test ob 
ich solche Frequenzen erreichen kann, was auch funktioniert hat.
Die die Fehler im Code (z.B. die "i < 256" in der for Schleife) kommen 
wohl daher, das ich den innerhalb kürzester Zeit geschrieben hab, und 
nach dem mein Test erfolgreich war, nicht 
verbessert/optimiert/korrigiert habe.

Es ging rein darum die maximale Frequenz zu ermitteln, welche bei mir 
bei dem Code bei ~400kHz lag.

Mit dem neuen AVR werde ich da sowieso ganz anders rangehen.

von Marvin K. (m_marvin)


Lesenswert?

S. Landolt schrieb:
> Aber verständliches Missverständnis: normalerweise heißt es ja 'General
> Purpose Working Registers'.

Ich hab sowieso nicht ganz verstanden warum diese Register GPIOR 
bezeichnet werden.
Kann mir das mal irgend jemand erklären?
Ich verstehe unter GPIO "General Purpose Input/Output" und bei GPIOR 
denke ich als erstes an "General Purpose Input/Output Register", was 
aber in dem Zusammenhang keinen sinn macht.

Warum nicht einfach GPWR "General Purpose Working Register" ?

von c-hater (Gast)


Lesenswert?

Marvin K. schrieb:

> Ich hab sowieso nicht ganz verstanden warum diese Register GPIOR
> bezeichnet werden.
> Kann mir das mal irgend jemand erklären?

Ist doch simpel: Es handelt sich um Register im IO-Addressraum, die aber 
im Unterschied zu den meisten Registern in diesem Bereich keinen 
speziellen Zweck haben, also nicht die Schnittstelle zu irgendeiner 
Hardware darstellen.

Sie sind also "general purpose"-Register im IO-Space.

Die MCU besitzt ebenfalls "general purpose"-Register. Diese haben mit 
den obigen Registern rein garnichts zu schaffen, außer der gemeinsamen 
Eigenschaft, dass sie (i.A.) keinen speziellen Zweck haben, sondern 
universell verwendbar sind.

von Gerhard O. (gerhard_)


Lesenswert?

Ich kann nicht umhin wieder einmal meine nichtgefragte Meinung zum 
Besten geben:-)

Für "Real World" komplexe Projekte mit Realzeit Interaktion sind solche 
extremen FW gesteuerten HW Aktionen, wie hier im Thread gefragt, eine 
Vergewaltigung oder unglücklicher Einsatz eines uC der nur unter engsten 
Randbedingungen zufriedenstellend funktionieren kann. Das gilt auch für 
diejenigen Gurus, die so etwas zustande bringen können. Es fragt sich 
dann, ob solche Unternehmungen wirklich professionell sein können. In 
allen anderen Fällen wo zusätzliche Peripherien und Kommunikation 
notwendig sind, scheint mir der Einsatz und Entwicklungsaufwand einer 
besseren Sache wert zu sein.

Wenn also die vorhandene Peripherie nicht sauber die gewünschte 
Funktionalität erbringen kann ist das aller Wahrscheinlichkeit ein 
Zeichen, daß idealerweise dedizierte HW wie CPLDs, FPGAs oder sonstige 
ASICs oder SSL/MSL zum Einsatz kommen sollten und man den uC nur für die 
parametrische Steuerung und Auswertung der Ergebnisse verwenden sollte.

Der Vorteil einer korrekten konzipierten HW-Lösung ist saubere 
Performanz ohne Kompromisse. Im Falle von Taktgeneratoren, also 
jitterarme Qualität der Ausgangssignale.

Mich befremdet es immer wieder wenn man aus einem uC das letzte 
herauskitzeln will ohne die geringsten Reserven für die Anwendung als 
Ganzes mehr zur Verfügung zu haben. Es mag zwar sportlich sein, 
professionell ist das m.M.n. nicht. Die einzige Ausnahme wäre eine 
einfache Anwendung als Ersatz einer ASIC Lösung wo das Teil nur eine 
singuläre Funktion erfüllen muß. Die meisten Anwendungen mit 
Menschenbedienung fallen aber nicht mehr unter diese Einschränkung.

Naja, wenn ihr es könnt - "More Power to you"

von MaWin (Gast)


Lesenswert?

Yalu X. schrieb:
> während das Zeitproblem bei den angestrebten 200kHz (oder auch nur
> 100kHz) für den ATmega328P nicht lösbar ist

Für schlechte Programmierer...

von Walter T. (nicolas)


Lesenswert?

Hallo Gerhard,

auch wenn ich normalerweise Deine Meinung zu schätzen weiß, muß ich hier 
massiv widersprechen.

"Professionell" will ich aber nicht argumentieren. "Professionell" ist 
es ja oft, teure Komponenten ohne Sinn und Verstand zusammenzustöpseln 
und dem Kunden dann eine große Rechnung zu präsentieren. "Professionell" 
ist das ja auch oft sinnvoll - es lässt sich viel Geld damit verdienen. 
In diesem Umfeld stimme ich unumwunden zu.

Ich stimme Dir auch zu, daß es absolut unklug ist, aus einer Hardware 
das absolut letzte herauskitzeln zu wollen, ohne Reserven für die 
Anwendung zu haben. Aber bei so einfachen Geschichten sind auch kleine 
MCUs noch weit hinter den Enden Ihrer Reserven.

Professionell (ohne Anführungszeichen) wäre es, erst einmal ein sauberes 
Lastenheft für die Anforderungen zu schreiben. (Im Rahmen der Erstellung 
des Lastenheftes würde man merken, daß die I/O-Anforderungen gar nicht 
so heftig sind, wie sie der Thread-Titel suggerieren). Dann suche ich 
mir die Hardware, auf der sich das sinnvoll realisieren lässt + 
Sicherheitsaufschlag + Bonuspunkte für Hardware, mit der ich Erfahrung 
habe + noch mehr Bonuspunkte für Hardware, an die ich leicht gelangen 
kann.

Für die meisten Steuerungsaufgaben ist selbst ein 8-Bitter massiv 
unterfordert. Ich nehme mittlerweile gerne die STM32, aber da bedingt 
die eigentlich Steueraufgabe oft nur 1...10% Auslastung, die grafische 
Nutzerschnittstelle 50% und der Rest ist Reserve. Der meiste 
Flash-Speicher geht bei mir fast immer für die Schriftarten drauf. 
Sprich: Sollte ich bei Weiterentwicklungen mehr Leistung brauchen, kann 
ich das problemlos erreichen, indem die grafische Ausgabe nur 
geringfügig weniger pompös gestaltet wird.

In diesem Thread liegt das Problem woanders. Die Anforderungen sind 
unnötig unrealistisch. Der TO wird damit scheitern. Das ist bei 
Anfängern normal, das ist auch nicht schlimm. Wichtig wird er der 
Schritt danach - was daraus gelernt wird.

von Norbert (Gast)


Angehängte Dateien:

Lesenswert?

So hat jeder seine Präferenzen. Ich würd's mit EINEM 99ct Prozessor 
machen.
Gut, von den beiden Kernen würden jeweils 100% Rechenleistung übrig 
sein, da die komplett unabhängige Ansteuerung für ACHT Kanäle in der 
PIO realisiert würde.
Der Prozessor müsste gelegentlich ein paar Daten auf einer Schnittstelle 
entgegen nehmen und Register programmieren, also bleiben wohl doch nur 
99,999% der Rechenleistung völlig ungenutzt.
Oh ja, bei einem CPU Takt von 125MHz betrüge die Schrittweite der 
Frequenzeinstellung bei 200kHz ~2.5Hz, bei 1000Hz ~ 62.5µHz (kein 
Schreibfehler, mikro)
Man kann's aber auch gerne mit einem 8-Bitter machen.

von S. Landolt (Gast)


Lesenswert?

an Marvin K.:
> ... nicht ganz verstanden warum diese Register ...

Es ist zu unterscheiden:

'General Purpose Working Registers':
Das sind die 32 Arbeitsregister, auf die der Befehlssatz angewandt 
werden kann. Man kann zum Beispiel mit ihnen rechnen.

'General Purpose I/O Registers':
Da möchte ich einfach das Datenblatt zitieren:
8.5.1 General Purpose I/O Registers
The ATmega48A/PA/88A/PA/168A/PA/328/P contains three General Purpose I/O 
Registers. These registers can be used for storing any information, and 
they are particularly useful for storing global variables and Status 
Flags. General Purpose I/O Registers within the address range 0x00 - 
0x1F are directly bit-accessible using the SBI, CBI, SBIS, and SBIC 
instructions.
  Letzteres gilt nur für GPIOR0, GPIOR1 und 2 liegen über 0x1F. Für alle 
drei gilt z.B.: Nix mit rechnen.

von Yalu X. (yalu) (Moderator)


Lesenswert?

MaWin schrieb:
> Yalu X. schrieb:
>> während das Zeitproblem bei den angestrebten 200kHz (oder auch nur
>> 100kHz) für den ATmega328P nicht lösbar ist
>
> Für schlechte Programmierer...

Ja, prinzipiell geht es schon, wenn man einen gewissen Jitter toleriert
und neben der Schrittfrequenzgenerierung nur wenige weitere Funktionen
implementieren möchte. Da der Jitter aber mit dem Einsatz eines anderen
Mikrocontrollertyps praktisch komplett eliminiert werden kann, würde ich
gar nicht lang mit dem ATmega328P herumdoktern, sondern das Ganze gleich
richtig machen.

Mit einem etwas performanteren ARM könnte man nicht nur problemlos die
sechs Schrittmotoren mit sehr fein abgestuften Schrittfrequenzen
ansteuern, sondern eine komplette Robotersteuerung ähnlich der eines
Industrieroboters implementieren, mit der bspw. der TCP in kartesischen
Koordinaten auf einer geraden Linie verfahren werden kann, und das Ganze
natürlich unter Berücksichtigung vorgegebener Limits für Geschwindigkeit
und Beschleunigung der einzelnen Achsen und des TCP.

von MaWin (Gast)


Lesenswert?

Yalu X. schrieb:
> Ja, prinzipiell geht es schon

Ach.

> wenn man einen gewissen Jitter toleriert

Der Jotter wurde vorgetechnrt, er liegt bei 0.1us

> und neben der Schrittfrequenzgenerierung nur wenige weitere Funktionen
> implementieren möchte.

Er möchte genau das, lies seinen Ursprungsartikel.

> Da der Jitter aber mit dem Einsatz eines anderen
> Mikrocontrollertyps praktisch komplett eliminiert werden kann

So so, besonders beliebt dabei die ARM Murks Chips den weltbekannten 
Billiganbieters bei denen die altertümliche 'gabs umsonst' 
drangeflanschte I/O mit geringerem unsynchronen Takt als der Prozessor 
läuft, so dass alleine das Zusammenspiel von softwarekontrolle über 
Hardware schon Jitter produziert.

von m.n. (Gast)


Lesenswert?

Norbert schrieb:
> da die komplett unabhängige Ansteuerung für ACHT Kanäle in der
> PIO realisiert würde.

Noch mal: die PIO zählt keine Schritte. Alternativ sage, wie genau das 
zu machen wäre. Die PIO ist zwar schnell aber ziemlich dumm und in der 
Programmgröße stark begrenzt. Bei zwei PIOs und sechs Motoren muß das 
Programm für einen Motor in zehn Schritten erledigt sein.

Da die Position des Motors bekannt sein muß (Steuerung), müssen folglich 
auch die Schritte gezählt werden. Wie oben geschrieben hat der RP2040 
auch acht PWM-Timer, deren TOP-Register (16 bit) zur Steuerung der 
Schrittfrequen völlig ausreicht. Jeder Überlauf erzeugt einen Interrupt, 
womit man die Schritte zählen kann.
Da der Jitter von einem Schrittmotor ignoriert wird, erübrigen sich auch 
Einstellungen an den FRAC-Registern.

Walter T. schrieb:
> In diesem Thread liegt das Problem woanders. Die Anforderungen sind
> unnötig unrealistisch. Der TO wird damit scheitern. Das ist bei
> Anfängern normal, das ist auch nicht schlimm.

Zusätzlich ist der TO auch voll ignorant.

von Norbert (Gast)


Lesenswert?

m.n. schrieb:
> Noch mal: die PIO zählt keine Schritte.
Also ich kann hier zB. die Zeit zwischen zwei Flanken zählen und werte 
damit USB Signale aus.

> Alternativ sage, wie genau das zu machen wäre.
Gerne, JMP Y--
Etwas genauer: Mit PUSH->FIFO den bzw. die gewünschten Wert(e) in die SM 
schieben und laufen lassen. FIFO kann man auch kombinieren und hat dann 
eine Tiefe von acht Werten.

>Die PIO ist zwar schnell aber ziemlich dumm und in der
> Programmgröße stark begrenzt. Bei zwei PIOs und sechs Motoren muß das
> Programm für einen Motor in zehn Schritten erledigt sein.
In die richtige Richtung gedacht, aber trotzdem knapp daneben ;-)
Ein PIO Programm kann von allen vier State-Machines ausgeführt werden. 
Für verschiedene IO-Pins. Also ist die Limitierung 32 Befehle. Für beide 
PIOs.

von Norbert (Gast)


Lesenswert?

m.n. schrieb:
> Wie oben geschrieben hat der RP2040
> auch acht PWM-Timer, deren TOP-Register (16 bit) zur Steuerung der
> Schrittfrequen völlig ausreicht.
Und das ist natürlich auch richtig, wenn man mit der verminderten 
Auflösung zurecht kommt. (Das weiß aber nur der TO)
Mehrere Wege führen hier zum Ziel.
Und wir haben noch nicht einmal über vollautomatisches Abfahren einer 
Sequenz mittels Timer gesteuertem, programmierbarem DMA gesprochen.

von m.n. (Gast)


Lesenswert?

Norbert schrieb:
> m.n. schrieb:
>> Noch mal: die PIO zählt keine Schritte.
> Also ich kann hier zB. die Zeit zwischen zwei Flanken zählen und werte
> damit USB Signale aus.
>
>> Alternativ sage, wie genau das zu machen wäre.
> Gerne, JMP Y--

Ja, ja, im Himmel ist Jahrmarkt. PIO als Totschlagargument.
Das sind Teillösungen für ganz andere Anwendungen. Gebraucht wird ein 
PIO-Programm, was einerseits Schritte erzeugt und diese auch in beiden 
Richtungen zählt und dann noch mit dem Hauptprogramm kommuniziert.

Bei 65 MHz oder mit JMP Y++?
Wohl kaum ;-)

Norbert schrieb:
> Und wir haben noch nicht einmal über vollautomatisches Abfahren einer
> Sequenz mittels Timer gesteuertem, programmierbarem DMA gesprochen.

Das ist auch gut so.
In der Praxis braucht man Steuerungen, die in Echtzeit Rampen erzeugen 
und auf externe Signale reagieren. Das stupide Abfahren einer 
vorgeferigten Tabelle per DMA reicht da nicht aus.
Bei einem Roboter muß z.B. ein "Zugreifen" auf verschieden große Objekte 
per Kraftaufnehmer überwacht werden. Da gibt es keine konstante Strecke 
abzufahren.
Siehe: Beitrag "Re: Höchstmögliche Schaltfrequenz an einem normalen AVR Ausgangs-Pin"
So macht man das richtig.

von Norbert (Gast)


Lesenswert?

m.n. schrieb:
> Ja, ja, im Himmel ist Jahrmarkt. PIO als Totschlagargument.
> Das sind Teillösungen für ganz andere Anwendungen. Gebraucht wird ein
> PIO-Programm, was einerseits Schritte erzeugt und diese auch in beiden
> Richtungen zählt und dann noch mit dem Hauptprogramm kommuniziert.
>
> Bei 65 MHz oder mit JMP Y++?
> Wohl kaum ;-)

DU hast verlangt das ein PIO Programm zählen muss.
Ich weiß schon vorher das ein PIO-Programm welches 100kHz erzeugt in 
einer Sekunde 100.000 Pulse abliefert und lasse es dann ohne Prozessor 
Interaktion stoppen.

Sinnvollerweise nutzt man nicht ein komplexes PIO-Programm sondern 
mehrere sehr ›Schmale‹ die gleichzeitig im Speicher gehalten werden 
können.

Und wenn das mal nicht reichen sollte - also ganz sicher nicht in diesem 
Fall - so lässt man per DMA ein Neues hinein schieben. Dauert nur einige 
wenige hundert Nanosekunden.

von Wilhelm M. (wimalopaan)


Lesenswert?

S. Landolt schrieb:
> Letzteres gilt nur für GPIOR0, GPIOR1 und 2 liegen über 0x1F. Für alle
> drei gilt z.B.: Nix mit rechnen.

Selbstverständlich kannst du damit rechnen: der Compiler wandelt dabei 
eine Zuweisung in ein ASM out um (und ein Lesen in ein ASM in).

von Ben B. (Firma: Funkenflug Industries) (stromkraft)


Lesenswert?

Wenn ihr noch ein paar Beiträge über das Thema schreibt, kann man die 
Maximalfrequenz in kHz am Beitragszähler ablesen.

von Yalu X. (yalu) (Moderator)


Lesenswert?

MaWin schrieb:
> Der Jotter wurde vorgetechnrt, er liegt bei 0.1us

Das ist der Jitter unter der Voraussetzung, dass
- keine Instruktionen mit 3 oder 4 Zyklen verwendet werden (also bsp.
  kein CALL) und
- kein neuer Interrupt ausgelöst wird, während der Interrupt-Handler
  läuft

In deinem Code vom 04.05.2022 15:14 ist die minimale Zeitdifferenz
zwischen zwei Interrupts 60 Zyklen, also 3µs. Liegen die berechneten
Impulse zweier Kanäle dichter als diese 3µs beisammen, wird trotzdem das
Ende des Interrupt-Handlers abgewartet, bevor er erneut aufgerufen wird.
Der maximale Jitter liegt also nicht bei 0,1µs, wie von dir behauptet,
sondern bei 3µs, das ist immerhin das 30-fache.

MaWin schrieb:
> Das Hauptprogramm berechnet die Tabellen immer ausreichend im Voraus,
> die werden vom zeitvariablen Interupt  im Ringpuffer abgearbeitet.

Für das konfliktfreie Beschreiben dieser Tabellen muss der Interrupt
gesperrt werden, wodurch sich die Bearbeitung eines Interrupts
zusätzlich um 1µs verzögern kann. Damit liegt der Jitter schon bei 4µs.

Dein Verfahren ist aber nicht nur jitterig, es ist auch nicht besonders
schnell. Geht man optimistischerweise davon aus, dass die Generierung
der Tabellenwerte nicht länger dauert als ihre Abarbeitung im Interrupt
(also ebenfalls nur 60 Taktzyklen, was ziemlich utopisch sein dürfte),
dann ergibt sich eine maximale Interrupt-Frequenz von 20MHz/120=167kHz.
Da ein Impuls für den Schrittmotortreiber aus zwei Pegelwechseln
besteht, ist die erzielbare Schrittfrequenz 83,3kHz. Berücksichtigt man
noch den Aufwand für die I²C-Kommunikation, reduziert sich diese
Frequenz noch einmal deutlich.

Oben hattest du behauptet, dass nur schlechte Programmierer keine 100kHz
schaffen. Ich lasse das am besten mal unkommentiert :)

MaWin schrieb:
> Alles andere der Impulserzeugung sollte im Hauptprogramm stattfinden,
> das sicherstellen muss, dass der Puffer mit den
> Interrupt-Timet-Aktionen nie leerläuft.

Wie genau willst du das sicherstellen?

Das Hauptprogramm muss ja neben der Generierung der Tabellenwert auch
noch die I²C-Kommunikation übernehmen. Oder möchtest du diese in einem
zweiten Interrupt abwickeln? Dann kannst du gleich noch einmal ein paar
µs zum Jitter addieren.

Irgendwo möchte der TE auch noch die Impulse für alle sechs Kanäle
zählen. Geschieht dies im Interrupt, wird der Jitter noch einmal
deutlich größer. Macht man das im Hauptprogramm bei der Generierung der
Tabellenwerte, braucht diese entsprechend mehr Zeit, wodurch die Gefahr
steigt, dass der Puffer leerläuft. In beiden Fällen entstehen dadurch
natürlich auch Einbußen in der maximal erreichbaren Ausgabefrequenz.

Nein, nein, MaWin, das ist alles nicht so trivial, wie du dir das in
deiner jugendlichen Naivität vorstellst ;-)

MaWin schrieb:
>> Da der Jitter aber mit dem Einsatz eines anderen
>> Mikrocontrollertyps praktisch komplett eliminiert werden kann
>
> So so, besonders beliebt dabei die ARM Murks Chips den weltbekannten
> Billiganbieters

Ich hatte dabei keinen bestimmten Anbieter im Auge. Und falls du es noch
nicht wissen solltest: Es gibt wesentlich mehr als nur einen Anbieter
von ARM-Controllern. Das ist etwas anders als bei den dir wohl besser
bekannten AVRs, die alle vom selben Hersteller kommen.

von Gerhard O. (gerhard_)


Lesenswert?

Re: Tarpan...
Hallo Nicolas,

Dein Beitrag ist eigentlich doch in gewisser Harmonie mit einigen meiner 
Gedanken. Wie gesagt, so lange die Lösung alle restlichen Anforderungen 
erfüllt ist ja alles in Ordnung.

Fast alle meiner uC Projekte verwenden Serial, I2C, SPI und da führt oft 
direkte FW-abhängige Takterzeugung auf 8-Bittern zu Konflikten mit den 
restlichen Anforderungen. Ich finde, den uC in eine 
Instruktionszwangsjacke zu stecken ist ungünstig wenn mehrere 
nicht-synchrone sporadische Nebenaufgaben erfüllt werden müssen. Auch 
Interrupts sind da kein Panacea.

Für mich ist eine Computeranwendung ein Aufgaben-Koordinator im größeren 
Sinn und nicht ein blind singulär arbeitender Sklave. In Deinem Beispiel 
mit Graphikdisplay ohne Graphik Controller ist eine 
Exekutionszwangsjacke besonders störend. Ohne zusätzliche Ressourcen und 
uC "Horse power" ist so eine mehrfach Takterzeugung ein zweifelhaftes 
Unterfangen.

Ist einfach nicht mein Bier. Aber wie schon zugegeben, wer es kann, 
"More Power to You".

Gruß,
Gerhard

von m.n. (Gast)


Lesenswert?

Yalu X. schrieb:
> dann ergibt sich eine maximale Interrupt-Frequenz von 20MHz/120=167kHz.
> Da ein Impuls für den Schrittmotortreiber aus zwei Pegelwechseln
> besteht, ist die erzielbare Schrittfrequenz 83,3kHz.

Zumindest das (und auch Jitter) kann man vermeiden, wenn der Ausgangspin 
per Hardware gemäß OCRx-Wert gesetzt wurde. Da die meisten 
Schrittmotortreiber nur 1 - 2 µs Pulsbreite brauchen, reicht das 
Rücksetzen des Pins am Ende der zugehörigen ISR. So hat die 
ISR-Verarbeitungszeit noch etwas Gutes ;-)

von Yalu X. (yalu) (Moderator)


Lesenswert?

m.n. schrieb:
> Yalu X. schrieb:
>> dann ergibt sich eine maximale Interrupt-Frequenz von 20MHz/120=167kHz.
>> Da ein Impuls für den Schrittmotortreiber aus zwei Pegelwechseln
>> besteht, ist die erzielbare Schrittfrequenz 83,3kHz.
>
> Zumindest das (und auch Jitter) kann man vermeiden, wenn der Ausgangspin
> per Hardware gemäß OCRx-Wert gesetzt wurde. Da die meisten
> Schrittmotortreiber nur 1 - 2 µs Pulsbreite brauchen, reicht das
> Rücksetzen des Pins am Ende der zugehörigen ISR. So hat die
> ISR-Verarbeitungszeit noch etwas Gutes ;-)

Genau das war ja mein Ansatz von oben (nur ohne Interrupt, um Taktzyklen
zu sparen):

Yalu X. schrieb:
> Evtl. reichen auch weniger Timer, wenn man die Output-Compares geschickt
> nutzt.
> ...

Leider ist das auf dem ATmega328P so nicht realisierbar, weil dieser nur
fünf voneinander unabhängige Output-Compare-Pins hat. Wenn man deswegen
auf einen anderen Controller wechselt, kann man auch gleich einen mit
sechs 16-Bit-Timern nehmen, dann läuft die Impulserzeugung komplett in
Hardware, und die Software muss nur noch die Periodendauern vorgeben. So
bleibt genug Rechenzeit übrig für die I²C-Kommunikation, das Zählen von
Impulsen, die Generierung von Rampen u.v.m.

von c-hater (Gast)


Lesenswert?

m.n. schrieb:

> Gebraucht wird ein
> PIO-Programm, was einerseits Schritte erzeugt und diese auch in beiden
> Richtungen zählt und dann noch mit dem Hauptprogramm kommuniziert.

Sagt wer? Die Aufgabenteilung zwischen PIO, Core und ggf. DMA habe doch 
ich als Programmierer selber in der Hand.

von c-hater (Gast)


Lesenswert?

Yalu X. schrieb:

> Leider ist das auf dem ATmega328P so nicht realisierbar, weil dieser nur
> fünf voneinander unabhängige Output-Compare-Pins hat.

???

Also ich zähle sechs, wobei man natürlich "Unabhängigkeit" verschieden 
auslegen kann. Klar ist, das die beiden OC-Pins eines Timers immer eine 
gewisse Abhängigkeit voneinander haben. Aber sie sind unabhängig genug 
voneinander, um für die gegebene Aufgabe nutzbar zu sein.

von Jobst M. (jobstens-de)


Lesenswert?

c-hater schrieb:
> Klar ist, das die beiden OC-Pins eines Timers immer eine
> gewisse Abhängigkeit voneinander haben. Aber sie sind unabhängig genug
> voneinander, um für die gegebene Aufgabe nutzbar zu sein.

Abgesehen davon, dass beide OCs eines Timers die selbe Frequenz 
ausgeben.

Gruß
Jobst

von c-hater (Gast)


Lesenswert?

Jobst M. schrieb:

> Abgesehen davon, dass beide OCs eines Timers die selbe Frequenz
> ausgeben.

Nicht, wenn man sie geeignet ansteuert.

Die Timer bieten recht viele Betriebsarten für die Timer selber und auch 
für das Verhalten der OC-Pins (welches auch noch für jede Betriebsart 
des Timers unterschiedlich sein kann).

Man muss halt einfach mal NACHDENKEN, wie man die Dinger mit den 
gegebenen Möglichkeiten für die gegebene Aufgabe sinnvoll einspannen 
könnte...

von Yalu X. (yalu) (Moderator)


Lesenswert?

c-hater schrieb:
> Yalu X. schrieb:
>> Leider ist das auf dem ATmega328P so nicht realisierbar, weil dieser nur
>> fünf voneinander unabhängige Output-Compare-Pins hat.
>
> ???
>
> Also ich zähle sechs, wobei man natürlich "Unabhängigkeit" verschieden
> auslegen kann.

Yalu X. schrieb:
> aber dummerweise teilen sich zwei davon (OC3B und OC4B) einen Ausgang,
> so dass leider nur fünf Kanäle möglich sind.

von c-hater (Gast)


Lesenswert?

Yalu X. schrieb:

> c-hater schrieb:
>> Yalu X. schrieb:
>>> Leider ist das auf dem ATmega328P so nicht realisierbar, weil dieser nur
>>> fünf voneinander unabhängige Output-Compare-Pins hat.
>>
>> ???
>>
>> Also ich zähle sechs, wobei man natürlich "Unabhängigkeit" verschieden
>> auslegen kann.
>
> Yalu X. schrieb:
>> aber dummerweise teilen sich zwei davon (OC3B und OC4B) einen Ausgang,
>> so dass leider nur fünf Kanäle möglich sind.

???

Wir reden von einem Mega328P. Der hat Timer0, 1 und 2. Nix 3 und nix 4.

Aber: Jeder der drei tatsächlich vorhandenen Timer hat wiederum ZWEI 
OC-Ausgange, nämlich OCxA und OCxB, zusammen also sechs.

Bist du besoffen?

von MaWin (Gast)


Lesenswert?

Yalu X. schrieb:
> Für das konfliktfreie Beschreiben dieser Tabellen muss der Interrupt
> gesperrt werden,

Nein. Du hast den code nicht mal ansatzweise verständen über den du hier 
ablästetst.

Wenn der Puffer immer ausreichend gefüllt ist (das kann die main-loop 
durch Abrufen von n sicherstellen, ist nichts zu tun, werden einfach 
Kommandos geschrieben die den Ausgangszustand am Port nicht ändern, 
bloss um den ewig neu triggernden Timer nicht stoppen zu müssen, dann 
muss da gar kein Interrupt gesperrt werden.
Der Zugriff auf n ist atomar da nur 1 byte, andere Werte müssen nicht 
betrachtet werden, keine semaphores etc.

Yalu X. schrieb:
> Nein, nein, MaWin, das ist alles nicht so trivial, wie du dir das in
> deiner jugendlichen Naivität vorstellst ;-)

Du bist das Kind das offensichtlich noch nie effizient programmiert hat, 
wohl nie musste.

Yalu X. schrieb:
> In deinem Code vom 04.05.2022 15:14 ist die minimale Zeitdifferenz
> zwischen zwei Interrupts 60 Zyklen, also 3µ

Du bist nicht in der Lage, Code in Assembler mit reservierten Registern 
zu schreiben und Puffer auf 256-byze boundaries anzulegen ?

Yalu X. schrieb:
> Liegen die berechneten
> Impulse zweier Kanäle dichter als diese 3µs beisammen, wird trotzdem das
> Ende des Interrupt-Handlers abgewartet, bevor er erneut aufgerufen wird

Das ist richtig, wobei ein geschickt in Assembler formulierter 
Interrupthandler schneller sein kann.


Yalu X. schrieb:
> kein neuer Interrupt ausgelöst wird, während der Interrupt-Handler
> läuft

Während der Abarbeitung von Interrupt-Funktionen sind Interrupts 
gesperrt. Die Timer-Zeit-Tabelle ist natürlich so anzulegen, dass 
aufeinanderfolgende Ticks zeitlich reinpassen.

m.n. schrieb:
> Zumindest das (und auch Jitter) kann man vermeiden

Nicht, wenn wie gezeigt die Pegelwechsel in software erfolgen, damit man 
mit nur 1 Timer auskommt.
Das ist sogar schneller als 6 Compare-Register in fliegendem Wechsel 
z.B. für Rampen neu zu beschreiben, wobei man sich auch noch mit den 
aktuellen Timerwerten synchronisieren muss.

Yalu X. schrieb:
> Ich hatte dabei keinen bestimmten Anbieter im Auge

Ich hab auch nur vom besonders beliebten Anbieter geschreiben. Dein 
Leseverständnis geht gehen 0.

von Dieter (Gast)


Lesenswert?

Vielleicht könntest Du es mit einem anderen Modul probieren.
RPi Pico Frequenzzähler bis 65 MHz
https://www.elektronik-labor.de/Raspberry/Pico18.html
"Auch diesmal wird der PWM-Ausgang am Port GP0 als Signalquelle 
verwendet. Hier wird die höchste mögliche PWM-Frequenz von 62,5 MHz 
erzeugt."

von Yalu X. (yalu) (Moderator)


Angehängte Dateien:

Lesenswert?

c-hater schrieb:
> Bist du besoffen?

Oh Mann, stellst du dich heute wieder an. Ist es denn so schwer, mal
einen Blick ins Datenblatt zu werfen? Du musst dazu nicht einmal viel
Text lesen, ein oder zwei Bilder reichen schon.

: Bearbeitet durch Moderator
von Jobst M. (jobstens-de)


Lesenswert?

c-hater schrieb:
> Jobst M. schrieb:
>
>> Abgesehen davon, dass beide OCs eines Timers die selbe Frequenz
>> ausgeben.
>
> Nicht, wenn man sie geeignet ansteuert.
>
> Die Timer bieten recht viele Betriebsarten für die Timer selber und auch
> für das Verhalten der OC-Pins (welches auch noch für jede Betriebsart
> des Timers unterschiedlich sein kann).
>
> Man muss halt einfach mal NACHDENKEN, wie man die Dinger mit den
> gegebenen Möglichkeiten für die gegebene Aufgabe sinnvoll einspannen
> könnte...

Na, ich komme gerade nicht drauf. Erzähl mal!

Wie muss man sie ansteuern, damit OCxA und OCxB eines Timers unabhängig 
voneinander arbeiten?
Also z.B. OCxA Frequenz steigend, OCxB Frequenz sinkend.

Bin gespannt.

Gruß
Jobst

von Jobst M. (jobstens-de)


Lesenswert?

Yalu X. schrieb:
> Ist es denn so schwer, mal
> einen Blick ins Datenblatt zu werfen?

Hat der TO denn den ATmega328P*B* ?

Der ohne B hat die nicht.

Gruß
Jobst

von c-hater (Gast)


Lesenswert?

Yalu X. schrieb:

> Oh Mann, stellst du dich heute wieder an. Ist es denn so schwer, mal
> einen Blick ins Datenblatt zu werfen?

Das muss man dich fragen. Das ist das Datenblatt eines 328PB, es ging 
aber um einen 328P...

Nein, das ist ganz offensichtlich nicht dasselbe. Scheint dir im Suff 
aber entgangen zu sein, anders ist diese krasse geistige Fehlleistung 
wohl nicht erklärbar...

Und selbst wenn es tatsächlich um einen 328PB gegangen wäre: Der hat 
halt zwar mehr Timer als der 328P, was die Sache unter Umständen 
einfacher macht (ich habe das nicht geprüft), aber er hat auf jeden Fall 
die drei, die auch der 328P hat, mitsamt ihren sechs OC-Ausgängen. Und 
allein das GENÜGT ja bereits, um die Anforderungen erfüllen zu können!

Also, sei ein Mann und gib' auch mal einen Fehler zu!

Oder sei das, was du als "Moderator" bist und lösche dieses Posting 
einfach. Ist doch so leicht. Man muss nichtmal eine Begründung 
angeben...

von Sebastian (Gast)


Lesenswert?

Sind OC1A und OC1B wirklich unabhängig voneinander in ihrer Frequenz 
steuerbar? Ich dachte bisher wenn man OCR1A benutzt um den TOP-Wert des 
Timers zu setzen dass man dann OC1A nicht mehr benutzen kann. Liege ich 
da falsch?

LG, Sebastian

von c-hater (Gast)


Lesenswert?

Jobst M. schrieb:

> Na, ich komme gerade nicht drauf.

Schwache Leistung. Aber leider recht typisch für reine Verwender von 
C-Wichsvorlagen.

> Wie muss man sie ansteuern, damit OCxA und OCxB eines Timers unabhängig
> voneinander arbeiten?
> Also z.B. OCxA Frequenz steigend, OCxB Frequenz sinkend.
>
> Bin gespannt.

Ist doch easy: Bringe alle drei Timer in den "Normal-Mode". Konfiguriere 
alle sechs OC-Kanäle für "toggle on compare match".

Der Rest ist Software. Software, die längst nicht so kritisch ist, als 
wenn man das Timing rein in Software implementieren wollte. Aber 
zugegebermaßen immer noch recht kritisch. Allerdings: in Asm machbar. 
Ohne großartige Tricks. Ich würde sogar sagen, das ginge auch in C. 
Allerdings: im Gegensatz zu Asm ohne Funktionsgarantie...

von Yalu X. (yalu) (Moderator)


Lesenswert?

MaWin schrieb:
> Yalu X. schrieb:
>> In deinem Code vom 04.05.2022 15:14 ist die minimale Zeitdifferenz
>> zwischen zwei Interrupts 60 Zyklen, also 3µ
>
> Du bist nicht in der Lage, Code in Assembler mit reservierten Registern
> zu schreiben und Puffer auf 256-byze boundaries anzulegen ?

Dein Code, auf den ich verwiesen habe und auf den sich meine Kommentare
bezogen, sieht für mich eher nach C als nach Assembler aus.

> Yalu X. schrieb:
>> Liegen die berechneten
>> Impulse zweier Kanäle dichter als diese 3µs beisammen, wird trotzdem das
>> Ende des Interrupt-Handlers abgewartet, bevor er erneut aufgerufen wird
>
> Das ist richtig, wobei ein geschickt in Assembler formulierter
> Interrupthandler schneller sein kann.

In Assembler wird der Code zwar etwas schneller und damit der Jitter
etwas weniger, aber das grundsätzliche Problem bleibt bestehen.

> Yalu X. schrieb:
>> kein neuer Interrupt ausgelöst wird, während der Interrupt-Handler
>> läuft
>
> Während der Abarbeitung von Interrupt-Funktionen sind Interrupts
> gesperrt. Die Timer-Zeit-Tabelle ist natürlich so anzulegen, dass
> aufeinanderfolgende Ticks zeitlich reinpassen.

Wie willst du die Timer-Zeit-Tabelle anlegen, wenn bspw. für einen Kanal
eine Periode von 400 Taktzyklen (50kHz) und für einen anderen eine
Periode von 417 Taktzyklen (ca. 48kHz) gewünscht wird? Da 400 und 417
teilerfremd sind, kommt es in regelmäßigen Zeitabständen zu einer
Situation, wo die Zeitpunkte der Impulse der beiden Kanäle nur 1
Taktzyklus auseinanderliegen. Der erste der beiden Impulse wird dann
noch zeitlich korrekt ausgegeben, der zweite wird um die Dauer des
Interrupt-Handlers verzögert -> Jitter.

Bevor wir hier noch lange weiterdiskutieren: Programmiere deinen Code zu
Ende (meinetwegen auch in Assembler), spiele ihn auf einen ATmega328 und
schau dir am Oszi die Ausgangssignale für verschiedene Frequenzen an.
Egal wie du es drehst und wendest, wirst du immer auf mindestens eines
der folgenden Probleme stoßen:

- inakzeptabel großer Jitter

- nur geringe Maximalfrequenz (deutlich unterhalb von dem, was dem TE
  vorschwebt)

- sehr bescheidene Frequenzauflösung (keine vernünftigen Rampen möglich)

Immer wenn du versuchst, eines der Probleme zu beheben, wird ein
anderes verstärkt werden.

Beitrag #7058108 wurde von einem Moderator gelöscht.
Beitrag #7058110 wurde von einem Moderator gelöscht.
Beitrag #7058111 wurde von einem Moderator gelöscht.
Beitrag #7058113 wurde von einem Moderator gelöscht.
Beitrag #7058114 wurde von einem Moderator gelöscht.
Beitrag #7058119 wurde von einem Moderator gelöscht.
Beitrag #7058123 wurde von einem Moderator gelöscht.
von Jobst M. (jobstens-de)


Lesenswert?

c-hater schrieb:
> Schwache Leistung. Aber leider recht typisch für reine Verwender von
> C-Wichsvorlagen.

Auch hier liegst Du falsch. Ich programmiere den AVR (und andere) rein 
in Assembler. Von mir stammt das Video da oben ...

c-hater schrieb:
> Ist doch easy: Bringe alle drei Timer in den "Normal-Mode". Konfiguriere
> alle sechs OC-Kanäle für "toggle on compare match".

Bekomme ich bis zu 3 Frequenzen mit je 2 Ausgängen mit unterschiedlicher 
Phase.

c-hater schrieb:
> Der Rest ist Software.

Bla bla. Also kannst Du es auch nicht. War mir klar.


Sebastian schrieb:
> Sind OC1A und OC1B wirklich unabhängig voneinander in ihrer Frequenz
> steuerbar? Ich dachte bisher wenn man OCR1A benutzt um den TOP-Wert des
> Timers zu setzen dass man dann OC1A nicht mehr benutzen kann. Liege ich
> da falsch?

Das ist richtig.


Gruß
Jobst

von Yalu X. (yalu) (Moderator)


Lesenswert?

c-hater schrieb:
> Das muss man dich fragen. Das ist das Datenblatt eines 328PB, es ging
> aber um einen 328P...

Ok, sorry, das war ein Missverständnis. Da mein obiger Ansatz – wenn
überhaupt – nur mit drei 16-Bit-Timern praktikabel ist (mit 8-Bit-Timern
wäre die Auflösung und/oder die Variationsbreite der einstellbaren
Frequenzen für einen sinnvollen Einsatz zu gering), bin ich
stillschweigend von der Variante mit den zwei zusätzlichen Timern, also
dem 328PB ausgegangen. Für den TE wäre dieser Unterschied vermutlich
kein Problem, da er ja einfach nur einen Controller verwenden möchte,
den er schon gut kennt.

von c-hater (Gast)


Lesenswert?

Jobst M. schrieb:

> c-hater schrieb:
>> Der Rest ist Software.
>
> Bla bla. Also kannst Du es auch nicht. War mir klar.

Ich kann es. Du allerdings wohl offensichtlich nicht. Mein Gott, ist 
doch nicht so schwierig. Der Zähler (der vom Timer) läuft durch. Jedes 
Mal, wenn sich eine Übereinstimmng des Zähler mit dem aktuellen Wert des 
OCR-Registers ergibt, wechselt der OC-Ausgang den Pegel.

Hast du das soweit erstmal begriffen? Wenn nicht, wäre jede weitere 
Ausführung "Perlen vor die Säue".

von Jobst M. (jobstens-de)


Lesenswert?

c-hater schrieb:
> Hast du das soweit erstmal begriffen? Wenn nicht, wäre jede weitere
> Ausführung "Perlen vor die Säue".

Natürlich habe ich das begriffen. Und nun bitte der Trick, zwei 
verschiedene Frequenzen dort heraus zu bekommen.

Gruß
Jobst

von c-hater (Gast)


Lesenswert?

Jobst M. schrieb:

> Natürlich habe ich das begriffen. Und nun bitte der Trick, zwei
> verschiedene Frequenzen dort heraus zu bekommen.

Na das ist ja mal einfach zum Grundlagenstudium: Schreibst du z.B. im 
Interrupt für OC0A:

OCR0A = OCR0A + 200;

und im Interrupt für OC0B:

OCR0B = OCR0B + 220;

Schon fertig. Hast du zwei verschiedene Frequenzen mit einem Timer. Du 
bist offensichtlich ein Vollidiot, weil du nicht selber darauf gekommen 
bist, so trivial die Sache ganz offensichtlich doch ist!

von MaWin (Gast)


Lesenswert?

Yalu X. schrieb:
> In Assembler wird der Code zwar etwas schneller und damit der Jitter
> etwas weniger, aber das grundsätzliche Problem bleibt bestehen.

Nein, du möchtest ein Problem herbeireden.

Es spielt bei 200kHz Mikrosteppingtakt keine Rolle, ob eine Taktflanke 3 
(oder eher 1) us zeitversetzt kommt.

Der Code ist gut geeignet, um die Schrittzeitpunkte aus einem DDA 
Algorithmus zeitgenau genug an Ausgabepins eines Mikroprozessors zu 
übertragen. Nämlich 0.1us genau zu dem Zeitpunkt wie in dem Array 
programmiert. Ja, welches um mindestens 1us voneinander Abstand habende 
Events enthalten darf.

Abgesehen davon, dass es sowieso Schwachsinn ist, bei Schrittmotoren 
deren stromregelnde Chopper üblicherweise mit 100kHz laufen irgendwas 
mit 200kHz senden zu wollen, wie ich schon im ersten Beitrag anmerkte.

Vor allem ist es kaum eine Lösung, bloss weil man schlecht in 
Programmierung ist, auf noch mehr Hardware auszuweichen, wie multiple 
Timer, Prozessoren mit nicht mehr zeitsynchron arbeitender I/O, 
Prozessoren mit cache die jedes timing ad absurdum führen, Aufteilung 
des Problems auf mehrere Prozessoren die auch noch miteinander 
kommunizieren müssen.

Lernt einfach anständig zu programmieren, ein ATmega328 reicht für das 
Problem aus. Und wird sogar das kürzeste Programm ergeben. Nein, ich 
schreib's hier nicht fertig. Ich lass dir den Vortritt.

von Ron T. (rontem)


Lesenswert?

c-hater schrieb:
> Du bist offensichtlich ein Vollidiot

MUSS DAS SEIN ???

von Jobst M. (jobstens-de)


Lesenswert?

c-hater schrieb:
> so trivial die Sache ganz offensichtlich doch ist!

Nein, ist sie nicht.

Glaubst Du echt, dass mir das setzen eines Timers im Timer-IRQ neu ist? 
Ja, offensichtlich - egal ...

Bei 20MHz Systemtakt und 100kHz Ausgabe auf 6 Kanälen benötigst Du 1,2 
Mio. IRQs/s bleiben für jeden 16 Takte (Inkl. Ein- und Rücksprung). Du 
hast eine gute Chance regelmäßig einen zu verpassen.

Außerdem musst Du, wenn Frequenzen im Verhältnis > 1:255 auf einem Timer 
(außer Timer 1) erzeugt werden, diesen Fall bearbeiten. Tip: der Timer 
IRQ für die geringere Frequenz kann es nicht erledigen, er wird nicht 
aufgerufen, weil nichts auf OCnx passieren darf.
Allein das erzeugen der Verhältnisse wird ein Spaß. Wird der Prescaler 
verändert, bekommst Du noch mehr Probleme.

Ich warte noch auf den Trick ...

Gruß
Jobst

von Jobst M. (jobstens-de)


Lesenswert?

Ron T. schrieb:
> MUSS DAS SEIN ???

Das ist c-hater, der kann nicht anders.

Gruß
Jobst

von Lust L. (lust)


Lesenswert?

MaWin schrieb:
> Lernt einfach anständig zu programmieren, ein ATmega328 reicht für das
> Problem aus

Nicht nur für dieses sondern sehr viele.
ARM ist für die meisten Steuerungsanwendungen absoluter Overkill und 
macht unter dem Strich alles nur komplizierter. Mit Assembler gewinnt 
man noch dazu jene Gestaltungsfreiheit, die stocksteifen Hochsprachen an 
vielen Stellen fehlt. Der Teufel liegt im Detail- dieses Threadthema ist 
wieder mal ein typisches...

von Wilhelm M. (wimalopaan)


Lesenswert?

Ich rufe die MegaHF-Challenge aus und nominiere Jobst M. und c-hater. Da 
der TO das sicher in C/C++ wollte, ist das auch eine Bedingung.

von m.n. (Gast)


Lesenswert?

Jobst M. schrieb:
> Natürlich habe ich das begriffen. Und nun bitte der Trick, zwei
> verschiedene Frequenzen dort heraus zu bekommen.

Entsprechende Programme hatte ich oben verlinkt.

Jobst M. schrieb:
> Außerdem musst Du, wenn Frequenzen im Verhältnis > 1:255 auf einem Timer
> (außer Timer 1) erzeugt werden, diesen Fall bearbeiten.

Auch bei Timer1 muß man mit Software nachhelfen, sofern man 
Schrittfrequenzen < 306 Hz (AVR @ 20 MHz) erzeugen möchte/muß. Bei 
meinen Taktgebern verwende ich uint32_t Werte für die Periodendauer. Bei 
20 MHz CPU-Takt sind dann Schritte ab 0,005 Hz einstellbar; das obere 
Bereichsende liegt im zig KHz-Bereich und ließe sich durch 
Assembler-Programmierung noch beschleunigen. Geschickter wäre es 
allerdings, ab einer gewissen Drehzahl von Micro- auf Vollschritt zu 
wechseln.

Die eingangs genannte untere Schrittfrequenz von 1 kHz beruht ja auf dem 
Irrtum, daß damit die Start-Stop-Frequenz typischer Motore eingehalten 
werden könne. Langsame Fahrten sind damit unmöglich.

von Carsten-Peter C. (carsten-p)


Lesenswert?

Hallo Jobst, Dein Video sieht schon gut aus. Hast Du Dein Programm 
selbst geschrieben? So schnell kann sich mein Motor nicht drehen, dafür 
muss er einiges an Masse bewegen. Es ist ein Unterschied, ob man ein 
paar Register setzt, um den Motor drehen zu lassen oder ihn auf eine 
Position laufen lässt. Lass Dich nicht ärgern!
Gruß Carsten

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.