Forum: Mikrocontroller und Digitale Elektronik STM32F103, PWM als Tongerator


von Jan (Gast)


Lesenswert?

Hallo,

ich wollte eine PWM eines STM32 als Tongerator benutzten. Dafür müsste 
ich ja ständig den Presacaler bzw. den Period wert ändern. Es gibt 
Befehle für den Compare Wert zu ändern (das müsste ja im Prinzip die 
Lautstärke sein).

Wie kann ich Presacler und Period wärend der "Laufzeit" ändern. oder 
muss jedes mal den Timer abschlaten und mit dem neuen Tonwert 
initialisieren?

Dank und Gruß
Jan

von Felix U. (ubfx)


Lesenswert?

Jan schrieb:
> Es gibt
> Befehle für den Compare Wert zu ändern (das müsste ja im Prinzip die
> Lautstärke sein).

Was? Die Lautstärke hängt von der Amplitude ab, nicht vom 
Frequenzgehalt.

Jan schrieb:
> Wie kann ich Presacler und Period wärend der "Laufzeit" ändern.

Du kannst die entsprechenden Register während der Laufzeit ändern. Die 
Namen der Register kannst du dem Datenblatt entnehmen (Müsste TIMx_CCRx 
sein)

von Marc (Gast)


Lesenswert?

>Was? Die Lautstärke hängt von der Amplitude ab, nicht vom
>Frequenzgehalt.

Schreib mal die Formel für die Messung der Lautstärke auf, dann wird's 
klarer ;-)

von Dr. Sommer (Gast)


Lesenswert?

Möchtest du die PWM als "DAC" nutzen, d.h. pro Analog-Sample einen oder 
mehrere Timer-Durchläufe haben, ggf. mit externem Tiefpass, um so 
beliebige Wellenformen erzeugen zu können?
Oder mit der PWM direkt die hörbare Frequenz (< 20kHz) erzeugen, sodass 
man immer ein Rechteck hört?

von Johnny B. (johnnyb)


Lesenswert?

Jan schrieb:
> ich wollte eine PWM eines STM32 als Tongerator benutzten. Dafür müsste
> ich ja ständig den Presacaler bzw. den Period wert ändern. Es gibt
> Befehle für den Compare Wert zu ändern (das müsste ja im Prinzip die
> Lautstärke sein).

Das geht mit dem STM32 ziemlich elegant, indem du die Wellenform zuerst 
in einem Array anlegst und dann im Hintergrund per DMA als PWM an den 
Timer schicken lässt.

von Jan (Gast)


Lesenswert?

Ich wollte einfach Rechteck Töne erzeugen.

Ich glaube ich habe die entsprechenden Befehle gefunden.
1
    /*
2
    TIM3->ARR = period;        //TIM_Period  // TIM_SetAutoreload
3
    TIMx->CCR1 = compare;     // setcompare // TIM_SetCompare1
4
    TIMx->PSC = prescaler;      //prescaler    // TIM_SetIC1Prescaler
5
    */
6
7
    TIM_SetAutoreload(TIM3, period);
8
    TIM_SetCompare1(TIM3,compare);
9
    TIM_SetIC1Prescaler(TIM3, prescaler);

Das mit dem DMA Zugriff zwischen Speicher und PWM hört sich sehr 
interessant an. Hast du dazu ein Beispiel? Mit DMA habe ich noch nie 
etwas gemacht...

von W.S. (Gast)


Lesenswert?

Jan schrieb:
> Wie kann ich Presacler und Period wärend der "Laufzeit" ändern. oder
> muss jedes mal den Timer abschlaten und mit dem neuen Tonwert
> initialisieren?

Nein, sowas geht ganz anders.

Zunächst stellst du dir die Periode deines PWM-Timers so ein, daß sie 
groß genug ist, um darin etwas mehr als sämtliche vorkommende 
Amplitudenwerte unterzubringen.

Also wenn du deine Töne mit 10 Bit Amplitudenauflösung abspielen willst, 
dann setzt du die Periode auf so etwa 1024+10+10, macht 1044. Das machst 
du, um mit der Amplitude nicht direkt an die Rails anzuecken, denn du 
mußt die PWM-Ausgabe ja analog weiterverarbeiten.

Dann stellst du den Prescaler so ein, daß sich mit Prescaler und 
Zählumfang von hier im Beispiel 1044 eine Audio-Samplerate deiner Wahl 
ergibt, die du auch noch per Interrupt verarbeiten kannst.

Dann stellst du den Comparewert auf Mitte ein, also 1024/2 + 10, macht 
522.

Dann hast du die Wahl:
a) du machst dir einen Ringpuffer ausreichender Größe und füllst ihn mit 
522.
b) du machst eine Variable, aus der dein Interruptprogramm erkennt, ob 
es was spielen soll oder nicht.

So, nun kannst du den PWM einschalten.

Im zugehörigen Interruptprogramm machst du folgendes:
Variante a) nimm den nächsten Wert aus dem Ringpuffer und schreibe an 
dessen Stelle 522 in den Ringpuffer. Dann wandelst du das Sample um: 
addiere 522 und schreib das in das Compare-register
Variante b) guck nach, ob du dudeln sollst. Wenn ja, dann nimm das 
nächste Sample aus deinem Puffer, wandle es wieder um (+522) und 
schreibe es in das Compareregister. Wenn nein, schreibe 522 in das 
Compareregister.

Hinter dem Ganzen auf der Pin-Seite mußt du natürlich das PWM per 
geeignetem Tiefpaß filtern, um die Samplefrequenz ausreichend zu 
dämpfen.

Damit kannst du Töne, aber auch kurze Sprachstücke wiedergeben. Für 
alles Weitere lies in der Lernbetty nach, da ist auch eine dezente 
Kompression der Audiodaten per SOL (Sierra-Format) dabei.

W.S.

von Johnny B. (johnnyb)


Lesenswert?

Jan schrieb:
> Das mit dem DMA Zugriff zwischen Speicher und PWM hört sich sehr
> interessant an. Hast du dazu ein Beispiel?

Im Dokument "AN4776" (General-purpose timer cookbook) von ST ist viel 
Nützliches erläutert, was Du brauchen könntest.
https://www.st.com/resource/en/application_note/dm00236305.pdf

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.