Computing stuff tied to the physical world

Picking up a signal

The next step is to send out packets which match the settings and protocol used by our “listen” setup. We can do this with a second node, using the same µC and radio driver:

DSC 4924

This one is running the blip code:

#include "spi.h"
#include "rf69.h"

RF69<SpiDevice> rf;

void sleepSetup () { ... }
extern "C" void WKT_IRQHandler () { ... }
void sleep (int millis) { ... }

int main () {
    LPC_SWM->PINENABLE0 |= 3<<2;        // disable SWCLK/SWDIO
    // lpc810 coin: sck=0p8, ssel=3p3, miso=2p4, mosi=1p5
    LPC_SWM->PINASSIGN3 = 0x00FFFFFF;   // sck  -    -    -
    LPC_SWM->PINASSIGN4 = 0xFF010205;   // -    nss  miso mosi

    sleepSetup();

    rf.init(1, 42, 8683);
    rf.txPower(0); // minimal

    uint16_t cnt = 0;
    while (true) {
        rf.send(0, &++cnt, sizeof cnt); // send out one packet
        rf.sleep();
        sleep(1000);                    // power down for 1 second
    }
}

The code is again very simple, but this time no more serial I/O or printf’s, instead there is some logic to put the radio and the µC into power down mode between transmissions.

And sure enough, once powered up, our listening node starts receiving packets:

[listen]
OK 80010100 (192+12:1)
OK 80010200 (188+352:1)
OK 80010300 (186-56:1)
OK 80010400 (188-142:1)
OK 80010500 (192-232:1)
OK 80010600 (191-220:1)
OK 80010700 (191-62:1)]
...

The data shown is: destination id, header byte, and 2-byte little-endian counter as payload.

Also shown in parentheses: the signal strength times -2 (so -96 dBm is reported as 192), the applied AFC (in ± steps of 61 Hz), and the current LNA gain settings (1=max, 7=min).

The reported signal level is very low, because this setup used an RFM69-433 as receiver with an RFM69-868 as transmitter. Just to show that they can (barely) hear each other. For normal use, the frequency bands need to match what the radios were designed for.

Success! We have an LPC810 + RFM69 sending packets to another LPC810 + RFM69!

If only it were that easy…

But that’s not the whole story.

It took many days of tinkering with the RF69 driver code, finding a configuration which worked, debugging the SPI communication with a logic analyser, and working out an API which separates the main driver logic from the hardware SPI interface via C++ templates.

But that’s another story. Perhaps more interesting in this context, is how the LPC810 pin choices came about. The original choices were made based on the physical layout of pins and trying to match them up for easy soldering to the RFM69 module. The LPC810 switch matrix is very convenient, since you can connect almost any hardware function to any pin.

There are no fixed pins used for SPI – we can simply assign them on startup as needed:

// lpc810 coin: sck=0, ssel=3, miso=2, mosi=1
LPC_SWM->PINASSIGN3 = 0x00FFFFFF;   // sck  -    -    -
LPC_SWM->PINASSIGN4 = 0xFF030201;   // -    nss  miso mosi

But there are some caveats, and the initial choice didn’t work because of them:

  • we need to disable SWDIO/SWCLK pins 2 and 3 to use them for something else:

    LPC_SWM->PINENABLE0 |= 3<<2;
    
  • we can re-use RESET pin 1, but then uploading becomes more complicated: instead of toggling the pin via FTDI, we have to power-cycle the chip to force upload mode

  • in “listen”, serial output must go to pin 4 (TXD) to pass through the FTDI interface:

    LPC_SWM->PINASSIGN0 = 0xFFFFFF04;
    
  • during uploads, the radio must be kept disabled, this is done by connecting its NSS pin to pin 3 (SWCLK), which remains high during ROM-based firmware upload

Note that the image & code of the sending node still show the original/problematic wiring.

All this setup and bit-fiddling could benefit from some standard wrapper code to make it a bit more intuitive and self-documenting, but for this initial demo it’ll have to do.

[Back to article index]