Skocz do zawartości

STM32 i nRF24L01 - problem z ponowieniem transmisji


Vroobee

Pomocna odpowiedź

Witam,

piszę z pytaniem odnośnie modułów nRF24L01. Procem nadrzędnym jest STM32F107RCT6. Mam dwa układy - nadajnik i odbiornik. Nadajnik zbiera pomiary z 8 kanałów ADC i z częstotliwością 50 Hz wysyła dane do odbiornika. Odbiornik odbiera dane i wysyła przez USB te dane do kompa. Wszystko jest git dopóki najpierw uruchomiony jest odbiornik, a potem nadajnik. Jeśli jest odwrotnie lub jeśli np. odbiornik zostanie zresetowany, to nadajnik cały czas sypie danymi, a odbiornik tych danych nie odbiera. Tak jakby układy nie mogły się sparować. Pytanie czy tak po prostu jest z tymi modułami czy coś jest nie tak w kodzie (mogę podesłać biblioteki z których korzystam i kody programów RX i TX). Ew. co zrobić, żeby ta transmisja została nawiązana ponownie przy np. braku ACK z odbiornika, nie wiem jakiś reset sprzętowy ? 

Link do komentarza
Share on other sites

Nie widząc kodu trudno coś powiedzieć, a za słabo znam STM-y żeby go oglądać...

Ja robię tak: nadajnik wysyła kolejną paczkę dopiero jeśli dostanie ACK lub minie timeout - ustawiam na pół sekundy. Nie miałem nigdy takich problemów (Arduino, RPi Pico, ESP32 w różnych konfiguracjach). Nadajnik zawsze pokazuje mi czy dostał odpowiedź (zwykła leda). Mogę resetować nadajnik czy odbiornik, bez różnicy.

Pamiętaj, że 50Hz to dość duża częstotliwość dla tego modułu (o ile pamiętam dopuszczalne opóźnienie ACK to 100 ms, ale mogę się mylić).

  • Lubię! 1
Link do komentarza
Share on other sites

Bazuję na bibliotece msalamon (LINK), zlikwidowałem tylko delaye do niezbędnego minimum (zamiast delaya dałem pętle for z taką iteracją, żeby bez problemu odbierać i nadawać w jednej transmisji). Cały init itp. wszystkie funkcje są można powiedzieć że takie same. Nadawanie realizowane timerem ustawionym na 50 Hz. Mogę podesłać kody bezpośrednio tutaj ale są tam też odpalone inne moduły np. usb czy i2c także może być nieczytelnie 😄 

Link do komentarza
Share on other sites

(edytowany)

 

Dobra - bo mi już trochę ręce opadają i nie bardzo wiem czego to moze być przyczyna, że po resecie odbiornika (nadajnik ciągle nadaje) odbiornik nie chce już odebrać żadnej wiadomości. Wygląda jakby nadajnik nie dostawał ACK bo uruchamiając testowo przerwanie od TX na diodzie nie chce się ona zaświecić po wysłaniu wiadomości 🤷‍♂️ Odbiornik gdy jest ciągle podłączony, a resetowany jest nadajnik wszystko jest odbierane i nie ma problemu. Gdy sytuacja jest odwrotna czyli odpięty od zasilania lub zresetowany zostanie odbiornik, a nadajnik ciągle wysyła pakiety, odbiornik przestaje odbierać, jakby nie mógł się "sparować" z nadajnikiem, gdy ten wysyła wiadomości w eter przecież do konkretnego odbiornika. W konkretnym zastosowaniu taka sytuacja nie może mieć miejsca bo nadajnik będzie w ciężko dostępnym miejscu. Jedynie wchodzi opcja zdalnego resetu ale jak nrf jest w trybie nadajnika to nie odbiera standardowo wiadomości, jedynie w ACK payload, no a jak wiadomo trzeba ją wysłać po odebraniu wiadomości przez odbiornik 😞 poproszę o pomoc bo serio nie wiem co może byc nie tak. Gdyby było potrzebne zdalne połączenie żeby zerknąć w kod to jestem otwarty na propozycje. 

EDIT: zapomniałem jeszce dodać, czasami zdarza się, że transmisja jest przerywana (nie wiem z jakiego powodu) i nadajnik ciągle później nadaje, a odbiornik przestaje odbierać już w ogóle. Dopiero reset nadajnika ponawia transmisję. 


Poniżej wklejam kod initu nrf24l01, funkcji wysyłania i odbierania (gdyby coś jeszcze było potrzebne to proszę o napisanie):

void nRF24_Init(SPI_HandleTypeDef *hspi)
{
	hspi_nrf = hspi;

	NRF24_CE_LOW;
	NRF24_CSN_HIGH;

	nRF24_Delay_ms(5); // Wait for radio power up

	nRF24_SetPALevel(NRF24_PA_PWR_0dBM); // Radio power
	nRF24_SetDataRate(NRF24_RF_DR_2MBPS); // Data Rate
	nRF24_EnableCRC(1); // Enable CRC
	nRF24_SetCRCLength(NRF24_CRC_WIDTH_1B); // CRC Length 1 byte
	//nRF24_SetRetries(0x04, 0x05); // 1000us, 7 times

#if (NRF24_DYNAMIC_PAYLOAD == 1) // nie używam dynamicznego payloadu - stały payload 32 bajty
	nRF24_WriteRegister(NRF24_FEATURE, nRF24_ReadRegister(NRF24_FEATURE) | (1<<NRF24_EN_DPL)); // Enable dynamic payload feature
	nRF24_WriteRegister(NRF24_DYNPD, 0x3F); // Enable dynamic payloads for all pipes
#else
	nRF24_WriteRegister(NRF24_DYNPD, 0); // Disable dynamic payloads for all pipes
	nRF24_SetPayloadSize(0, NRF24_PAYLOAD_SIZE); // Set 32 bytes payload for pipe 0
#endif
	nRF24_SetRFChannel(50); // Set RF channel for transmission
	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_ms(1);

	nRF24_EnableRXDataReadyIRQ(1);   //dla odbiornika, nadajnik ma 0
	nRF24_EnableTXDataSentIRQ(0);
	nRF24_EnableMaxRetransmitIRQ(0);

	nRF24_Delay_ms(1);

	nRF24_ClearInterrupts();
}

Nadajnik:

nRF24_TX_Status nRF24_SendPacket(uint8_t* Data, uint8_t Size)
{
	if(Size > 32)
		return NRF24_NO_TRANSMITTED_PACKET;

	nRF24_WriteTXPayload(Data, Size);   
	nRF24_Delay_ms(1);
	nRF24_WaitTX();

	return NRF24_TRANSMITTED_PACKET;
}

void nRF24_WriteTXPayload(uint8_t * data, uint8_t size)
{
#if (NRF24_DYNAMIC_PAYLOAD == 1)
	nRF24_WriteRegisters(NRF24_CMD_W_TX_PAYLOAD, data, size);
#else
	nRF24_WriteRegisters(NRF24_CMD_W_TX_PAYLOAD, data, NRF24_PAYLOAD_SIZE);
#endif
}

void nRF24_WaitTX()
{
	uint8_t status;

	NRF24_CE_HIGH;
	for (uint8_t i = 0; i <15; i++);  //minimal delay
  
	do
	{
		for (uint8_t i = 0; i <15; i++)
		//nRF24_Delay_ms(1);
		status = nRF24_ReadStatus();

		if((status & (1<<NRF24_MAX_RT)) || (status & (1<<NRF24_TX_DS))){
			FN1_ON;
		}
	}while(!((status & (1<<NRF24_MAX_RT)) || (status & (1<<NRF24_TX_DS))));

	FN1_OFF;

	NRF24_CE_LOW;
}

Odbiornik (odbieranie w przerwaniu - zdarzeniem):

void nRF24_EventRxCallback(void)
{
	do
	{
		counter++;
		nRF24_ReceivePacket(Message, &MessageLength);
		sprintf(usb_buffer, "%s\r", Message);
		usb_send(usb_buffer);
		usb_buf_clear();

		HAL_GPIO_TogglePin(FN1_GPIO_Port, FN1_Pin);
	} while(!nRF24_IsRxEmpty());
}

nRF24_RX_Status nRF24_ReceivePacket(uint8_t* Data, uint8_t *Size)
{
#if (NRF24_INTERRUPT_MODE == 0)   // używam przerwań więc if nieaktywny
	if(nRF24_RXAvailible()){
		nRF24_ReadRXPaylaod(Data, Size);
		return NRF24_RECEIVED_PACKET;
	} else {
		return NRF24_NO_RECEIVED_PACKET;
	}
#else
	nRF24_ReadRXPaylaod(Data, Size);
	return NRF24_RECEIVED_PACKET;
#endif
}

void nRF24_ReadRXPaylaod(uint8_t *data, uint8_t *size)
{
#if (NRF24_DYNAMIC_PAYLOAD == 1)  //sztywny payload więc if nieaktywny 
	*size = nRF24_GetDynamicPayloadSize();
	nRF24_ReadRegisters(NRF24_CMD_R_RX_PAYLOAD, data, *size);
#else
	nRF24_ReadRegisters(NRF24_CMD_R_RX_PAYLOAD, data, NRF24_PAYLOAD_SIZE);
#endif
#if (NRF24_INTERRUPT_MODE == 0)		// używam przerwań więc if nieaktywny
	nRF24_WriteRegister(NRF24_STATUS, (1<NRF24_RX_DR));
	if(nRF24_ReadStatus() & (1<<NRF24_TX_DS))
		nRF24_WriteRegister(NRF24_STATUS, (1<<NRF24_TX_DS));
#endif
}

 

 

Edytowano przez Vroobee
Link do komentarza
Share on other sites

Zarejestruj się lub zaloguj, aby ukryć tę reklamę.
Zarejestruj się lub zaloguj, aby ukryć tę reklamę.

jlcpcb.jpg

jlcpcb.jpg

Produkcja i montaż PCB - wybierz sprawdzone PCBWay!
   • Darmowe płytki dla studentów i projektów non-profit
   • Tylko 5$ za 10 prototypów PCB w 24 godziny
   • Usługa projektowania PCB na zlecenie
   • Montaż PCB od 30$ + bezpłatna dostawa i szablony
   • Darmowe narzędzie do podglądu plików Gerber
Zobacz również » Film z fabryki PCBWay

(edytowany)

Najlepiej wlutować kondensator (kondensatory) bezpośrednio na płytce między pinami zasilania. 0805 100 nF idealnie pasuje. Brak odbioru to taki dość typowy objaw braku kondensatora.

Edytowano przez ethanak
Link do komentarza
Share on other sites

33 minuty temu, ethanak napisał:

Najlepiej wlutować kondensator (kondensatory) bezpośrednio na płytce między pinami zasilania. 0805 100 nF idealnie pasuje. Brak odbioru to taki dość typowy objaw braku kondensatora.

Kondensator jest: 100nF i 22uF elektrolit 🙂

Link do komentarza
Share on other sites

(edytowany)

Takie głupie pytanie... masz znak NUL na końcu danych? Bo takie użycie sprintf jak masz w odbiorniku to ewidentny błąd.

Poczytaj co znaczy * w stringu formatującym - np.

sprintf("%-*.*s\n", //dalej doczytasz

No i snprintf, a nie sprintf.

Edytowano przez ethanak
  • Lubię! 1
Link do komentarza
Share on other sites

W definicji bufora może być, ale co sprintf zrobi z %s to inna sprawa.

Ale w sumie to Twój program, jeśli uważasz że tak jest dobrze to ja już nie będę się kłócił. Tylko więcej nie pytaj "dlaczego to nie działa".

Link do komentarza
Share on other sites

Nie no, nie mówię, ze to działa skoro nie działa 🙂 ale wydawało mi się ze przy definicji bufora to jedno miejsce wystarczy. Sprawdzę tak czy siak za niedługo i zobaczę czy będzie coś lepiej czy nie. 

Link do komentarza
Share on other sites

Jak poczytasz mana do sprintfa masz tam w przykładach funkcję, która alokuje tyle pamięci ile trzeba. Często z tego korzystam i polecam 🙂

Mam w programie funkcję "monitor" która wysyła wynik printfa na port UDP. Nie interesują mnie jakieś bufory i ich rozmiary piszę coś w stylu

monitor(ip, port, "%f\n", x);

Zapoznaj się z tym przykładem.

Link do komentarza
Share on other sites

W sumie nie wiem. Jeśli jakiś błąd powoduje niedeterministyczne działanie programu - efekty mogą być ciekawe.

W każdym razie jeśli jakiś fragment programu zachowuje się nie tak jak trzeba - warto sprawdzić czy gdzieś nie ma jakiegoś myku i jeśli jest, pozbyć się go.

Ja np. mam ciekawostkę - w kodzie robota był błąd (funkcja w pewnych warunkach była niepotrzebnie wywoływana), teoretycznie poprawiłem... ale nie działa mi parę innych funkcji które powinny być niezależne.

Różnica taka, że Ty masz kilkadziesiąt linii programu, a ja mam ponad 5000 😞

Link do komentarza
Share on other sites

Dołącz do dyskusji, napisz odpowiedź!

Jeśli masz już konto to zaloguj się teraz, aby opublikować wiadomość jako Ty. Możesz też napisać teraz i zarejestrować się później.
Uwaga: wgrywanie zdjęć i załączników dostępne jest po zalogowaniu!

Anonim
Dołącz do dyskusji! Kliknij i zacznij pisać...

×   Wklejony jako tekst z formatowaniem.   Przywróć formatowanie

  Dozwolonych jest tylko 75 emoji.

×   Twój link będzie automatycznie osadzony.   Wyświetlać jako link

×   Twoja poprzednia zawartość została przywrócona.   Wyczyść edytor

×   Nie możesz wkleić zdjęć bezpośrednio. Prześlij lub wstaw obrazy z adresu URL.

×
×
  • Utwórz nowe...

Ważne informacje

Ta strona używa ciasteczek (cookies), dzięki którym może działać lepiej. Więcej na ten temat znajdziesz w Polityce Prywatności.