Elektroda.pl
Elektroda.pl
X

Search our partners

Find the latest content on electronic components. Datasheets.com
Elektroda.pl
Please add exception to AdBlock for elektroda.pl.
If you watch the ads, you support portal and users.

Moduł radiowy RFM95W i odebranie pakietu większego niż pojemność FIFO

13 Apr 2021 21:34 444 11
  • Level 29  
    Witam, męczę się z prawidłowym ustawieniem tego modułu do odebrania pakietu danych, który jest prawie 2x większy niż pojemność FIFO. Kombinuję na wszelkie sposoby, aby ze wskazanego DIO tego modułu odebrać właściwe przerwanie i je obsłużyć w callbacku EXTI w STM32.
    Nie mam większego problemu z odebraniem danych z pierwszej raty tego pakietu w locie, czyli zbieram do tablicy te pierwsze 64 bajty, następnie ćwiczę aby jakoś w drugim rzucie odebrać brakujące dane, które w sumie mają mieć około 108 bajtów. Załączam screeny z manuala modułu radiowego odnośnie ustawień jego portów DIO. Aktualnie korzystam z DIO0 i DIO1, które mam podłączone do portów STM32 jako EXTI. Czy jakoś w locie powinienem wymusić wyczyszczenie FIFO, przez np. włączenie trybu TX i od razu powrót do RX? Mam wrażenie, że ciągle zbieram tą drugą ratę jakby z nieopróżnionego FIFO, czyli powiedzmy pierwszy bajt we FIFO w drugim rzucie jest jakby sklonowany w całym FIFO (nie zdążył się przesunąć ?)- nie wiem jak mam to określić. Definiuję już rejestry mappingu DIO na payload ready, na fifo level, na fifo empty i jakoś nie przynosi to efektu. Zegar SPI ustawiony na 5MHz, próbowałem zwalniać, nie widać zmian, proszę o jakieś nakierowanie.
    Wg manuala muszę czytać FIFO w locie, aby nie doszło do jego przepełnienia, ale to tyle teorii. Jak to zrobić praktycznie? Czy absolutnie nie powinien zmieniać trybu pracy Rx przy odbiorze tej drugiej raty i tylko polegac na przerwaniach od RFM95? FIFO czytam w trybie burst, najpierw 64 bajty i potem kolejne 44.
    For Rx:
    FIFO must be unfilled “on-the-fly” during Rx to prevent FIFO overrun.
    1) Start reading bytes from the FIFO when FifoEmpty is cleared or FifoThreshold becomes set.
    2) Suspend reading from the FIFO if FifoEmpty fires before all bytes of the message have been read
    3) Continue to step 1 until PayloadReady or CrcOk fires
    4) Read all remaining bytes from the FIFO either in Rx or Sleep/Standby mode

    FifoThreshold ustawiam w pierwszym czytaniu FIFO na 64 bajty w drugim czytaniu na 32 bajty, rejestr RegPayloadLength ustawiam też na 64 bajty a nawet na 0 i jakoś nie widzę efektu.

    Poniżej fragmenty kodu i moje kombinacje do odczytu FIFO po wysłaniu krótkiego polecenia do urządzenia i odebrania od niego pakietu danych, pętle opóźniające wstawiam, aby coś podiagnozować.
    Code: c
    Log in, to see the code



    Moduł radiowy RFM95W i odebranie pakietu większego niż pojemność FIFO
    Moduł radiowy RFM95W i odebranie pakietu większego niż pojemność FIFO
  • VIP Meritorious for electroda.pl
    Na początek wymuszaj czyszczenie FIFO zaraz po przełączeniu się do TX. Po odebraniu pakietu i odczytaniu go przez SPI, na końcu bufora zostaje jeden bajt, który dokłada się do wysyłanego pakietu (na początku, jako ilość bajtów) kiedy przełączasz się na TX. Dokumentacja zapomniała o tym wspomnieć. To powinno też rozwiązań notoryczne odczytywanie identycznej wartości z FIFO po odebraniu pakietu.
    A co do samego programu, to jest napisany z użyciem magic numbers, więc nie mam pewności czy wszystko dobrze wpisujesz. Osobiście wolę używać definicji zbudowanych na podstawie dokumentacji. W ten sposób ustawienia określam wydając polecenia tekstowe, zamiast kodów liczbowych.
    Algorytm można znacząco poprawić o diagnostykę zamiast stosować zwykły timeout i odczyt, a operacje przez SPI powinny być weryfikowane pod kątem przepełnienia bufora. Na pewno wysyłasz to co należy do RFM? STM32 mają 4 różne generacje modułów SPI. W tych nowszych dane są buforowane i/lub składane w pakiety przed wysłaniem i może to powodować niespodzianki.
  • Level 29  
    Dzięki za odpowiedź, proszę jeszcze o wskazanie czy poniższy rejestr RegFifoThresh(0x35) powinienem ustawić na wartość 0x41 (czyli 7 bit ma być zerem, a wtedy dostaję przerwanie na DIO1, którego mapping ustawiam na FiFoLevel) ? W pierwszym czytaniu FIFO mam zebrać 65 bajtów zamiast 64?
    Moduł radiowy RFM95W i odebranie pakietu większego niż pojemność FIFO

    Drugie pytanie, czy to czyszczenie FIFO robić od razu po każdym wejściu w tryb Tx (może też po Rx? ) np. przez zapis 1 do bitu FifoOverrun poniższego rejestru?
    Moduł radiowy RFM95W i odebranie pakietu większego niż pojemność FIFO

    Dodam, że używam sniffera na RPi4 i dokładnie widzę co wysyłam i co odbieram i bardziej to czego nie odbieram a jest na snifferze i dlatego widzę, że drugie czytanie FIFO mam błędne na STM32.
    Czy zamiast polegać na przerwaniu z DIO zaraz po przejściu do trybu Rx powinienem w pętli czytać rejestr RegIrqFlags2 i reagować tylko na ustawienie jego bitu FifoLevel po czym odczytać FIFO w pierwszym czytaniu?
  • VIP Meritorious for electroda.pl
    W moich układach mam pakiety o zmiennej długości, a FIFO threshold jest ustawiony tylko dla nadawania na wartość w zakresie 7-10 bajtów. Przerwanie dla odebranych danych jest zgłaszane po odebraniu ilości wszystkich bajtów wskazanych pierwszą wartością pakietu. I to działa bezbłędnie.
    Po zgłoszeniu przerwania od RX, włączam tryb Standby i odczytuję dane, ale operuję tylko na pakietach o długości do 64 bajtów. Jak kiedyś wrócę do rozwijania protokołu transmisji, to przetestuję opcję z dłuższymi pakietami. Pewnie skorzystam z sekcji Payload Data Extraction from FIFO na stronie 36. w dokumentacji dla modułów RFM95/96/97/98(W), która mówi o warunkach jakie muszą być spełnione dla poprawnego pakietu i jak odczytać dane z ostatniego pakietu, kiedy FIFO nie podlega czyszczeniu.
  • Level 29  
    U mnie mam tak, że tzw. krótkie pakiety mają 11 bajtów do wysyłu i odbioru i dla nich oddzielnie konfiguruję tryby Tx i Rx- tu jest wszystko OK, następnie najczęściej mam też odpowiedzi długie na 107 bajtów i tu kombinuję z właściwym ustawieniem rejestrów RegPayloadLength oraz RegFifoThresh po czym czekam na przerwania DIO0 lub DIO1 od RFM95 i czytam FIFO. Załączam screen z małymi komentarzami, gdyby Kolega był w stanie mi tutaj coś odpowiedzieć? Pierwsza paczkę zbieram idealnie 65 bajtów z przerwania wystawionego na DIO0. Na podglądzie systicka widać, że nie wyskoczyłem poza timeout- więc moim zdaniem tu przerwanie działa idealnie. Poniższe linijki do odczytu brakującego ciągu to już kombinowanie jak koń pod górę, bo żaden z portów DIO nie zgłasza mi tego jak należy, czyli albo za wcześnie, albo za późno, albo wcale.
    Pewnie uruchomię po pierwszym czytaniu ciągły odczyt rejestru RegIrqFlags2 i tu będę szukał momentu odebrania drugiego rzutu danych zamiast polegać na zgłoszeniu się któregoś DIO- czy to ma sens?

    Moduł radiowy RFM95W i odebranie pakietu większego niż pojemność FIFO

    edit. w komentarzu w linii 300 powinno być // oczekiwanie na DIO0 z timeout 1s

    Wydaje mi się, że ta informacja na temat Payload Data Extraction from FIFO dotyczy tylko konfigu w tryb LoRa, ja natomiast używam modulacji OOK.
    Moduł radiowy RFM95W i odebranie pakietu większego niż pojemność FIFO
  • VIP Meritorious for electroda.pl
    Może zamiast tak kombinować, to spróbujesz tego co jest opisane na stronie 69 w sekcji Unlimited Length Packet Format i dalej do strony 71? Jeżeli wysyłany pakiet ma długość 107 bajtów, albo jest ładowany na raz do bufora nadajnika z odpowiednio niską prędkością po SPI, albo musi być ładowany po kawałku, z odpytywaniem flagi FIFO, albo zachowaniem zależności czasowych.
    W odbiorniku ten pakiet będzie też odbierany jako pakiet ciągły, co wymusza konieczność czytania FIFO zanim załadujesz 65 bajtów. Później, to już po ptokach. Proponuję ustawić znacznik dla FIFO na poziomie 44 bajty i odczytywać na ślepo 44 bajty jak tylko zgłosi się bufor przez linię DIO1 w trybie FifoLevel, ewentualnie możesz zrobić polling, ale to będzie takie lamerskie podejście. To daje czas na reakcję na przerwanie, a w przypadku odczytania FIFO do zera, daje to gwarancję przyjęcia pozostałych 64 bajtów, które można już spokojnie odczytać bez ryzyka utraty pakietu. Można rozbić całość na 3 lub więcej odczytów, ale nie widzę takiej potrzeby. 107 < 128, co przy sensownej prędkości SPI daje szansę odczytania całego długiego pakietu przed zapełnieniem FIFO. Jak FIFO się wypełni, to nie ma już miejsca na kolejne bajty i reszta pakietu jest tracona.
    Czekanie na timeout nic nie daje. Jak dane nie dotarły, to już nie dotrą. Jak jest błąd CRC to pakiet należy odrzucić i przywrócić odpowiedni stan modułu radiowego, np. wejść w tryb odbiornika i wyczyścić FIFO.

    Nie jest też dla mnie jasne czy korzystasz z trybu continuos w obszarze toru RF (czyli transmisja bez obsługi pakietów), czy jednak z pakietami, ale w trybie ciągłego nasłuchu. Przypuszczam, że to drugie.
    Jest też różnica między pakietem o zerowej długości, czyli pakietem o tzw. nielimitowanej długości, czy jednak określasz długość pakietu i wysyłasz ten parametr jako pierwszy bajt pakietu. Wpisanie 0 to nie jest deklaracja pakietu o długości 64 bajty.
  • Level 29  
    Dziękuję Marku za dotychczasowe podpowiedzi, ale pytań przybywa. Korzystam z trybu packet mode. Po pierwsze czy takie czyszczenie FIFO poprzez ustawienie bitu FifoOverrun na 1 w rejestrze RegIrqFlags2(0x3F) jest prawidłowym działaniem? Zrobiłem odczyt tego rejestru zaraz po nastawieniu bitu FifoOverrun i z odczytu wyszło, że ustawiony jest bit FifoEmpty - więc wygląda na prawidłowe zadziałanie. Drugie pytanie czy pin NSS powinienem trzymać w stanie niskim po zakończeniu pierwszego czytania FIFO i dopiero wrócić z nim do stanu wysokiego po drugim czytaniu? Czy po konfigu do Rx też od razu wstawiać czyszczenie FIFO i dopiero po tym czekać na przerwania z DIO? Czy w ogóle reagować na DIO0, które ustawia mi się na PayloadReady czy używać tylko DIO1 jako FifoLevel? Jak rozumieć zgłoszenie się DIO0 przy PayloadReady, czy jeśli zadeklaruję rejestr RegPayloadLength(0x32) na wartość 0x6B (czyli moje 107 bajtów) to oznacza, że RFM95 odebrał pełny sygnał i pierwszą część już ma we FIFO, a drugą część mi wepchnie do FIFO jak je odczytam, czy muszę wtedy też wykonać swoje FIFO_clear(); ?

    Code: c
    Log in, to see the code


    Ważne pytanie, czy po pierwszym czytaniu FIFO mam zmienić tryb na Sleep / Standby, a może lepiej przed samym czytaniem FIFO. I wtedy ponownie uruchomić Rx, odczekać na DIO1 i zrobić Sleep modułu po czym odczytać druga cześć z FIFO?
  • VIP Meritorious for electroda.pl
    Transmisja długiego pakietu to zdarzenie niepodzielne. Trzeba odczytywać FIFO jak tylko osiągnie sensowny poziom i czytać stale do zakończenia transferu albo odczytywać z prędkością odpowiadającą prędkości transmisji w torze radiowym. Ten układ nie ma żadnego innego bufora danych, więc jeżeli nie może zapisać do FIFO, to traci dane.
    Jak wpiszesz długość pakietu 107 bajtów i będziesz czekał na przerwanie PayloadReady, to już po wszystkim. Nie wnikam na tym etapie czy pierwsze bajty zostaną nadpisane nowszymi, czy nowsze zostaną odrzucone. Po prostu nie zadziała.
    Nie przesyłałem długich pakietów, ponieważ kosztuje to dużo energii i zajmuje dużo czasu antenowego. Ryzyko złapania błędu rośnie z ilością bajtów w pakiecie. Wolę wysłać krótsze pakiety na zasadzie ping-pong, a na końcu sleep.
    Czyszczenie FIFO wykonuję po każdym wejściu w tryb TX. W trybie RX nie zauważyłem takiej potrzeby, jeżeli wszystko jest odczytane. Tutaj chyba automat układu działa dobrze. Obawiam się, że zbytnio już tutaj nie pomogę.
  • Level 29  
    Dzisiaj testowo odpuściłem poleganie na przerwaniach zgłaszanych na portach DIO od RFM95. Po każdym wysłaniu pakietu z żądaniem nastawiam w pętli while sprawdzanie rejestru RegIrqFlags2(0x3F), po natrafieniu na ustawiony bit FifoLevel wykonuję od razu pierwsze czytanie FIFO, robię to przy nastawieniu FifoThreshold na wartości pomiędzy 40 a 64 bajty i wygląda to sensownie, mam wrażenie, że bardziej niezawodnie niż obsługa przerwań z DIO. No, ale cały czas nie mogę się przebić i drugie czytanie powoduje mi praktycznie odczyt powielonego dziesiątki razy pierwszego bajtu z pierwszego czytania, nie pomaga pomiędzy czytaniami wstawianie czyszczenia FIFO. Przed drugim czytaniem sprawdzałem też zawartość rejestru RegIrqFlags2(0x3F) na różne opcje, ale cały czas błądzę.


    Moduł radiowy RFM95W i odebranie pakietu większego niż pojemność FIFO
  • Level 22  
    Na potrzeby oprogramowania napisałem kod który przesyła NRF24 dużo dłuższe dane niż pozwalają na to bufory sprzętowe radyjek.
    Kod stary. Teraz zrobiłbym to lepiej.
    Kolejka FiFo tam jest i dzielenie tego ile wejdzie w jeden pakiet.
    Moduł radiowy RFM95W i odebranie pakietu większego niż pojemność FIFO
  • Level 29  
    Bitrate w moim sygnale radiowym to 16384 b/s, modulacja OOK na 868,35MHz, pamiętam gdy robiłem to samo na module RFM69 to musiałem drastycznie zejść z zegarem SPI do poziomu baud rate = 39.062 KBits/s wtedy dopiero udawało się złapać prawidłowo w locie te 107 bajtów i CRC pasowało. Moduł RFM95 jest nieco nowszym układem i myślałem, że przejdę finalnie na to radio, chociaż nie mam pewności czy różni się czymkolwiek jeśli chodzi o obsługę modulacji OOK, bardziej mi zależało na większej czułości odbiornika. Jeszcze parę wieczorów pobadam temat, jak nie wyjdzie to wracam do RFM69. Najbardziej mnie martwi, że nie mogę się pozbyć z FIFO jakby ostatniego bajtu 0xA9, który nie wiadomo skąd mi się tam bierze, nie pomaga na to czyszczenie FIFO albo muszę dać RFM95 niewielką pauzę, aby zdążył się ogarniać z tym czyszczeniem. Prawdopodobnie przez ten niewyczyszczony ostatni bajt drugie czytanie mam same 0xA9.
  • Level 29  
    Jakiś czas temu udało mi się uruchomić ten pełny odczyt danych w ilości 107 bajtów. Jako, że bitrate w sygnale radiowym wynosi 16384b/s, z przeliczenia wychodzi 488us pomiędzy bajtami. Przerwanie jest odebrane z DIO0 po napłynięciu do FIFO pierwszego bajtu, resztę załatwiło odpytywanie rejestru 0x3F i sprawdzanie bitu FifoEmpty, jeśli FIFO nie jest puste to dałem odczyt pojedynczego bajtu i tak w pętli operacja powtórzona 107 razy.
    Fragment kodu poniżej:
    Code: c
    Log in, to see the code
pcbway logo