Forum: Mikrocontroller und Digitale Elektronik Mp3 Wiedergabe - Jitter.. sinnvoller Code?


von Manuel Fegerl (Gast)


Lesenswert?

Hallo euch allen :)

Ich stehe vor dem folgenden Problem:

Mein MP3-Player (mit AT89C51SND1C) funktioniert mittlerweile ganz gut..
er gibt MP3-Dateien von einer FAT32-formatierten Festplatte aus und man
hört das am Audioausgang.. so wie sichs gehört :)

Leider treten regelmäßig Jitter auf.. es scheint nun so dass einfach
der Datenstream nicht schnell genug ist.. vor allem beim wechsel des
Clusters.

Derzeit funktioniert das ganze so:
MP3-Interrupt -> Buffer von 512 Byte wird aufgebraucht, wenn leer ->
Buffer von der HDD neu aufgefüllt.. das geht scheinbar schnell genug,
solange man sich im selben Cluster befindet.

Muss ein neuer Cluster errechnet werden, scheint es so als wäre der
FAT32 Code etwas zu lange, wodurch dies etwas zu lange dauert.. es
entsteht ein Jitter (Kurzes Störgeräusch.. etwa alle 2-3s, was in etwa
einem Cluster entspricht).

Nun bin ich auf der Suche nach einer Lösung für dieses Problem.. die
Lösung die mir als erstes einfiel funktioniert leider nicht

(Da der MP3-Player ansich nur über die Interrupts funktioniert, könnte
man über das Hauptprogramm die neuen Clusternummern quasi
vorberechnen.. dies funktioniert jedoch leider nicht, da in der
berechnung auch Festplattenzugriffe sind, d.h. sie würden sich mit dem
MP3-Dekoder (sobald dieser wieder aktiv werden will) überschneiden..)

Bin gespannt was euch dazu einfällt.. vielen Dank schon einmal :)

von Matthias (Gast)


Lesenswert?

Hi

Du willst double-buffering verwenden. D.h. du hast zwei Buffer. Einer
wird immer befüllt während der andere abgespielt wird.

Matthias

von Benedikt (Gast)


Lesenswert?

Liest du vor dem neuen Cluster erst die FAT von der Festplatte ?
Dieser abwechselnde Zugriff leert vermutlich den Puffer der Festplatte,
so dass diese immer zwischen beiden Stellen hin und her springen muss,
was einige ms dauern kann.
Abhilfe: Viel SRAM verwenden, und einen Teil der FAT da
zwischenspeichern. Wenn die Festplatte nicht, oder nur gering
fragmentiert ist, funktioniert das super.

von ape (Gast)


Lesenswert?

Einfach ein zusätzliches SRAM an den Controller und dann dem Decoder
einen ausreichend großen Buffer spendieren, 16kB Buffer sollten da
schon reichen. Der Interrupt der den Decoder fütter bedient sich nur
aus diesem Buffer. Der Buffer wird dann regelmäßig aus der Mainloop
heraus gefüttert. Das hat den Vorteil, das keine Festplattenzugriffe
aus einem Interrupt heraus geschehen, die sich dann mit andern in die
Quere kommen könnten (z.B. wenn man ein neues Lied auf der Festplatte
sucht, während eines im Hintergrund abgespielt wird)
Ein 16kB großer Buffer reicht im Worstcase (320kbps) 0,4s lang. Wenn du
einen einigermaßen vernünftigen Code hast, der an keiner Stelle blockt,
wenn zum Beispiel auf eine Eingabe gewartet wird, sollte das locker
reichen.

von Hagen (Gast)


Lesenswert?

Ich stimme da ape zu, am besten einen großen Ringbuffer der immer in
Happen von 512 Bytes gefüllt wird. Wenn du den Buffer zb. 8Kb groß
machst so hast du 16 solcher 512 Bytes Blöcke. Du kannst also 15 Buffer
schon im vorhinein laden. Desweiteren meine ich auch das der MP3 Dekoder
über Interupts gefüttert werden muß. Der Buffer wird aber in der
Mainloop deiner Anwendung befüllt, durch Polling wenn der nächste 512
Bytes Abspiel-Buffer fertig ist. Das hat, wie Ape schon sagte, den
Vorteil das die ISR ungestört arbeiten kann.

Gruß Hagen

von Manuel Fegerl (Gast)


Lesenswert?

@Benedikt: ja genau.. das dürfte das problem sein

Die Idee mit dem zusätzlichen Ram ist ansich gut, leider jedoch nicht
verwirklichbar.. Die Hardware ist soweit fertig und soll nicht mehr
verändert werden.. außerdem gibts keine freien Ports die verwendet
werden könnten..

1,5K XRAM habe ich in etwa zur verfügung (entspricht 3 sektoren).. also
leider nicht sehr viel

ich könnte also eventuell diese 1,5k als ringspeicher mit 3 sektoren
verwenden.. sobald ein sektor komplett gelesen wurde, könnte das
hauptprogramm nachschub anfordern... fraglich jedoch ob dies sinnvoll
ist?

eine andere möglichkeit wäre, dass ich die clusternummern schon im
vorraus herausfinde und zwischenspeichere.. jede clusternummer ist 4
byte groß, somit sollten sich einige in 1,5k ausgehen..

wie seht ihr das?

von Hagen (Gast)


Lesenswert?

Du machst es jetzt so das du nur einen Buffer hast. Ist der komplett
abgespielt lädst du erst von der FAT die nächsten Daten in diesen
Buffer nach, richtig ?

Baue 2 Buffer, sobald der 1. Buffer abgespielt wird lädst du in den 2.
Buffer die nächsten Daten. Danach Buffer 2 abspielen und in Buffer 1
die Daten laden.

Das sollte auf alle Fälle besser als deine jetzige Methode arbeiten
(falls ich dich richtig verstanden habe)

Gruß hagen

von Manuel Fegerl (Gast)


Lesenswert?

ja, diese idee kam mir auch schon..

ich füllte dafür 2 buffer zunächst voll an.. sobald der erste gelesen
ist wird er neu aufgefüllt...

jedoch funktionierte das nicht einwandfrei.. mir ist noch unklar
wieso.. werd das nocheinmal verfolgen

von Manuel Fegerl (Gast)


Lesenswert?

Hm.. das ganze erweist sich als recht schwierig für mich...

Bislang funktioniert das ganze nicht so wie ich mir das vorstelle..
vielleicht hat wer nen denkansatz für mich..

Ich machs derzeit so:

Die Funktion die daten vom IDE-Bus bringt alterniert automatisch
zwischen Buffer[0] und [1]. Bevor der MP3-Dekoder aktiviert wird, wird
diese 2x geladen, um so beide Buffer einmal anzufüllen.

Zusätzlich exisitieren die Hilfs-bits "needsector" und
"readfrombuffer"

wird nun ein Buffer komplett gelesen wird needsector auf 1 gesetzt.
Außerdem wird readfrombuffer getoggelt, und die feldvariable (die auf
das gewünschte byte zeigt auf 0 zurückgesetzt).

Das Hauptprogramm prüft laufend ob needsector=1 ist, und falls ja
startet es die IDE-Daten-Funktion um somit den Buffer neu aufzufüllen..
anschließend wird needsector wieder 0.

Für den Notfall: sobald die MP3-Funktion erkennt dass der bytezähler
größer als 400 ist, wärend gleichzeitig needsector immer noch auf 1
ist, wird der mp3-dec-interrupt disabled, und mit break; abgebrochen..
sollte somit also im hauptprogramm weitermachen, welches nachdem der
nächste sektor gelesen wurde, den mp3-decoder wieder aktiviert.

Leider funktioniert das ganze so nicht :(

Da ich über keine direkte debugfunktion am Chip verfüge ist das ganze
schwer zu erfassen.. ich kann mir also nur hin und wieder informationen
am display ausgeben.. diese haben folgendes gezeigt:

Beim Abbruch ist needsector = 0
Der Abbruch erfolgt bei Byte 509 eines Sektors.. also mittendrin
9 erfolgreiche Datenanforderungen wurden durchgeführt bevor der Crash
passiert

Thx für Tipps.. vielleicht weiß ja jemand überhaupt eine elegantere
methode

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.