Using Semtech SX1231 to Transmit Custom Frames

Lately I have been experimenting a bit with the Semtech SX1231(aka. RFM69) module. Here is a little write up about my experience in using the module for transmitting custom frame.

What I describe here probably isn’t new information, I haven’t checked if anyone already implemented something like this.

Goal

What I want to achieve is to send a custom frames from a Raspberry PI running Linux. With custom frames I mean a frame that doesn’t use some commonly used protocol or coding. I will use the Somfy RTS system here as an example.

In the past I’ve used Si4010 modules for this purpose with my SER4010 firmware. But Si4010 modules are not widely available and loading/programming the SER4010 firmware into the module is not trivial. The SX1231 has very good availability and doesn’t need any custom firmware, making it a good alternative.

An advantage of the SX1231 module above any cheap OOK modulator, is that it is tunable. For example the Somfy RTS system uses a carrier frequency of 433.46 MHz, while most simple OOK modulator modules use a frequency of 433.92
MHz.

SX1231 Continuous mode

One option the SX1231 offers to send custom frames is called continuous mode. In this mode the data is provided to the SX1231 from an external MCU on the data pin. The SX1231 acts as a simple modulator. To use this mode from a Raspberry PI, the data has to be bit banged on a GPIO port pin.

Down side of this is that your software needs to meet tight deadlines to trigger the GPIO pin in time. This can be a problem if you run an complex operating system like Linux on a Raspberry Pi.

SX1231 Unlimited Packet mode

A better way would to use the packet engine and buffering build in to the SX1231. In this case the SX1231 takes care of the timing.

The packet engine is pretty smart and can do various frame handling task like preamble generation, encoding and CRC. However since we try to send custom frames, this is not what we want. Luckily the SX1231 allows all of this extra packet handling to be turned off.

The packet engine has three packet length settings: Fixed, Variable or Unlimited packet length. The first two modes limit the length of a frame to about 255 bytes. As we see later on, encoding a custom frame can take up a lot of bits. So Unlimited mode is the better solution here.

In unlimited length packet mode with all packet handling features disabled the packet engine works like a simple output data serializer. Meaning the data bytes are taken from the FIFO one by one and shifted out to the modulator bit by bit. The rate at which the bits are shifted out is configured by the baud rate.

As the name implies, are frames send in unlimited mode not limited in size. This is achieved by refilling the FIFO buffer on the fly during transmission. The module can trigger an interrupt when the FIFO runs empty, allowing the host MCU to refill the buffer. In general this should give the MCU enough time to react.

How to encode a frame

The data is serialized at a fixed baud rate. This means that the frame to be transmitted must be encoded as a bit pattern that defines the signal level for every interval. To do this we first must find an appropriate baud rate to use.

To be able to encode a frame it must be possible to represent every interval as a multiple of the baud rate period. In a lot of protocols all intervals are divisible by the smallest interval. In this case the baud rate will be equal to 1/(smallest interval).  However in some cases this is not possible.

If we take the Somfy RTS protocol as example.

Description Duration Times smallest interval
HW. Sync 2416 us 4x
Soft. Sync 4550 us 7.53x
1/2 symbol time 604 us 1x

As can be seen in the table above the soft. sync. period is not integer divisible by the smallest period. One solution in this case could be to choose a period of 302 us instead. The soft. sync duration in this case is within 1% from the closest integer multiple of the basic period, which would in most cases be close enough.

In practice however, it was found that the length of the soft. sync. interval is not very critical and an interval of 8 * 604 = 4832 is still close enough.

In general using a lower serialization baud rate is better since it takes more time to send the data in the SX1231 FIFO. And thus the software has more time to refill the FIFO when it is running empty.

So now the preamble of a Somfy RTS signal can be represented with the following bit string:

1111000011110000111111110

Okay, but the SX1231 packet engine works with bytes instead of bits. But here we have 2 1/8 byte!

One solution would be to multiply the baud rate by 8, giving 17 bytes to encode the preamble. But we wanted to keep the bit rate low…

In this case the modulation used is OOK. This means that if a 0 is transmitted, nothing is transmitted. So if we add 7 ‘0’ bits to the beginning of the data, the receiver won’t notice this.

Now the preamble can be encoded at a bit rate of 1656 bit/s (=1/604us) as:

00000001 11100001 11100001 11111110
  0x01     0xe1     0xe1     0xe1

You might wonder, ‘This is only the preamble, what about the data bits’. That I’ll leave as an exercise for the reader;).

libsx1231_ods

Nice theory, but I want to see proof! Since I already have a lot of code that implement parts of this functionality in other project, I decided to create a little proof-of-concept library.

You can find the code on GitHub:

https://github.com/dimhoff/sx1231_ods

I only did some short tests with it, but it seems to work as expected.