Goto page Previous 1, 2, 3
Marek
Guest
Sun Oct 02, 2022 1:11 pm
On Wed, 28 Sep 2022 13:06:14 +0200, Atlantis <marekw1986NOSPAM@wp.pl>
wrote:
Quote:
To jest właśnie plan na dalszą rozbudowę projektu. W wersji na
PIC32
było to trochę kłopotliwe, bo biblioteka TLS z MLA jest dość
leciwa. Da
A czemu tak kurczowo się trzymasz MLA? Harmony też działa OK choć
troszkę na początku sprawia wrażenie bardziej skomplikowanego. Ale
jest bardzo podobny do MLA, nawet da się użyć uniwersalne wrapery by
projekt poszedł przezroczyście na mla/Harmony.
--
Marek
Atlantis
Guest
Sun Oct 02, 2022 7:06 pm
On 2.10.2022 15:05, Marek wrote:
Quote:
Teraz mi się przypomniało, że miałem podobne problemy z tym projektem, z
socket buf na spiram nawet 128kB (używany wewnętrznie przez stos MLA)
powodował po pewnej chwili buffer underrun a o wiele mniejszy bufor
aplikacyjny na dane (ale nie socket buffer) w ram mcu dawał spokojnie
radę.
Jestem coraz mocniej przekonany, że winę za ten stan rzeczy może ponosić
zbyt mały rozmiar bufora odbiorczego gniazda sieciowego. W momencie gdy
aktualny pakiet jest przetwarzany (dane z niego są ładowane do pamięci
SPI) brakuje miejsca na przyjęcie kolejnego i wymuszana jest
retransmisja, powodująca w efekcie spowolnienie transmisji.
Przypomniałem sobie w międzyczasie, że bardzo podobny problem miałem na
prototypie tej konstrukcji, pracującej na PIC24FJ256DA210. Tam też nie
udało mi się uzyskać poprawnego odtwarzania streamów większych niż 32
kbps. Uznałem wtedy, że winę za to musi ponosić zbyt niskie taktowanie
magistrali SPI, na której pracuje ENC28J60. Wtedy się nad tym za bardzo
nie zastanawiałem, bo dysponowałem już nowsza wersją hardware'u. Jednak
teraz z perspektywy czasu wydało mi się to dziwne, bo w końcu 16 MHz to
nie mało.
Przypomniałem sobie także, że w tym projekcie na PIC24 także miałem
problemy z pamięcią. Układ ma co prawda 96kB RAM-u, jednak korzystanie z
niej nie jest takie oczywiste, bo tylko 32kB to dostępna bezpośrednio
pamięć, w której może znajdować się stos i sterta. Reszta to specjalna
pamięć stronnicowana, w której można umieszczać np. bufory ba dane.
Jednak z uwagi na to, że trzeba z nią postępować w odpowiedni sposób,
nie da się z niej bezpośrednio korzystać w standardowych bibliotekach.
W pewnym momencie zacząłem mieć problemy, które interpretowałem jako
nadpisywanie stosu. Pozmniejszałem więc rozmiary wszystkich buforów,
które musiały się mieścić głównej pamięci - w tym buforów odbiorczych
gniazd sieciowych.
Teraz przeprosiłem się z tym projektem na PIC24 i przyjrzałem mu się
bliżej. Po pierwsze wykorzystałem tę dodatkową pamięć (EDS) do
zaimplementowania 16kB bufora cyklicznego na dane audio. Już samo to
pozwoliło mi zaoszczędzić trochę głównej pamięci. Po drugie wczytałem
się trochę w opcje konfiguracyjne i zobaczyłem, że ten procesor ma
ustawieni o nazwie "Data model", które może przyjmować wartość "small"
lub "large". W "small" wszystkie zmienne statyczne oraz globalne muszą
zmieścić się w pierwszych 8kB RAM-u. W "large" nie ma tego ograniczenia.
Okazuje się, że to właśnie to ustawienie (a nie nadpisywanie stosu)
powodowało u mnie problemy. Okazało się więc, że tak naprawdę mam
jeszcze całkiem sporo "głównej" pamięci do zagospodarowania.
Pozwoliło mi to zwiększyć rozmiar bufora odbiorczego gniazda sieciowego
do ponad 6kB. To zdecydowanie poprawiło sytuację. Streamy 192kbps nadal
nie odtwarzają się poprawnie, ale te 128kbps i 160kbps już tak.
Mateusz Viste
Guest
Sun Oct 02, 2022 7:41 pm
2022-10-02 o 21:06 +0200, Atlantis napisał:
Quote:
Jestem coraz mocniej przekonany, że winę za ten stan rzeczy może
ponosić zbyt mały rozmiar bufora odbiorczego gniazda sieciowego.. W
momencie gdy aktualny pakiet jest przetwarzany (dane z niego są
ładowane do pamięci SPI) brakuje miejsca na przyjęcie kolejnego i
wymuszana jest retransmisja, powodująca w efekcie spowolnienie
transmisji.
To chyba niezupełnie tak - stack ogłasza raczej okienko nie większe,
niż rozmiar bufora gniazda, a zatem retransmisje z powodu "dostałem
pakiet ale nie miałem gdzie go zapisać" nie powinny mieć miejsca.
Oglądałeś połączenie pod jakimś wiresharkiem? Faktycznie widzisz tam
retransmisje?
Stawiałbym raczej na zbyt małe okienko, a więc i niewielką ilość
danych dostępnych z wyprzedzeniem, przez co jakikolwiek loss albo
chwilowe opóźnienie uniemożliwia dalsze odtwarzanie.
Quote:
Pozwoliło mi to zwiększyć rozmiar bufora odbiorczego gniazda
sieciowego do ponad 6kB. To zdecydowanie poprawiło sytuację.
To zaledwie 4 pakiety. Wychodzi coś w okolicach 400ms dźwięku - malutko.
Mateusz
Atlantis
Guest
Tue Oct 04, 2022 7:04 am
On 2.10.2022 15:11, Marek wrote:
Quote:
A czemu tak kurczowo się trzymasz MLA? Harmony też działa OK choć
troszkę na początku sprawia wrażenie bardziej skomplikowanego. Ale jest
bardzo podobny do MLA, nawet da się użyć uniwersalne wrapery by projekt
poszedł przezroczyście na mla/Harmony.
Po pierwsze kwestia czasu - mam kilka pootwieranych projektów, które
rozwijam niewielkimi krokami od kilku lat. To typowo hobbystyczne
projekty, więc wszystko zależy od tego, czy znajdę czas i motywację. A
jeśli już znajdę, to wolę go poświęcić na dodanie nowej funkcjonalności
niż przepisywanie istniejącego kodu pod nowe biblioteki.
Po drugie istniejące projekty są już na tyle rozbudowane, że mogę
traktować je jako podstawę do tworzenia kolejnych. Wszystko co ma
działać działa, jest dostępna bazowa funkcjonalność (np. konfiguracja
przez WWW), więc jeśli chcę stworzyć jakiś szybki projekt, to wystarczy
skopiować istniejący i zmodyfikować niektóre pliki. I to przedłużą życie
MLA w moich projektach.
Po trzecie - oryginalnie planowałem powolne przechodzenie na STM32 i
biblioteki HAL, więc uczenie się Harmony wydawało mi się nie mieć za
dużo sensu. Jednak koniec końców rozstanie się z PIC32 okazało się być
trudniejsze niż sądziłem i nie tylko kontynuuję istniejące projekty na
nich, ale też zdarzyło mi się zacząć kilka nowych, mniejszych.
Atlantis
Guest
Wed Oct 05, 2022 3:23 pm
Ok, kompletnie nie mam pojęcia co może być powodem takiego zachowania
projektu. Wyczerpałem już chyba wszystkie pomysły. Na chwilę obecną
udało mi się sprawdzić następujące kwestie:
- Dodałem prosty kod do pomiaru ilości bajtów odbieranych w ciągu
sekundy. Dzięki temu mogłem ustalić, że zaraz po połączeniu z serwerem
nadającym stream mam transfer około 20 kB/s (co mniej-więcej pasuje do
bitrate'u 192 kbps), jednak zaraz potem spada on do 1-2 kB i zaczyna się
"czkawka". Bufor musi się przez dłuższą chwilę napełniać, żeby odtworzyć
krótki fragment audio.
- Zakomentowałem wszystkie operacje zapisu odebranych danych do pamięci
SPI RAM (w razie gdyby faktycznie to ona powodowała problemy). Po prostu
od razu zwalniam bufor z odebranymi danymi i zgłaszam gotowość do
odbierania kolejnych. I faktycznie - w tej sytuacji miałem ciągły
transfer w okolicach 20 kB/s.
- Już pomyślałem, że winę faktycznie ponosi pamięć SPI, przygotowałem
więc bufor cykliczny w zwykłej pamięci RAM. Implementacja nie jest może
idealna, ale sprawdziła się już w innym projekcie (na PIC24). Bufor jest
co prawda mały - testowałem wariant 4kB i 8kB - ale na wcześniejszych
wersjach hardware'u tych kilka kB w zupełności wystarczało do płynnego
odtwarzania. Niestety, po wgraniu tej wersji wrócił problem - prędkość
dość szybko spada do 1-2 kB.
- Żeby było ciekawiej zarówno 128kB bufor w pamięci SPI, jak i 8kB bufor
w zwykłym RAM-ie bez najmniejszego problemu sprawdzają się, gdy karmię
je danymi z karty SD. Wtedy odtwarzanie działa całkowicie normalnie.
Podejrzewam, że winę musi ponosić mój własny bład, którego jednak za nic
nie jestem w stanie namierzyć. Jeśli ktoś ma czas i ochotę żeby rzucić
okiem, to aktualna wersja jest dotępna na GitHubie:
https://github.com/marekw1986/InternetRadioSTM32/blob/main/code/Core/Src/vs1003.c
Kluczowe miejsca:
Callback obsługujący odbieranie przychodzących danych:
https://github.com/marekw1986/InternetRadioSTM32/blob/abb4f47bfd4c06ca0d56f6b03b287c5d4a4d9f3f/code/Core/Src/vs1003.c#L869
Miejsce w maszynie stanów, gdzie ładowane są dane do bufora, ale bez
odtwarzania. Tutaj też realizowany jest opóźniony odbiór tych danych,
których nie dało się odebrać w callbacku z uwagi na brak miejsca w buforze:
https://github.com/marekw1986/InternetRadioSTM32/blob/abb4f47bfd4c06ca0d56f6b03b287c5d4a4d9f3f/code/Core/Src/vs1003.c#L477
To samo co powyżej, tylko podczas normalnego odtwarzania:
https://github.com/marekw1986/InternetRadioSTM32/blob/abb4f47bfd4c06ca0d56f6b03b287c5d4a4d9f3f/code/Core/Src/vs1003.c#L509
Miejsce w którym do bufora cyklicznego ładowane są dane z systemu plików
(karta SD lub pendrive):
https://github.com/marekw1986/InternetRadioSTM32/blob/abb4f47bfd4c06ca0d56f6b03b287c5d4a4d9f3f/code/Core/Src/vs1003.c#L541
Guest
Wed Oct 05, 2022 6:37 pm
Atlantis <marekw1986NOSPAM@wp.pl> wrote:
Quote:
Ok, dopisa?em kilkana?cie linijek kodu odpowiedzialnego za mierzenie
ilo?ci danych obieranych w serwera w ci?gu sekundy. Po prostu sumuj?
ka?d? kolejn? warto?? p->tot_ten ze zmienn? tymczasow?, kt?ra co sekund?
jest przepisywana do zmiennej trzymaj?cej aktualn? warto?? pomiaru a
potem zerowana.
Przeprowadzi?em dwa pomiary podczas odbierania streamu radiowej Jedynki.
Pierwszy by? przy zakomentowanych operacjach zapisy do pami?ci SPI RAM.
Wychodzi? transfer na poziomie 21-25 kB/s (czyli 168-200 kbps). Warto??
zgodna z bitratem typowego strumienia audio.
Natomiast po odkomentowaniu tych operacji warto?? spada do 5-11 kB/s
(40-88 kbps) co t?umaczy przerywany d?wi?k.
Nie wiem na ile to ma znaczenie, ale dodatkowo wida?, ?e w obydwu
przypadkach na pocz?tku transmisja jest nieco szybsza i po kilku
sekundach stabilizuje si? wok?? ni?szej warto?ci.
To by wskazywalo na zbyt male bufory/okno danych. Sprzet wyraznie
moze pracowac szybciej, ale kontrola przeplywu TCP mu nie pozwala.
Ja bym sprawdzil co sie dzieje jak wywalisz caly kod odpowiedzialny
za dzwiek i zostawisz tylko odbior strumienia, ale potwierdzajac
w takim tempie (w przyblizeniu) jak kodek by je odbieral.
Jeszcze moze glupie pytanie: w jakim tempie piszesz/czytasz ten
RAM SPI? DMA powinno przerzucac dane z maksymalna predkoscia
SPI, ale RAM moze miec porabany protokol a jak go obsluzysz
przez software to moga byc straty predkosci.
Quote:
Generalnie mo?na ju? wyci?gn?? kilka wniosk?w:
1. Mo?na ca?kowicie odrzuci? tez?, ?e win? za spowolnienia ponosi
projekt p?ytki i gubienie pakiet?w z powodu b??d?w na warstwie
sprz?towej (interfejs RMII). Gdyby tak by?o, to efekt by?by widoczny
ca?y czas.
2. Operacja zapisu do pami?ci SPI RAM ma wp?yw na szybko?? transferu
danych. Jednak nie jest to raczej prosta zale?no?? na zasadzie pami?ci
maj?cej niewystarczaj?c? szybko??. Jak ju? m?wi?em - ten bufor
ca?kowicie normalnie dzia?a z lokalnymi no?nikami, poza tym przy
pr?dko?ci taktowania 18 MHz powinno by? mo?liwe przesy?anie danych ze
znacznie wi?ksz? pr?dko?ci? ni? tych kilka kB/s. Poza tym problemy
wyst?powa?y te? w przypadku stosowania (du?o mniejszego) bufora w
normalnej pami?ci.
Pytanie kiedy potwierdzasz odbior: przed czy po zapisie do SPI
RAM. Jesli po to potwierdzenie jest opoznione i efektywnie
zmniejsza dostepne okno.
Quote:
Na chwil? obecn? stawia?bym raczej na moj? oryginaln? tez?: w czasie gdy
program jest zaj?ty zapisywaniem oryginalnego pakietu, Ethernet nie jest
w stanie odebra? nast?pnej porcji danych (bo ko?czy mu si? jaki?
bufor/okno odbiorcze) i dochodzi do retransmisji, kt?ra spowalnia realn?
pr?dko?? przesy?u danych.
Pisales ze jest 6kB na bufory LWIP. To 4 pakiety maksymalnej
wielkosci. Jesli 1 to wlasnie odbierany pakiet (nie wiem
czy LWIP ma na niego oddzielny bufor) a 1 to pakiet ktory
przerabiasz to zostaja 2 pakiety na buforowanie. Zaleznie
od szybkosci to moze byc 250-150 ms buforowania. Niby moze
dzialac ale ma prawo sie rwac.
Piszesz o jakims "buforze audio". Nie wiem co to ma byc,
ale datasheet VS1003 mowi o przesylaniu bloku 32 bajtow,
czyli w zasadzie jesli jest portrzebny jakis bufor to
na poziomie max setek bajtow. Czyli pownny byc dziesiatki
kilobajtow wolnej pamieci: STM32F107 ma 64KB RAM.
Moim zdaniem rozsadny projekt przydzielilby duzy kawalek
pamieci dla LWIP. Tak na oko minimum 15KB (10 pakietow
maksymalnej wielkosci). Przy 64KB RAM powinno byc
mozliwe przydzielnie LWIP 40KB (zwykle przyjmuje sie ze
implementacja TCP potrzebuje minimalnie 40KB do pracy,
ty masz jeden strumien a LWIP powinien byc oszczedny,
wiec moze bedzie dzialalo z mniejsza iloscia).
Przeplyw danych powiniem byc nastepujacy:
ETH -> bufor LWIP -> VS1003
Ewentualnie buforek powiedzmy 256 bajtow dla DMA pomiedzy
STM a VS1003 (taki buforek, podzielony na polowki po 128
bajtow wystarcza zeby DMA pracowalo plynnie).
Quote:
I teraz mam kilka pyta? co do tego, jak w?a?ciwie dzia?a Ethernet w STM32:
Samo pobieranie danych z sieci do bufora odbiorczego jest realizowane w
tle przez sprz?t, czy te? p?tla g??wna programu musi regularnie
wywo?ywa? jaki? sterownik? To znaczy je?li bufor odbiorczy jest
dostatecznie du?y, to dane b?d? nadal dochodzi?y nawet wtedy, je?li
p?tla g??wna b?dzie zaj?ta czym? innym?
Ethernet ma swoje DMA ktore wrzuca pakiet do pamieci. Jak sie
dzieje cos co wymaga uwagi procka to zglasza przerwania.
Ten interfejs moze wrzucic dane do listy buforow (nie trzeba
jednego ciaglego bufora). Czyli jak sa dostepne bufory
to jest minimalne obciazenie procka. Ale kluczem jest
dostepnosc buforow. Nie wiem jak to rozwiazuje LWIP.
Jedna mozliwosc to kolejka buforow uzupelniana przez
petle glowna, wtedy procedura obslugi przerwania pobiera
bufory z kolejki (o ile sa dostepne). Ale mozna to
robic inaczej.
Jeszcze jedna uwaga: w STM transmisje danych powinno
robic DMA. "Dogladac" DMA powinny procedury obsugi
przerwan. Normalny kod powinien sledzic stan polaczenia
TCP, przygotowywac pakiety potwierdzenia (to robi LWIP)
i robic zarzadanie "wysokopoziomowe". Wiekszosc
operacji "petli glownej" powinna byc malo krytyczna
czasowo. Najwiecej uwagi moim zdaniem wymaga generowanie
potwierdzen (czyli wywolanie 'tcp_recved'), tak zeby
miec wlasciwa wielkosc okna TCP.
--
Waldek Hebisch
Atlantis
Guest
Thu Oct 06, 2022 7:47 am
On 05.10.2022 18:37, antispam@math.uni.wroc.pl wrote:
Quote:
To by wskazywalo na zbyt male bufory/okno danych. Sprzet wyraznie
moze pracowac szybciej, ale kontrola przeplywu TCP mu nie pozwala.
Które opcja w konfiguracji lwIP za to odpowiada? W stosie TCP/IP od
Microchipa po prostu ustawiało się parametr określający wielkość bufora
odbiorczego i nadawczego przy konfiguracji konkretnego socketu. W lwIP
nie widzę czegoś takiego niestety.
Quote:
Ja bym sprawdzil co sie dzieje jak wywalisz caly kod odpowiedzialny
za dzwiek i zostawisz tylko odbior strumienia, ale potwierdzajac
w takim tempie (w przyblizeniu) jak kodek by je odbieral.
Najbliższą rzeczą do tego jaką zrobiłem było wywalenie zapisywania
nadchodzących danych do bufora cyklicznego. I wygląda na to, że wtedy
leciały z maksymalną dostępną prędkością, odpowiadającą bitrate'owi
streama. Nie bardzo wiem natomiast jak w przypadku lwIP narzucić tempo
odpowiadające tempu zapotrzebowania na dane przez VS10xx. W przypadku
stosu od Microchipa było to proste - przychodzące dane trafiały do
bufora FIFO socketa, z którego mogłem je pobierać porcjami o dowolnej
wielkości. Jeśli dobrze rozumiem w przypadku lwIP i RAW API jest inaczej
- mam obowiązek przyjąć całą porcję danych zgłoszoną przez callback
odbiorczy, zwolnić pamięć i wywołać tcp_recved. Stąd potrzeba stosowania
bufora cyklicznego.
Quote:
Jeszcze moze glupie pytanie: w jakim tempie piszesz/czytasz ten
RAM SPI? DMA powinno przerzucac dane z maksymalna predkoscia
SPI, ale RAM moze miec porabany protokol a jak go obsluzysz
przez software to moga byc straty predkosci.
Na chwilę obecną nie używam DMA - dane są po prostu przepisywane z
jednego miejsca w drugie w pętli. Myślałem, że SPI może powodować
opóźnienia, jednak tę hipotezę można już odrzucić ponieważ:
- Urządzenie zachowuje się identycznie w przypadku bufora cyklicznego w
ulokowanego pamięci SPI, jak również (mniejszego) w zwykłym RAM-ie.
- Żadne problemy nie występują w przypadku odtwarzania z karty SD.
Quote:
Pytanie kiedy potwierdzasz odbior: przed czy po zapisie do SPI
RAM. Jesli po to potwierdzenie jest opoznione i efektywnie
zmniejsza dostepne okno.
To tak można?

Myślałem, że tcp_recved() wolno mi wywołać dopiero po
przetworzeniu odebranych danych i zwolnieniu pamięci za pomocą pbuf_free().
Quote:
Pisales ze jest 6kB na bufory LWIP. To 4 pakiety maksymalnej
wielkosci. Jesli 1 to wlasnie odbierany pakiet (nie wiem
6kB to chyba było odnośnie wcześniejszej wersji urządzenia,
zrealizowanej na PIC-u. Tam dość łatwo było ustawić konkretną wielkość
bufora odbiorczego.
Quote:
Piszesz o jakims "buforze audio". Nie wiem co to ma byc,
ale datasheet VS1003 mowi o przesylaniu bloku 32 bajtow,
czyli w zasadzie jesli jest portrzebny jakis bufor to
na poziomie max setek bajtow. Czyli pownny byc dziesiatki
kilobajtow wolnej pamieci: STM32F107 ma 64KB RAM.
Dodatkowy bufor na dane audio, pośredniczący w komunikacji pomiędzy
źródłem danych (Ethernet, lokalny nośnik pamięci) a VS10xx. Praktyka
pokazała, że jego zastosowanie dość mocno zwiększa stabilność, zwłaszcza
w przypadku Ethernetu. Implementowałem go do tej pory na jeden z dwóch
sposobów:
- klasyczny bufor cykliczny
- Dwuczęściowy bufor. Gdy jedna część karmi dekoder MP3, druga jest
ładowana danymi z zewnątrz. Potem następuje zamiana.
To właśnie tę funkcję w projekcie pełni pamięć SPI RAM.
J.F
Guest
Thu Oct 06, 2022 3:18 pm
On Sun, 2 Oct 2022 09:39:10 +0200, Atlantis wrote:
Quote:
Ok, dopisałem kilkanaście linijek kodu odpowiedzialnego za mierzenie
ilości danych obieranych w serwera w ciągu sekundy. Po prostu sumuję
każdą kolejną wartość p->tot_ten ze zmienną tymczasową, która co sekundę
jest przepisywana do zmiennej trzymającej aktualną wartość pomiaru a
potem zerowana.
Przeprowadziłem dwa pomiary podczas odbierania streamu radiowej Jedynki.
Pierwszy był przy zakomentowanych operacjach zapisy do pamięci SPI RAM.
Wychodził transfer na poziomie 21-25 kB/s (czyli 168-200 kbps). Wartość
zgodna z bitratem typowego strumienia audio.
Natomiast po odkomentowaniu tych operacji wartość spada do 5-11 kB/s
(40-88 kbps) co tłumaczy przerywany dźwięk.
Ciekawe co na to serwer - nie moze ci wyslac danych odpowiednio
szybko, buforowac tez nie moze w nieskonczonosc - powinien gdzies u
siebie przeskakiwac na aktualne dane.
Quote:
Nie wiem na ile to ma znaczenie, ale dodatkowo widać, że w obydwu
przypadkach na początku transmisja jest nieco szybsza i po kilku
sekundach stabilizuje się wokół niższej wartości.
Ogolna zasada TCP - serwer wysyla na początku kilka pakietow danych,
dokladnie to TCP_window bajtow, a potem czeka na potwierdzenie
pierwszego.
W przypadku radia moze byc inaczej, jesli nie ma u siebie bufora
danych. No ale nawet wtedy te ~20kB/s szybko uzbiera, a Ty nie
nadążasz odebrac.
Quote:
Generalnie można już wyciągnąć kilka wniosków:
1. Można całkowicie odrzucić tezę, że winę za spowolnienia ponosi
projekt płytki i gubienie pakietów z powodu błędów na warstwie
sprzętowej (interfejs RMII). Gdyby tak było, to efekt byłby widoczny
cały czas.
2. Operacja zapisu do pamięci SPI RAM ma wpływ na szybkość transferu
danych. Jednak nie jest to raczej prosta zależność na zasadzie pamięci
mającej niewystarczającą szybkość. Jak już mówiłem - ten bufor
całkowicie normalnie działa z lokalnymi nośnikami, poza tym przy
prędkości taktowania 18 MHz powinno być możliwe przesyłanie danych ze
znacznie większą prędkością niż tych kilka kB/s. Poza tym problemy
występowały też w przypadku stosowania (dużo mniejszego) bufora w
normalnej pamięci.
Na chwilę obecną stawiałbym raczej na moją oryginalną tezę: w czasie gdy
program jest zajęty zapisywaniem oryginalnego pakietu, Ethernet nie jest
w stanie odebrać następnej porcji danych (bo kończy mu się jakiś
Z grubsza mozliwe, ale patrz nizej.
A moze przerwania sa blokowane ?
Quote:
bufor/okno odbiorcze) i dochodzi do retransmisji, która spowalnia realną
prędkość przesyłu danych.
Troche wątpie. Przy zgubieniu pakietu timeout sie wlacza, i to mogą
byc grube sekundy. Chyba bys nie uzyskal 5-11 kB/s.
No chyba, ze radio ma domyslnie jakies krotsze czasy.
Algorytm doboru timeoutu w TCP dosc skomplikowany ...
ale moze mozesz u siebie przetestowac - zasymuluj np zgubienie co
setnego pakietu.
Raczej bym sie spodziewal problemu w jakims opoznieniu w wyslaniu
potwierdzenia. Ale zeby az tak to SPI zwalniało? 18MHz wydaje sie
sporo ... a ogladales oscyloskopem? Albo czy mierzyles
przepustowosc/czas zapisu pakietu?
A w ogole ... masz tam jakies zabezpieczenie kolejnosci w tej
bibliotece? Bo powiedzmy przychodzą pakiety nr 1, 2, 3, a nr 4 nie
przychodzi. Ale przychodzi nr 5, 6, 7 ... i co wtedy - nie dostaniesz
callbacka z nr 5, a bufory 5, 6, 7 zostaną skasowane ?
Ba, bez zadnych retransmisji moga przyjsc pakiety w kolejnosci
1, 2, 3, 5, 4, 6, 8, 7, itp.
J.
Atlantis
Guest
Fri Oct 07, 2022 6:40 pm
On 6.10.2022 17:18, J.F wrote:
Quote:
Ciekawe co na to serwer - nie moze ci wyslac danych odpowiednio
szybko, buforowac tez nie moze w nieskonczonosc - powinien gdzies u
siebie przeskakiwac na aktualne dane.
I wszystko wskazuje na to, że tak to właśnie działa. Przynajmniej
odnoszę wrażenie, że dźwięki które słyszę z przerwami nie są kolejnymi
fragmentami tego samego strumienia audio, ale raczej "okienkami" które
aktualnie udaje się odebrać.
Quote:
W przypadku radia moze byc inaczej, jesli nie ma u siebie bufora
danych. No ale nawet wtedy te ~20kB/s szybko uzbiera, a Ty nie
nadążasz odebrac.
Tak. Pytanie tylko dlaczego nie nadążam tego odebrać. Można było
teoretyzować o niskiej przepustowości pamięci SPI RAM (co i tak było
wątpliwe, bo 18 MHz to naprawdę szybka transmisja) ale ta teoria padła w
momencie, gdy identyczny problem udało się stwierdzić także w przypadku
zastosowania bufora cyklicznego w RAM-ie.
Quote:
Z grubsza mozliwe, ale patrz nizej.
A moze przerwania sa blokowane ?
Jakie przerwania? W moim kodzie w ogóle nie używam przerwań związanych z
Ethernetem. Używam gotowych sterowników dostarczanych przez producenta
mikrokontrolera oraz gotowego stosu (lwIP). W rozsądnym projekcie
użytkownik nie powinien w ogóle przejmować się przerwaniami - powinny
one w tle ładować dane do jakiegoś FIFO. Zresztą nigdzie w dokumentacji
nie znalazłem ani jednej wzmianki o przerwaniach.
O ile informacje na jakie udało mi się trafić w Internecie są poprawne,
to procedura odbioru jest następująca:
- Stos wywołuje zarejestrowana wcześniej funkcję obsługi callbacku
odbiorczego.
- Do tej funkcji przekazywany jest wskaźnik na struct pbuf. Struktura
zawiera dynamicznie alokowany bufor na payload. Może też zawierać
wskaźniki do kolejnych struktur tego samego typu.
- Z jednej lub kilku struktur trzeba pobrać dane i gdzieś je zapisać.
- Jeśli już skończyliśmy tę operację, wywołujemy pbuf_free() aby zwolnić
pamięć oraz tcp_recved() aby zwiększyć rozmiar okna (poinformować
serwer, że może przesłać więcej).
U mnie może się zdarzyć sytuacja, że otrzymanych danych będzie więcej
niż miejsca w buforze. Wtedy nie mogę ich odebrać od razu - muszę się z
tym wstrzymać do czasu, aż dekoder MP3 wyjmie z bufora odpowiednią ilość
danych. Wtedy odbiór tej konkretnej paczki jest opóźniony i odbywa się w
pętli głównej.
W żadnym miejscu nie mam do czynienia z przerwaniami.
Quote:
Troche wątpie. Przy zgubieniu pakietu timeout sie wlacza, i to mogą
byc grube sekundy. Chyba bys nie uzyskal 5-11 kB/s.
Kiedy transmisja zaczyna mulić to nie jest 5-11 kB/s, a 0-2kB/s.
Quote:
Raczej bym sie spodziewal problemu w jakims opoznieniu w wyslaniu
potwierdzenia. Ale zeby az tak to SPI zwalniało? 18MHz wydaje sie
sporo ... a ogladales oscyloskopem? Albo czy mierzyles
przepustowosc/czas zapisu pakietu?
Nie, bo wydawało mi się to nie mieć sensu. Udało mi się ustalić, że wina
nie leży po stronie pamięci SPI. Przemawiają za tym dwa argumenty:
- Pamięć SPI doskonale sprawdza się przy buforowaniu streama z karty SD.
- Ten sam problem występuje, jeśli dane przychodzące przez TCP próbuję
zapisywać do bufora cyklicznego ulokowanego w zwykłym RAM-ie.
Quote:
A w ogole ... masz tam jakies zabezpieczenie kolejnosci w tej
bibliotece? Bo powiedzmy przychodzą pakiety nr 1, 2, 3, a nr 4 nie
przychodzi. Ale przychodzi nr 5, 6, 7 ... i co wtedy - nie dostaniesz
callbacka z nr 5, a bufory 5, 6, 7 zostaną skasowane ?
Wydaje mi się, że przecież chyba TCP ogarnia kwestię pakietów
przychodzących w złej kolejności i użytkownik nie musi się przejmować tą
kwestią podczas pisania aplikacji. Ten problem pojawia się dopiero w
przypadku zastosowania UDP.
Tak czy inaczej lwIP ma opcję związana właśnie z tą kwestią. Jeśli
dobrze rozumiem to można wybrać jak ma się zachować stos. W przypadku
zgubienia któregoś z pakietów w sekwencji można albo trzymać nadmiarowe
do momentu otrzymania brakującego, albo poprosić jeszcze raz o wysłanie
całej sekwencji licząc, że tym razem przyjdą wszystkie i po kolei.
Próbowałem obydwu ustawień.
Swoją drogą, czy ktoś może mi wyjaśnić w jaki sposób skonfigurować lwIP,
żeby mieć dostatecznie duży bufor odbiorczy? W stosie od Microchipa po
prostu ustawiało się wielkość bufora nadawczego i odbiorczego dla
konkretnego gniazda. Tutaj cała masa opcji, które nic mi wprost nie mówią...
https://github.com/marekw1986/InternetRadioSTM32/blob/main/code/LWIP/Target/lwipopts.h
Marek
Guest
Sun Oct 09, 2022 6:25 am
On Sun, 2 Oct 2022 21:06:11 +0200, Atlantis <marekw1986NOSPAM@wp.pl>
wrote:
Quote:
Jestem coraz mocniej przekonany, że winę za ten stan rzeczy może
ponosić
zbyt mały rozmiar bufora odbiorczego gniazda sieciowego. W momencie
gdy
aktualny pakiet jest przetwarzany (dane z niego są ładowane do
pamięci
SPI) brakuje miejsca na przyjęcie kolejnego i wymuszana jest
retransmisja, powodująca w efekcie spowolnienie transmisji.
A czy problemy z odtwarzaniem przez sieć nie wynikają ze słabej
wydajności stosu tcpip iwip/mla przy "odległych" podłączeniach? Np.
MLA szybko działa w lokalnej sieci (kilkaset kB/s) ale przez internet
jest już znacznie wolniejszy (kilka kB/s) niż oczekiwany wpływ
szybkości łącza. Problem rozwiązuje uzycie lokalnego proxy: gdy
łączymy się z internetu do mcu przez lokalne proxy np. raspi szybkość
pozostaje zachowana jak przy połączeniu lokalnym. Czy ktoś się
domyśla z czego to wynika?
Czy próbowałeś odtwarzać przez lokalne proxy? Odwrotna sytuacja niż
opisana wyżej. Uruchomić proxy do oryginalnego streamu na lokalnym
komputerze w tym samym segmencie sieci co jest player na iwip/mla i
niech ten player pobiera stream z proxy w lokalnej sieci a nie
bezpośrednio z urla z internetu.
--
Marek
Atlantis
Guest
Sun Oct 09, 2022 8:19 am
On 9.10.2022 08:25, Marek wrote:
Quote:
A czy problemy z odtwarzaniem przez sieć nie wynikają ze słabej
wydajności stosu tcpip iwip/mla przy "odległych" podłączeniach? Np. MLA
szybko działa w lokalnej sieci (kilkaset kB/s) ale przez internet jest
już znacznie wolniejszy (kilka kB/s) niż oczekiwany wpływ szybkości
łącza.
Wszystkie wersje tego urządzenia na PIC32 i MLA zawsze wyciągały
wystarczającą szybkość, żeby być w stanie płynnie odtwarzać streamy z
odległych serwerów. Przez odległe mam na myśli nawet studenckie
rozgłośnie zza oceanu. ;)
Wczoraj udało mi się znaleźć źródło problemu. Okazało się ono być
banalne, ale leżało w trochę nieoczekiwanym miejscu. Mianowicie prędkość
SPI dedykowanego VS1003 była za mała. Nie wpadłem na to od razu, bo
prędkość była w pełni wystarczająca aby odtwarzać nawet MP3 o większych
bitrate'ach z lokalnych nośników.
Problemem było to, w jaki sposób stos lwIP na RAW API dostarcza dane. W
MLA można pobierać sobie dowolną ilość danych z bufora. W przypadku lwIP
taka operacja jest możliwa jedynie przy użyciu socket API, które wymaga
RTOS-a. Tutaj natomiast muszę albo:
- Przyjąć całą paczkę danych w callbacku odbiorczym, zwolnić pamięć i
zgłosić gotowość przyjęcia kolejnej porcji.
- Opóźnić tę operację i wykonać ją trochę później w pętli głównej.
Nie po prostu zapisać w buforze tyle danych, ile aktualnie mam wolnego
miejsca.
I tutaj problemem było tempo w jakim VS1003 by w stanie przyjmować dane.
Zbyt często po prostu dochodziło do sytuacji, kiedy po przyjściu nowej
paczki danych w buforze wciąż nie było dostatecznej ilości miejsca na
jej przyjęcie i trzeba było czekać aż VS przeniesie je do swojego
wewnętrznego bufora.
Po przyspieszeniu SPI wszystko zaczęło się odbywać dużo sprawniej.
Okazało się jednak, że przy buforze cyklicznym umieszczonym w pamięci
RAM (a więc ograniczonym do kilku kB) co jakiś czas zdarza się minimalne
przycięcie. Po przywróceniu 128kB bufora w pamięci SPI RAM wszystko
zaczęło działać zupełnie płynnie, chociaż na dobrą sprawę pewnie mógłbym
jeszcze dość znacznie zmniejszyć rozmiar tego bufora.
Obecnie będę musiał jeszcze trochę zoptymalizować program, zwłaszcza pod
kątem użycia pamięci. Może uda mi się jej trochę odzyskać po
przywróceniu bardziej oszczędnych ustawień lwIP.
Poza tym pingi nie wyglądają idealnie. Większość ma typową dla Ethernetu
wartość 0.1-0.5 ms, jednak podczas odtwarzania streamu mniej więcej co
piąty przychodzi z opóźnieniem od kilkudziesięciu do nawet ponad 100 ms.
W przypadku wersji na PIC32 też były opóźnienia, ale nie aż tak duże.
Marek
Guest
Sun Oct 09, 2022 12:45 pm
On Sun, 9 Oct 2022 10:19:19 +0200, Atlantis <marekw1986NOSPAM@wp.pl>
wrote:
Quote:
Wszystkie wersje tego urządzenia na PIC32 i MLA zawsze wyciągały
wystarczającą szybkość, żeby być w stanie płynnie odtwarzać streamy
z
odległych serwerów. Przez odległe mam na myśli nawet studenckie
rozgłośnie zza oceanu.
Ale na moment zostawmy strumieniowanie. Czy robiłeś testy porównawcze
transferu połączenia z internetu do "serwera" opartego na MLA w
porównaniu do połączenia z tym samym (i do tej samej usługi) w
lokalnym segmencie sieci? Interesuje mnie, czy to zjawisko jest tylko
u mnie czy powszechne w takich małych stosach tcpip.
--
Marek
J.F
Guest
Mon Oct 10, 2022 8:36 am
On Fri, 7 Oct 2022 20:40:36 +0200, Atlantis wrote:
Quote:
On 6.10.2022 17:18, J.F wrote:
Ciekawe co na to serwer - nie moze ci wyslac danych odpowiednio
szybko, buforowac tez nie moze w nieskonczonosc - powinien gdzies u
siebie przeskakiwac na aktualne dane.
I wszystko wskazuje na to, że tak to właśnie działa. Przynajmniej
odnoszę wrażenie, że dźwięki które słyszę z przerwami nie są kolejnymi
fragmentami tego samego strumienia audio, ale raczej "okienkami" które
aktualnie udaje się odebrać.
W przypadku radia moze byc inaczej, jesli nie ma u siebie bufora
danych. No ale nawet wtedy te ~20kB/s szybko uzbiera, a Ty nie
nadążasz odebrac.
Tak. Pytanie tylko dlaczego nie nadążam tego odebrać. Można było
teoretyzować o niskiej przepustowości pamięci SPI RAM (co i tak było
wątpliwe, bo 18 MHz to naprawdę szybka transmisja) ale ta teoria padła w
momencie, gdy identyczny problem udało się stwierdzić także w przypadku
zastosowania bufora cyklicznego w RAM-ie.
Z grubsza mozliwe, ale patrz nizej.
A moze przerwania sa blokowane ?
Jakie przerwania? W moim kodzie w ogóle nie używam przerwań związanych z
Ethernetem. Używam gotowych sterowników dostarczanych przez producenta
mikrokontrolera oraz gotowego stosu (lwIP). W rozsądnym projekcie
użytkownik nie powinien w ogóle przejmować się przerwaniami - powinny
one w tle ładować dane do jakiegoś FIFO. Zresztą nigdzie w dokumentacji
nie znalazłem ani jednej wzmianki o przerwaniach.
O ile informacje na jakie udało mi się trafić w Internecie są poprawne,
to procedura odbioru jest następująca:
- Stos wywołuje zarejestrowana wcześniej funkcję obsługi callbacku
odbiorczego.
- Do tej funkcji przekazywany jest wskaźnik na struct pbuf. Struktura
zawiera dynamicznie alokowany bufor na payload. Może też zawierać
wskaźniki do kolejnych struktur tego samego typu.
Zeby wywolac funkcje i przekazac bufor, to musi wiedziec, ze jakies
dane przyszly. Czyli przerwanie.
A jak funkcja dlugo obsluguje ... moze przerwania sa wyłączone, dopóki
nie skonczy.
Quote:
- Z jednej lub kilku struktur trzeba pobrać dane i gdzieś je zapisać.
- Jeśli już skończyliśmy tę operację, wywołujemy pbuf_free() aby zwolnić
pamięć oraz tcp_recved() aby zwiększyć rozmiar okna (poinformować
serwer, że może przesłać więcej).
U mnie może się zdarzyć sytuacja, że otrzymanych danych będzie więcej
niż miejsca w buforze. Wtedy nie mogę ich odebrać od razu - muszę się z
tym wstrzymać do czasu, aż dekoder MP3 wyjmie z bufora odpowiednią ilość
danych. Wtedy odbiór tej konkretnej paczki jest opóźniony i odbywa się w
pętli głównej.
I tu masz pare ryzyk:
a) przy niewielkim buforze opoznienie w wyslaniu potwierdzenia moze
skutkowac za duzym spowolnieniem transmisji,
b) bufory ci sie przepelniają, bo parametr TCP_window jest za duzy,
i serwer na poczatku przysyla ci za duzo danych,
Quote:
W żadnym miejscu nie mam do czynienia z przerwaniami.
Dekoder karmiony w petli glownej?
A moze tam sie zdarzaja duze opoznienia na inne akcje ?
Quote:
Troche wątpie. Przy zgubieniu pakietu timeout sie wlacza, i to mogą
byc grube sekundy. Chyba bys nie uzyskal 5-11 kB/s.
Kiedy transmisja zaczyna mulić to nie jest 5-11 kB/s, a 0-2kB/s.
A to juz moze byc, szczegolnie jesli widzisz, ze dociera kilka
pakietow, a potem dluga przerwa ..
Quote:
Raczej bym sie spodziewal problemu w jakims opoznieniu w wyslaniu
potwierdzenia. Ale zeby az tak to SPI zwalniało? 18MHz wydaje sie
sporo ... a ogladales oscyloskopem? Albo czy mierzyles
przepustowosc/czas zapisu pakietu?
Nie, bo wydawało mi się to nie mieć sensu. Udało mi się ustalić, że wina
nie leży po stronie pamięci SPI. Przemawiają za tym dwa argumenty:
- Pamięć SPI doskonale sprawdza się przy buforowaniu streama z karty SD.
- Ten sam problem występuje, jeśli dane przychodzące przez TCP próbuję
zapisywać do bufora cyklicznego ulokowanego w zwykłym RAM-ie.
To drugie w zasadzie wyjasnia, ale oscyloskop i tak moze pomoc.
Tu nawet nie oscyloskop, ale analizator logiczny za kilkadziesiąt zl.
Quote:
A w ogole ... masz tam jakies zabezpieczenie kolejnosci w tej
bibliotece? Bo powiedzmy przychodzą pakiety nr 1, 2, 3, a nr 4 nie
przychodzi. Ale przychodzi nr 5, 6, 7 ... i co wtedy - nie dostaniesz
callbacka z nr 5, a bufory 5, 6, 7 zostaną skasowane ?
Wydaje mi się, że przecież chyba TCP ogarnia kwestię pakietów
przychodzących w złej kolejności i użytkownik nie musi się przejmować tą
kwestią podczas pisania aplikacji.
TCP tak, pytanie, czy masz pelne TCP ..
Quote:
Ten problem pojawia się dopiero w
przypadku zastosowania UDP.
Tak czy inaczej lwIP ma opcję związana właśnie z tą kwestią. Jeśli
dobrze rozumiem to można wybrać jak ma się zachować stos. W przypadku
zgubienia któregoś z pakietów w sekwencji można albo trzymać nadmiarowe
do momentu otrzymania brakującego, albo poprosić jeszcze raz o wysłanie
całej sekwencji licząc, że tym razem przyjdą wszystkie i po kolei.
Próbowałem obydwu ustawień.
Tak ogolnie TCP dziala tak, ze jak znikl jeden pakiet, to trzeba go
retransmitowac. A po nim wysylane sa ponownie wszystkie nastepne.
Po otrzymaniu pakietu "niekolejnego", stos odbiorczy byc moze moze
chwile poczekac - moze akurat "kolejny" przyjdzie, a nastepny juz
czeka w buforze.
Przy czym raczej nie podejrzewam, zeby niekolejne byly twoim
problemem.
Quote:
Nie znam, nie poradze.
J.
Goto page Previous 1, 2, 3