Samples abspielen mit PWM

Durch die Nutzung eines Tiefpassfilters lässt sich mit PWM ein Mittelwert zwischen den beiden Zuständen aus und an erzeugen. Idealisiert werden die Sinuskomponenten des Signals dabei entfernt. Bei LEDs wird das zum Dimmen genutzt, also um die Helligkeit zwischen 0 Prozent und 100 Prozent einzustellen. Erreicht wird das über die Anpassung des Duty Cycles - grob vereinfacht entspricht ein Duty Cycle von 25 Prozent einem Viertel der maximalen Helligkeit, 66 Prozent zwei Dritteln.

Stellenmarkt
  1. Software Developer für Anwendungen und Schnittstellen (m/w / divers)
    Continental AG, Villingen
  2. Embedded Linux-Programmierer (m/w/d) Entwicklung
    wenglor MEL GmbH, Eching
Detailsuche

Der Tiefpassfilter ist dabei übrigens die Trägheit des menschlichen Auges. Gleiches lässt sich für Spannungen erreichen; um damit Töne erzeugen zu können, muss die PWM aber deutlich schneller laufen. Da die PWM-Module beim RP2040 mit dem Systemtakt - in diesem Beispiel 141,6 MHz - betrieben werden, lässt sich problemlos ein PWM-Signal im Kilohertz-Bereich erzeugen. Zusammen mit einem Filter aus einem Widerstand und einem Kondensator ergibt das ein durchaus akzeptables Analogsignal.

Wird der Duty Cycle des PWM-Signals variiert, lassen sich beliebige Signalformen erzeugen. Dazu benötigen wir digital abgetastete Tondaten - auch als Samples bezeichnet. Je nachdem wie schnell das Sample wiedergegeben wird, variiert die Tonhöhe. Zum Testen habe ich mir erst einmal Samples eines Sinus- und Dreiecksignals erzeugt.

Das erste Testprogramm

Für den ersten Test verwende ich ein Sample mit 16 Abstastwerten einer Sinusschwingung. Die einzelnen Abtastwerte werden vom DMA-Automat mit variabler Geschwindigkeit in das Vergleichsregister des verwendeten PWM-Moduls kopiert. Je schneller das passiert, desto höher der Ton.

Golem Karrierewelt
  1. DP-203 Data Engineering on Microsoft Azure: virtueller Vier-Tage-Workshop
    24.-27.10.2022, virtuell
  2. C++ Programmierung Basics: virtueller Fünf-Tage-Workshop
    24.-28.10.2022, virtuell
Weitere IT-Trainings

Die Geschwindigkeit des DMA-Automaten kann auf zwei Arten gesteuert werden: Entweder indem einer der vier Timer des Automaten selbst verwendet oder ein weiteres PWM-Modul genutzt wird. Die DMA-Timer haben dabei einen Nachteil: Sie können den Systemtakt maximal um den Faktor 65.536 (216) verlangsamen. Damit sind, bei 16 Abtastwerten pro Periode der Sinusschwingung und 141,6 MHz Systemtakt, nur Töne mit 135 Hz oder mehr möglich.

Zum Testen reicht das - also werfen wir einen Blick auf den Code (pwm_snd_test.c):

  1. gpio_init(16);
  2. gpio_set_dir(16, GPIO_OUT);
  3. gpio_set_function(16, GPIO_FUNC_PWM);
  4.  
  5. pwm_set_clkdiv_int_frac(pwmSlice, 3, 0);
  6. pwm_set_wrap(pwmSlice, 1023);
  7. pwm_set_counter(pwmSlice, 0);
  8.  
  9. dmaChannelId = dma_claim_unused_channel(true);
  10.  
  11. dmaChannelConf = dma_channel_get_default_config(dmaChannelId);
  12. channel_config_set_transfer_data_size(&dmaChannelConf, DMA_SIZE_16);
  13. channel_config_set_read_increment(&dmaChannelConf, true);
  14. channel_config_set_write_increment(&dmaChannelConf, false);
  15. channel_config_set_ring(&dmaChannelConf, false, 5);
  16.  
  17. dmaTimer = dma_claim_unused_timer(true);
  18.  
  19. dma_timer_set_fraction(dmaTimer, 1, 40227);
  20.  
  21. channel_config_set_dreq(&dmaChannelConf, dma_get_timer_dreq(dmaTimer));
  22.  
  23. dma_channel_configure(dmaChannelId, &dmaChannelConf, &pwm_hw->slice[pwmSlice].cc, samples, 35200, true);
  24.  
  25. pwm_set_enabled(pwmSlice, true);

Die ersten drei Zeilen dienen dazu, GPIO-Pin 16 für die Ausgabe des PWM-Signals zu aktivieren. Danach wird das zugehörige PWM-Modul initialisiert (die Module können nur bestimmte Pins ansteuern). Zuerst wird der Taktteiler des Moduls auf drei gesetzt - das Zählerregister wird mit einem Drittel des Systemtakts hochgezählt. Der Maximalwert des Registers wird auf 1.023 gesetzt, ein Vergleichswert von 511 würde dann die Hälfte der Maximalspannung erzeugen. Die letzte Zeile des Blocks setzt noch das Zählerregister. Die PWM-Frequenz liegt damit bei etwa 46,1 kHz.

  • Größerer Ausschnitt aus dem erzeugten Signal: links ein reiner Sinus, rechts Überlagerung aus Sinus und Rechtecksignal. (Bild: Johannes Hiltscher, Golem.de)
  • Das Grundsignal, mit dem das PWM-Signal die Spannungspegel erzeugt. Hier erzeugt ohne Vorteilung des Systemtakts. (Bild: Johannes Hiltscher, Golem.de)
  • In den PWM-Modulen des RP2040 läuft ein Zähler zwischen 0 und einem Maximalwert. Bei jedem Zählschritt wird sein Wert mit einem Register (Counter Compare) verglichen; ist der Zähler kleiner oder gleich, wird eine 1 ausgegeben, sonst eine 0. (Bild: Johannes Hiltscher, Golem.de)
  • So funktioniert die Abtastratenkonvertierung: Anhand des Ausgangssamples werden neue Abtastpunkte mit der Frequenz des Mixers erzeugt. Bei niedrigen Frequenzen werden neue Punkte erzeugt, bei hohen nur einige ausgewählt. (Bild: Johannes Hiltscher, Golem.de)
  • Das Ausgangssignal ist nicht ganz sauber, aber als Sinus erkennbar. Die Frequenz stimmt auch, hier ein G4.  (Bild: Johannes Hiltscher, Golem.de)
Das Grundsignal, mit dem das PWM-Signal die Spannungspegel erzeugt. Hier erzeugt ohne Vorteilung des Systemtakts. (Bild: Johannes Hiltscher, Golem.de)

Dann folgt die Konfiguration eines DMA-Kanals, den ich mir von der Bibliothek mittels dma_claim_unused_channel() zuweisen lasse. Danach wird zuerst die Größe der einzelnen Datenblöcke auf 16 Bit gesetzt, dann das Verhalten der Lese- und Schreibadresse konfiguriert: Die Leseadresse wird nach jedem Datenblock erhöht, die Schreibadresse nicht - es wird immer in das Counter-Compare-Register des PWM-Moduls geschrieben.

Dann folgt eine der kleinen Komfortfunktionen des DMA-Automaten: Durch die Konfiguration eines Rings wird er angewiesen, bei der Leseadresse nur die niederwertigsten fünf Bit zu verwenden. So liest er immer dieselben 16 2-Byte-Werte. Damit das funktioniert, muss der Puffer, aus dem gelesen wird, allerdings an einer 32-Byte-Adresse ausgerichtet sein. Das funktioniert, indem in seine Definition __attribute__((aligned(32))) eingefügt wird.

Danach lässt man sich einen der Timer des DMA-Automaten zuteilen. Der wird so konfiguriert, dass er die komplette Sinusschwingung mit (etwa) 220 Hz überträgt. Dann wird dieser Timer als Data-Request-Quelle für den DMA-Kanal eingestellt. Der Data Request ist ein weiteres Feature des Automaten, über ihn kann eine andere Hardware-Einheit die Geschwindigkeit der Datenübertragung steuern. Danach wird die Konfiguration des Kanals gesetzt, gleichzeitig noch Schreib- und Leseadresse, und die Anzahl der zu übertragenden Datenblöcke sowie der Kanal werden gleich noch mit aktiviert.

Zuletzt wird das PWM-Modul aktiviert, damit auch etwas zu hören ist. Der akustische Eindruck und das Oszilloskop sagen: funktioniert. Mit dem kleinen Lautsprecher mit Plastikmembran klingt es zwar sehr nach Geburtstagskarte, hat aber extremen 8-Bit-Charme. Also auf zu größeren Taten: polyphone Klänge mit mehreren Tonspuren!

Bitte aktivieren Sie Javascript.
Oder nutzen Sie das Golem-pur-Angebot
und lesen Golem.de
  • ohne Werbung
  • mit ausgeschaltetem Javascript
  • mit RSS-Volltext-Feed
 Analogwandlung mit PWMPolyphonie: Mehrere Tonspuren 
  1.  
  2. 1
  3. 2
  4. 3
  5. 4
  6. 5
  7. 6
  8.  


Aktuell auf der Startseite von Golem.de
Cloudgaming
Google Stadia scheiterte nur an sich selbst

Die Technik war nicht das Problem von Alphabets ambitioniertem Cloudgaming-Dienst. Das Problem liegt bei Google. Ein Nachruf.
Eine Analyse von Daniel Ziegener

Cloudgaming: Google Stadia scheiterte nur an sich selbst
Artikel
  1. Tiktok-Video: Witz über große Brüste kostet Apple-Manager den Job
    Tiktok-Video
    Witz über große Brüste kostet Apple-Manager den Job

    Er befummle von Berufs wegen großbrüstige Frauen, hatte ein Apple Vice President bei Tiktok gewitzelt. Das kostete ihn den Job.

  2. Copilot, Java, RISC-V, Javascript, Tor: KI macht produktiver und Rust gewinnt wichtige Unterstützer
    Copilot, Java, RISC-V, Javascript, Tor
    KI macht produktiver und Rust gewinnt wichtige Unterstützer

    Dev-Update Die Diskussion um die kommerzielle Verwertbarkeit von Open Source erreicht Akka und Apache Flink, OpenAI macht Spracherkennung, Facebook hilft Javascript-Enwicklern und Rust wird immer siegreicher.
    Von Sebastian Grüner

  3. Vantage Towers: 1&1 Mobilfunk gibt Vodafone die Schuld an spätem Start
    Vantage Towers
    1&1 Mobilfunk gibt Vodafone die Schuld an spätem Start

    Einige Wochen hat es gedauert, bis 1&1 Mobilfunk eine klare Schuldzuweisung gemacht hat. Doch Vantage Towers verteidigt seine Position im Gespräch mit Golem.de.

Du willst dich mit Golem.de beruflich verändern oder weiterbilden?
Zum Stellenmarkt
Zur Akademie
Zum Coaching
  • Schnäppchen, Rabatte und Top-Angebote
    Die besten Deals des Tages
    Daily Deals • LG OLED TV 2022 65" 120 Hz 1.799€ • ASRock Mainboard f. Ryzen 7000 319€ • MindStar (G.Skill DDR5-6000 32GB 299€, Mega Fastro SSD 2TB 135€) • Alternate (G.Skill DDR5-6000 32GB 219,90€) • Xbox Series S + FIFA 23 259€ • PCGH-Ratgeber-PC 3000€ Radeon Edition 2.500€ [Werbung]
    •  /