2024-07-22 11:31 AM
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()
2024-07-22 12:07 PM
> 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.