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 :)
Hi Du willst double-buffering verwenden. D.h. du hast zwei Buffer. Einer wird immer befüllt während der andere abgespielt wird. Matthias
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.
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.
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
@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?
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
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
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.