iwanders / plainRFM69

A library for the RFM69 radio module.
MIT License
32 stars 12 forks source link

Poor reception with RFM69HWC #16

Open Eli-S-Bridge opened 10 months ago

Eli-S-Bridge commented 10 months ago

I'm running example scripts with an RFM69HWC. The code works but I am getting only intermittant reception with communication between two radios running on modified M0 arduinos. When I use the radiohead library reception is perfect (so the hardware is OK). But I would prefer to use plainRFM69 so I can have control over interrupts. I just can't figure out what I need to do to get the transmission to work properly. I've got a high power version of the radio, and I've tried several variations on rfm.setTxPower(14, true), but there's no effect on reception. I will note that touching one of the antennas improves reception, which imples hardware issues. But again, everything works with the example scripts in radiohead. I'm just wondering if there's some incompatibility with RFM69HWC that I'm unaware of.

iwanders commented 10 months ago

Which frequency of chip? I wonder if you run into https://github.com/iwanders/plainRFM69/pull/13 I never got word back from testing of that, but an overflow in the frequency could affect the results. Can you try that branch?

Eli-S-Bridge commented 10 months ago

I'm using 434mHz modules, so a 32bit overflow is probably not the issue.

Eli-S-Bridge commented 10 months ago

By the way, thanks for responding.... I pulled out all the RFM69 registers from a plainRFM69 script and from radiohead (see below). There might be a clue among the differing registers. For instance, I was surprised to see the carrier frequency bytes (RegFrf...) were different. I'm not sure I have time to parse all of these registers out, but I suspect the difference in performance is explained in there somewhere.

PlainRFM69     |   Radiohead       |  register description
reg no: value     reg no: value.       reg no, name, defaults, description

0x0: 0x0   | 0x0: 0x0   | 0x00 RegFifo 0x00 FIFO read/write   access
0x1: 0x10  | 0x1: 0x4   | 0x01 RegOpMode 0x04 Operating modes of the transceiver
0x2: 0x0   | 0x2: 0x1   | 0x02 RegDataModul 0x00 Data operation mode and Modulation   settings 
0x3: 0x1A  | 0x3: 0x0   | 0x03 RegBitrateMsb 0x1A Bit Rate setting, Most Significant   Bits
0x4: 0xB   | 0x4: 0x80  | 0x04 RegBitrateLsb 0x0B Bit Rate setting, Least Significant   Bits
0x5: 0x0   | 0x5: 0x10  | 0x05 RegFdevMsb 0x00 Frequency Deviation setting, Most   Significant Bits
0x6: 0x52  | 0x6: 0x0   | 0x06 RegFdevLsb 0x52 Frequency Deviation setting, Least   Significant Bits
0x7: 0x6C  | 0x7: 0x6C  | 0x07 RegFrfMsb 0xE4 RF Carrier Frequency, Most Significant   Bits
0x8: 0x90  | 0x8: 0x80  | 0x08 RegFrfMid 0xC0 RF Carrier Frequency, Intermediate Bits
0x9: 0x2   | 0x9: 0x0   | 0x09 RegFrfLsb 0x00 RF Carrier Frequency, Least Significant   Bits
0xA: 0x41  | 0xA: 0x41  | 0x0A RegOsc1 0x41 RC Oscillators Settings
0xB: 0x40  | 0xB: 0x40  | 0x0B RegAfcCtrl 0x00 AFC control in low modulation index   situations
0xC: 0x2   | 0xC: 0x2   | 0x0C Reserved0C 0x02 -
0xD: 0x92  | 0xD: 0x92  | 0x0D RegListen1 0x92 Listen Mode settings
0xE: 0xF5  | 0xE: 0xF5  | 0x0E RegListen2 0xF5 Listen Mode Idle duration
0xF: 0x20  | 0xF: 0x20  | 0x0F RegListen3 0x20 Listen Mode Rx duration
0x10: 0x24 | 0x10: 0x24 | 0x10 RegVersion 0x24
0x11: 0x9F | 0x11: 0x7F | 0x11 RegPaLevel 0x9F PA selection and Output Power control
0x12: 0x9  | 0x12: 0x9  | 0x12 RegPaRamp 0x09 Control of the PA ramp time in FSK mode
0x13: 0x1A | 0x13: 0x1A | 0x13 RegOcp 0x1A Over Current Protection control
0x14: 0x40 | 0x14: 0x40 | 0x14 Reserved14 0x40 -
0x15: 0xB0 | 0x15: 0xB0 | 0x15 Reserved15 0xB0 -
0x16: 0x7B | 0x16: 0x7B | 0x16 Reserved16 0x7B -
0x17: 0x9B | 0x17: 0x9B | 0x17 Reserved17 0x9B -
0x18: 0x88 | 0x18: 0x8  | 0x18 RegLna 0x08 0x88 LNA settings
0x19: 0x55 | 0x19: 0xE0 | 0x19 RegRxBw 0x86 0x55 Channel Filter BW Control
0x1A: 0x8B | 0x1A: 0xE0 | 0x1A RegAfcBw 0x8A 0x8B Channel Filter BW control during the   AFC routine
0x1B: 0x40 | 0x1B: 0x40 | 0x1B RegOokPeak 0x40 OOK demodulator selection and control in   peak mode
0x1C: 0x80 | 0x1C: 0x80 | 0x1C RegOokAvg 0x80 Average threshold control of the OOK   demodulator
0x1D: 0x6  | 0x1D: 0x6  | 0x1D RegOokFix 0x06 Fixed threshold control of the OOK   demodulator
0x1E: 0x10 | 0x1E: 0x10 | 0x1E RegAfcFei 0x10 AFC and FEI control and status
0x1F: 0x0  | 0x1F: 0x0  | 0x1F RegAfcMsb 0x00 MSB of the frequency correction of the AFC
0x20: 0x0  | 0x20: 0x0  | 0x20 RegAfcLsb 0x00 LSB of the frequency correction of the AFC
0x21: 0x0  | 0x21: 0x0  | 0x21 RegFeiMsb 0x00 MSB of the calculated frequency error
0x22: 0x0  | 0x22: 0x0  | 0x22 RegFeiLsb 0x00 LSB of the calculated frequency error
0x23: 0x0  | 0x23: 0x2  | 0x23 RegRssiConfig 0x02 RSSI-related settings
0x24: 0xBE | 0x24: 0xFF | 0x24 RegRssiValue 0xFF RSSI value in dBm
0x25: 0x0  | 0x25: 0x0  | 0x25 RegDioMapping1 0x00 Mapping of pins DIO0 to DIO3
0x26: 0x5  | 0x26: 0x5  | 0x26 RegDioMapping2 0x05 0x07 Mapping of pins DIO4 and DIO5,   ClkOut frequency
0x27: 0xD8 | 0x27: 0x80 | 0x27 RegIrqFlags1 0x80 Status register: PLL Lock state,   Timeout, RSSI > Threshold...
0x28: 0x0  | 0x28: 0x0  | 0x28 RegIrqFlags2 0x00 Status register: FIFO handling flags...
0x29: 0xE4 | 0x29: 0xFF | 0x29 RegRssiThresh 0xFF 0xE4 RSSI Threshold control
0x2A: 0x0  | 0x2A: 0x0  | 0x2A RegRxTimeout1 0x00 Timeout duration between Rx request   and RSSI detection
0x2B: 0x0  | 0x2B: 0x0  | 0x2B RegRxTimeout2 0x00 Timeout duration between RSSI   detection and PayloadReady
0x2C: 0x0  | 0x2C: 0x0  | 0x2C RegPreambleMsb 0x00 Preamble length, MSB
0x2D: 0x3  | 0x2D: 0x4  | 0x2D RegPreambleLsb 0x03 Preamble length, LSB
0x2E: 0x98 | 0x2E: 0x88 | 0x2E RegSyncConfig 0x98 Sync Word Recognition control
0x2F: 0x1  | 0x2F: 0x2D | 0x2F-0x36 RegSyncValue1-8 0x00 0x01 Sync Word bytes, 1 through   8
0x30: 0x1  | 0x30: 0xD4 |  
0x31: 0x1  | 0x31: 0x0  |  
0x32: 0x1  | 0x32: 0x0  |  
0x33: 0x0  | 0x33: 0x0  |  
0x34: 0x0  | 0x34: 0x0  |  
0x35: 0x0  | 0x35: 0x0  |  
0x36: 0x0  | 0x36: 0x0  |  
0x37: 0x50 | 0x37: 0xD0 | 0x37 RegPacketConfig1 0x10 Packet mode settings
0x38: 0x4  | 0x38: 0x40 | 0x38 RegPayloadLength 0x40 Payload length setting
0x39: 0x0  | 0x39: 0x0  | 0x39 RegNodeAdrs 0x00 Node address
0x3A: 0x0  | 0x3A: 0x0  | 0x3A RegBroadcastAdrs 0x00 Broadcast address
0x3B: 0x85 | 0x3B: 0x0  | 0x3B RegAutoModes 0x00 Auto modes settings
0x3C: 0x1  | 0x3C: 0x8F | 0x3C RegFifoThresh 0x0F 0x8F Fifo threshold, Tx start   condition
0x3D: 0x0  | 0x3D: 0x2  | 0x3D RegPacketConfig2 0x02 Packet mode settings

Edit; put the table in triple backticks for monospace and added some spaces for alignment.

iwanders commented 10 months ago

Thanks for providing comparison!

I'm not sure I have time to parse all of these registers out

I think the difference (ignoring some register that I think don't matter) boils down to:

RegFrf
  plainRFM:  0x6c9002 -> 0x6c9002 * 61 = 433999994 Hz
  radiohead: 0x6c8000 -> 0x6c8000 * 61 = 433750016 Hz
RegFdev:
  plainRFM:  0x0052 -> 0x0052 * 61 = 5002  Hz
  radiohead: 0x1000 -> 0x1000 * 61 = 249856  Hz
RegPacketConfig1
  plainRFM:  0x50=0b01010000 -> fixed length, whitening, crc
  radiohead: 0xD0=0b11010000 -> variable length, whitening, crc
RegSyncConfig
  plainRFM:  0x98=0b10011000 -> SyncSize:3 + 1 = 4,SyncOn
  radiohead: 0x88=0b10001000 -> SyncSize:1 + 1 = 2,SyncOn
RegSyncValue{0..8}
  PlainRFM: [0x1, 0x1, 0x1, 0x1] = [0b00000001, 0b00000001, 0b00000001, 0b00000001]
  RadioHead: [0x2D, 0xD4] = [0b00101101, 0b11010100]
RegDataModul:
  PlainRFM: no shaping
  Radiohead: 01, Gaussian filter BT=1.0
RegBitrate{Msb,Lsb}:
  plainRFM:  0x1a0b = 6667 -> 32e6(FXO_SC) / 6667 = 4799.7600119994 bit/s
  radiohead: 0x0080 =  128 -> 32e6(FXO_SC) / 128 = 250000.0 bit/s
RegPaLevel:
  plainRFM:  0x9F = 0b10011111 -> Pa0: on, pa1: off, pa2: off
  raiodhead: 0x7F = 0b01111111 -> Pa0: off, pa1: on, pa2: on
RegRssiThresh:
  plainRFM: 0xe4 -> -114 dbm
  radiohead: 0xff -> -128 dbm
RegRxBw:
  plainRFM:  0x55
  radiohead: 0xe0
RegAfcBw:
  plainRFM:  0x8b
  radiohead: 0x1a
RegPreamble :
  plainrfm: Preamblesize: 3 bytes
  radiohead: Preamblesize:  4 bytes
RegPayloadLength:
  plainrfm: fixed 4 bytes
  radiohead: variable
RegPacketConfig2:
  plainrfm: nothing
  radiohead: restart Rx after receipt.
RegFifoThresh:
  plainRFM: fifolevel, with 1
  radiohead; fifo not empty, with 0b1111

For instance, I was surprised to see the carrier frequency bytes (RegFrf...) were different.

The difference isn't that large, just multiply the register with 61 to get the frequency in Hz; 433999994 for plainRFM, 433750016 for radiohead. You could use setFrequency with 433750016 to get the exact same as radiohead.

One thing that does stand out to me is the SyncValues; RegSyncValue in the above, for plainRFM this is set to 0x01, but this data is not whitened (page 52 of the datasheet), so those may actually be bad values... I know that's set by this section but it may be worth changing to what radiohead uses.

Another; RegPaLevel, see above comparison, switch that to be the same as Radioheads, I'm not sure if all chips support the power amplifier options used here.

In this comparison, the baudrates are vastly different, with 4.8kb/s vs 250kb/s, that means transmissions take a pretty significant different duration, if there's any (periodic) interference in the environment plainRFM would be much more affected by that, you could try running setRecommended() followed by baud300000(), that sets it up for 300kb/s, which may set things up more similar to radiohead. Maybe even try this first, depending on the environment this may make a world of difference.

When I developed this library years ago I only really tested with three radios and short ranges. That project (not on github) used the following in the initialization;

    this->rfm->setRecommended(); // set recommended paramters in RFM69.

    this->rfm->setPacketType(true, true); // set the used packet type.
    this->rfm->setBufferSize(this->buffer_size);   // set the internal buffer size.
    this->rfm->setPacketLength(64); // set the packet length.
    this->rfm->setFrequency(this->frequency); // set the frequency.

    this->rfm->setNodeAddress(this->kernel->getPlatformAddress());
    this->rfm->setBroadcastAddress(PLATFORM_ADDRESS_BROADCAST);

    this->rfm->baud153600();
    this->rfm->setPreambleSize(10); 

    // tell the RFM to represent whether we are in automode on DIO 2.
    this->rfm->setDioMapping1(RFM69_PACKET_DIO_2_AUTOMODE);

    // set pinmode to input.
    pinMode(this->dio2_pin, INPUT);

    // Tell the SPI library we're going to use the SPI bus from an interrupt.
    SPI.usingInterrupt(this->dio2_pin);

    // hook our interrupt function to any edge.
    attachInterrupt(this->dio2_pin, interrupt_RFM, CHANGE);

    // start receiving.
    this->rfm->receive();

I only needed like 3 meters of range and for that it seemed to work well. But it's like 10 years ago, so I probably forgot countless weeks of frustration trying to get it to work reliably ;)

Hope this gives you some pointers on what you could try and what the differences are. Remember that plainRFM subclasses from bareRFM69, so you can call any of those methods to directly modify registers.

Eli-S-Bridge commented 10 months ago

Thank you for all of this informaiton.

I tried just changing just the baud rate as you recommended ("baud(300000)"), but that resulted in no messages being recieved.

So I moved writeRegister() to make it a public function, and just set registers to match the settings in Radiohead as follows.

rfm.writeRegister(1, 4);
rfm.writeRegister(2, 1);
rfm.writeRegister(3, 0);
rfm.writeRegister(4, 0x80);
rfm.writeRegister(5, 0x10);
rfm.writeRegister(6, 0);
rfm.writeRegister(8, 0x80);
rfm.writeRegister(9, 0);
rfm.writeRegister(0x11, 0x7F);
rfm.writeRegister(0x18, 0x08);
rfm.writeRegister(0x19, 0xE0);
rfm.writeRegister(0x1A, 0xE0);
rfm.writeRegister(0x23, 0x0);
rfm.writeRegister(0x24, 0xBE);
rfm.writeRegister(0x27, 0xD8);
rfm.writeRegister(0x29, 0xFF);
rfm.writeRegister(0x2D, 0x04);
rfm.writeRegister(0x2E, 0x88);
rfm.writeRegister(0x2F, 0x2D);
rfm.writeRegister(0x37, 0x00);
rfm.writeRegister(0x38, 0x04);

With those settings reception is good but I get random messages (see below). It's not missing any packets (despite the "packetloss" messages), so I guess I am in a pretty noisy environment. I have CRC checking turned off and there are no sync words so I think using those features would get rid of some of the mess. Unfortunately, this is all the work I can do today. I'll post more progress soon.

Packet (4): 146 Packetloss detected! Packet (4): 147 Packet (4): 447749699 Packetloss detected! Packet (4): 148 Packetloss detected! Packet (4): 3718659856 Packetloss detected! Packet (4): 3619914529 Packetloss detected! Packet (4): 3266891158 Packetloss detected! Packet (4): 149 Packetloss detected! Packet (4): 1447554770 Packetloss detected! Packet (4): 466365913 Packetloss detected! Packet (4): 150 Packetloss detected! Packet (4): 151 Packet (4): 152 Packet (4): 3053510378 Packetloss detected! Packet (4): 153 Packetloss detected! Packet (4): 4110991270 Packetloss detected! Packet (4): 244994896 Packetloss detected! Packet (4): 154 Packetloss detected! Packet (4): 155 Packet (4): 2811694902 Packetloss detected! Packet (4): 1815969940 Packetloss detected! Packet (4): 1398638066 Packetloss detected! Packet (4): 903718780

iwanders commented 10 months ago

I have CRC checking turned off and there are no sync words so I think using those features would get rid of some of the mess

Without both of these, you have nothing that will prevent noise from being decoded as data. Especiall with RegRssiThresh at -128 dBm, that is a very low detection threshold, so if you have any 443 MHz background noise, it'll likely be able to decode data from it. But as you can see, that data is just wrong. Adding crc and sync words will likely allow you to reduce the spurious receptions significantly, perhaps even completely.

I'm still surprised that you didn't get reliable reception with lower baud rates, I recall testing lower baudrates and getting reasonably reliable reception through multiple concrete walls, but that environment likely had very little background noise.

Eli-S-Bridge commented 9 months ago

Got stuck today trying to write my own writeRegister routine (so I can use plainRFM69 unaltered). Seems simple but I could not get this to work:

void writeRFM69Register(uint8_t RFM_Reg, uint8_t RFM_Val) {  //write a byte to a radio register.
    pinMode(SLAVE_SELECT_PIN, OUTPUT);
    SPI.beginTransaction(SPISettings(10000000, MSBFIRST, SPI_MODE0));  // gain control of SPI bus
    digitalWrite(SLAVE_SELECT_PIN, LOW);
    SPI.transfer(0x80 | (RFM_Reg & 0x7F)); 
    SPI.transfer(RFM_Val);
    digitalWrite(SLAVE_SELECT_PIN, HIGH);
    SPI.endTransaction();    // release the SPI bus
}

So I gave up and used the function in bareRFM69.cpp. Is there a reason for it to be a private function?

I changed the RSSI threshold and got perfect transmission and reception within a range of register values from 0x50 to 0x78. Next I will implement CRC and syncwords.

iwanders commented 9 months ago

Hmm, sure looks like that should work... no real reason it's a private function, just never needed to be public before. I haven't used this chip in years, so my memory on all of these things is a bit hazy.

I changed the RSSI threshold and got perfect transmission and reception within a range of register values from 0x50 to 0x78

Nice, glad you're getting it working.

Eli-S-Bridge commented 9 months ago

Just one more appeal for help, I think. I found that the automode and interupt systems would not work for me (I'm working toward something that will use interrupts and SPI elsewhere). So what I need is to just poll an interrupt pin (DIO0) to see if a message has come in, and if so, read it. I've got that working, and I now have a much simplified radio interface that just uses functions to read and write to the radio registers, to reset the radio, and to fill and read the FIFO. I've taken these functions out of plainRFM69 and I have my own versions in the main sketch. It all works so long as I still create an instance of plainRFM69 with:

plainRFM69 rfm = plainRFM69(SLAVE_SELECT_PIN);

BUT...If I don't create the instance, then the code compiles and runs but there's no communication with the radio -- all register reads come back as 0xFF. So I'm trying to find the magic button that gets pushed when creating an instance. Any ideas?

In case you are wondering why I don't just keep the instance...I'm coding for a device that will have lots of non-programmer as users, and I'm trying to keep the overhead low. The fewer libraries to download and update the better.

Thanks again for all of your help. Here's the sketch in case it is useful to others:


/*
 *  Modified from code by Ivor Wanders
 *  MIT License, see the LICENSE.md file in the root folder.
*/

#include <SPI.h>
#include <Arduino.h>
#include <plainRFM69.h>

// slave select pin.
#define SLAVE_SELECT_PIN 8     

// connected to the reset pin of the RFM69.
#define RESET_PIN 7

#define LED_RFID      43  // (PA27) Pin to control the LED indicator.
#define RADIO_INT     9  // 

// define serial com parameters
#define Serial SerialUSB // SerialUSB

//create instance of plainRFM69 = why is this necessary???
plainRFM69 rfm = plainRFM69(SLAVE_SELECT_PIN);

uint32_t counter = 0; // to count the messages.
bool gotMessage = 0;

void setup(){
    pinMode(RADIO_INT, INPUT);
    Serial.begin(9600);
    SPI.begin(); 
    blinkLED(LED_RFID, 3, 200);
    delay(3000);
    Serial.println("POWER ON!!");
    radioReset(RESET_PIN); // send the RFM69 a hard-reset.

    //settings rendered by rfm.setRecommended(), with modifications
    radioWriteRegister(0x18, 0x08); //Set regLNA to turn on LnaZin and have  gain set by the internal AGC loop
    radioWriteRegister(0x2D, 0x04); //4 LSB for preamble bytes. default = 3; MSB defaults to 0
    radioWriteRegister(0x2E, B10011000);  //Sync on; FifoFillCondition = 0;  3 sync bytes, no tolerance
    radioWriteRegister(0x2F, 0x2D); // Sync value: Set to arbitrary value - same across network
    radioWriteRegister(0x29, 0x64); //setRSSIThreshold (trial & error) 
    radioWriteRegister(0x6F, 0x30); //setContinuousDagc                   0               0
    radioWriteRegister(0x02, 0x01); //set DataModul to one to turn on guassan filter
    radioWriteRegister(0x3C, 0x7F & 15 ); //FIFO threshold; first bit zero -> TX when fifo over threshold. other bits = threshold (need to experiment)
    radioWriteRegister(0x19, 0xE0);  //Channel filtering?? DccFreq = B010; RxBwMant = B10, RxBwExp = B101
    radioWriteRegister(0x1A, 0xE0);  //Channel filtering?? DccFreqAfc = B111, RxBwMantAfc = B01, RxBwExpAfc = B000
    radioWriteRegister(0x13, 0x1A); //setPALevel...
    radioWriteRegister(0x11, 0x7F); //setPALevel: power almost at max
    radioWriteRegister(0x07, 0x6C);  //Frequency MSB for 434,000,000 Mhz 
    radioWriteRegister(0x08, 0x80);  //Frequency MidSB for 434,000,000 Mhz 
    radioWriteRegister(0x09, 0x00);  //Frequency LSB for 434,000,000 Mhz 

    //Settings from radioHeand and trial & error.
    radioWriteRegister(1, 4);
    radioWriteRegister(3, 0);
    radioWriteRegister(4, 0x80);
    radioWriteRegister(5, 0x10);
    radioWriteRegister(6, 0);
    radioWriteRegister(0x23, 0x0);
    radioWriteRegister(0x24, 0xBE);
    radioWriteRegister(0x25, 0x40); //RFM69_DIO_MAPPING
    radioWriteRegister(0x27, 0xD8);
    radioWriteRegister(0x30, 0x1);
    radioWriteRegister(0x31, 0x1);
    radioWriteRegister(0x32, 0x1);
    radioWriteRegister(0x2F, 0x3D);
    radioWriteRegister(0x37, 0xD0); //packet config, Variable length, whitening on, CRC on
    radioWriteRegister(0x38, 0x20); //RFM69_PAYLOAD_LENGTH

    //Final settings
    radioWriteRegister(0x3D, 0); //no interpacket delay, no auto RX restart, no AES (encryption)
    radioWriteRegister(0x3C, 0x01); //minimum package threshold
    radioWriteRegister(0x3B, B00000000);  //Automode setting - turn it off
    radioWriteRegister(0x5A, 0x55); // RFM69_TEST_PA1: Normal mode and Rx mode
    radioWriteRegister(0x5C, 0x70); //RFM69_TEST_PA2: Normal mode and Rx mode

    radioWriteRegister(0x01, B00010000); //set to receiver mode

    radioDumpRegisters(); // view all registers

    delay(5);
}

void loop(){
char choose = 'R'; //Change to something other than "R' before loading to transmitter
    if (choose == 'R'){
        Serial.println("Going Receiver!");
        receiver(); 
        // this function never returns and contains an infinite loop.
    } else {
        Serial.println("Going sender!");
        sender();
        // idem.
    }
}

void sender(){
    uint32_t counter = 0; // the counter which we are going to send.
    uint8_t tx_buffer[13];  //buffer is 1 more than message. First byte is length
    //Send 12 numbers but change the 11th one each time...
    tx_buffer[12] = 1; tx_buffer[1] = 2; tx_buffer[2] = 3; tx_buffer[3] = 4;
    tx_buffer[4] = 5; tx_buffer[5] = 6; tx_buffer[6] = 7; tx_buffer[7] = 8;
    tx_buffer[8] = 9; tx_buffer[9] = 0; tx_buffer[10] = 1; tx_buffer[11] = 2;

    while(true){
      delay(2000);
      tx_buffer[11] = counter;
      tx_buffer[0] = 12;
      Serial.print("Send:");Serial.println(counter);
      radioWriteRegister(0x01, B00000100);  //First Set mode register to receive mode
      //(0b010<<5) + (0b110<<2) + (0b11) = B01011011  
      radioWriteRegister(0x3B, B01011011);  //set to automode - start transmitting when FIFO level is above the thresshold
      radioWriteFIFO(tx_buffer, 12);
      radioWriteRegister(0x01, B00000100); // Back to recieve mode.

      counter++; // increase the counter.
      blinkLED(LED_RFID, 3, 200);  
    }
}

void receiver(){
    uint8_t rx_buffer[66] = {0};
    uint32_t* rx_counter = (uint32_t*) &rx_buffer;
    while(true){
        delay(1000);
        uint8_t rd = digitalRead(RADIO_INT);
        Serial.println(rd);
        if(rd) {
          SPI.beginTransaction(SPISettings(10000000, MSBFIRST, SPI_MODE0));  // gain control of SPI bus
          digitalWrite(SLAVE_SELECT_PIN, LOW);
          //this->chipSelect(true); // assert chip select
          //SPI.transfer((RFM69_FIFO % RFM69_READ_REG_MASK));
          SPI.transfer((0 % 0x7));
          uint8_t len = SPI.transfer(0);
          //len = len > (max_length-1) ? (max_length-1) : len; //Contain max value of len
          for (uint8_t i=0; i < len; i++){
              rx_buffer[i] = SPI.transfer(0);
          }
          digitalWrite(SLAVE_SELECT_PIN, HIGH);
          SPI.endTransaction();    // release the SPI bus 

          Serial.print("Received Packet ("); Serial.print(len); Serial.println("): "); 
          for (byte i=0; i<len; i++) {
             Serial.print(rx_buffer[i]); Serial.print(" ");
          }
          Serial.println();
          gotMessage = 0;
        }
    }
}

void blinkLED(uint8_t ledPin, uint8_t repeats, uint16_t duration) { //Flash an LED or toggle a pin
  pinMode(ledPin, OUTPUT);             // make pin an output
  for (int i = 0; i < repeats; i++) {  // loop to flash LED x number of times
    digitalWrite(ledPin, LOW);         // turn the LED on (LOW turns it on)
    delay(duration);                   // pause again
    digitalWrite(ledPin, HIGH);        // turn the LED off (HIGH turns it off)
    delay(duration);                   // pause for a while
  }                                    // end loop
}                                      // End function

void radioReset(uint8_t pin){ // function to send the RFM69 a hardware reset.
    pinMode(pin, OUTPUT);
    digitalWrite(pin, HIGH);
    delayMicroseconds(150); // pull high for >100 uSec
    pinMode(pin, INPUT); // release
    delay(10); //  wait 10 milliseconds before SPI is possible.
}

void radioWriteRegister(uint8_t reg, uint8_t data){
    SPI.beginTransaction(SPISettings(10000000, MSBFIRST, SPI_MODE0));  // gain control of SPI bus
    digitalWrite(SLAVE_SELECT_PIN, LOW);
    //this->chipSelect(true); // assert chip select
    //SPI.transfer(RFM69_WRITE_REG_MASK | (reg & RFM69_READ_REG_MASK)); 
    SPI.transfer(0x80 | (reg & 0x7F));  // send write instruction (high byte = 1) 
    SPI.transfer(data);
    digitalWrite(SLAVE_SELECT_PIN, HIGH);
    //this->chipSelect(false);// deassert chip select
    SPI.endTransaction();    // release the SPI bus  
}

uint8_t radioReadRegister(uint8_t reg){
    uint8_t foo;
    SPI.beginTransaction(SPISettings(10000000, MSBFIRST, SPI_MODE0));  // gain control of SPI bus
    digitalWrite(SLAVE_SELECT_PIN, LOW);
    //SPI.transfer((reg % RFM69_READ_REG_MASK));
    SPI.transfer(reg % 0x7F); //use modulo of 0x7F to ensure read instruction (high byte of address = 0)
    foo = SPI.transfer(0);
    digitalWrite(SLAVE_SELECT_PIN, HIGH);// deassert chip select
    SPI.endTransaction();    // release the SPI bus
    return foo;
}

void radioWriteFIFO(uint8_t *buf, uint8_t len){
    for(byte i = 0; i < len; i++) {
      Serial.print(buf[i]); Serial.print(" ");
    }
    Serial.println();
    //uint8_t* r = reinterpret_cast<uint8_t*>(buffer);
    SPI.beginTransaction(SPISettings(10000000, MSBFIRST, SPI_MODE0));  // gain control of SPI bus
    digitalWrite(SLAVE_SELECT_PIN, LOW); // assert chip select
    //SPI.transfer(RFM69_WRITE_REG_MASK | (RFM69_FIFO & RFM69_READ_REG_MASK)); 
    SPI.transfer(0x80);  //high bit = 1 to indicate write instruction - reg address is 0x00 for FIFO
    for (uint8_t i=0; i < len ; i++){
        // Serial.print("Writing to FIFO: "); Serial.println(r[i]);
        SPI.transfer(buf[i]);
    }
    digitalWrite(SLAVE_SELECT_PIN, HIGH); // deassert chip select
    SPI.endTransaction();    // release the SPI bus
}

void radioDumpRegisters() { //View all radio registers
  uint8_t val;
  for (int i = 0; i <= 0x3d; i++) {
    Serial.print("0x");
    Serial.print(i, HEX);
    Serial.print(": 0x");
    val = radioReadRegister(i);
    Serial.println(val, HEX);
  }
  int j = 0x58;
  Serial.print("0x");
  Serial.print(j, HEX);
  Serial.print(": 0x");
  Serial.println(radioReadRegister(j), HEX);
  j = 0x5A;
  Serial.print("0x");
  Serial.print(j, HEX);
  Serial.print(": 0x");
  Serial.println(radioReadRegister(j), HEX);
  j = 0x5C;
  Serial.print("0x");
  Serial.print(j, HEX);
  Serial.print(": 0x");
  Serial.println(radioReadRegister(j), HEX);
  j = 0x6F;
  Serial.print("0x");
  Serial.print(j, HEX);
  Serial.print(": 0x");
  Serial.println(radioReadRegister(j), HEX);
  j = 0x71;
  Serial.print("0x");
  Serial.print(j, HEX);
  Serial.print(": 0x");
  Serial.println(radioReadRegister(j), HEX);
}

edit; added cpp to the triple backticks for syntax highlighing.

iwanders commented 9 months ago

Cool, I'm glad you're getting it all working!

So I'm trying to find the magic button that gets pushed when creating an instance. Any ideas?

Absolutely, thanks for sharing your code. I think the missing bit is the pinMode call, by default pins are in high impedance mode (INPUT), in your sketch it is not set to OUTPUT mode.

The plainRFM69 constructor delegates here to the bareRFM69 constructor, which performs that pinMode(this->cs_pin, OUTPUT); call. If you add pinMode(SLAVE_SELECT_PIN, OUTPUT); to your setup, I have no doubt you can eliminate the instance of plainRFM69.