Skip to main content
Visitor II
July 22, 2024
Question

NRF24 communication between Stm32g431RB and raspberry pi 4

  • July 22, 2024
  • 1 reply
  • 1349 views

Hello, i used to have an arduino + NRF24L01 communicating with a raspberry pi, wich worked without any issues.

I dont have much knowledge in this area, and due to the lack of documentation in communicating these devices using nrf24, i find myself at a loss when trying to communicate the stm32 and the raspberry pi 4. Id apreciate whatever help can be given to solve this problem.

I have the stm32 as the transmitter and the raspberry pi as the receiver.

 

nrf24 library used for the stm32: https://github.com/elmot/nrf24l01-lib/tree/master

nrf24 python library: bjarne-hansen/py-nrf24: Library for NRF24L01 communication using pigpiod on Raspberry Pi. (github.com)

 

The issue seems to be that the receiver does not enter the while nrf.data_ready. 

 

I dont have much experience posting help on forums, so i hope i havent missed anything. The simplest form of working code for the stm32 and the raspberry pi would help a lot. 

 

Code in the Stm32g431RB:

 

int runRadio(void) {
	UART_SendStr("\r\nSTM32L432KC is online.\r\n");

	// RX/TX disabled
	nRF24_CE_L();

	// Configure the nRF24L01+
	UART_SendStr("nRF24L01+ check: ");
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wmissing-noreturn"
	if (!nRF24_Check()) {
		UART_SendStr("FAIL\r\n");
		while (1) {
			Toggle_LED();
			Delay_ms(50);
		}
	}
#pragma clang diagnostic pop
	UART_SendStr("OK\r\n");

	// Initialize the nRF24L01 to its default state
	nRF24_Init();

#if (DEMO_TX_SINGLE_ESB)

	// This is simple transmitter with Enhanced ShockBurst (to one logic address):
	// - TX address: '1SNSR'
	// - payload: 5 bytes
	// - RF channel: 100
	// - data rate: 512Kbps
	// - CRC scheme: 2 byte

 // Set RF channel
 nRF24_SetRFChannel(100);

 // Set data rate
 nRF24_SetDataRate(nRF24_DR_250kbps);

 // Set CRC scheme
 nRF24_SetCRCScheme(nRF24_CRC_2byte);

 // Set address width, its common for all pipes (RX and TX)
 nRF24_SetAddrWidth(5);

 // Configure TX PIPE
 static const uint8_t nRF24_ADDR[] = { '1', 'S', 'N','S','R' };
 nRF24_SetAddr(nRF24_PIPETX, nRF24_ADDR); // program TX address
 nRF24_SetAddr(nRF24_PIPE0, nRF24_ADDR); // program address for pipe#0, must be same as TX (for Auto-ACK)

 // Set TX power (maximum)
 nRF24_SetTXPower(nRF24_TXPWR_0dBm);

 // Configure auto retransmit: 10 retransmissions with pause of 2500s in between
 nRF24_SetAutoRetr(nRF24_ARD_250us, 15);

 // Enable Auto-ACK for pipe#0 (for ACK packets)
 // nRF24_EnableAA(nRF24_PIPE0);

 nRF24_DisableAA(nRF24_PIPE0);

 // Set operational mode (PTX == transmitter)
 nRF24_SetOperationalMode(nRF24_MODE_TX);

 // Clear any pending IRQ flags
 nRF24_ClearIRQFlags();

 // Enable DPL
 nRF24_SetDynamicPayloadLength(nRF24_DPL_ON);

 // Wake the transceiver
 nRF24_SetPowerMode(nRF24_PWR_UP);


 // Some variables
 uint32_t packets_lost = 0; // global counter of lost packets
 uint8_t otx;
 uint8_t otx_plos_cnt; // lost packet count
	uint8_t otx_arc_cnt; // retransmit count


 // The main loop
 payload_length = 5;
 j = 0;
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wmissing-noreturn"
 while (1) {
 	// Prepare data packet
 	for (i = 0; i < payload_length; i++) {
 		nRF24_payload[i] = (uint8_t) 1;// j++
 		if (j > 0x000000FF) j = 0;
 	}

 	// Print a payload
 	UART_SendStr("PAYLOADKK:>");
 	UART_SendBufHex((char *)nRF24_payload, payload_length);
 	UART_SendStr("< ... TX: ");

 	// Transmit a packet
 	tx_res = nRF24_TransmitPacket(nRF24_payload, payload_length);
		otx = nRF24_GetRetransmitCounters();
		otx_plos_cnt = (otx & nRF24_MASK_PLOS_CNT) >> 4; // packets lost counter
		otx_arc_cnt = (otx & nRF24_MASK_ARC_CNT); // auto retransmissions counter
 	switch (tx_res) {
			case nRF24_TX_SUCCESS:
				UART_SendStr("OK");
				break;
			case nRF24_TX_TIMEOUT:
				UART_SendStr("TIMEOUT");
				break;
			case nRF24_TX_MAXRT:
				UART_SendStr("MAX RETRANSMIT");
				packets_lost += otx_plos_cnt;
				nRF24_ResetPLOS();
				break;
			default:
				UART_SendStr("ERROR");
				break;
		}
 	UART_SendStr(" ARC=");
		UART_SendInt(otx_arc_cnt);
		UART_SendStr(" LOST=");
		UART_SendInt(packets_lost);
		UART_SendStr("\r\n");

 	// Wait ~0.5s
 	Delay_ms(500);
		Toggle_LED();
 }
#pragma clang diagnostic pop
// Function to transmit data packet
// input:
// pBuf - pointer to the buffer with data to transmit
// length - length of the data buffer in bytes
// return: one of nRF24_TX_xx values
nRF24_TXResult nRF24_TransmitPacket(uint8_t *pBuf, uint8_t length) {
	volatile uint32_t wait = nRF24_WAIT_TIMEOUT;
	uint8_t status;

	// Deassert the CE pin (in case if it still high)
	nRF24_CE_L();

	// Transfer a data from the specified buffer to the TX FIFO
	nRF24_WritePayload(pBuf, length);

	// Start a transmission by asserting CE pin (must be held at least 10us)
	nRF24_CE_H();

	// Poll the transceiver status register until one of the following flags will be set:
	// TX_DS - means the packet has been transmitted
	// MAX_RT - means the maximum number of TX retransmits happened
	// note: this solution is far from perfect, better to use IRQ instead of polling the status
	do {
		status = nRF24_GetStatus();
		if (status & (nRF24_FLAG_TX_DS | nRF24_FLAG_MAX_RT)) {
			break;
		}
	} while (wait--);

	// Deassert the CE pin (Standby-II --> Standby-I)
	nRF24_CE_L();

	if (!wait) {
		// Timeout
		return nRF24_TX_TIMEOUT;
	}

	// Check the flags in STATUS register
	UART_SendStr("[");
	UART_SendHex8(status);
	UART_SendStr("] ");

	// Clear pending IRQ flags
 nRF24_ClearIRQFlags();

	if (status & nRF24_FLAG_MAX_RT) {
		// Auto retransmit counter exceeds the programmed maximum limit (FIFO is not removed)
		return nRF24_TX_MAXRT;
	}

	if (status & nRF24_FLAG_TX_DS) {
		// Successful transmission
		return nRF24_TX_SUCCESS;
	}

	// Some banana happens, a payload remains in the TX FIFO, flush it
	nRF24_FlushTX();

	return nRF24_TX_ERROR;
}

 

 

 

Raspberry pi Python code:

 

 

import argparse
from datetime import datetime
import struct
import sys
import time
import traceback

import pigpio
from nrf24 import *

# A simple NRF24L receiver that connects to a PIGPIO instance on a hostname and port, default "localhost" and 8888, and
# starts receiving data on the address specified. Use the companion program "simple-sender.py" to send data to it from
# a different Raspberry Pi.
#
if _name_ == "_main_":

 print("Python NRF24 Simple Receiver Example.")
 
 # Parse command line argument.
 parser = argparse.ArgumentParser(prog="simple-receiver.py", description="Simple NRF24 Receiver Example.")
 parser.add_argument('-n', '--hostname', type=str, default='localhost', help="Hostname for the Raspberry running the pigpio daemon.")
 parser.add_argument('-p', '--port', type=int, default=8888, help="Port number of the pigpio daemon.")
 parser.add_argument('address', type=str, nargs='?', default='1SNSR', help="Address to listen to (3 to 5 ASCII characters)")

 args = parser.parse_args()
 hostname = args.hostname
 port = args.port
 address = args.address

 # Verify that address is between 3 and 5 characters.
 if not (2 < len(address) < 6):
 print(f'Invalid address {address}. Addresses must be between 3 and 5 ASCII characters.')
 sys.exit(1)
 
 # Connect to pigpiod
 print(f'Connecting to GPIO daemon on {hostname}:{port} ...')
 pi = pigpio.pi(hostname, port)
 if not pi.connected:
 print("Not connected to Raspberry Pi ... goodbye.")
 sys.exit()

 # Create NRF24 object.
 # PLEASE NOTE: PA level is set to MIN, because test sender/receivers are often close to each other, and then MIN works better.
 nrf = NRF24(pi, ce=25, payload_size=RF24_PAYLOAD.DYNAMIC, channel=100, data_rate=RF24_DATA_RATE.RATE_250KBPS, pa_level=RF24_PA.MIN)
 nrf.set_address_bytes(len(address))

 # Listen on the address specified as parameter
 nrf.open_reading_pipe(RF24_RX_ADDR.P1, address)
 
 # Display the content of NRF24L01 device registers.
 nrf.show_registers()

 # Enter a loop receiving data on the address specified.
 try:
 print(f'Receive from {address}')
 count = 0
 while True:

 # As long as data is ready for processing, process it.
 while nrf.data_ready():
 # Count message and record time of reception. 
 count += 1
 now = datetime.now()
 print("data ready")
 # Read pipe and payload for message.
 pipe = nrf.data_pipe()
 payload = nrf.get_payload() 

 # Resolve protocol number.
 protocol = payload[0] if len(payload) > 0 else -1 

 hex = ':'.join(f'{i:02x}' for i in payload)

 # Show message received as hex.
 print(f"{now:%Y-%m-%d %H:%M:%S.%f}: pipe: {pipe}, len: {len(payload)}, bytes: {hex}, count: {count}")

 # If the length of the message is 9 bytes and the first byte is 0x01, then we try to interpret the bytes
 # sent as an example message holding a temperature and humidity sent from the "simple-sender.py" program.
 if len(payload) == 9: #and payload[0] == 0x01:
 values = struct.unpack("<Bff", payload)
 print(f'Protocol: {values[0]}, temperature: {values[1]}, humidity: {values[2]}')
 
 # Sleep 100 ms.
 time.sleep(0.1)
 except:
 traceback.print_exc()
 nrf.power_down()
 pi.stop()

 

 

 

 

1 reply

Pavel A.
Super User
July 22, 2024

The issue seems to be that the receiver does not enter the while nrf.data_ready. 

This is line 60 in your python snippet. Is there any error message printed on the python side? If the program just hangs, type ctrl/C and see in the stack trace where it was interrupted.