Hallo Community,
ich bin neu hier und beschäftige mich seid ein paar Tagen mit
Controllers. Genauer genommen mit den MSP430. Als Chip benutze ich den
G2553.
Da ich dieses Jahr meine Ausbildung als Informatiker anfing, hab ich mir
ein kleines Projekt vorgenommen, um mein Feingefühl in der Welt der
uController zu trainieren.
Und zwar hatte ich vor, als erstes, eine .wav Datei auf einer SD-Karte
abzuspeichern die ich dann mit dem uController verbinde.
Das Audiosignal soll erstmal eine Mono Datei sein, sprich ein Kanal.
Ich hab mich nun etwas eingelesen, wie ich das Signal ausgeben kann.
Einmal mittels DAC und die weitere Möglichkeit wäre mittels PWM womit
man einen Tiefpass vorher beschaltet.
http://www.ti.com/lit/ug/tidu703/tidu703.pdf
Okay, der G2553 beinhaltet keinen DAC, also benutze ich als erstes die
PWM.
Ich weiß nun, dass eine Sampling Rate von 8000 Hz ausreicht um 4000 Hz
Mono Datei abzuspielen.
Was ich mir noch im unklaren bin, ist das Thema mit der Auflösung. Zwar
ist mir klar, dass ich mit 16-Bit 65.536 Werte speichern kann, aber wie
gehe ich hantier ich damit.
Und ist es egal ob ich 8-Bit benutze oder 16-Bit?
Das ausrechnen der Bitrate soll auch kein Problem sein. Bei 1 Kanal x zB
16Bit x 8 kHz = 128 kBit/s
Der erforderte Speicher für beispielsweise 5 Sekunden auf der SD-Karte
wären dann doch: 128 kBit/s / 8 x 5 = 80 Byte
Ist das so korrekt?
Danke im voraus für jede Unterstützung.
Florian schrieb:> Ich weiß nun, dass eine Sampling Rate von 8000 Hz ausreicht um 4000 Hz> Mono Datei abzuspielen.> Was ich mir noch im unklaren bin, ist das Thema mit der Auflösung. Zwar> ist mir klar, dass ich mit 16-Bit 65.536 Werte speichern kann, aber wie> gehe ich hantier ich damit.> Und ist es egal ob ich 8-Bit benutze oder 16-Bit?
Die Qualität bei 16 bit ist höher. Du gibst 8000 mal in der Sekunde
einen neuen PWM-Wert vor (vorausgesetzt Deine PWM ist schnell genug).
Den Wert kannst Du genauer (16Bit) oder nicht so genau (8Bit)
einstellen.
Florian schrieb:> Das ausrechnen der Bitrate soll auch kein Problem sein. Bei 1 Kanal x zB> 16Bit x 8 kHz = 128 kBit/s
ja. bzw. 16kB (Kilobyte) / Sekunde
Florian schrieb:> Der erforderte Speicher für beispielsweise 5 Sekunden auf der SD-Karte> wären dann doch: 128 kBit/s / 8 x 5 = 80 Byte> Ist das so korrekt?
nein. Mach mal 'nen Überschlag mit dem Wert oben :-)
Guten Abend Rainer, vielen Dank für deine Antwort.
Hab das jetzt mit der Auflösung soweit verstanden.
Rainer U. schrieb:
>> Der erforderte Speicher für beispielsweise 5 Sekunden auf der SD-Karte>> wären dann doch: 128 kBit/s / 8 x 5 = 80 Byte>> Ist das so korrekt?>> nein. Mach mal 'nen Überschlag mit dem Wert oben :-)
Ach total vertan, hab das kilo vergessen, bedeutet es wären dann 80.000
Byte.
Ich hab eine erklärung gefunden wie man umgeht, wenn man den Speicher
ausrechnen möchte miteinbezogen dem Takt der CPU und der PWM.
Bleiben wir bei dem Beispiel mit den 5 Sekunden Audiodatei.
Bei einer CPU Frequenz von 16 MHz, einer gewählten Auflösung von 16-Bit
bekäme ich eine PWM Frequenz von 16 Mhz / 2^16 = 244 Hz und wenn ich das
nun durch 2 teilen müsste, wegen dem Nyquist-Theorem, bekäme ich dann
eine hörbare Frequenz von 122 Hz?! So und diese dann noch mal der 5
Sekunden, bekäme ich 610 Byte.
Das scheint mir aber sehr wenig zu sein. Kann das soweit stimmen, oder
hab ich wieder ein blöden Fehler gemacht?
Hallo,
hab da noch eine Frage.
Wenn ich statt PWM die DAC benutze und mittels DMA die Daten vom Flash
raushole und dem DAC übergebe, brauch ich da unbedingt eine
samplingrate?
Im Datasheet bspw. von dem msp430f2619 finde ich unter dem Kapitel DAC
nichts zu einer conversion time, wie es der Fall bei dem ADC ist.
Und noch eine Frage bezüglich des Arrays, wie groß muss das Array mind.
sein wenn ich eine .wav Datei da ablegen möchte?
Florian schrieb:> brauch ich da unbedingt eine samplingrate
Natürlich. Das ist die Geschwindigkeit, mit der die Daten dem
D/A-Wandler übergeben werden.
> wie groß muss das Array mind. sein wenn ich eine .wav Datei da ablegen> möchte?
Wie groß ist eine .wav-Datei?
Rufus Τ. F. schrieb:
> Florian schrieb:>> brauch ich da unbedingt eine samplingrate>> Natürlich. Das ist die Geschwindigkeit, mit der die Daten dem> D/A-Wandler übergeben werden.
Hallo Rufus, danke für die Antwort. Wenn ich einen Blick in das
Datasheet von dem msp430f2619 werfe, finde ich aber in den Tabellen
nichts dazu.
Kannst du mir einen Tipp geben, wo ich das finde?
Rufus Τ. F. schrieb:
> Wie groß ist eine .wav-Datei?
Nun ja, wie oben schon ausgerechnet mit den gleichen Parameter, müsste
dass dann bei 5 Sekunden .wav Datei einer Größe von 80 kByte sein.
Aber was hat das dann mit der Rechnung mit der PWM zutun? Wo ich weiter
oben eine Größe von 610 Byte herausbekomme.
Bin für jeden Tipp und Ratschlag sehr dankbar
> eine hörbare Frequenz von 122 Hz?! ... bekäme ich 610 Byte
16 Bit Auflösung gehen schlicht und einfach nicht mit deiner PWM.
Du musst umgekehrt rechnen. Du nimmst die PWM Frequenz und die
gewünschte Audiofrequenz. Berechnest damit die mögliche Auflösung. Da
werden so 12 Bit herauskommen.
Nächstes Problem. Dein MC muss die Daten von der Karte holen, in 12 Bit
verschieben und die PWM-Register rechtzeitig füllen. Klappt nur, wenn du
die Interrupts geschickt nutzt und auf den Overhead sauberer
Programmierung verzichtest.
Florian schrieb:> Wenn ich einen Blick in das Datasheet von dem msp430f2619 werfe, finde> ich aber in den Tabellen nichts dazu.
Wie soll das auch im Datenblatt stehen? Die Samplerate ist die
Abspielgeschwindigkeit Deiner Audiodaten, und hängt von Dir bzw. dem die
Audiodaten erstellenden Programm ab.
Wenn das beispielsweise CD-Audio ist, beträgt die Samplerate 44.1 kHz.
Du musst dann dafür sorgen, daß mit diesem Takt die Daten an den DAC
übergeben werden.
Der DAC im 'F2619 ist dafür schnell genug, wenngleich er mit seinen 12
Bit Auflösung eher nicht für Audiozwecke geeignet ist.
Was aber hat das mit PWM zu tun? Wenn Du einen DAC verwendest, gibt es
keine PWM; die PWM ist ein Trick, einen DAC nachzuahmen. Wenn Du aber
einen hast (wie im 'F2619), dann musst Du keinen nachahmen.
Du solltest Dir vielleicht nochmal genau überlegen, was Du eigentlich
erreichen willst -- und womit.
Florian schrieb:> Rufus Τ. F. schrieb:>> Florian schrieb:>>> brauch ich da unbedingt eine samplingrate>>>> Natürlich. Das ist die Geschwindigkeit, mit der die Daten dem>> D/A-Wandler übergeben werden.>> Hallo Rufus, danke für die Antwort. Wenn ich einen Blick in das> Datasheet von dem msp430f2619 werfe, finde ich aber in den Tabellen> nichts dazu.
Der F2619 hat R2R-DACs. Die arbeiten theoretisch unendlich schnell,
allerdings haben die Eingangs- und Ausgangs-Puffer Grenzen (siehe
"settling time" und "slew rate" im Datenblatt), die du mit den
DAC12AMP-Bits auch anpassen kannst.
Danke für die Antworten Leute.
Noch einer schrieb:
> Du musst umgekehrt rechnen. Du nimmst die PWM Frequenz und die> gewünschte Audiofrequenz. Berechnest damit die mögliche Auflösung. Da> werden so 12 Bit herauskommen.
Ich hab das mal umgekehrt gerechnet, wie du mir das empfohlen hast.
Zum Verständnis: Die maximale PWM Frequenz ist ja die max. Clock
Frequenz (hier wenn man den DCO verwendet wären das 16 MHz) geteilt
durch 2, entspricht 8 MHz.
Diese 8 MHz teile ich nun durch meine gewünschte Audiofrequenz (ich nehm
mal die max. Hörbare Frequenz, dass wären 20 kHz) multipliziere das mit
2, wegen dem Gesetz nach Shannon für die Abtastrate und bekomme 40 kHz
heraus.
Teile ich nun 8 MHz / 40 kHz bekomme ich = 200 dann zieh ich mittels
logarithmus duales den exponenten und erhalte 7,6 Bit.
Rufus Τ. F. schrieb:
> Was aber hat das mit PWM zu tun? Wenn Du einen DAC verwendest, gibt es> keine PWM; die PWM ist ein Trick, einen DAC nachzuahmen. Wenn Du aber> einen hast (wie im 'F2619), dann musst Du keinen nachahmen.>> Du solltest Dir vielleicht nochmal genau überlegen, was Du eigentlich> erreichen willst -- und womit.
Danke für den Tipp. Mein Vorhaben war, ehe ich mir einen neuen MCU
kaufe, ich erstmal mittels PWM schauen bzw. hören wollte, wie die
Qualität des zu wiedergebenen Audio ist.
Clemens L. schrieb:
> Der F2619 hat R2R-DACs. Die arbeiten theoretisch unendlich schnell,> allerdings haben die Eingangs- und Ausgangs-Puffer Grenzen (siehe> "settling time" und "slew rate" im Datenblatt), die du mit den> DAC12AMP-Bits auch anpassen kannst.
Danke, werde ich mir behalten!
> Teile ich nun 8 MHz / 40 kHz
Anfangs warst du noch der Meinung, 4 kHz reichen dir. Und die Player mit
PWM haben alle Tiefpassfilter mit 3-4 KHz.
10-12 Bit und 4-8 kHz wird da als bester Kompromiss angesehen. Mehr
Qualität geht mit Mikrocontroller PWM nicht.
@noch einer
Danke nochmals für deine Antwort.
Vor ein paar Tagen bekam ich nun einen MSP mit integrierten DAC
ausgeliehen.
Ich habe auch soweit erfolgreich ein Summen mittels Array bzw. Schleife
wiedergeben können.
Da ich aber nun unterschiedliche Frequenzen wiedergeben muss, um eine
gescheite Melodie zu hören, bedarf es mehr Hintergrundwissen. Das
Internet habe ich auch schon nun seid paar Tagen durchfostert finde aber
keine nützlcihe Literatur die schritt-für-schritt erklärt wie man
mittels array verschiedene Melodien ausgibt.
Hier wollte ich mich nun an euch wieder wenden, ob ihr evtl ein paar
nützlcihe LINKs kennt, auf denen ich noch nicht gestoßen bin.
Florian schrieb:> Das> Internet habe ich auch schon nun seid paar Tagen durchfostert finde aber> keine nützlcihe Literatur die schritt-für-schritt erklärt wie man> mittels array verschiedene Melodien ausgibt.
Schritt 1) lade Deine Daten in das Array (am einfachsten eine WAV-Datei)
Schritt 2) lies das Array in einer Schleife aus und gib die Werte an den
DAC
Schritt 3) für eine andere Melodie, wiederhole Schritt 1 und 2
Zu welchem Schritt hast Du fragen und welche? Ich rate mal: Schritt 1
Lies in Wikipedia nach, wie eine wav-Datei aufgebaut ist. Lies auch über
MP3 und erkenne den erheblichen Zusatzaufwand zum decodieren.
@Planlos:
Ja danke für die Internetseite.
Rainer U. schrieb:
> Schritt 1) lade Deine Daten in das Array (am einfachsten eine WAV-Datei)> Schritt 2) lies das Array in einer Schleife aus und gib die Werte an den> DAC
Hallo Rainer, vielen Dank für die Hilfe. Das hab ich schon getan kam
leider nur unsinn heraus.
Hab dann nachdem ich hier wieder reingeschrieben habe, weiter das
Internet und das Forum hier durchforstet und stieß dann auf einen
älteren Thread wo jemand das gleiche mal vorhatte. Werde von dort den
Lösungsvorschlag mal ausprobieren, hoffe das es dann klappt.
Was ich bis jetzt habe ist das hier:
while((IFG1&OFIFG)!=0);// bis Oszillator eingeschwungen
58
59
BCSCTL1|=XTS;
60
61
// für MCLK: Wähle XT2 und Teiler 8
62
// für SMCLK: Wähle XT2 und Teiler 8
63
BCSCTL2|=SELM_2+DIVM_3+SELS+DIVS_3;
64
65
66
while(1)
67
{
68
setup();
69
70
thisNote=0;
71
72
delay(1000);
73
}
74
}
75
76
77
78
voidtone(unsignedintNote,unsignedintDuration)
79
{
80
DAC12_0DAT=Note*Duration;
81
}
82
83
84
85
voidsetup()
86
{
87
for(thisNote=0;thisNote<7;thisNote++)
88
{
89
intnoteDuration=1000/noteDurations[thisNote];
90
91
92
93
tone(melody[thisNote],noteDuration);
94
95
96
97
intpauseBetweenNotes=noteDuration*1.30;
98
99
delay(pauseBetweenNotes);
100
}
101
102
}
103
104
105
106
voiddelay(unsignedintm_sec)
107
{
108
while(m_sec--)
109
{
110
__delay_cycles(800);
111
}
112
}
Die Clock und die delay Funktion sind noch nciht richtig eingestellt,
dass muss ich noch machen.
Und die Noten länge, habe ich erstmal willkürlich gewählt.
Ach so, Du willst Töne einer Tonleiter ausgeben.. Das hat oben nicht so
ausgesehen. Bei Deiner Melodie fehlen 2x "a" :-)
Mach Dir eine "Note" für die Pause, dann kannst Du Töne und Pausen
gleich behandeln und zwischen 2 Tönen eine Pause machen oder auch nicht.
Dann bau Dir erstmal eine Funktion, die einen Notenwert als Argument
akzeptiert und diesen ausgibt. Evtl. reicht es Dir schon, wenn Du den
Port langsamer oder schneller ein- und ausschaltest.
Also prinzipiell wenn Du 2 Timer hast:
einen Timer(1) stellst Du mit der Notenlänge,
einen zweiten (2) mit der Periodendauer.
In der ISR on Timer2 schaltest Du den Ausgabepin um, in der ISR vom
Timer1 steuerst Du, wie lang der Ton sein soll und machst ihn dann
irgendwann aus.
Damit bekommst Du "Rechteck-Töne", wenn Du das beherrscht, fällt Dir
alles weitere leichter.
@Rainer:
Danke für den Tipp den werde ich gleich mal ausprobieren.
Rainer U.:
> Ach so, Du willst Töne einer Tonleiter ausgeben..
Naja fürs erste, da mein ersteres Vorhaben, in einem Array den Hexcode
speichern und dann per DAC ausgeben, nicht funktioniert hat und ich dann
den Tipp nachgehen wollte.
Mein erstes Ziel liegt noch darin, dass ich eine beliebe WAV Audio Datei
mittels Programm in Hexadezimal umwandel, und das wiedergebe.
Florian schrieb:> dass ich eine beliebe WAV Audio Datei> mittels Programm in Hexadezimal umwandel
Die Werte stehen da schon "hexadezimal" drin und müssen gar nicht
umgewandelt werden - das ist das einfache an einer WAV-Datei.
@Rainer:
Ich hab das jetzt nicht so ganz gemacht wie du es mir geschildert hast,
funktioniert aber, auch wenn die Melodie etwas zu schnell abgespielt
wird.
Und zwar dauert eine Melodie ca. 75ms, statt den gewünschten 15sek.
Kommt aber noch!
Hier mein Code bisher.
Die Notenlänge hab ich noch nicht implementiert.
// alle meine Entchen: c d e f g g a a a g a a a g f f f f e e d d d d c
153
154
155
voidsetup(void)
156
{
157
if(dieseNote<laenge_melody)
158
{
159
switch(melody[dieseNote])
160
{
161
casea:TACCR0=a;break;
162
casec:TACCR0=c;break;
163
cased:TACCR0=d;break;
164
casee:TACCR0=e;break;
165
casef:TACCR0=f;break;
166
caseg:TACCR0=g;break;
167
168
default:TACCR0=R;break;
169
}
170
}
171
else
172
{
173
dieseNote=0;
174
delay(10);
175
}
176
}
177
178
179
voiddelay(unsignedintm_sec)
180
{
181
while(m_sec--)
182
{
183
__delay_cycles(8000);// 1000 for 1MHz
184
}
185
}
Ich hab statt ein Rechteck, einen Sinus benutzt den ich wie man sieht in
einem Array abgelegt habe.
Bin für Jedermann's Vorschläge dankbar, wie ich nun sinnvollerweise die
Notenlänge programmiere, damit da auch was vernünftiges heraus kommt.
Ok habs hinbekommen, endlich höre ich was gescheites!
Hab einfach den zweiten array mit eingebunden, damit ich pro Note nicht
nur eine Periode bekomme, sondern bezüglich der Notenlänge X-viele
Perioden ich ausgebe.
Wenn jemand weitere Anregungen hat, wie man den letzten Schritt evtl
eleganter gestaltet hätte bzw. andere Stellen, bin ich für jeden
Dankbar.
Florian schrieb:> Ok habs hinbekommen, endlich höre ich was gescheites!
Na fein!
Der Rhythmus sieht etwas schräg für mich aus, und der Text hat
Migrationshintergrund? ("Alle Meine Entchen schwimmem auf See") ? :-)
Rainer U. schrieb:
> Der Rhythmus sieht etwas schräg für mich aus, und der Text hat> Migrationshintergrund? ("Alle Meine Entchen schwimmem auf See") ? :-)
Danke Rainer, hab ich verbessert :)
Nach einer längeren Pause, da ich noch an anderen Sachen beschäftigt
war, wollte ich ab heute weiter machen.
So mein Vorhaben ist nun der, dass ich gern eine wav Datei die ich
vorher in Hex umgewandelt habe, abzuspielen. Hab mich auch ein bisschen
über die Struktur des wave Dateiformat eingelesen.
Und ich mein Rainer du hast mir ja schon geschildert, dass es kein
großer Akt ist, eine wav Datei abzuspielen. Einfach die Werte in ein
Array speichern und per DAC ausgeben.
Die ? ? ? schrieb:
> Kannst du bitte einmal erklären, wie das Ganze funktioniert? DAC, Timer,> Interrupt, ..., Sinustabelle, ...
Nun ja, ich gebe dank Interrupt die Freq aus, die gerade im
Array(melody) dran ist.
Und das geschiet mittels eines Sinus, den ich aus dem Array abspiele.
Da aber der Sinus nicht nur einmal durchlaufen wird, sonst wäre ja der
Ton paar ms lang, habe ich die Notenperiode mit eingefügt. Im Array
'interval'.
So und da schaut das Programm, wie oft nun Sinuse abgespielt werden
sollen!
Das Herzstück ist natürlich der Timer. Der definiert, wie schnell das
Prog in das Interrupt reinspringt. Und das wie oft der reinspringt, ist
abhängig von der jeweiligen Freq, die gerade dran ist.
Florian schrieb:> Nun ja, ich
...
habe nicht das programmiert, was ich beschrieben habe.
In der Timer ISR wird immer eine vollständige Periode durchlaufen. Dann
wird die nächste Frequenz eingestellt, wieder für eine Periode, usw.
Deine Töne sind alle unter 500Hz. Was für ein Audio Stück soll das
werden?
Mein Tipp:
1. Töne von 1kHz bis mind. 7kHz auswählen
2. Sinustabelle verkleinern
3. Tastung (Timer Intervall) an höchsten Ton anpassen
4. Notenlänge berücksichtigen. Immer als vielfaches der aktuellen
Periode/2.
Die ? ? ? schrieb:
> habe nicht das programmiert, was ich beschrieben habe.
Jain. Ich hab nachdem ich den Beitrag mit dem Code gepostet habe,
geschrieben, dass ich es danach hinbekommen habe.
Und im neuen Code habe ich das Array 'Interval', was einfach so da steht
berücksichtigt.
Meine Beschreibung belief sich auf die neueste Version meines Programms.
Die ? ? ? schrieb:
> In der Timer ISR wird immer eine vollständige Periode durchlaufen. Dann> wird die nächste Frequenz eingestellt, wieder für eine Periode, usw.
Das stimmt, halt für die Version des Programmcodes den ich da gepostet
habe.
Die ? ? ? schrieb:
> Deine Töne sind alle unter 500Hz. Was für ein Audio Stück soll das> werden?
Ich wollte Beispielsweise 'Alle meine Entchen' spielen. Und da hab ich
halt die Noten im Internet für die Melodie gefunden. Gesucht, welche
Frequenzen die Noten ergeben und dann im Programm übernommen.
Die ? ? ? schrieb:
> Mein Tipp:> 1. Töne von 1kHz bis mind. 7kHz auswählen
Kannst du mir den Schritt etwas genauer erklären, wieso das sinnvoller
ist?
Die ? ? ? schrieb:
> 2. Sinustabelle verkleinern
Ich hab geplant, einen viertelsinus zu implementieren, dass ist noch
besser als Werte vom Array zu lesen.
Die ? ? ? schrieb:
> 4. Notenlänge berücksichtigen. Immer als vielfaches der aktuellen> Periode/2.
Meinst du hier mit Periode/2 eine achtelperiode? Wie die in dem Array
'interval' zu finden ist?
Das hab ich dann in der neuen Version, wenn ich dich so verstanden habe,
schon eingebaut.
So sieht meine neue Unterfunktion 'setup' aus:
Ich hab nun mittels eines wav to c converter, ein sehr großes Array
erstellt.
Ein Teil des Arrays in meinem Programm kopiert, dass widerum die
einzelnen Werte ans DAC übermittelt.
Hab die .wav Datei auf 8000Hz Sampling Rate und 8Bit Auflösung mittels
Audacity gewandelt.
Hab ebenfalls im Programm den Timer so eingestellt, dass er nach 125us -
was 8000Hz entspricht - in die ISR reinspringt und von dort einen Wert
im Array an den DAC weiter gibt.
Das Programm ist sehr simpel und hat keine Sinusfunktion, wie das
Programm davor.
Meine Frage nun, wie berückstichtige ich die 8Bit Auflösung bzw.
allgemein die Auflösung einer Musikdatei, wenn ich mit uC programmiere
wo ich Audiodateien ausgeben möchte.
Und ist das Vorgehen so richtig, was ich bis jetzt geschildert habe?
Leider kann ich noch nicht viel hören, da der Flash-Speicher einfach zu
klein auf dem uC ist.
Mein nächstes Vorhaben wird sein, eine SD-Karte dran zu schließen.
Du musst dich mal entscheiden, was du willst. Erst hast du einzelne
Noten hintereinander gehängt und jetzt geht es mehrfach überlagerte Töne
(nix mehr einfacher Sinus).
Die ? ? ? schrieb:
> Du musst dich mal entscheiden, was du willst. Erst hast du einzelne> Noten hintereinander gehängt und jetzt geht es mehrfach überlagerte Töne> (nix mehr einfacher Sinus).
Hi, danke für deine einzelnen Beiträge. Entschieden habe ich mich schon.
Und zwar habe ich ja in meinem allerersten Beitrag ja geschrieben, dass
ich gern eine .wav Datei ausgeben möchte.
Da mir aber noch das Wissen zu fehlte, wie ich mit Sampling Rate,
Auflösung und generell mit Frequenzen arbeite, wurde mir hier im Forum
empfohlen, Töne anhand einer Notentabelle mittels einer Sinustabelle
auszugeben. Und die Idee gefiel mir halt, dass ich dies auch tat.