Działająca biblioteka C do VS1003?

Próbuję właśnie uruchomić urządzenie posiadające sprzętowy dekoder MP3 VS1003. Urządzenie wykonałem w dwóch wariantach: z układem PIC32MX795F512L oraz szesnastobitowym układem PIC24 (zacząłem od tego drugiego, ale w międzyczasie postanowiłem przenieść projekt na układ 32 bitowy). Ma to znaczenie o tyle, że w obydwu wersjach kod zachowuje się tak samo, czyli raczej można wykluczyć problem wynikający ze specyfiki sprzętowej, np. pin zajęty przez jakieś układ peryferyjny.

Płytki zostały zaprojektowane w oparciu schematy z PDF-ów producenta. W obydwu wersjach schemat jest identyczny, a ukłąd ścieżek prawie identyczny. Przyglądałem się wielokrotnie i błędów w połączeniach nie dostrzegam.

Od strony programowej próbowałem posłużyć się tym kodem z STM32 znalezionym na GitHubie, portując go na PIC24/PIC32.

formatting link
Dekoder częściowo działa. W pętli głównej czytam do bufora po kawałku plik MP3, a potem wysyłam te dane do układu. Przed wysłaniem każdego kolejnego bajtu czekam w pętli na ustawienie linii DREQ (tymczasowa prowizorka, lepiej byłoby to zrobić na przerwaniach). Po dotarciu do końca pliku zaczynam go czytać od nowa.

Dźwięk jest odtwarzany, ale najlepsze co uzyskałem to "ćwierkający" efekt. Co ciekawe najlepsze efekty uzyskałem przy małym buforze na fragmenty danych z pliku (zaledwie 16 bitów). Gdy ustawię więcej, "ćwierkanie" staje się szybsze przechodzi w szum albo wręcz nastaje cisza. Efekty nie są też w 100% powtarzalne, nie zawsze odtwarzanie chce się rozpocząć.

Co najdziwniejsze, przy większych rozmiarach bufora program szybciej dociera do końca pliku, jakby linia DREQ nic nie dawała - jej konfigurację po stronie MPU sprawdzałem wiele razy i wszystko wydaje się być ok.

W tej chwili skończyły mi się pomysły i jeśli nic innego nie przyjdzie mi do głowy, przeportuję popularną bibliotekę z Arduino, napisaną w C++. Nie chciałbym jednak wyważać otwartych drzwi, jeśli istnieje jakaś dobra biblioteka w C, którą można łatwo przenosić między rodzinami mikrokontrolerów, albo która ma wersję dla PIC32.

Reply to
Atlantis
Loading thread data ...

Dlaczego? Stan wysoki na DREQ zezwala przesłanie bez sprawdzania stanu linii DREQ min. 32 bajtów kolejnych danych ze strumienia. Jeśli po wysłaniu każdego bajtu sprawdzasz stan linii DREQ może to być za wolne i powodujesz buffer underrun dekodera. Oczywiście może być jeszcze problem, że przesyłane dane są porozrywane, gdzieś przy czytaniu z pliku gubisz bajty lub nie przesyłasz całego odczytanego z pliku bufora do vs'a tylko jakiś jego fragment.

Reply to
Marek

Taki efekt występuje gdy do vs'a przesyłasz popsuty strumień i vs szybko "przewija" do przodu szukając początek prawidłowej ramki, wtedy DREQ rzadko robi się low bo nie ma pełnego dekodowania strumienia.

Reply to
Marek

Dokładnie tak to właśnie brzmi - jakby strumień dźwiękowy co chwilę przeskakiwał o chwilę do przodu, z charakterystycznym "ćwierknięciem". Poświęciłem jeszcze chwilę czasu na przeportowanie teb biblioteki z Arduino:

formatting link
Efekt jest dokładnie taki sam, więc to ja muszę robić coś źle.

Kod odpowiedzialny za odczyt i przesyłanie ich do ukłądu wygląda następująco:

res = f_read(&fsrc, buffer, sizeof(buffer), &br); if(res == FR_OK) { VS1003_playChunk(buffer, br); } //End of file if(br == 0) { res = f_lseek(&fsrc, 0); if (res != FR_OK) printf("f_lseek ERROR\r\n"); else printf("f_lseek OK\r\n"); }

Kod funkcji VS1003_playChubk() można znaleźć tutaj, ja po prostu przeniosłem go z C na C++.

formatting link
Eksperymentuję też z rozmiarami bufora i odstępami czasowymi pomiędzy kolejnymi odczytami z pliku i zapisami do VS1003. Udaje mi się uzyskać lepsze i gorsze efekty, ale za każdym razem są one dalekie od ideału.

Może robię coś nie tak i plik należy czytać w specyficzny sposób? Albo nie wszystkie formaty MP3 są kompatybilne z tym układem? Albo trzeba odczytać metadane i w oparciu o nie skonfigurować układ?

Reply to
Atlantis

Chyba, że ten układ potrzebuje bardziej zaawansowanego buforowania po stronie MCU? Coś na zasadzie dwóch buforów: jeden aktywny i drugi zapasowy. Z pierwszego pobierane są dane paczkami po 32 bajty w momencie ustawienia pinu DREQ, a drugi czeka na swoją kolej. Gdy pierwszy się opróżni, drugi jest oznaczany jako aktywny, a pierwszy wypełnia się kolejną porcją danych z pliku.

Reply to
Atlantis

Rozumiem, że ten cytowany kod jest w pętli? Jedyne co mi przychodzi do głowy to, że pin DREQ nie jest prawidłowo skonfigurowany w mcu (odczyt stanu nie jest prawidlowy: w rzeczywistości vs ma pełny bufor a funkcja i tak mu wysyła dane).

Kompatybilność masz w datasheet vs'a, ale raczej musiałby to być dość skrajny przypadek pliku MP3.

Nie, vs robi to automatycznie czytając format z każdej ramki MPEG podczas feedu, stąd możesz plik zacząć nawet odtwarzać ze środka. Natomiast w przypadku formatów pcm np. wav musisz przesłać plik od początku by vs z headera pliku odczytał sobie wpierw metadane (częstotliwość próbkowania, liczna kanałów, liczbę bitów/próbkę itp.) i o ile pamiętam jeśli chce się przerwać odtwarzanie wav przed jego końcem i zacząć odtwarzać inny plik/format to trzeba ten koniec odpowiednio zasygnalizować zapisem w specjalnym rejestrze. W nagłówku wav jest liczba sampli stąd vs wie kiedy plik się "kończy" i należy od nowa analizować prZycjodzavy strumień by go zidentyfikować (wav/MP3 itp).

Reply to
Marek

Bufor vs'a to ok 8kB, gdy DREQ jest high oznacza to, że minimum 32 bajty można przesłać ale może to być więcej. Sprawdź czy ma pewno wyrabia się mcu (nie ma sytuacji, że dreq jest cały czas high) oraz czy nie występuje stacja przeciwna - mcu przelewa vs'a danymi bo widzi dreq cały czas high (zle skonfigurowany pin, brak połączenia elektrycznego z vs).

Reply to
Marek

Tak, kod jest uruchamiany w pętli głównej.

To była pierwsza rzecz, jaka przyszła mi do głowy. Tyle tylko, że:

1) Sprawdziłem kilka razy. Na najnowszej wersji płytki (tej z PIC32) DREQ to RC1. Konfiguracja tego pinu wygląda u mnie następująco: #define VS_DREQ_TRIS TRISCbits.TRISC1 #define VS_DREQ_PIN PORTCbits.RC1 VS_DREQ_TRIS = 1; 2) Pin RC1 ma tylko jedną alternatywną funkcją jest T2CK. Nigdzie w tym projekcie nie wykorzystuję Timera2, a już na pewno nie z zewnętrznym taktowaniem. 3) Bliźniaczy problem występuje także na płytce z PIC24, a tam piny są inne. Musiałem to uwzględnić przenosząc kod i byłoby mało prawdopodobne, gdybym robiąc to popełnił identyczny błąd. Kod z drugiej płytki też sprawdziłem parokrotnie. 4) Z linii DREQ korzysta także funkcja inicjująca VS1003, a ona przechodzi prawidłowo.

Spróbowałem jeszcze następującego kodu w pętli głównej:

while (VS_DREQ_PIN) { br = 0; res = f_read(&fsrc, buffer, 32, &br); if (res == FR_OK && br) { data_mode_on(); for (i=0; i<br; i++) VS1003_SPI_transfer(buffer[i]); data_mode_off(); } if (br == 0) { VS1003_stopSong(); VS1003_startSong(); f_lseek(&fsrc, 0); } }

Efektem jest świergot w słuchawkach, jakby dźwięk byl bardzo szybko przewijany na podglądzie. Potem pojawia się terkot, po którym następuje cisza.

Reply to
Atlantis

Ok, przyczyna się znalazła i okazała się być całkowicie sprzętową - pin TEST był niepodłączony do VCC. Takie rzeczy mogłyby mieć swoją drogą wewnętrzne pull-upy...

Reply to
Atlantis

Ten kod nie jest optymalny dla vs'a. Jak dreq jest wysoki to dopiero robisz fread, a to już za późno. Na DREQ high musisz już mieć gotowy odczytany z sd bufor w ram a nie dopiero go czytać z sd. Sekwencja powinna wyglądać tak: najpierw czytasz pierwszy bufor, wysyłasz go do vs'a tak długo aż zasygnalizuje DREQ low, dopiero wtedy uzupelniasz/czytasz następny bufor z sd i sprawdzasz przed jego wysłaniem czy dreq jest high. Bufor w ram na dane (typu FIFO) musisz mieć min 10kB (musi być większy niż bufor vs'a) bo inaczej pierwsze wypełnienie bufora vs'a będzie zbyt płytkie, co nie da czasu na odczyt kolejnej porcji danych (fread możesz robić tylko wtedy gdy w buforze vs'a jest wystarczająco dużo danych). Inaczej zawsze będziesz miał zawsze nieczyste odtwarzanie z różnymi dziwnymi efektami. W pętli czytania zrób też tymczasowy printf gdy DREQ jest low, by się upewnić czy faktycznie mcu widzi ten stan. Jeszcze jest kwestia SPI, czy driver SPI vs'a na pewno czeka na przesłanie całego bufora SPI (bufora słowa SPI) przed wysłaniem następnego słowa?

{
Reply to
Marek

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.