Archiv verlassen und diese Seite im Standarddesign anzeigen : 12x PWM + TWI-Slave ... möglich?
Hallo!
In Bascom will es nicht richtig, deswegen hab ich mal vor, es in ASM zu probieren. Allerdings will ich wissen, ob ich dabei technisch überhaupt Erfolg haben kann. Ich muss 12 Software-PWMs (8 Bit) haben. Ausserdem soll der Mega8 noch als TWI-Slave arbeiten, um die PWM-Werte entgegenzunehmen. Ca. 30x12 Byte pro Sekunde. Was ich mich frage ist, ob die PWMs sichtbar unterbrochen werden, wenn Daten kommen (Es hängen 4 RGB-LEDs an dem Controller). Das wäre nämlich absolut gar nicht gut in der Anwendung.
als Nicht-Programmierer:
technisch ähnelt die Funktion doch einer 10 - 20- Kanal Servosteuerung.
als Anregung hier:
https://www.roboternetz.de/phpBB2/viewtopic.php?t=9063
gruss stupsi
hmmm gutes Beispiel. Der SD20 war mir auch schonmal in den Sinn gekommen. Das ist ja dann quasi Multithreading. Wie macht der AVR das?
12 Software-PWMs (8 Bit) haben. Ausserdem soll der Mega8 noch als TWI-Slave arbeiten, um die PWM-Werte entgegenzunehmen
Im wesentlichen ist das von 3 Faktoren abhängig.
1. Von der Taktfrequenz des Controllers, die ich hier schon mal auf 16MHz anheben würde.
2. Von der PWM Frequenz.
3. Von möglichst wenig Code in den Interruptroutinen.
Bei 16MHz und einem Taktteiler von 8 komm ich auf eine PWM Frequenz von 30 Hz. Der Controller kann dabei 2048 Takte (~Kommandos) zwischen 2 Interrupts ausführen.
Bei 16MHz und einem Taktteiler von 1 komm ich auf eine PWM Frequenz von 244 Hz. Der Controller kann dabei 256 Takte (~Kommandos) zwischen 2 Interrupts ausführen. Das dürfte vermutlich zu wenig für eine stabile Funktion sein.
Die Teilerfaktoren /2 und /4 lassen sich im Prescaler nicht einstellen.
Mein Vorschlag wäre die 16MHz Taktfrequenz extern zu teilen (/2, /4) und die geteilte Frequenz auf den T0 Eingang zu geben. Dieser Takteingang taktet dann den Timer0 mit Prescaler 1, der dann als PWM Quelle dient.
Ich würd diesen Timer mit Overflow Interrupt laufen lassen.
In diesem Overflow Interrupt wird ein weiterer Zähler hochgezählt der mit den gewünschten PWM Registern verglichen wird und je nach Zählerstand die 12 Ausgänge aus-, bzw einschaltet.
Bei einem Teilerfaktor von 4 krieg ich dann 1024 Prozessortakte bevor ein Overflow Interrupt ausgeführt wird, als PWM Frequenz krieg ich dabei 60Hz raus und das sollte passen.
Eventuell kann man auch den Timer 1 als Taktteiler (OC1A mit CTC ?)vergewaltigen, dann könntest Du ohne externe Bauteile auskommen.
Wieviel Prozessorleistung dein TWI noch schluckt kann ich nicht sagen.
Kannst ja deinen fertigen Code mal über den Simulator austesten.
Ein möglicher Lösungsansatz wäre auch noch die PWM Werte nach ihrem Wert zu sortieren und sie in aufsteigender Reihenfolge mit dem Comparematch Register des Timers 1 zu vergleichen.
Liegen die Werte allerdings sehr nahe beieinander oder sind sie gleich, wird es auch hier zu Problemen kommen.
linux_80
17.06.2007, 12:57
Hallo,
und evtl. das TWI nicht per ISR erledigen, sondern einfach TWINT pollen, denn TWI kann ruhig mal ein paar Takte warten bis es bedient wird.
Wenn das PWM auf TWI warten müsste ist das gleich zu erkennen, andersrum nicht.
Noch ne Idee:
Den Timer 2 mit einem Teilerfaktor von 1024 laufen lassen und mit dem Comparematch Interrupt bei jedem neuen Zählerstand des TCNT2 Registers einen Interrupt auslösen lassen. Also OCR2 in jedem neuem Interrupt um 1 erhöhen. In diesem Interrupt auch die einzelnen Kanäle löschen oder setzen.
Das ergibt eine PWM Frequenz von 60Hz wenn ich mich nicht verrechnet hab.
Ausserdem wir auch nur ein Timer verbraten.
Das mit dem TWINT Pollen halt ich auch für eine gute Idee.
ohje leute, ihr überfordert mein hirn. ich hab vor allem bis auf ein lauflicht auf nem tiny noch nie asm geproggt.. ich hab gerad versucht nachzuvollziehen, was ihr mir genau sagen wollt, aber ich komm nicht auf den punkt. wie wäre es mit einem schnipsel pseudocode für einen unwissenden, nur damit mir der ablauf klar wird? danke! :)
Mal die Timer 2 Idee:
Du initialisierst den Timer2, damit er mit einem Teilerfaktor von 1024 von der Taktfrequenz des Controllers läuft.
Du gibst den Output Comparematch 2 interrupt frei.
Du setzt das OCR2 Register auf 1.
Du gibst mit SEI alle Interrupts frei.
Das war schon mal die Initialisierung.
Jetzt musst Du noch die OCR Interrupt Routine schreiben.
1. Alle verwendeten Register + SREG auf dem Stack sichern "PUSH"
2. Du liest das OCR2 Register aus und vergleichst mit diesem Wert deine gewünschten PWM Werte.
Ist der OCR Wert kleiner oder gleich wird der entsprechende Kanal angeschaltet.
Ist der OCR Wert größer wird der entsprechende Kanal abgeschaltet.
3. Nun noch den OCR Wert um 1 erhöhen und schauen ob er nun den Wert 0 hat (läuft nach 256 Zyklen wieder auf 0, da ja nur 8 Bit).
4. Den OCR Wert in das OCR2 Register schreiben.
5. Hat der OCR Wert den Wert 0, nochmals um 1 erhöhen und in das OCR2 Register des Timers 2 zurückschreiben.
6. Gesicherte Register + SREG mit POP wieder zurückschreiben.
Codeschnipsel:
PUSH r16
IN r16,SREG
PUSH r16
PUSH r17
IN r16,OCR2
LDS r17,pwm1
CP r17,r16
BRCC k1ein
CBI PORTB,0 ; 1.Kanal aus
RJMP k2
k1ein:
SBI PORTB,0 ; 1. Kanal ein
k2:
LDS r17,pwm2
CP r17,r16
BRCC k2ein
CBI PORTB,1 ; 2.Kanal aus
RJMP k3
k2ein:
SBI PORTB,1 ; 1. Kanal ein
k3:
usw, usw, für alle PWM Kanäle......
INC r16
BRNE writeocr2
INC r16
writeocr2:
OUT OCR2,r16
POP r17
POP r16
OUT SREG,r16
POP r16
RETI
Das wars, deine Software PWM ist fertig.
Welche Register für die benötigten Teilerfaktoren, Interruptfreigaben wie beschrieben werden müssen, müsste ich jetzt selber im Datenblatt nachschauen, aber das kannst Du ja selber auch machen.
Hinweis:
Das mit dem 2x Erhöhen beim Wert 0 brauchst Du um die LED's auch mal ganz abschalten zu können, bei OCR2=0 und PWM Wert 0 würde sonst der entsprechende Kanal kurz eingeschaltet.
Ich muss 12 Software-PWMs (8 Bit) haben.
Problemlos möglich, ich hab vor nicht allzulanger Zeit 16 Software PWM Kanäle mit 8 Bit Auflösung bei 500 Hz realisiert.
Der Mikrocontroller lief dabei mit 16 MHz und er war von der Rechenzeit her zu ca. 30% ausgelastet, insofern die PWM Werte konstant blieben.
Neue PWM Werte benötigten ca. 3-4 ms um verarbeitet zu werden.
Ausserdem soll der Mega8 noch als TWI-Slave arbeiten, um die PWM-Werte entgegenzunehmen. Ca. 30x12 Byte pro Sekunde.
Bei meiner Anwendung wurden die neuen Daten über die serielle Schnittstelle übertragen. Flackern oder Stehenbleiben gab er wären der Übertragung nicht.
Im übrigen würde ich die TWI nicht pollen sondern mit einem Interupt und entsprechenden Statusflags arbeiten.
Vom Prinzip her funktioniert es recht einfach, der Code allerdings ist wesentlich komplexer und Assemblertypisch recht schlecht lesbar. Deshalb möchte ich hier davon Abstand nehmen ihn zu posten.
Das Funktionsprinzip (ein kurzer Umriss):
Ich benötige einen schnelllaufenden Timer, welcher für die Ansteuerung der LED`s zuständig ist.
Die eingehenden Daten werden in eine Kanalmatrix umgerechnet, welche neben dem tatsächlich angesprochenem Kanal(Pin) auch den entsprechenden Helligkeitswert beinhaltet. Anschließend wird die Kanalmatrix nach der Helligkeit sortiert und gepackt. Diese Daten stehen dann im RAM bereit und werden in der Timerroutine nur noch ausgegeben.
Bei Bedarf kann ich das System das dahinter steckt gerne näher erläutern.
Grüße,
Hanni
Bei Bedarf kann ich das System das dahinter steckt gerne näher erläutern
500 Hz bei 16 Kanälen - Bo eh, das würd mich schon interessieren wie Du das hingekriegt hast ????
Kannst Du mal das Verarbeitungsschema posten ?
...Bei 16MHz und einem Taktteiler von 8 komm ich auf eine PWM Frequenz von 30 Hz (...) Bei 16MHz und einem Taktteiler von 1 komm ich auf eine PWM Frequenz von 244 Hz...
???????
Sei bitte so nett und erklär mal Deinen Rechenweg.
Ich komm bei nem Prescaler von 8 und einer Quantisierung von 8 Bit bei 16Mhz Taktfrequenz auf 325,5Hz wenn man 12 Kanäle haben möchte.
Ich komm bei nem Prescaler von 8 und einer Quantisierung von 8 Bit bei 16Mhz Taktfrequenz auf 325,5Hz wenn man 12 Kanäle haben möchte.
Erklär ich dir gerne.
16MHz / 8 (Prescaler) / 256 (TCNT Zyklen bis Timer Überlauf) = 7812,5 Hz
Die PWM soll 8 Bit Auflösung haben, also sind nochmal 256 Überläufe für einen Zyklus nötig. 7812,5 / 256 = 30,52 also ~30Hz.
Klar kann man das entsprechende TCNT Register auch mit einem Preload Wert versehen und damit die PWM Frequenz erhöhen, allerdings wird dadurch die Anzahl der ausführbaren Kommandos zwischen 2 Timer Overflow Interrupts verkürzt.
Wenn noch Luft in den Ausführungszeiten ist kann und sollte man das natürlich machen.
Kannst Du mal das Verarbeitungsschema posten ?
Jesses, na da hab ich mich ja auch etwas eingelassen :).
Naja, ich werde trotzdem einmal versuchen es anhand eines Beispiels mit 4 Kanälen zu erklären. Nehmen wir weiter an, diese Kanäle sind alle an einem Port an den Pins 0-3.
Datenaufbereitung
Die jeweiligen Helligkeitwerte der einzelnen Kanäle kommen seriell Kanal für Kanal über die serielle Schnittstelle in den Mikrocontroller.
Also Kanal 1, Kanal 2, Kanal 3, Kanal 4.
Diese Daten werden im RAM zwischengespeichert.
Wurde der letzte Kanal empfangen wird erst einmal überprüft ob es sich tatsächlich um neue Werte handelt oder ob diese mit den alten indentisch sind.
Sind es neue Daten wird ein Backup dieser gefahren (zu Vergleichszwecken). Sind es keine neue Daten wird solange gewartet bis wieder ein paar Daten im Speicher stehen.
Anschließend wird der Jeweiligen Helligkeit ein Kanal in Form eines Bitmusters zugeordnet.
Das sieht dann im Speicher wie folgt aus:
Kanal 1 = 83,
Kanal 2 = 43,
Kanal 3 = 154,
Kanal 4 = 3
83, 0b00000001
43, 0b00000010
154, 0b00000100
3, 0b00001000
Anschließend werden diese Daten nach dem Helligkeitwert sortiert.
Das Ergebniss sieht im Speicher wie folgt aus.
3, 0b00001000
43, 0b00000010
83, 0b00000001
154, 0b00000100
Nun wird, fals nicht vorhanden eine Helligkeit 0 hinzugefügt und die bei dieser Helligkeit aktiven LED's berechnet.
das sieht dann so aus:
0, 0b00001111
3, 0b00001000
43, 0b00000010
83, 0b00000001
154, 0b00000100
Diese Daten werden anschließend gepackt, also die Kanäle mit gleicher Helligkeit zusammengefasst.
Zum Schluss werden diese Daten in einen Ausgabepuffer geschrieben und stehen damit der PWM Erzeugung zur Verfügung.
PWM Erzeugung
In einer Timer Interrupt Routine, welche alle 125 Takte aufgerufen wird passiert das folgende:
1. wird ein vorhandener Zählerwert mit der nächsten Helligkeit verglichen. Stimmen diese überein wird die jeweilige Kanalmatrix aus dem Speicher geholt und ausgegeben, sowie die nächste Helligkeit als Vergleichswert geladen.
2. der Zähler wird um eins erhöht.
3. ist der Zählerwert = 255 so wird der Zähler Resetet und der Vergleichswert auf 0 gesetzt.
----------------------------------------------------------------------------
So .. ich hoffe das war jetzt so halbwegs verständlich erklärt.
Grüße,
Hanni
...16MHz / 8 (Prescaler) / 256 (TCNT Zyklen bis Timer Überlauf) = 7812,5 Hz
Die PWM soll 8 Bit Auflösung haben, also sind nochmal 256 Überläufe für einen Zyklus nötig. 7812,5 / 256 = 30,52 also ~30Hz....
hmmm... Warum soll da nochmal durch 256mal geteilt werden?
Geht es dabei darum mögliche Fehler, die durch gleiche Werte bei der PWM entstehen weitestgehend zu minimieren weil der µC ja nicht Multitaskingfähig ist?
Geht es dabei darum mögliche Fehler, die durch gleiche Werte bei der PWM entstehen weitestgehend zu minimieren weil der µC ja nicht Multitaskingfähig ist?
Nein es geht dabei nicht um Fehler.
Ein Timer erzeugt einen Timer Overflow Interrupt wenn der Zählerstand von 255 auf 0 wechselt - der Timer also überläuft.
Da ich wegen der 12 Kanäle das nicht mit einem Comparematch Register realisieren würde, muss ein "externer Zäher", also ein Register oder RAM Speicherplatz in der Interruproutine hochgezählt und mit den gewünschten Comparematch Werten verglichen werden.
Da eine Auflösung von 8 Bit also 256 Stufen gewünscht ist braucht auch dieser externe Zähler nochmal 256 Overflow Interruptroutinen für seine Funktion.
Eine Beschleunigung dieses Prozesses wäre durch Laden des TCNT Registers mit einem Preload Wert (z.B. 127) während des Interrupts möglich, oder durch eine Verringerung der Auflösung.
Der Preload Wert darf aber nicht zu hoch werden, sonst kann der Interrupt bis zum Auftreten des nächsten Interrupts nicht vollständig abgearbeitet werden und der Controller wird dadurch Interrupts verschlucken.
Ausserdem muss zur Abarbeitung der SPI Kommandos auch noch etwas Prozessorleistung zur Verfügung stehen.
@hanni
Ich glaub ich versteh schon wie Du das gemacht hast.
Ich hatte auch so eine ähnliche Idee.
Das Problem dabei ist nur, das wenn viele Werte nah beieinander liegen, aber nicht gleich sind, die Abarbeitungszeit während des Interrupts zu kurz werden könnte, und auch da Interrupts verloren werden könnten.
Aus diesem Grund hab ich diese Idee wieder verworfen.
Ich glaub ich versteh schon wie Du das gemacht hast.
Ich hatte auch so eine ähnliche Idee.
Das Problem dabei ist nur, das wenn viele Werte nah beieinander liegen, aber nicht gleich sind, die Abarbeitungszeit während des Interrupts zu kurz werden könnte, und auch da Interrupts verloren werden könnten.
Aus diesem Grund hab ich diese Idee wieder verworfen.
Also im schlechtesten aller Fälle dauert meine ISR ca. 50 Takte (von 125 verfügbaren). Daher kann ich das Problem nicht wirklich nachvollziehen ...
Ursprünglich war das ganze übrigens für eine 10 Bit PWM mit maximal 250 Hz ausgelegt ... daher weiss ich, das bei 8Bit mit 500 Hz genügend Reserven vorhanden sind.
Grüße,
Hanni
Powered by vBulletin® Version 4.2.5 Copyright ©2024 Adduco Digital e.K. und vBulletin Solutions, Inc. Alle Rechte vorbehalten.