BAM - eine mögliche Alternative zu PWM bei Multichannel-Anwendungen

  • Bei einer Internet-Recherche bin ich zufällig über BAM (Bit Angle Modulation) zur Helligkeitssteuerung von LEDs gestolpert, welche vor allem bei Multichannel-Anwendungen einen entscheidenden Vorteil in der deutlich niedrigeren Prozessorauslastung (kürzere Interrupt-Routinen und viel weniger Aufrufe pro Zyklus) hat.


    Ein Forumeintrag, welcher die BAM-Methode sehr schön erklärt (leider nur Englisch)


    Vorstellung der BAM-Methode in einer Application Note der 'Erfinder' (auch nur Englisch)


    Gruss
    Neni

  • Hört sich doch sehr interessant an . Jedoch ist mein English nicht so perfekt um den ganzen Text zu vollziehen.
    Leider spuckt auch Wikipedia nichts dazu aus.
    Muss mich mal weiterinformiern.
    :thumbup:
    Mfg niki1

  • Also BAM ist eigentlich ganz einfach zu erklären, vor allem wenn man sich die Bilder in den beiden verlinkten Beschreibungen ansieht. Im Prinzip wird der Helligkeitswert selbst als serieller Pulscode ausgegeben, und zwar während eines Zyklus alle entsprechenden Bits (also 8 Bit bei einer 8-Bit-BAM). Die Dauer jedes einzelnen Bits (ob 0 oder 1 ist egal) am Ausgang ist proportional zur seiner Wertigkeit. Wenn also das niederwertigste Bit (Bit 0) einen bestimmten Zeitabschnitt lang ausgegeben wird, dann wird Bit 1 doppelt so lange, Bit 2 dann 4 Zeitabschnitte lang, Bit 3 8 Zeitabschnitte, Bit 4 16 Zeitabschnitte, Bit 5 32 Zeitabschnitte, Bit 6 64 Zeitabschnitte und Bit 7 128 Zeitabschnitte lang ausgegeben. Bei einem 8-Bit-Wort wäre dann damit ein Zyklus abgeschlossen.


    Bei der PWM (als Beispiel auch 8-Bit Auflösung) muss man für einen Zyklus ja 255 konstante Zeitabschnitte durchlaufen. Nehmen wir mal an, jeder Zeitabschnitt würde 10 µs dauern, dann wäre die Zyklusdauer 255 x 10 µs = 2,55 ms, d.h. man hätte eine PWM-Frequenz von etwas unter 400 Hz. Bei X zu steuernden Kanälen muss man bei der PWM in jedem dieser Zeitabschnitte von 10 µs X Vergleiche (hat der Zeitabschnittszählwert den Kanal-PWM-Wert erreicht?) durchführen und dann die jeweiligen Ausgänge entsprechend setzen. Bei vielen Kanälen kommt man da an die Limite dieser 10 µs im Beispiel, und da das praktisch durchgehend Zyklus für Zyklus und 255 mal pro Zyklus gemacht werden muss (die Vergleiche), hat der Prozessor bei entsprechend vielen Kanälen kaum noch Zeit für Anderes, wenn ich wirklich knapp an die Limite von 10µs rangehe.


    Bei BAM ist das anders. Nehmen wir als Beispiel wieder eine 8-Bit-BAM und legen wir fest, dass die Zyklen-Wiederholrate diese knapp 400 Hz von PWM-Beispiel oben betragen soll. Dann ist der kleinste Zeitabschnitt (der für Bit 0) immer noch 10 µs. Ich muss also immer noch gewährleisten, dass ich in etwas weniger als 10µs alle meine Portausgänge (Kanäle) setzen kann. Aber ich muss keine Vergleiche durchführen, sondern nur die Ports entsprechend den Bits in den jeweiligen Helligkeitswerten (0 - 255) setzten. Damit kann ich hier schon mehr Kanäle steuern, und ich kann tatsächlich die Limite von 10µs gnadenlos ausfüllen, wie wir gleich sehen werden. Ich muss nämlich die Routine (Interrupt), die mit die Ports setzt nur 8 mal (im Vergleich zu 255 mal bei PWM) pro Zyklus aufrufen. Ich setze also beim ersten Aufruf alle Ports entsprechend den Bit 7 der Kanal-Helligkeitswerte, wobei das Portsetzen wie beschrieben maximal 10 µs dauert. Der nächste Aufruf erfolgt aber erst nach 1,28 ms, dann setze ich alle Ports entsprechend dem Bit 6, dann nach 640 µs entsprechend Bit 5 usw. nach folgenden Zeiten - 320 µs, 160 µs, 80 µs, 40 µs - und nach weiteren 20 µs Bit 0 für den letzten Zeitabschnitt von 10 µs. Dann fängt der Zyklus wieder von vorne an und dauert, wenn man alle Zeiten zusammenzählt, - oh welch ein Wunder ;) - genau die 2,55 ms von oben. Man sieht also, dass der Prozessor bei der BAM Ewigkeiten an Zeit übrig hat, um sich dann noch um andere Dinge kümmern zu können, wie konkrete Abläufe und Sequenzen zu steuern, Kommunikation mit einem Steuergerät (PC etc.) usw.


    Nun, hoffentlich war das auch ohne bildliche Darstellung eine genügend verständliche Erklärung.


    Gruss
    Neni

  • Ja klar. Deshalb schreibe ich auch, dass sich die Implementation v.a. bei Multichannel-Anwendungen lohnt. Wenn man mehr als 10 - 12 Kanäle mit einem µC steuern will, ohne auf externe PWM-Chips angewiesen zu sein, dann gibt's eben kaum µCs mit entsprechend vielen Hardware-PWM-Kanälen, und man ist dann auf eine Software-Implementation angewiesen. Mit einem Mega32 bei 16 MHz zum Beispiel sollte man mit BAM locker über 24 Kanäle bei 8 Bit und genügend hoher Wiederholrate (entspricht Frequenz bei PWM) zu schaffen, und dabei wäre der µC noch fähig, komplexe Abläufe, Programme und Sequenzen/Animationen zu berechnen und zu steuern.


    Gruss
    Neni

  • Das klingt gut, ich hab noch genau einen ATmega32 und der steckt aktuell im Pollinboard für jenen Zweck.


    Gibts für Bascom Codebeispiele wie das auszusehen hat? Auf dem Steckbrett habe ich jetzt meine
    6x6 Matrix zusammen gepuselt, daher 12 Kanäle sind zu steuern (oder hab ich was übersehen?)


    Die verschiedenen Farben habe ich ersteinmal weg gelassen.


    Gruß!

  • Das klingt gut, ich hab noch genau einen ATmega32 und der steckt aktuell im Pollinboard für jenen Zweck.
    Gibts für Bascom Codebeispiele wie das auszusehen hat?


    Wie wär es mal mit nen bisl eigenem Gehirnschmalz :?: Immer nur C&P ist doch auf die Dauer auch langweilig ;)


  • Wie wär es mal mit nen bisl eigenem Gehirnschmalz :?: Immer nur C&P ist doch auf die Dauer auch langweilig ;)


    Hat nix mit Copy&Paste zu tun. Was Programmieren mit Bascom angeht bin
    ich im Momentn och ein ganz kleines Licht und in Ermangelung von nem
    "Microcontroller und Bascom für Dummies"-Buch brauche ich halt andere
    Lernmaterialien. Und ich lerne lieber am Objekt als mit Einzelheiten anzufangen
    und auch dann noch für jeden Pups fragen zu müssen.


    Und von wegen "immer nur.." wenn ich mal endlich nen RGB-PWM Code für
    Bascom gefunden hätte, müsste ich dafür wohl auch nicht mehr fragen.

  • Stimmt das folgende Schema zum ausprogrammieren einer BAM:


    Als erstes einen Timer im Comparemode mit Interrupt ohne Reloadwert deffinieren.


    Zählervariable i
    Variable Helligkeit(8bit)


    interrupt routine
    {
    variable temp


    temp=Helligkeit um i Stellen nach rechts verschieben
    temp=temp logisch und mit 01Hex verknüpfen //nur die letzte stelle von temp zählt
    ausgabepin=temp //auf 0 oder 1 setzen
    comparewert=comparewert+(2^i)*verzögerung //damit der nächste interruptaufruf mehr oder weniger spät kommt (wertigkeit der
    // einzelnen Bits)
    i=i+1 //i für das nächste bit vorbereiten
    i=i logisch und mit 07hex verknüpfen //damit i nur von 0-7 zählt
    }


    Stimmt dieser Ansatz so?

  • Der code würde so ungefähr funktionieren, wenn man den Timer im Compare-Mode zur Interrupt-Erzeugung verwenden würde.
    Allerdings wäre in der Interrupt-Routine "comparewert = 2^i * minimales_intervall" zu setzen (und nicht "comparewert = comparewert + 2^i * minimales_intervall"). Die (2^i * x)-Funktion liesse sich natürlich einfach durch i-fachen left shift und left roll (LSL und ROL) der beiden Bytes des comparewertes hintereinander bewerkstelligen. Noch schneller würde es wohl gehen, wenn man die Comparewerte (oder Timer-Reload-Werte, falls man nicht den Compare-Modus nutzen will) im Voraus ausrechnet, sie als Datenreihe in den Flash programmiert oder in das SRAM schreibt (bei Programmstart), und dann bei jedem Interrupt-Durchlauf mittels i als Index aus dem Flash oder dem SRAM lädt und in die entsprechenden Register schreibt.


    Gruss
    Neni