Hallo, ich habe ein Problem in meinem selbstgebauten MP3-Player: Ich verwende einen ATMEGA128 mit 8Mhz, eine SD-Karte und einen VS1053 MP3-Dekoder von VLSI. Die Wiedergabe von MP3s über die SPI-Schnittstelle von SD-Karte zum MP3-Dekoder funktioniert wunderbar. Er streamt die gesamte Datei zum VS1053 und an den angeschlossenen Cinch-Ausgängen höre ich auch die Musik in guter Qualität. Das µC-Programm sucht die DAtei im FAT16-System, liest jeweils einen 512 Byte-Block der Datei von der SD-Karte, speichert ihn in einem Puffer zwischen und schreibt die 512 Byte in 16x 32-Byte-Häppchen in den VS1053. Das Problem ist, das beim abspielen unangenehme Klick-Geräusche unregelmässig aber sehr schnell während der gesamten Wiedergabe zu hören sind . Ich habe nicht die geringste Ahnung, was ich dagegen tun soll, ich habe schon so ziemlich alles ausprobiert, von anderen Lautsprechern über unterschiedliche Bitraten und Abtastraten. Die Schaltung und das Layout (Masseflächen, 100nF usw.)entspricht der aus dem Datenblatt des MP3-Dekoders, . Kann mir jemand helfen?? MfG Christian H.
Ich denke nicht, das es ein analoges Problem ist (Lautsprecher, Verstärker o.ä.). Es könnte sein, dass der Datenstrom abreißt.
Ich denke auch, daß der Datenstrom abreißt. Du kannst in einem Register abfragen, wie voll Dein Puffer ist. Mach eine LED an, falls weniger als ca. 64 Byte drin sind, und schau mal ob sie immer beim Knacken aufblitzt..
Ich würde auch auf ein abreißen den Datenstroms tippen. Lädst du die nächsten 512 Bytes erst nach, wenn du des letzte Byte der aus dem Puffer versendet hast? In diesem Fall könntest du ein sleep einbauen und man Wert herumspielen. Falls dies der Grund ist, müssten durch das Sleep die Aussetzer größer werden.
Martin wrote: > Ich denke nicht, das es ein analoges Problem ist (Lautsprecher, > Verstärker o.ä.). Es könnte sein, dass der Datenstrom abreißt. Sollte der Datenstrom abreißen, so ließe sich dieser Effekt mit der Wahl deutlich geringerer Bitraten (z.B. 96kBit/s) reduzieren oder vollständig verhindern. Ändert sich denn tatsächlich bei niedrigeren Bitraten die Häufigkeit der Klicks? Was natürlich auch möglich ist, sind Lesefehler von der SD-Karte, die unregelmäßig unter bestimmten Umständen auftreten. Bist Du sicher, dass Dein FAT-Code korrekt ist? Vielleicht gibt es Probleme z.B. beim Clusterwechsel?
Ich hatte solche Klicks auch in meinem MP3-Player beim Abspielen von USb-festplatten. Es lag eindeutig am Datenstrom. Beim Wechsln der Cluster wurde die Festplatte plötzlich unerwartet langsam. Da hilft nur ein größerer Zwischenpuffer.
Hallo, also wenn deine SPI Schnittstelle mit 4Mhz(max. bei 8Mhz Takt vom Atmega), glaube ich nicht das der Datenstrom nicht ausreicht. Ich hatte damals auch die 512byte in den Atmega gechrieben und anschliessend an den VLSI geschickt. Nebenbei noch Display mit Zeit anzeige und lalalala gemacht. Warteste du denn auch immer auf das DREQ vom VLSI beim senden beiner 32byte Bröckchen? Ansonsten wäre Code und Platine interressant. GRUSS
Ich habe jetzt mal die MP3 von 192kbit/s auf 24kbit/s verändert, die Klicks sind immer noch da, aber deutlich seltener. Zur Info: Ich verwende die FAT-Implementierung von Ulrich Radig, wobei ich beim Lesen eines Dateisektors eine Funktion hinzugefügt habe , die von der SD-Karte 512 Byte direkt in ein Array Schreibt. Wie erkenne ich denn, ob der Cluster-Wechsel schuld daran ist?? Hier die Funktion, die von der SD-Karte liest, sie wird vom Fat-System bei jedem auslesen eines Datei-Blocks gerufen: unsigned char sd_read_data_sector(unsigned long addr) //###################################################################### ###### { int a=0; //Commando 16 zum lesen eines Blocks von der SD - Karte unsigned char cmd[] = {0x51,0x00,0x00,0x00,0x00,0xFF}; /*Die Adressierung der SD-Karte wird in Bytes angegeben, addr wird von Blocks zu Bytes umgerechnet danach werden diese in das Commando eingefügt*/ addr = addr << 9; //addr = addr * 512 cmd[1] = ((addr & 0xFF000000) >>24 ); cmd[2] = ((addr & 0x00FF0000) >>16 ); cmd[3] = ((addr & 0x0000FF00) >>8 ); //Sendet Commando cmd mit entsprechender Sector-Adresse an SD-Karte, dort wird Chip Select auf low gesetzt if (sd_write_command (cmd) != 0) { return; } //Wartet auf Start Byte von der MMC/SD-Karte (FEh/Start Byte) while (spi_read_byte() != 0xfe) { }; while(a<512) { // Schreibe Daten von SD-Karte in globalen Puffer aus Performancegründen 16 mal 32 dataptr[a++] = spi_read_byte(); dataptr[a++] = spi_read_byte(); dataptr[a++] = spi_read_byte(); dataptr[a++] = spi_read_byte(); dataptr[a++] = spi_read_byte(); dataptr[a++] = spi_read_byte(); dataptr[a++] = spi_read_byte(); dataptr[a++] = spi_read_byte(); dataptr[a++] = spi_read_byte(); dataptr[a++] = spi_read_byte(); dataptr[a++] = spi_read_byte(); dataptr[a++] = spi_read_byte(); dataptr[a++] = spi_read_byte(); dataptr[a++] = spi_read_byte(); dataptr[a++] = spi_read_byte(); dataptr[a++] = spi_read_byte(); dataptr[a++] = spi_read_byte(); dataptr[a++] = spi_read_byte(); dataptr[a++] = spi_read_byte(); dataptr[a++] = spi_read_byte(); dataptr[a++] = spi_read_byte(); dataptr[a++] = spi_read_byte(); dataptr[a++] = spi_read_byte(); dataptr[a++] = spi_read_byte(); dataptr[a++] = spi_read_byte(); dataptr[a++] = spi_read_byte(); dataptr[a++] = spi_read_byte(); dataptr[a++] = spi_read_byte(); dataptr[a++] = spi_read_byte(); dataptr[a++] = spi_read_byte(); dataptr[a++] = spi_read_byte(); dataptr[a++] = spi_read_byte(); } a=0; //SD-Karte deaktivieren sd_disable(); return; } Zum Finden der Datei im FAT-System und Schreiben der Daten aus dem Array in den MP3-Dekoder gibt es folgende Funktion: void play_file(unsigned char *File_name) //###################################################################### ###### { //play=1; #if DEBUG_Mode usart_write("\r\nButton gedrueckt - Abspielmodus gestartet \r\n"); #endif int Cluster; unsigned long Size; unsigned char Dir_Attrib ; int x=0; int anzahl_datei_sektoren=0; sd_read_csd(Buffer); // Auf Native-Mode setzen,Stream Mode Mp3WriteRegister(SCI_MODE, 0x08, 0x40); // Suche auf SD-Karte im Root-Verzeichnis nach Datei usart_write("\r\n Suche nach Datei %s",File_name); // Puffer Array löschen flush_buffer(); if (fat_search_file((unsigned char *)File_name,&Cluster,&Size,&Dir_Attrib,Buffer) == 1) { usart_write("\r\n Datei %s gefunden",File_name); usart_write("\r Spiele Datei : %s ab",File_name); anzahl_datei_sektoren=Size/512; // Anzahl der Cluster, die von dieser Datei belegt werden for (int b = 0;b<anzahl_datei_sektoren;b++) // Wenn die Datei gefunden, lese die Sektoren aus { #if DEBUG_Mode usart_write("\r Schreibe Block %i ab",b); #endif fat_read_file_sector (Cluster,Buffer,b); // ein Sector wird in dataptr geschrieben mp3_data_enable(); // MP3-Modul bereit für Datenempfang while(x <512) // Für bessere Performance werden 16 * 32 Byte an VS1053 übertragen { spi_write_byte(dataptr[x++]); spi_write_byte(dataptr[x++]); spi_write_byte(dataptr[x++]); spi_write_byte(dataptr[x++]); spi_write_byte(dataptr[x++]); spi_write_byte(dataptr[x++]); spi_write_byte(dataptr[x++]); spi_write_byte(dataptr[x++]); spi_write_byte(dataptr[x++]); spi_write_byte(dataptr[x++]); spi_write_byte(dataptr[x++]); spi_write_byte(dataptr[x++]); spi_write_byte(dataptr[x++]); spi_write_byte(dataptr[x++]); spi_write_byte(dataptr[x++]); spi_write_byte(dataptr[x++]); spi_write_byte(dataptr[x++]); spi_write_byte(dataptr[x++]); spi_write_byte(dataptr[x++]); spi_write_byte(dataptr[x++]); spi_write_byte(dataptr[x++]); spi_write_byte(dataptr[x++]); spi_write_byte(dataptr[x++]); spi_write_byte(dataptr[x++]); spi_write_byte(dataptr[x++]); spi_write_byte(dataptr[x++]); spi_write_byte(dataptr[x++]); spi_write_byte(dataptr[x++]); spi_write_byte(dataptr[x++]); spi_write_byte(dataptr[x++]); spi_write_byte(dataptr[x++]); spi_write_byte(dataptr[x++]); while (!(PINB & (1<<mp3_dreq))) ; } mp3_data_disable(); x=0; } } usart_write("\r\n Datei : %s abgespielt",File_name); send_zero(); Mp3SoftReset(); //play=0; } Vielleicht hilft euch das ja weiter Mfg Christian
Christian Har wrote:
> Zur Info: Ich verwende die FAT-Implementierung von Ulrich Radig, wobei
Das hatte ich befürchtet.
Diese FAT-Implementierung ist ohne weitere Optimierungen nicht so gut
für einen kontinuierlichen Datenstrom (=MP3s abspielen) geeignet.
Das Problem liegt hier (Ausschnitt aus der aktuellen Quelltextdatei von
U. Radig):
1 | //############################################################################
|
2 | //Lesen eines 512Bytes Blocks von einem File
|
3 | void fat_read_file (unsigned int Cluster,//Angabe des Startclusters vom File |
4 | unsigned char *Buffer, //Workingbuffer |
5 | unsigned long BlockCount) //Angabe welcher Bock vom File geladen |
6 | //werden soll a 512 Bytes
|
7 | //############################################################################
|
8 | {
|
9 | //Berechnung des Blocks aus BlockCount und Cluster aus FATTabelle
|
10 | //Berechnung welcher Cluster zu laden ist
|
11 | |
12 | unsigned long Block = (BlockCount/cluster_size); |
13 | |
14 | //Auslesen der FAT - Tabelle
|
15 | fat_load (Cluster,&Block,Buffer); // !!! PROBLEM !!! |
16 | Block = ((Block-2) * cluster_size) + cluster_offset; |
17 | //Berechnung des Blocks innerhalb des Cluster
|
18 | Block += (BlockCount % cluster_size); |
19 | //Read Data Block from Device
|
20 | mmc_read_sector (Block,Buffer); |
21 | return; |
22 | }
|
Diese Funktion liest ja bekanntlich einen Sektor von der SD-Karte. Allerdings wird hier vor dem Lesen JEDES Sektors erstmal die FAT-Tabelle ausgelesen (Funktion fat_load(...)). Dies führt zu einer ziemlich bescheidenen Performance. Denn eigentlich müsste man nur aus der FAT-Tabelle lesen, wenn man das Ende eines Clusters erreicht hat, da man dann erst das Folgecluster bestimmen muss. In Deinem Fall führt das also dazu, dass beim Lesen eines Sektors der MP3-Datei erstmal 1 bis x Sektoren aus der FAT-Tabelle gelesen werden, um so äußerst ineffizient den zu lesenden Sektor zu bestimmen. Ein einfacher Optimierungsansatz wäre hier, die aktuelle Sektornummer innerhalb des aktuellen Clusters global zu speichern und erst die FAT-Tabelle zu lesen, sobald die aktuelle Sektornummer == Anzahl Sektoren pro Cluster ist. gruß daniel
Hallo, außerdem würde ich deinem play_file, die ganzen USART Geschichten mal, CSD-Register auslesen, sowie bei jeder Übertragung den Modus von deinem VLSI einzustellen, rausnehmen. Das while (!(PINB & (1<<mp3_dreq))) , würde ich an den Anfang der Schleife setzen nicht ans Ende, ansonsten schiesst du eventuell 32bytes in den Wind. Und was soll das MP3SoftReset() machen ? Gruss
Ich habe die fat_read_file folgendermaßen verändert, aber die Clicks sind immer noch da. Ich habe, wie Daniel P. vorgeschlagen hat, eine globale Variable einfügt, die von 0 bis cluster_size -1 zählt und nur einen neuen Cluster aus der FAT lädt, wenn die clustersize überschritten wird. Sollten die Clicks denn nicht auch mit konstantem Abstand auftreten, wenn es um Clusterwechsel geht?? Sie kommen ein paar dutzend mal pro sekunde, aber eher in unregelmäßigen abständen. @ Fubu: Die von dir angesprochenen Dinge werden nur einmalig aufgerufen, und nicht ständig beim abspielen der MP3. Sie dürften also keinen Einfluss haben. Hier meine Änderung: //###################################################################### ###### //Lesen eines 512Bytes Blocks von einem File void fat_read_file_sector (unsigned int Cluster,//Angabe des Startclusters vom File unsigned long BlockCount) //Angabe welcher Block vom File geladen //werden soll a 512 Bytes //###################################################################### ###### { //Berechnung des Blocks aus BlockCount und Cluster aus FATTabelle //Berechnung welcher Cluster zu laden ist unsigned long Block = (BlockCount/cluster_size); //Auslesen der FAT - Tabelle if(aktueller_cluster_block > cluster_size-1) { fat_load (Cluster,&Block,Buffer); } Block = ((Block-2) * cluster_size) + cluster_offset; //Berechnung des Blocks innerhalb des Cluster Block += (BlockCount % cluster_size); //Read Data Block from Device sd_read_data_sector (Block); aktueller_cluster_block++; return; }
Hier mal eine einfache Maßnahme um zu überprüfen, ob Dein Klicken tatsächlich seine Ursache im FAT-System hat: 1.) SD-Karte formatieren 2.) einen einzigen song auf die karte kopieren. Da vorher alle sektoren frei waren, sollte der Song nun in linear zusammenhängenden Sektoren auf der Karte abgespeichert sein. 3.) Wie gewohnt den StartCluster (und damit den ersten Sektor) des Songs über die FAT-Funktionen von U. Radig bestimmen. 4.) Song abspielen, dabei aber nicht die FAT-Funktion verwenden, sondern nach dem Lesen des Liedstartsektors einfach direkt den nächsten Sektor lesen und abspielen. Ich hoffe das war so irgendwie verständlich!? Sollte das Klicken danach nicht mehr bestehen, ist tatsächlich eine weitere Optimierung der FAT-Funktionen nötig. Andernfalls solltest Du vielleicht mal Deine Schaltung posten, die SPI-Frequenzen überprüfen, mal die Übertragungsrate SD-Karte -> µC messen usw... Die von mir bereits vorgeschlagene Optimierung von U.Radigs FAT war nur ein Anfang, sollte allerdings eigentlich schon ein flüssiges Abspielen der MP3s ermöglichen... Die Bestimmung des Folgeclusters ist in der FAT-Library aber ebenfalls nicht besonders effizient gelöst und kostet eine Menge Zeit. Auch hier kann durch eine globale Variable, welche sich den aktuellen Cluster merkt, ein deutlicher Performancegewinn erzielt werden.
Falls genug RAM vorhanden kann man die cluster auch vor dem laden der datei heraus finden und in einen buffer ab legen.
Lupin wrote: > Falls genug RAM vorhanden kann man die cluster auch vor dem laden der > datei heraus finden und in einen buffer ab legen. Das wäre natürlich die eleganteste Lösung. Bei FAT32 kommen da allerdings schnell einige kB zusammen. Eine Minute MP3-Material mit 320kBit/s entspricht etwa 4800 Sektoren, bei einer Sektorzahl pro Cluster von 32 wären das 150 Cluster pro Minute. Für einen 4 Minuten-Song wären das bereits 2400 Bytes an Clusternummern, die man precachen müsste. Klar, bei 4 Minuten ginge das noch, aber es gibt ja auch längere Songs...
Es sollte auch ohne diese aufwendigen Tricks ausreichend schnell sein. Das Dateisystem von Radig ist etwas dumm für mp3s, das stimmt. Ich musste da einiges umbiegen, da in der alten Version die ich damals hatte, bei jedem Sector read von Dateianfang aus die Clusterchain neu gesucht wurde. Die erste Minute jeder Datei liefen problemlos, danach wurde die Ausgabe immer stottriger. Selbst mit einer verbesserten Clusterverfolgung kommt das Dateisystem bei weitem noch nicht an das von ELM Chan ran. Damit habe ich auf einem dsPIC mit 13MHz SPI Takt schon durchschnittliche Datenraten in der Größenordnung von rund 1MByte/s erreicht, mit Festplatten im langsamen PIO Modus sogar >2MByte/s. Auf einem AVR sollte es nicht sehr viel langsamer sein. Mein mp3 Player mit VS1011 und dem modifizierten Radig Dateisystem macht zumindest auch bei 320kbit/s keine Probleme, und da steckt nur ein mega8 mit internem Takt drin...
Daniel P. wrote: > Hier mal eine einfache Maßnahme um zu überprüfen, ob Dein Klicken > tatsächlich seine Ursache im FAT-System hat: > > 1.) SD-Karte formatieren > 2.) einen einzigen song auf die karte kopieren. Da vorher alle sektoren > frei waren, sollte der Song nun in linear zusammenhängenden Sektoren auf > der Karte abgespeichert sein. > 3.) Wie gewohnt den StartCluster (und damit den ersten Sektor) des Songs > über die FAT-Funktionen von U. Radig bestimmen. > 4.) Song abspielen, dabei aber nicht die FAT-Funktion verwenden, sondern > nach dem Lesen des Liedstartsektors einfach direkt den nächsten Sektor > lesen und abspielen. > So jetz hab ich habe ich mal, wie von Daniel P vorgeschlagen, eine Datei auf die SD-Karte gepackt und einfach die Sektoren nacheinander gestreamt. Ich kann die MP3 hören, nur leider sind die Klicks immer noch da. Das lässt ja wohl darauf schliessen, daß es sich auch um die Hardware handeln kann. Anbei mal mein Schaltplan: Zur Info, ich habe das STK525, für das ich ein erweiterungboard gebaut habe, das über einen 40Poligen Connector mit dem STK verbunden wird. Der Audioausgang geht über zwei Cinch Buchsen.
Zeig mal nen Bild von deinem Aufbau.. entweder die Übertragung vno µC zu VS ist mistig oder von SD-> µC. Mache mal nen Foto vom gesamtaufbau.. MFG
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.