Monday, August 26, 2019
433MHz OOK radio signalling
I am working on a super low budget project using cheap OOK/ASK 433.92 MHz modules. The project has some sensors that can be periodically read by an ATTiny85 and the data sent to a base station using a VirtualWire OOK codec. The distances involved are generally pretty far for these type of radios. I am looking for about 500m from the farthest one, and 150m from the closest one, all through ~150m of bush, plus some distance across open water.
I have obtained usable reception currently, at these distances and in implementing this project, I’ve had to do a bunch of investigation into low cost radio transmitters and receivers, the available encoding software and its quirks, antenna design and other interesting details.
Transmitters
The quality of the cheap 434 MHz transmitters is all over the map, and the documentation about their design is pretty scarce to non-existent. I think most of them are designed to match a 1/4 wave whip at ~35R or are matched to ~50R or perhaps not designed with any particular matching impedance. The transmitters all seem to be designed to be single ended and most of them have no nearby RF ground making it awkward to attach a differential pair. Except for the most expensive one, there is no documented matching impedance or output power. Later I discovered that start-up time is another undocumented, but possible critical parameter.
Receivers
The project requirement is simply to have the fixed base-station receiver. It needs to be sensitive and reliable. I have messed with several different 433MHz ASK receivers. They are of varying quality and designs. The cheapest and poorest ones are based on a super-regenerative design that is wholly unsuited to this project. The better ones use a super-heterodyne design, with a crystal LO and ceramic IF filter.
I would like the base station to have a received signal strength indication (RSSI) from the senders. This will be desirable when initially placing senders and optimizing antenna orientation and placement, as well as for early warning about link budget issues that could arise due to vegetation or weather. Not many cheap receiver modules have a documented RSSI output, but some of the chip-sets for the better super-heterodyne designs do have an RSSI indicator.
The first I’ve had luck with are the OnShine RXA30 based on a Princeton PT4301-X superhet receiver chip. This chip does provide a “peak detector” AGC gain control output that lets you get an idea of RSSI. The AGC control voltage does not change when the internal attenuators are switched, so somewhere maximum and minimum signal strength, there’s an overlap between two signal levels that are about 20dB apart. Since this is on the super-strong end of the receive signal levels, and I am interested in the signal strength at the weak end, maybe that’s okay.
I got a better result with an RXB6 module based on a Synoxo SYN500R superhet receiver. This chip does have a documented RSSI output and I have successfully managed to tack a small wire onto the proper pin to get the signal off of the module. Although it is documented, I have gotten mixed results with the actual signal available. On one module that works fine otherwise, the RSSI output does not seem to work at all. In the modules where it works, it seems to have to be characterized on each individual module.
The process is pretty simple: when I put the sender and receiver in the same room with decent antennas, I get some upper reading. Then if I carry the receiver down the road, at the point where the signal becomes almost unusable — a step or so back from the point where it disappears, then I get some other number. This is approximately 0.5*Vcc at the strongest and 0.2*Vcc at the weakest usable signal.

This is OK, but it is not ideal. It also bothers me that the module does not simply have a documented and characterised RSSI output of some kind, and if I could find a cheap, well designed module that had one, I would use it instead. The black Linx modules you can see in both collections are first-rate modules with well characterised and documented features including RSSI indication and settable transmit power. These units also cost about 20 times as much as the cheepies, so I am mostly using them as test drivers.
Data encoding
Encoding data for transmission by these little radios is a common problem with many possible implementations. In the past I have successfully reverse engineered proprietary schemes and I have successfully used VirtualWire in projects.
I’ve been looking at alternate TX/RX libraries and some features I would want that RadioHead RH_ASK and VirtualWire doesn’t have are forward error correction and compact implementations.
The ideal air interface should be one with
- tested, reliable implementations,
- compact implementation suitable for the ATTiny85
- forward error correction
- timing tolerance/flexibility
In terms of forward error correction, I looked at a couple of options that I thought could help me. First is a Reed-Solomon library for Arduino by simonyipeter. This looks very clever, but the implementation uses large tables that would consume more memory than is actually available on an ATTiny85. Although the code could be restructured to use ROM for a lot of this, I simply don’t have the time to do the rewrite and debugging needed.
I was particularly keen on Andreas Rohner’s implementation of RFTransmitter and RFReceiver. This transmitter is still a little large and complicated for the ATTiny85, but the library does address a number of serious problems with Virtual Wire.
VirtualWire does not have error correction. Also, despite the claims of RH_ASK, I find that the RadioHead implementation simply won’t fit on an ATTiny85 with the other parts of my project. It also demands to use pins that I don’t have for functions I don’t need or want. At some point though, I happened upon this simple VirtualWires send-only implementation by mr-k on Stack Exchange. It is super compact and ideal for the ATTiny85. I started using it with a VirtualWire receiver on the receiving end and was successful almost right away. I decided at this point to go with the VirtualWire protocol and use Mr-K’s compact implementation on the ATTiny85 for sending.
Timing issues
After getting a couple of simple test application running with good success, I started to have some frustrating problems with reliability, particularly with certain individual ATTiny85 parts. While debugging this situation, I discovered problems with the Virtual Wire receiver’s sensitivity to timing. There turn out to be multiple problems with my sender implementation:
First, because I am using the internal 8-MHz oscillator in the ATTiny85, the overall sender system timing is not super stable. Chips can vary the precise clock speed with temperature and voltage, and speed can vary a bit between individual chips. This last was the source of my initial problems.
Second, the brute-force timing implementation in mr-k’s VirtualWire sender leads to the signal timing being skewed a little slow, and this needs to be compensated by tuning the timing a bit. Here you can see that the preamble waveform that should be exactly 500us high and 500us low is running a little slow — overall about 980 Hz versus an ideal 1,000 Hz.

All of this is only really a factor because the Virtual Wire receiver is more sensitive to timing that it likely should be. As it turns out 2% from nominal timing, either faster or slower, is liable to make the signal unusable.
Initially I started by tuning the OSCCAL on the ATTiny85 to get the system clock as close as possible to 8.00MHz, at the target battery voltage. After some experimentation, I found that the default tuning on the chips I had was really very good and it was hard to make any real improvement on the tuning. The VirtualWire signalling waveform was still too slow by as much as 3%, even on systems using a crystal oscillator. This led me to implement a timing adjustment in the VirtualWire sender code, which made a huge difference in the reliability of the link.
While making these tuning changes and measuring the results on my oscilloscope, I found another serious timing consideration. It turns out that the radio transmitter I was using for this test has a significant delay between when the transmit signal is asserted and when the transmitter reaches full power. The delay is about 65 microseconds or over 13% of the nominal bit time. This is harder to compensate for in software and it is likely a timing that varies amongst radio designs.

Empirical timing analysis
In the interests of discovering the optimal tuning of the VirtualWire transmit clocking, I set up an experiment to transmit short messages using a variety of clock rate offsets and to see which offsets worked and which didn’t. In my experiment I am using a baud rate of 2,000 bauds/sec which uses a fundamental bit timing of 500us. For testing I am using a transmitting MCU that has a crystal oscillator so that ATTiny RC oscillator tuning isn’t a factor. I used the transmit radio with the slow startup and did not specifically compensate its effects.
The experiment consisted of transmitting short messages using slight variations in the fundamental timing of the VirtualWire signal. I transmitted one message at each timing variation, then repeated the variation pattern, sending one message per minute over a couple of days.
- Receiver is stock VirtualWire 1.27
- Sender is hacked VW sender with brute force timing
- Message is 5 octets (plus 16-bit CRC) nominally 2000 baud, approx 73ms, about 150 bit times
Each message encodes the timing variation used and from a log of all received messages, it is possible to do a statistical analysis which timing variations are most readily received overall. The following chart shows the results.

The original timing caused by the software delays making the timing about 2.8% slow is shown in red. This is quite close to the overall cutoff in receivability at about 3.8% slow. I think that this is the reason I found that one ATTiny85 might work where another didn’t, since variations in RC oscillator timing could put things over the edge.
The ideal 500us timing is shown in green. Interestingly this isn’t in the centre of the workable range and I think that this is due to the slow turn-on of the radio I used. A slightly slower timing 1% longer than nominal probably helps to offset the slow turn-on.
Antennas

The link budget I’m working with is pretty narrow. I believe I am getting ~ -96 dBm at the location where the receiver needs to be, as measured with my RFExplorer in perfect weather conditions. The receiver sensitivity is ~ -112 dBm so low batteries, bad weather, vegetation or cobwebs on the antennas could put me close to the limit.
The only RF instrument I have that operates in the 433mhz band is an RFExplorer. The antenna design process I’ve been using is to read ideas about transmission lines, baluns and antennas, try to hack something out of materials at hand and then measure the results by watching the signal strength recorded on my RF Explorer sitting on a nearby shelf when I attach the antenna to a test transmitter. Things that make the received signal stronger are good, things that don’t I reject.
After messing with little baluns wound onto cores scrounged from CFL lights I have settled on using a twisted pair taken from a CAT5e cable as both a transmission line and current balun. I can use a 150mm length of UTP soldered on one end directly to the dipole elements, and on the other, connected to the radio via a 2.5mm header connector. It seems to work alright.
I thought about one of those cheap Chinese $80 Nano-VNAs, but even that would add costs to the project that I am unsure are worth it. I will likely fabricobble an RF power meter if I can rummage out a couple of suitable diodes from my junk bin. This would help just for comparing the RF power level of different transmitters.