Hello,
I'm using the Adafruit RFM69HCW radio module with a Pi Pico, and want to send a custom data packet over FSK. Using RadioHead and other RFM69 libraries, they all write data to the RFM69's onboard FIFO buffer over SPI which then packetises the data in the form seen below, from page 51 of the data sheet found here:
This format is laid out nicely in the packet_mode_rx example provided by jlmurdoch - which provides a really nice and straightforward way to interface with the RFM69 and specific registers.
/*
* Packet Mode:
* - Preamble (x bytes) = 0x55
* - Syncword (2 bytes) = 0x2DD4
* - Length (1 byte) = 0x1C
* - Address (1 byte) = 0x8D or 0x0D
* - Payload (<length> bytes)
* - CRC-16 (2 bytes - appears to be broken)
*/
However, I would like to use the RadioHead Library, as it includes the functionality of the addressed packets and works very reliability for me, but I want to send out data in my own packet format.
I can send out my own data packet within the 60-64 payload bytes (depends on AES Encryption which I am not using) to send out a custom packet but seems very wasteful and not very efficient.
Is it possible to send data to the FIFO and have it not be packetised and still work within the RadioHead library by changing the format in the RF69.cpp/h files or even transmit data by sending it directly to the DIO2 pin, which I have been doing with success, by viewing the output using my RTL-SDR, but I have had no success in receiving any of the transmitted data with a second RFM69.
Here is the code I used to transmit the FSK packet using DIO2, it actually reads a serial input from the pico which converts it into bits to transmit as the long term view is I want to transmit data received from the UART port of the pico in the future.
/*
* Generic Radio Example
*/
#include <SPI.h>
#define RFM69HCW_G0_IRQ 17 // E - PayloadReady/CrcOk
#define RFM69HCW_CS 21 // D - SPI Chip Select
#define RFM69HCW_RST 20 // C - Reset
#define RFM69HCW_G2_DIO2 14 // A - Data
// #define RFM69HCW_G1_DIO1 13 // 13 - DCLK if Gaussian FSK needed
//#define MODULATION OOK
#define MODULATION FSK
#define FREQ 433.92
#define BITRATE 1000
#define BANDWIDTH DCCFREQ_4 << 5 | RXBWMANT_16 << 3 | RXBWEXP_0
#define AFC_BANDWIDTH DCCFREQ_4 << 5 | RXBWMANT_16 << 3 | RXBWEXP_0
#define BIT_SYNC 0x60 // Bit Sync off, as pulses are asymmetrical
#define FREQDEV 4700
// RFM69HCW clock speed - do not change
#define FXOSC 32000000.0
enum { FSK, OOK };
uint8_t spi_cmd(uint8_t addr, uint8_t value) {
uint8_t status;
digitalWrite(RFM69HCW_CS, LOW);
SPI.transfer(addr);
status = SPI.transfer(value);
digitalWrite(RFM69HCW_CS, HIGH);
return status;
}
// Set the wnr bit to write (Section 5.2.1)
uint8_t spi_write(uint8_t addr, uint8_t value) {
return spi_cmd(addr | 0x80, value);
}
// Pass nothing when reading
uint8_t spi_read(uint8_t addr) {
return spi_cmd(addr, 0x00);
}
void rfminit() {
// Read the version register, if it's not 0x24, something is wrong
if(spi_read(0x10) == 0x24)
Serial.println(F("RFM69HCW SPI Working"));
else
Serial.println(F("RFM69HCW SPI Failed"));
// RegOpMode: Standby Mode & wait
spi_write(0x01, 0x04);
while(!(spi_read(0x27)) & 0x80);
// RegDataModul: Continuous w/ bit-sync and no other shaping
uint8_t modulation = MODULATION;
spi_write(0x02, BIT_SYNC | modulation << 3);
//spi_write(0x02, 0x00);
uint16_t freqdev = FREQDEV / (FXOSC / 524288);
spi_write(0x05, (freqdev >> 8) & 0x3F);
spi_write(0x06, freqdev & 0xFF);
// RegFrf*: Frequency across 3 bytes
uint32_t freqrf = (FREQ * 1000000) / (FXOSC / 524288);
spi_write(0x07, (freqrf >> 16) & 0xFF);
spi_write(0x08, (freqrf >> 8) & 0xFF);
spi_write(0x09, freqrf & 0xFF);
// RegBitrate*: Bitrate needed for Bit Synchronizer
uint16_t bitrate = FXOSC / BITRATE;
spi_write(0x03, (bitrate >> 8) & 0xFF);
spi_write(0x04, bitrate & 0xFF);
spi_write(0x0A, 0x88); // Calibrating the oscillator
while (!(spi_read(0x0A) & 0x08));
Serial.println(F("Oscillator Cal done"));
// ClkOut set to Off to save some power
spi_write(0x26, 0x07);
/*
* TX- Settings
*/
// High Power toggles
spi_write(0x5A, 0x5D); // Section 3.3.7 PA1 on for +20dBm
spi_write(0x5C, 0x7C); // Section 3.3.7 PA2 on for +20dBm
// Power Settings for Tx
spi_write(0x13, 0x0F); // Default = 0x1A. Disable OCP = 0x0F
spi_write(0x11, 0x7F); // Default = 0x9F. 23dBm = 0x1F, PA1+2 on = 0x60
//spi_write(0x11, 0x08); // Low Power Mode
// spi_write(0x12, 0x09); // Default = 0x09. Ramp time for FSK
// Sleep
spi_write(0x01, 0x00);
while(!(spi_read(0x27)) & 0x80);
}
void setup() {
// Setup pins other than SPI, VDD and ground
pinMode(RFM69HCW_CS, OUTPUT);
pinMode(RFM69HCW_RST, OUTPUT);
pinMode(RFM69HCW_G2_DIO2, OUTPUT);
// pinMode(RFM69HCW_G1_DIO1, OUTPUT); // For DCLK
// For flashing the LED on emitting
pinMode(LED_BUILTIN, OUTPUT);
Serial1.setTX(0);
Serial1.setRX(1);
// Serial console: e.g. cu -s 115200 -l /dev/ttyACM0
Serial.begin(115200);
Serial1.begin(9600);
delay(5000);
// Section 5.2.1 - SPI Interface
digitalWrite(RFM69HCW_CS, HIGH);
SPI.begin();
SPI.beginTransaction(SPISettings(8000000, MSBFIRST, SPI_MODE0));
Serial.println(F("SPI connection open"));
// Section 7.2.2 - Manual Reset
digitalWrite(RFM69HCW_RST, HIGH);
delayMicroseconds(100);
digitalWrite(RFM69HCW_RST, LOW);
// Spec says 5ms, but takes longer
delay(6);
// Configure the receiver
rfminit();
}
void loop() {
digitalWrite(LED_BUILTIN, HIGH);
// Section 3.2.2 - Async output is on DIO2
digitalWrite(RFM69HCW_G2_DIO2, HIGH);
// Transmit
spi_write(0x01, 0x0C);
while(!(spi_read(0x27)) & 0x80);
Serial1.println("55");
if (Serial1.available()){
String hexString = Serial1.readStringUntil('\n');
hexString.trim();
uint8_t hexValue = strtol(hexString.c_str(),NULL,16);
Serial.println(hexValue, HEX);
for (int i=7; i>=0;i--){
int bitValue = (hexValue >> i) & 1;
Serial.println(bitValue);
digitalWrite(RFM69HCW_G2_DIO2, bitValue);
delayMicroseconds(1000);
}
}
delayMicroseconds(1000);
// // Sleep
spi_write(0x01, 0x00);
while(!(spi_read(0x27)) & 0x80);
delay(3000);
digitalWrite(LED_BUILTIN, LOW);
}
Thank you, any help is appreciated ![]()
-Harvey
