Temat nRF24L01+ wisiał u mnie na liście “do zrobienia” w zasadzie odkąd powstał ten blog. Układ ten jest jednym z najpopularniejszych wśród układów radiowych. Moduły z Chin kosztują przysłowiowe grosze, a możliwości jakie oferują te nRFy są nieziemskie. Dlaczego zatem trwało to u mnie tyle czasu?Problem polegał na tym, że kilka lat temu, kiedy jeszcze psiałem tylko na AVR miałem z tymi modułami ogromny problem. Nie mogłem ich zmusić do pracy z przerwaniami. Teraz, gdy mam o wiele więcej doświadczenia poszło prawie od razu. Gdy już się odblokowałem to postanowiłem pójść za ciosem i napisać tę mini serię o tych świetnych modułach.
Cała seria o nRF24L01+:
Układ nRF24L01+
Układ ten obsługuje komunikację radiową na częstotliwości 2,4 GHz. Posiada 126 programowalnych kanałów, na których może nadawać. Najlepsze jest to, że te kanały nie nachodzą na siebie tak jak np. kanały WiFi.
Ustawiać można również prędkość transmisji oraz moc nadajnika. Przyda się do ograniczania poboru mocy. Do tego również przyda się tryb Power Down.
Teraz najlepsze. Układy nRF24L01+ wspierają technologię Enchanced ShockBurst™. Brzmi niczym jakiś dziwny slogan reklamowy. Co to nam daje? Najważniejsze rzeczy to:
- Automatyczna obsługa pakietów radiowych. Nie musisz się zastanawiać na tym, czy trzeba wysyłać po radiu jakieś bity startu, stopu, preambuły i inne tego typu rzeczy. Do nRFa wrzucasz tylko to co chcesz de facto wysłać i on sam to opakowuje w pakiety. Przy odbiorze natomiast sam do zdekoduje zwracając Twoje dane czyli tzw. Payload.
- Payload jest dynamiczny. Co to oznacza? Możesz nadawać wiadomości o wielkości 1-32 bajtów, a moduły między sobą same przekażą sobie ile tych danych przeszło w Payloadzie.
- Automatyczne potwierdzenie odbioru pakietu. Nie musisz odsyłać żadnych “okejek” z powrotem. ACK jest sprzętowe i jeśli odebrałeś Payload, obydwie strony będą o tym wiedziały.
- Automatyczna kontrola CRC. Nie musisz tego sam liczyć i sprawdzać. Robi to za Ciebie układ! Jeśli pakiet przyjdzie uszkodzony, nRF go odrzuci i nie odeśle potwierdzenia przy okazji na przykład zmuszając do retransmisji układ nadawczy.
- Odbiór z wielu nadajników. Maksymalnie z sześciu. Pomaga to łączyć układy w układ siatki, gwiazdy i inne figury.
Układy są adresowane 3-5 bajtami. Przy czym adres “tunelu” Pipe 0 i 1 są w zasadzie dowolne. Pozostałe Pipe’y 2÷5 posiadają identyczną starszą część adresu jak Pipe 1. Różnią się jedynie najmłodszym bajtem. Tłumaczy to ten rysunek z dokumentacji.
Moduły z nRF24L01+
Wspomniałem na początku, że popularność układu zawdzięczamy między innymi tanim i łatwo dostępnym modułom z Chin. Podstawowy moduł posiada wyprowadzenia na klasycznych goldpinach 2,54″ i kosztuje kilka zł.
Jest też wersja “MINI” która jest delikatnie mniejsza i pozwala na montaż SMD.
Tym, którym zależy na dobrym zasięgu spodobają się moduły ze sporą anteną zewnętrzną oraz wzmacniaczem RF. Na tych modułach można wykręcić niezłe zasięgi.
Wszystkie te moduły znajdziesz do kupienia w moim sklepie.
Niestety nie jest aż tak pięknie. Muszę Cię trochę przestrzec. W Chinach jak to w Chinach lubi się kopiować. Układ nRF24L01+ został skopiowany i wydany pod nazwą Si24R1. Działają “tak samo”, ale wiadomo jak to może z nimi bywać. Podchodziłbym do nich z lekkim dystansem.
W swoim sklepie wyraźnie oznaczam jaki układ został położony na module. Jednak wiadomo – na scalaku można napisać wszystko, więc tak naprawdę nikt nie wie co tam siedzi. Ja z mojej strony robię co mogę.
Schemat podłączenia do Nucleo
Skorzystam z klasycznych układów na pinach 2,54″. Podłączenie dla nadajnika i odbiornika jest identyczne. Poniżej masz pinout samego modułu. Niestety nie jest on opisany na PCB, więc podłączenie chwilę zajmuje.
Ważne jest to, że układ nRF24L01+ zasilany jest z 3V3. Gdyby nie chciał z jakiegoś powodu działać poprawnie, warto dorzucić kondensator elektrolityczny jak najbliżej pinów zasilania np. 1 uF. Potrafi dużo pomóc.
Konfiguracja w CubeIDE
Do testów wykorzystałem dwie prawie identyczne płytki Nucleo – F401RE i F410RB. Dzięki temu projekty nadajnika i odbiornika są niemal takie same 🙂
Wersje oprogramowań, z których korzystam:
- STM32CubeIDE v1.3.0
- STM32CubeMX v5.6.0 wbudowany w IDE
- Biblioteka HAL dla F4 v1.25.0
Projekt stworzyłem z domyślnym ustawień peryferiów dla Nucleo – UART i Serial Debug mam z głowy 🙂
Do komunikacji z mikrokontrolerem moduł wymaga interfejsu SPI. Obsługuje on maksymalnie 10 MHz, więc standardowo jak przystało na układy SPI. Pewnie da się spokojnie podkręcić, gdyby się uprzeć 🙂
Lubię wykorzystywać piny Arduino, bo mam do nich łatwy dostęp również analizatorem logicznym. SPI1 jest na tych pinach, więc to jego użyję.
Ustaw w tryb Full-Duplex Master. Jeśli zrobiłeś tak jak ja z ustawieniami domyślnymi to HCLK masz ustawiony na 84 MHz, a co za tym idzie SPI taktowane jest zegarem 42 MHz . Preskaler do SPI ustawiłem na 16, więc wynikowo na zegarze SPi uzyskam coś około 2,63 MHz. Idealnie do podglądu na mało wydajnym analizatorze logicznym.
Moja konfiguracja jest na screenie.
Moduły nRF24 mają jeszcze kilka innych pinów: CE, CSN, IRQ. Dwa pierwsze są to wejścia, więc piny MCU musisz ustawić jako GPIO Output.
IRQ to przerwanie, więc ustaw GPIO_EXTI.
Ja użyłem PA9, PB6 i PC7, które są obok pinów SPI. Wszystko jest w kupie.
Na razie przerwań nie użyjemy, ale warto mieć już skonfigurowane GPIO 🙂
Kod
Jak wspomniałem na wstępie do tego wpisu, bibliotekę miałem już częściowo przygotowaną sprzed kilku lat. Z tego, co się orientuję bazowałem na popularnej i dosyć dobrze działającej bibliotece RF24 z Arduino. Nie było wtedy tam dobrej obsługi przerwań, a moje próby zakończyły się chwilową porażką.
Wracam silniejszy i już doszedłem do działających przerwań, ale o nich będzie w kolejnej części serii o nRF24. Dzisiaj przedstawię Ci konfigurację układu oraz podstawowy tryb działania, czyli polling.
Zacznę od inicjalizacji.
void nRF24_Init(SPI_HandleTypeDef *hspi) { hspi_nrf = hspi; NRF24_CE_LOW; NRF24_CSN_HIGH; nRF24_Delay(5); // Wait for radio power up nRF24_SetPALevel(NRF24_PA_PWR_0dBM); // Radio power nRF24_SetDataRate(NRF24_RF_DR_250KBPS); // Data Rate nRF24_EnableCRC(1); // Enable CRC nRF24_SetCRCLength(NRF24_CRC_WIDTH_1B); // CRC Length 1 byte nRF24_SetRetries(0x04, 0x07); // 1000us, 7 times nRF24_WriteRegister(NRF24_DYNPD, 0); // Disable dynamic payloads for all pipes nRF24_SetRFChannel(10); // Set RF channel for transmission nRF24_SetPayloadSize(0, NRF24_PAYLOAD_SIZE); // Set 32 bytes payload for pipe 0 nRF24_EnablePipe(0, 1); // Enable pipe 0 nRF24_AutoACK(0, 1); // Enable auto ACK for pipe 0 nRF24_SetAddressWidth(NRF24_ADDR_SIZE); // Set address size nRF24_Delay(20); nRF24_EnableRXDataReadyIRQ(0); nRF24_EnableTXDataSentIRQ(0); nRF24_EnableMaxRetransmitIRQ(0); nRF24_Delay(20); nRF24_ClearInterrupts(); }
Jak zwykle w moich bibliotekach trzeba podać wskaźnik do handlera SPI, z którego chcemy korzystać.
Może zwróciłeś już wcześniej na to uwagę, ale mamy taki pin jak CE. To nie jest pin CS od SPI. Ten pin służy do wyboru trybu nadawania i odbierania. Libka w pełni się nim zajmuje 🙂
Inicjalizacja obejmuje między innymi takie rzeczy jak:
- Ustawienie mocy nadajnika
- Ustawienie prędkości transmisji
- Włączenie CRC i retransmisji
- Ustawienie kanału RF
- Wielkość Payload
- Wielkość adresów
Na końcu są ustawienia przerwań. Na tę chwilę wszystkie wyłączyłem, ale trzeba je jeszcze skasować. Wyłączone zostanie tylko odzwierciedlenie na pinie IRQ. Rejestry zachowują się tak jakby te przerwania były i będziemy z nich korzystać, aby dowiedzieć się, czy coś przyszło.
Wszystkie te ustawienia, zwłaszcza moc nadawania, prędkość i kanał możesz spokojnie ustawić według swoich upodobań. Czy to zmienić w inicjalizacji, czy już później – to sam zadecydujesz.
Są jeszcze dwie stałe, które ustawiasz w pliku nRF24_Defs.h.
#define NRF24_PAYLOAD_SIZE 1 #define NRF24_ADDR_SIZE 3
Odpowiadają one za wielkość Payload (1-32) oraz długość adresowania (3-5).
Teraz trzeba ustawić adresy. W RX ustawiasz adres, pod którym chcesz odbierać. W TX – do jakiego nadajesz. Na końcu włączam odpowiedni tryb.
Dla nadajnika będzie to tak.
nRF24_SetRXAddress(0, "Nad"); nRF24_SetTXAddress("Odb"); nRF24_TX_Mode();
Odbiornik:
nRF24_SetRXAddress(0, "Odb"); nRF24_SetTXAddress("Nad"); nRF24_RX_Mode();
I już można nadawać/odbierać. W przykładzie mam ustawioną długość Payload jako jeden znak, więc przesyłać będę cyfry 0-9.
for(i=0; i<10; i++) { MessageLength = sprintf(Message, "%d", i ); nRF24_WriteTXPayload(Message); HAL_Delay(1); nRF24_WaitTX(); HAL_Delay(1000); }
W tym prostym kodzie przygotowuję liczbę pod postacią znaku ASCII, wpisuję ją to TX Payload oraz czekam na nadanie. I tak co sekundę. Jak to odebrać?
if(nRF24_RXAvailible()) { nRF24_ReadRXPaylaod(Nrf24_Message); MessageLength = sprintf(Message, "%c\n\r", Nrf24_Message[0]); HAL_UART_Transmit(&huart2, Message, MessageLength, 1000); }
Funkcja nRF24_RXAvailible() sprawdza bit RX_DR w rejestrze statusowym. Mówi on nam o tym, że coś przyszło i czeka w FIFO nRFa. Jeśli mamy coś, to trzeba odczytać funkcją nRF24_ReadRXPaylaod().
Później przywracam liczbę i wypycham ją na UART. Efekt działania.
Podsumowanie
Tak wygląda najprostsza obsługa, czyli blokujący polling. Nie wykorzystałem też jeszcze dynamicznego Payload. Układ nRF24L01+ może nam podać ile przyszło i ile ma wyjść danych. Nie musimy wtedy ograniczać się do sztywnej długości wiadomości. Na pewno będzie to przydatne.
Tym zajmę się w kolejnym wpisie. Tak samo, jak obsługą przerwaniową, która jest zdecydowanie lepsza niż odpytywanie układu.
Jeśli artykuł Ci się spodobał, możesz mnie wesprzeć kupując coś u mnie 🙂 https://sklep.msalamon.pl/
Cała seria:
Pełny projekt wraz z biblioteką znajdziesz jak zwykle na moim GitHubie: NADAJNIK, ODBIORNIK
Jeśli zauważyłeś jakiś błąd, nie zgadzasz się z czymś, chciałbyś coś dodać istotnego lub po prostu uważasz, że chciałbyś podyskutować na ten temat, napisz komentarz. Pamiętaj, że dyskusja ma być kulturalna i zgodna z zasadami języka polskiego.
5 komentarzy
Adam Fulara · 31/12/2020 o 13:28
Super, korzystam. Kilka godzin walczyłem z połączeniem STM32 (BluePill) do działającego systemu nRF24l01 na Raspberry Pi (Zero). Napisałem wpis z programem jak to można w miarę szybko zrobić, dopisałem kilka funkcji do tej biblioteki, może komuś się przyda (np. wypisanie rejestrów nRF na STM32). http://fx-team.fulara.com/stm32-nrf24l01-rpi/
Mateusz Salamon · 04/01/2021 o 08:17
Dzięki za podzielenie się!
SaS · 25/05/2020 o 01:55
Nie miałem okazji użyć tych modułów choć leża u mnie już długo. Ten wpis zmotywuje mnie aby wypróbować je w praktyce w najbliższym czasie.
Mateusz Salamon · 28/05/2020 o 12:37
Bierz bo są fajne tyle tylko, że “Not for new design” według Nordica 🙁 Ciekawe co je zastąpi.
dambo · 04/07/2020 o 18:05
Nordic ma mega procki z wbudowanym radio i chyba w tym kierunku to pójdzie + możesz na nich użyć różnych protokołów jak BLE itp, ale też zrobić tzw “proprietary protocol”. Nawiasem jako ciekawostka – jest też od nich procek, który ma “wbudowanego” właśnie tego NRFa w jednej obudowie, dla dużych graczy kupujących w setkach tysięcy jakieś układy im ich mniej tym lepiej/taniej – hobbyści to żaden target.