stronę

Po uporaniu się z (banalnym jak się okazało) problemem z Ethernetem na płytce z PIC32MZ zabrałem się za podobny układ na STM32F407. Tutaj znów trafiłem na dziwny problem, tym razem jednak prawie na 100% software'owy.

Sytuacja wygląda następująco: jakiś czas temu zaprojektowałem płytkę pod proste radio internetowe na STM32F107 + DP83848 + VS1003. Płytka działa idealnie. Na chwilę obecną mam na niej FreeRTOS + lwIP + FatFS + własną aplikację klienta TCP do odbierania streamów z Internetu. Jest też serwer HTTPD (ten z pakietu lwIP, włączony przez kliknięcie odpowiedniej opcji w CubeMX). Serwer na chwilę obecną udostępnia jedynie kilka statycznych stron, w wolnej chwili będe musiał dopisać funkcje CGI.

Na chwilę obecną wszystko to działa poprawnie i stabilnie, jednak płytka dość szybko okazała się być zbyt ciasna - w tej chwili wykorzystanie pamięci RAM dochodzi do 90% i chociaż jeszcze nie powoduje to problemów ze stabilnością, postanowiłem przenieść się na coś większego.

W jeden weekend powstała więc kolejna rewizja, z STM32F407. Przeniesienie projektu nie powodowało większych problemów. Konfigurację pinów i peryferiów wyklikałem na nowo w CubeMX i wygenerowałem kod. Ethernet ruszył z miejsca. Potem zacząłem uruchamiać kolejne funkcjonalności i przenosić swój kod. Wszystko działało poprawnie.

Do momentu, aż nie postanowiłem odpalić także serwera HTTPD. Kliknąłem opcję w CubeMX, wygenerowałem kod, dodałem plik fsdata.c (obraz udostępnianych stron), dodałem wywołanie httpd_init(). Wszystko tak jak w starym projekcie.

Po wgraniu skompilowanego kodu na płytkę okazało się, że serwer nie tylko nie chce działać, ale także zawiesza całą resztą. W momencie próby wejścia na stronę oprogramowanie przestaje reagować - nie wykonuje się mój kod a urządzenie przestaje być widoczne w sieci i nie odpowiada na pingi. Jeśli tylko zakomentuję wywołanie httpd_init(), problem znika.

Przyjrzałem się bliżej problemowi, podpiąłem debugger żeby zobaczyć, czy przypadkiem program nie utyka w jakiejś nieskończonej pętli, jednak wszystko wskazywało na to, że FreeRTOS nadal działa.

Spróbowałem więc innego podejścia i dodałem w różnych taskach cyklicznie wywoływane printy.

W tej chwili mam dwa taski utworzone przeze mnie: MainTask - priorytet "Normal", tam odbywają się wszystkie operacje związane z moją aplikacją. IoTask - priorytet "Idle", jak sama nazwa wskazuje przeznaczony do obsługi interfejsu użytkownika. W tej chwili jest tam kilka operacji, a na końcu każdego przebiegu pętli wywoływane jest osDelay(20).

Do tego w tle swoje własne taski tworzy m.in. lwIP oraz sterownik USB.

Okazało się, że w momencie podjęcia próby wejścia na stronę przestają wykonywać się printy z MainTask, ale te z IoTask nadal są wykonywane.

Pierwsza myśl jaka przyszła mi do głowy to problemy ze stosem, jednak:

- TOTAL_HEAP_SIZE w FreeRTOS/Config parameters w jest ustawiony na 20kB. W starym projekcie było trochę ponad 14kB.

- Stosy tasków mają rozmiary takie jak w projekcie z działającej płytki, wliczając w to rozmiary stosów bibliotek, które mogę ustawić w ich konfiguracji.

- Próbowałem manipulować rozmiarami stosów i TOTAL_HEAP_SIZE, w pewnym momencie zwiększając je dwukrotnie. Nie pomogło.

- Nie pomogły też eksperymenty z różnymi opcjami Memory Management scheme. W tej chwili jest domyślna (heap_4) - ta sama co w starej wersji projektu.

- Próbowałem też podnieść rozmiar MEM_SIZE w ustawieniach lwIP z domyślnych 1600 bajtów do 10 kB. Nie pomogło.

Przeglądałem konfiguracje starego i nowego projektu, ale żadna istotna różnica nie rzuca mi się w oczy. Pewnie chodzi o jakiś drobiazg, którego nie potrafię zauważyć. Jest tutaj ktoś, kto na podstawie przedstawionych objawów mógłby wskazać potencjalne źródło problemu?

Reply to
Atlantis
Loading thread data ...

Drąż temat dalej: w którym miejscu się zatrzymuje ten MainTask? Albo: która operacja z IoTask zatrzymuje Main? Trzeba powrzucać więcej pułapek, albo przesuwać te printy metodą połowienia.

Reply to
Mirek

Wygląda na to, że MainTask po prostu zatrzymywał się w miejscu, w którym moja aplikacja oczekiwała na przybycie kolejnej paczki danych, które po wykrzaczeniu się stosu TCP/IP nigdy nie przychodziły.

Przeprowadziłem eksperyment podczas odtwarzania z nośnika lokalnego. Jeśli próbuję w tym czasie dostać się do serwera HTTP na urządzeniu sieć przestaje działać momentalnie (pingi nie dochodzą) ale Zarówno MainTask jak i IoTask kręcą się nadal i odtwarzanie jest kontynuowane.

Wygląda więc na to, że głównym problemem jest crash lwIP/łączności sieciowej przy pierwszej próbie dostania się do serwera. Próbowałem jeszcze raz porównać konfigurację działającego układu (na STM32F107) z tym obecnym, ale jeśli już, to nowa wersja dostaje więcej zasobów w paru miejscach.

Reply to
Atlantis

Nie mam pojęcia jak to jest zbudowane, ale można by sprawdzić czy wywala go samo połączenie TCP czy ten httpd. A jeśli podłączysz się telnetem? wywala od razu czy stoi połączenie? A jak stoi połączenie to wywala się jak coś wyślesz, czy grzecznie odpowiada, że nie rozumie? (400)

Reply to
Mirek

Dobry pomysł.

Okazuje się, że serwer przyjmuje połączenie z z telnetu. Działa nawet timeout jeśli zbyt długo zwlekam z wysłaniem requestu. Jeśli wyślę dwie puste linie albo jakieś bzdury i pustą linię, to serwer grzecznie się rozłącza bez wykrzaczania czegokolwiek. Podobnie wygląda sytuacja jeśli wyśle "GET" i pustą linię.

Problemy zaczynają się dopiero wtedy, gdy próbuję wysłać sekwencję "GET " (spacja na końcu) + pusta linia. Wtedy już płytka traci połączenie z siecią. Tak samo wygląda oczywiście sytuacja, jeśli próbuję np "GET /index.htm HTTP/1.1".

Jakiś pomysł co może odpowiadać za taki stan rzeczy?

W przypadku zdrowej płytki wysłanie "GET " + pusta linia skutkuje po prostu zwróceniem błedu 404.

Reply to
Atlantis

formatting link
formatting link
Nie jesteś sam :)

Adam Górski

Reply to
Adam Górski

Nie pojmuję co Ty pokazujesz. IwIP jest aż tak niedopracowany/niestabilny czy tylko trudny w poprawnej implementacji przy pierwszym podejściu?? Myślałem, że to pewna i dobra alternatywa np. dla stosów mchp (MLA/Harmony) a tu takie kwiatki?

Reply to
Marek

Muszę się temu dokładniej przyjrzeć, jednak do tej pory nie miałem podobnego problemu w projektach związanych używających lwIP. Miałem jeden problem z aplikacją wykorzystującą raw sockety, ale tam winnym okazał się mój kod na warstwie aplikacji, który ciężko było pogodzić z filozofią opartą na callbackach. To był jeden z powodów dla których jednak postawiłem na FreeRTOS - dzięki niemu zyskałem dostęp do standardowych socketów. W końcu lwIP jest wykorzystywany przez środowisko ESP8266/ESP32. Nie tylko nie spotkałem się tam z niestabilnością stosu, ale też układy te są coraz częściej wykorzystywane w komercyjnych projektach.

Generalnie na chwilę obecną wychodzi na to, że serwer www przyjmuje połączenia i jest w stanie odbierać dane. Problem pojawia się dopiero po tym, jak przesłany zostanie prawidłowy request HTTP GET. To znów mogłoby wskazywać na jakiś problem z pamięcią albo nadpisywaniem stosu, tylko już próbowałem zwiększać przydziały pamięci do dość znacznych wartości, a kod prawidłowo działa na płytce z dużo mniejszymi zasobami.

Reply to
Atlantis

Pokazuję , że wiele osób miało problem lub nadal ma. Nie jesteś jedyny któremu się wykłada. Szukałbym podobnych przypadków.

Z drugiej strony powinna być jakaś przykładowa aplikacja od ST.

lwIP był portowany na wiele platform. Na jednych działa lepiej na innych gorzej. Zależy od umiejętności i wiedzy osoby wykonującej port oraz od ustawień.

A baboli to w nim było.... - odnoszę się tutaj do wersji 1.3.0-1.4.0 z którymi miałem przyjemność na platformie Luminary Micro - później TI.

W moim przypadku wyp....ło się losowo po wielu godzinach pracy. Nie udało mi się ustalić dlaczego.

Czy lwIP , switch , kable czy PC.

Efekty samodokumentujacego się kodu i niepełnego testowania.

Powyższe jest wyłącznie moją subiektywną opinią i nie ma na celu obrażania kogokolwiek. Wynika wyłącznie z dziesiątek dupogodzin które odsiedziałem.

Pozdrawiam

Adam Górski

Reply to
Adam Górski

To co opisujesz (+wskazane problemy innych) wcale nie wzbudza zaufania do tego IwIP.... Na stosie MLA mam urządzenia mission critical obsługujące procesy produkcyjne chodzące 24h już z 8 lat non stop, nie wyobrażam sobie by urządzenie miało niestabilny stos wieszając się i wstrzymując/zaburzając produkcję. Nie wspominajac o mało poważnych pierdołach typu inteligentny dom. Tak rozglądam się z alternatywą bo stos MLA/Harmony trochę hermetyczny a fajnej by było coś na innych mcu zrobić...

Reply to
Marek

No ale co, nie ma możliwości zdebugowania w którym miejscu kodu się zatrzymuje?

Reply to
Marek

Czyli httpd nic nie zwraca - najwyraźniej ma problem z wysłaniem czegokolwiek. Podejrzewałem jeszcze jakiś krzak w danych strony - jakiś niedozwolony znak czy po prostu niemożliwość odczytania tych danych... ale wtedy 404 powinien zwracać bez problemu... no chyba że on sprawdza czy ma coś takiego do wysłania, próbuje odczytać i dup.

No właśnie, w a w przypadku innych śmieci ta zdrowa wyrzuca bad request

400 czy też tylko się rozłącza?
Reply to
Mirek

On 24.01.2023 20:15, Marek wrote: .

Już od paru lat stosuję w swoich projektach sos MLA i mam podobne obserwacje. Urządzenia działające 24/7 właściwie nigdy same z siebie nie gubiły połączenia ani się nie zawieszały. Od jakiegoś czasu stosuję też ESP8266/ESP32, gdzie pod maską również siedzi lwIP. I tutaj także stabilność wygląda bardzo dobrze. Jeden ze swoich starszych projektów przeniosłem z tandemu PIC32+ENC28J60 na ESP8266. Doświadczenia z korzystania były bardzo zbliżone - płytka działała nieprzerwanie tygodniami (albo i miesiącami) podczas testów. Zawieszeń albo niestabilności nie zauważyłem.

STM32 w zastosowaniach sieciowych używam od niedawna. Projekt z którym mam problemy jest drugą płytką tego rodzaju. Ta pierwsza zachowywała się stabilnie. Dopiero teraz trafiłem na ten problem.

Dlatego jednak podejrzewam, że możliwości są dwie:

- Ja zrobiłem coś nie tak i teraz muszę znaleźć przyczynę (najbardziej prawdopodobne).

- Za wadliwe działanie odpowiada fragment kodu wygenerowany przez STM32CubeMX, wtedy będę musiał go znaleźć i naprawić.

Reply to
Atlantis

Hmm... Ta hipoteza ma sens w kontekście tego jak działa serwer HTTPD z lwIP. Stronę WWW konwertuje się do tablic C za pomocą odpowiedniego narzędzia (windowsowy plik exe, jednak działa pod Linuksem z Wine), podobnie jak miało to miejsce z HTTP2 z MLA na PIC32. Treść wyświetlana w przypadku błedu 404 powinna być dostarczona w formie pliku "404.htm", umieszczonego w głównym katalogu konwertowanej strony. Dzięki temu mamy możliwość przygotowania komunikatu o błędzie w formie konsystentnej wizualnie z całą resztą. Nie wiem jak z innymi kodami błędów - nie sprawdzałem.

Czyli w przypadku prośby o nieistniejący plik, serwer również będzie chciał pobrać stronę z tego miniaturowego fs-a we flashu.

Mamy więc dwie prawdopodobne możliwości:

- Serwer wiesza się na próbie dostania pobrania pliku

- Serwer wiesza się na próbie wysłania danych

To drugie wydaje się trochę bardziej prawdopodobne biorąc pod uwagę fakt, że awaria wykrzacza całą komunikacje sieciową, ale nie powoduje zawieszenia schedulera RTOS-a.

Zdrowa płytka po prostu się rozłącza, nie odsyłając niczego. Telnet zostawia tylko informację "Connection closed by foreign host."

Reply to
Atlantis

Taki jest plan. Problemem jest mocno ograniczona ilość czasu na debugowanie tego wieczorami. ;)

Reply to
Atlantis

Ło matko, a w Harmony też tak jest? Nie zrobili jeszcze w "normalnego" httpd serwującego pliki z fatfs + handlery cgi-bin? Przecież jakakolwiek aktualizacja kontentu strony to rekompilacja całości, nonsens...

Reply to
Marek

No to wyprintuj tą stronę, będzie wiadomo że ją prawidłowo czyta z tablicy.

No coś tam mówiłeś, że nie odpowiada na pingi. A który wątek odpowiada na pingi? A pingi z większymi pakietami chodzą?

A w ogóle to masz tam jeszcze coś, co może wysyłać dane? Może jakiś netcat udp-sender albo coś?

Reply to
Mirek

Marek snipped-for-privacy@fakeemail.com napisał(a):

Nie zawsze masz jakąś pamięć poza Flashem wewnątrz uC.

Reply to
Grzegorz Niemirowski

Marek snipped-for-privacy@fakeemail.com napisał(a):

Jest dopracowany. To dojrzały projekt, stosowany masowo. Sam też używam. Stawiam na nieumiejętność implementacji.

Reply to
Grzegorz Niemirowski

Ok, dodałem jeszcze kilka printf-ów w kodzie. Udało mi się na razie ustalić jeszcze tyle, że:

  1. Płytka odbiera i parsuje request GET, wyciągając z niego ścieżkę dostępu do żądanego pliku.
  2. Funkcje fs_open() jest wołana z tą ścieżką jako parametrem.
  3. Plik jest znajdowany, ponieważ funkcja zwraca status "ok".
  4. Wywoływana jest jeszcze funkcja fs_close.
Reply to
Atlantis

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.