Right so, I'm using an Arduino Nano ESP32, RPI5, and BM019. In short this code reads a rfid tag and sends that data to the rpi via WiFi. However, there isn't enough range between the Arduino and RasPi on WiFi with a USB antenna. I figured that I'd slap on an Ethernet attachment and bobs your uncle, all good. But that is not the case. I think the issue is that I need to tell the Arduino to:
activate the BM019
read the chip
store the data
deactivate BM019
activate the Ethernet
wait for connection
send data
deactivate the Ethernet
activate the BM019
repeat.
Now I am able to ping the nano. So I'm pretty sure its connected to the rpi. Oh I should mention that the RPI is creating an Ethernet connection with:
sudo ip addr add 10.0.0.1/8 dev eth0
sudo ip link set eth0 up
Eventually, I'll config this to auto start but for now I'm just doing this.
So in summary, I was able to use the Arduino Nano to read data from a BM019 and set it to a python program on a raspi5 over WiFi. When I tried to add a Ethernet chip I ran into a few issues I don't know how to fix. I think the solution is to activate and deactivate each chip because only one can be used at a time but I'm not sure how to do that.
I've attached my Ethernet code and my WiFi code for the Arduino as well as the WiFi part of the Python code. The rest is related to other software but I just need the text string from the BM019. I've also attached images of my setup.
Thank you for the help.
Ethernet:
/*
NFC Communication with the Solutions Cubed, LLC BM019
and an Arduino Nano ESP32. The BM019 is a module that
carries ST Micro's CR95HF, a serial to NFC converter.
Wiring:
Arduino BM019
IRQ: Pin 9 DIN: pin 2
SS: pin 10 SS: pin 3
MOSI: pin 11 MOSI: pin 5
MISO: pin 12 MISO: pin4
SCK: pin 13 SCK: pin 6
W5500 Wiring:
Arduino W5500
SS: pin 5 SS
MOSI: pin 11 MOSI
MISO: pin 12 MISO
SCK: pin 13 SCK
*/
#include <SPI.h>
#include <Ethernet.h>
#include <ArduinoJson.h>
// Ethernet configuration for direct connection
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
IPAddress ip(10, 0, 0, 2); // ESP32 static IP
IPAddress serverIp(10, 0, 0, 1); // Raspberry Pi IP
const int serverPort = 5000;
EthernetClient client;
const int SSPin = 10; // Slave Select pin for BM019
const int EthCSPin = 5; // Slave Select pin for W5500
const int IRQPin = 9; // Sends wake-up pulse
byte TXBuffer[40]; // transmit buffer
byte RXBuffer[40]; // receive buffer
byte NFCReady = 0; // used to track NFC state
void setup() {
pinMode(IRQPin, OUTPUT);
digitalWrite(IRQPin, HIGH);
pinMode(SSPin, OUTPUT);
digitalWrite(SSPin, HIGH);
pinMode(EthCSPin, OUTPUT);
digitalWrite(EthCSPin, HIGH);
Serial.begin(115200);
// Initialize SPI
SPI.begin();
SPI.setDataMode(SPI_MODE0);
SPI.setBitOrder(MSBFIRST);
SPI.setClockDivider(SPI_CLOCK_DIV32);
// Start Ethernet with static IP
Ethernet.init(EthCSPin);
Ethernet.begin(mac, ip);
// No need for DHCP in direct connection
Serial.print("Ethernet IP address: ");
Serial.println(Ethernet.localIP());
// Check Ethernet hardware
if (Ethernet.hardwareStatus() == EthernetNoHardware) {
Serial.println("Ethernet shield was not found.");
while (true);
}
// Give some time for Ethernet to initialize
delay(1000);
// BM019 wakeup pulse
delay(10);
digitalWrite(IRQPin, LOW);
delayMicroseconds(100);
digitalWrite(IRQPin, HIGH);
delay(10);
}
/* SetProtocol_Command programs the CR95HF for
I *SO/IEC 15693 operation.
This requires three steps.
1. send command
2. poll to see if CR95HF has data
3. read the response
If the correct response is received the serial monitor is used
to display successful programming.
*/
void SetProtocol_Command()
{
byte i = 0;
// step 1 send the command
digitalWrite(SSPin, LOW);
SPI.transfer(0x00); // SPI control byte to send command to CR95HF
SPI.transfer(0x02); // Set protocol command
SPI.transfer(0x02); // length of data to follow
SPI.transfer(0x01); // code for ISO/IEC 15693
SPI.transfer(0x0D); // Wait for SOF, 10% modulation, append CRC
digitalWrite(SSPin, HIGH);
delay(1);
// step 2, poll for data ready
digitalWrite(SSPin, LOW);
while(RXBuffer[0] != 8)
{
RXBuffer[0] = SPI.transfer(0x03); // Write 3 until
RXBuffer[0] = RXBuffer[0] & 0x08; // bit 3 is set
}
digitalWrite(SSPin, HIGH);
delay(1);
// step 3, read the data
digitalWrite(SSPin, LOW);
SPI.transfer(0x02); // SPI control byte for read
RXBuffer[0] = SPI.transfer(0); // response code
RXBuffer[1] = SPI.transfer(0); // length of data
digitalWrite(SSPin, HIGH);
if ((RXBuffer[0] == 0) & (RXBuffer[1] == 0)) // is response code good?
{
Serial.println("Protocol Set Command OK");
NFCReady = 1; // NFC is ready
}
else
{
Serial.println("Protocol Set Command FAIL");
NFCReady = 0; // NFC not ready
}
}
/* Inventory_Command chekcs to see if an RF
t *ag is in range of the BM019.
This requires three steps.
1. send command
2. poll to see if CR95HF has data
3. read the response
If the correct response is received the serial monitor is used
to display the the RF tag's universal ID.
*/
void Inventory_Command()
{
byte i = 0;
// step 1 send the command
digitalWrite(SSPin, LOW);
SPI.transfer(0x00); // SPI control byte to send command to CR95HF
SPI.transfer(0x04); // Send Receive CR95HF command
SPI.transfer(0x03); // length of data that follows is 0
SPI.transfer(0x26); // request Flags byte
SPI.transfer(0x01); // Inventory Command for ISO/IEC 15693
SPI.transfer(0x00); // mask length for inventory command
digitalWrite(SSPin, HIGH);
delay(1);
// step 2, poll for data ready
// data is ready when a read byte
// has bit 3 set (ex: B'0000 1000')
digitalWrite(SSPin, LOW);
while(RXBuffer[0] != 8)
{
RXBuffer[0] = SPI.transfer(0x03); // Write 3 until
RXBuffer[0] = RXBuffer[0] & 0x08; // bit 3 is set
}
digitalWrite(SSPin, HIGH);
delay(1);
// step 3, read the data
digitalWrite(SSPin, LOW);
SPI.transfer(0x02); // SPI control byte for read
RXBuffer[0] = SPI.transfer(0); // response code
RXBuffer[1] = SPI.transfer(0); // length of data
for (i=0;i<RXBuffer[1];i++)
RXBuffer[i+2]=SPI.transfer(0); // data
digitalWrite(SSPin, HIGH);
delay(1);
if (RXBuffer[0] == 128) // is response code good?
{
Serial.println("Inventory Command OK");
NFCReady = 2;
}
else
{
Serial.println("Inventory Command FAIL");
NFCReady = 0;
}
}
/* Write Memory writes data to a block of memory.
T *his code assumes the RF tag has less than 256 blocks
of memory and that the block size is 4 bytes. The block
written to increments with each pass and if it exceeds
20 it starts over. Data is also changed with each write.
This requires three steps.
1. send command
2. poll to see if CR95HF has data
3. read the response
*/
void loop() {
if (NFCReady == 0) {
delay(100);
SetProtocol_Command();
} else if (NFCReady == 1) {
delay(100);
Inventory_Command();
} else {
delay(100);
Read_Memory();
}
delay(2000);
}
void Read_Memory() {
byte i = 0;
byte block = 0;
byte totalBlocks = 28;
String chipData = "chip_data:";
for (block = 0; block < totalBlocks; block++) {
digitalWrite(SSPin, LOW);
SPI.transfer(0x00);
SPI.transfer(0x04);
SPI.transfer(0x03);
SPI.transfer(0x02);
SPI.transfer(0x20);
SPI.transfer(block);
digitalWrite(SSPin, HIGH);
delay(1);
digitalWrite(SSPin, LOW);
while (RXBuffer[0] != 8) {
RXBuffer[0] = SPI.transfer(0x03);
RXBuffer[0] = RXBuffer[0] & 0x08;
}
digitalWrite(SSPin, HIGH);
delay(1);
digitalWrite(SSPin, LOW);
SPI.transfer(0x02);
RXBuffer[0] = SPI.transfer(0);
RXBuffer[1] = SPI.transfer(0);
for (i = 0; i < RXBuffer[1]; i++) {
RXBuffer[i + 2] = SPI.transfer(0);
}
digitalWrite(SSPin, HIGH);
delay(1);
if (RXBuffer[0] == 128) {
for (i = 0; i < 4; i++) {
byte dataByte = RXBuffer[3 + i];
if (dataByte < 0x10) {
chipData += "0";
}
chipData += String(dataByte, HEX);
if (block != totalBlocks - 1 || i != 3) {
chipData += ":";
}
}
} else {
Serial.println("Read Memory Block Command FAIL");
return;
}
}
// Ethernet connection to Raspberry Pi
if (client.connect(serverIp, serverPort)) {
client.println(chipData);
client.stop();
Serial.println("Data sent to Raspberry Pi");
} else {
Serial.println("Failed to connect to Raspberry Pi!");
}
}
python
# Constants
#SERVER_IP = '0.0.0.0'
SERVER_IP = '10.0.0.2' # Pi's Class A IP
#SERVER_IP = '192.168.1.100'
SERVER_PORT = 5000
...
def handle_client(client_socket):
try:
while True:
data = client_socket.recv(4096).decode('utf-8')
if not data:
break
if data.startswith("chip_data:"):
chip_queue.put(data[len("chip_data:"):].strip()) # Add chip data to the queue
else:
logging.warning("Invalid data received.")
except Exception as e:
logging.error(f"Error handling client: {e}")
finally:
client_socket.close()
def start_server():
try:
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.bind((SERVER_IP, SERVER_PORT))
server_socket.listen(1)
logging.info(f"Listening for connections on {SERVER_IP}:{SERVER_PORT}...")
while True:
client_socket, client_address = server_socket.accept()
logging.info(f"Connection from {client_address}")
threading.Thread(target=handle_client, args=(client_socket,)).start()
except Exception as e:
logging.error(f"Error starting server: {e}")
finally:
server_socket.close()


