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 ?
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
Marvin K. schrieb: > Bei einer CPU Frequenz von 20MHz sollte das doch gehen oder ? Welchen Jitter kannst du tolerieren?
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.
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.
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.
Keine Daten, nur ein 1-200kHz Signal, egal ob Rechteck, Sägezahn usw.
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.
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).
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?
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.
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.
Ε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.
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.
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.
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).
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
Du könntest dein Vorhaben auch zum Anlass nehmen, von AVR auf ARM umzusteigen. Die haben meist mehr Timer und mehr Megahertz.
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 | }
|
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)
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.
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.
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
Man könnte auch die Variablen direkt hochzählen, ich probiere das jetzt einfach mal aus.
Εrnst B. schrieb: > Timer mit 20MHz bis 100 Laufen lassen -> 200kHz wohl eher 100kHz, oder bis 50 laufen lassen.
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.
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
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 ?
Hab den Fehler gefunden, kleiner Tipfehler bei einem der Register, hatte den Timer im falschen Modus.
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.
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.
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.
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.
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.
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.
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
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
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.
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.
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.
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.
Ε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.
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
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.
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
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).
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.
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.
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
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
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?
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
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?
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
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.
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.
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 ?
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).
Korrektur, ~32 kHz. 62kHz ist ja nur die Frequenz mit der getoggelt wird.
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.
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.
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.
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.
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? ;-)
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
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
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 ;-)
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 ...
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.
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.
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 ;-)
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.
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
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
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
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.
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.
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
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.
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.
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 :-(
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
Jobst M. schrieb: > Ich habe hier ... Hast Du da ein sehr interessantes Objektiv oder einen sehr interessanten Motor?
Walter T. schrieb: > Hast Du da ein sehr interessantes Objektiv oder einen sehr interessanten > Motor? Kamera: Panasonic DMC-SZ8 Motor: ACT 11HS5406 Gruß Jobst
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.
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
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.
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.
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?
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
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!
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.
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.
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
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.
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.
Gerald M. schrieb: > Ram lesen und schreiben sind ebenfalls Single Cycle Instructions. Nein. Gruß Jobst
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...
@ c-hater: Hier geht es nicht um Assembler. Lass die sinnlosen Anspielungen.
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.
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.
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
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
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.
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.
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.
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.
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)
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 ;-)
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).
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).
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 ...
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.
Marvin K. schrieb: > Meine frage ist ob der ATxmega es erlaubt über die SPI Schnittstelle den > Flash zu beschreiben. Nein
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.
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.
> ü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.
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.
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).
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.
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.
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.
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.
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
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."
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 ...
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.
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.
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 ?
S. Landolt schrieb: > (übrigens, am Rande: "währe" ist nicht das Wahre) Ja, wenn es nur das wäre ;-)
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.
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.
> 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.
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.
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.
Aber nicht die Einzelbit-Funktionen.
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.
PSOC 6 hat 32 Timer 8x 32Bit 24x 16Bit Oder PSOC 5 mit UDBs selber machen
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
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 ...).
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.
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.
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!
Aber verständliches Missverständnis: normalerweise heißt es ja 'General Purpose Working Registers'.
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.
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" ?
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.
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"
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...
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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).
Wenn ihr noch ein paar Beiträge über das Thema schreibt, kann man die Maximalfrequenz in kHz am Beitragszähler ablesen.
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.
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
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 ;-)
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.
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.
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.
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
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...
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.
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?
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.
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."
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
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
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
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...
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
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...
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.
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
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.
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".
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
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!
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.
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
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...
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.
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.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.