This project will go over the basics of RF communication, as well as show off a few reliability and power saving techniques. I designed this project to be used for sending sensor data from battery-powered sensors in hard to get to locations. Regardless of the application space, there are some really great details on RF communication below that could help take your design to the next level.
Before I dive into specific details of this project, we need to gain a deeper understanding of the RF communication reliability.
"Reliable" Wireless CommunicationReliability is an interesting topic in the world of engineering, because nothing can ever be guaranteed. We design for the worst case, but even that is not enough in some situations. When it comes to wireless communication, this is no exception. One of the difficulties in sending information wirelessly is accounting for bit-flips. Put simply, a bit-flip is simply sending a "1" and having the receiver read it as a "0" (or vice versa). These can obviously have tremendous impacts on a system, because sending a "1" verses a "0" could lose you the election or it could mean losing control of your car (Yes, there is actually an entire Radio Lab podcast that talks about this very topic, and I HIGHLY recommend you give it a listen). So now that we all agree that bit-flips can have a lot of negative consequences, how can we design our system to prevent them?
When designing effective RF systems, environmental factors must be taken into account. These can be physical factors, such as trees blocking the path between RF transmitter and receiver. They can be come in the form of high frequency noise, which can produced incorrect results when the transmitter is off, or affect transmitted messages when the transmitter is on. Another factor that is generally left out is the imperfect transmitter and receiver. Although they are extremely accurate, they can still be biased by things like noise, extreme temperature, and humidity. So how can we design for all of these difficulties?
Choosing the Right AntennaThe first issue is making sure that we have enough range to transmit the data. This can be done by attaching an antenna that is tuned to our transmission frequency on both the transmitter and receiver. These antennas help act as amplifiers for the desired signal band, which helps increase the power output on the transmitter, and helps cut down on some of the noise on the receiver end. A properly designed antenna looks something like the image below:
The graph shown above is the antenna's voltage standing wave ratio (VSWR). This is essentially a ratio of the measured voltages across a transmission line. This matters because it tells us a lot about how signals are reflected. If there is a large difference in voltage across a transmission line, then there will be a large current moving through the antenna, and a signal will be transmitted. If there is no difference in voltage across the transmission line, then no signal will be reflected. If a large component of the signal is reflected, this will deconstructivley interfere with incoming waves, causing measurements to be unreliable.
Keeping this in mind, we want to make sure that our antenna performs well at our transmission frequency (VSWR close to 1) and it performs extremely poorly at non transmission frequencies (VSWR extremely high). With low reflection of frequencies we want to capture, we are increasing efficiency by absorbing the signal. With high reflection of unwanted frequencies, we are decreasing the magnitude by reflecting waves back, and creating deconstructive interference. Just by adding a frequency matched antenna to our transmitter and receiver should help increase efficiency in both transmitter and receiver, while also helping to remove some noise from the environment. Both the MAX1472 EV-Kit and MAX1473 EV-Kits have an antenna adapter available to quickly add an antenna.
Squelch CircuitryAnother important feature that we want to utilize in the MAX1473 receiver is the squelch functionality. Squelch is used to ensure that we are reading the transmitted signal as opposed to naturally occurring noise. In order to help combat this, the data slicer (circuitry that takes the RF signal and translates it to digital) is also connected to a peak detector circuit. This peak detector sets the reference voltage for the data slicer. If the incoming data has a magnitude greater than the peak detector's threshold, then the output is "1", and if it below this threshold it is "0". The peak detector also detects the incoming transmission's peak voltage (hence the name). As the average voltage of the incoming signal increases, so does the peak detector output. An example is shown below. The blue line is the peak detector output, the red represents the digital output from the data slicer, and the green is the incoming signal. In actual receivers, the incoming data will be filtered multiple times and amplified before entering the peak detector, but for understanding the concepts, we can assume this is the direct RF signal.
As shown, when the incoming data is above the peak detector threshold, the digital output is high. When it is below, the digital output is low. From 0 ms to about 30 ms, the average voltage of the wave is fairly constant, so the peak detector remains relatively constant at about 2 volts. From 30 ms to 70 ms or so, the average voltage of the incoming wave increases, so the peak detector threshold increases as well.
When we transmit data within the receiver's range, the peak detector will slowly increase the threshold voltage until it matches the average incoming signal voltage. By increasing the threshold voltage, we are effectively cutting out the very low-power environmental noise, which has a much lower average voltage. Depending on how quickly the peak detector can react, you may need to send a "warm-up" signal to the receiver, so that the peak detector has time to increase its threshold, and cut out unwanted noise. This also means that when we are not transmitting data, threshold falls down to the average voltage of the environmental noise. Once it is lowered to the noise level, it will begin to "chatter." This is simply a result of the peak detector's output lowering to the point that noise is the prominent signal, and it will output seemingly random data as it waits for a stronger transmission.
In order to combat this noise, we add what is refered to as squelch. The squelch is essentially just a bias on the peak detector output. Instead of leaving the output floating, which allows the output to fall all the way down to noise level, we put a know voltage at the output, just above the average voltage of the noise. That way, the lowest possible output from the peak detector is set above the noise level, and it will not trigger any data out. This will also increase the responsiveness of the receiver. Since the threshold is already starting above 0 V, it will not need as much time to "warm up." Be careful though, because you need to ensure that your transmission average voltage is greater than whatever squelch you add, otherwise you might lose your message!
The final note regarding the peak detector circuit is knowing your average signal strength. In some applications, the data being received may bias the peak detector. For example, if during a long transmission the initial data values consist of mostly 1's, the peak detector output will start to rise above the signal's true average. This can cause issues when you then start sending a mix of 0's and 1's, because the peak detector may have surpassed the actual average transmission voltage. For short transmissions, this may not matter as much, because the peak detector output will not increase enough to actually begin affecting the incoming readings. For longer transmissions, this could actually drastically affect your results, because having a majority of 1's in the beginning of a transmigration could increase the data slicer threshold, and begin to reject some of the incoming data.
For this very reason, a new method of data transmission called "Manchester Encoding" was developed. The goal of this encoding is to guarantee that a signal will remain high and low for equal amounts of time. Instead of a signal being high representing a 1, and low representing 0, this encoding requires that the signal go from low to high to represent 1, and high to low to represent 0. Since the signal transitions from one state to the other, and it is in both states for equal amounts of time, the average of the signal will stay constant. While I did not implement this encoding for my project, if your application requires long transmissions, it is an important feature to add.
The final defense against bit-flips during transmission is the error correcting code (ECC). ECC is found in all types of communications, as well as in many memory ICs and microcontrollers. ECC has a lot of advantages, but there are still a few important things to note:
1) ECC can notify the user if a transmission failed. There are some cases that will go undetected by ECC regardless of the type implemented. When dealing with an ECC that does not detect a failed transmission, generally it is more an issue with the hardware setup than it is with the software. ECC can try to fix small errors, but if more than 20% or so of the bits being sent are being flipped, sometimes the ECC will miss the failed transmission.
2) ECC can fix some bit-flips. ECCs are made to correct flipped bits. Their effectiveness, however, depends on their type and their implementation. We cannot have a receiver read "00100001" and expect it to realize we meant for it to read "1111111." A more realistic case would be reading "11110111" and realizing it should be "11111111." Similarly to the last point, if your receiver is reading something like 20% or more of the bits flipped, it is probably a setup issue, not an ECC problem.
3) ECC is a trade off between efficiency and robustness. We have to find the balance of effectively correcting code, and not using extensive resources (time, memory, power, etc.). You could store each individual bit 100 times in memory to almost guarantee its successful transmission, but this is by no means efficient. You could also use no ECC, which requires no overhead at all, but could result in incorrect data or code being used. We have to take these design considerations into account when building our RF ECC module.
In this project I decided to implement a form of Forward Error Correction (FEC). This typology aims at correcting bit-flips or alerting the controller when data being read is incorrect. The main idea of FEC is encoding messages so that the transmission will be longer, but the message will be more robust. In this implementation, I will be encoding every 2 bits into 8 bits. That means my transaction overhead will increase, as I have to send more, but my message should withstand more bit flips.
ForwardErrorCorrection(FEC)
The code itself works by checking the Hamming distance between a look-up table and the received message. Hamming distance refers to the number of differences between 2 sets of bits. In this case, we are checking the Hamming distance between the incoming message, and the look-up table. As shown below, each 2 bit sequence has a unique 8 bit encoded message. Every time "11" enters the encoder, it is encoded as 0x1F. Likewise, when "10" is encoded, it produces 0x06. These table values were selected in order to maximize hamming distance between encoded values.
After the message is encoded and sent, the receiver checks the hamming distance between the incoming message and the encoder table values. For example, if the receiver reads 0x1F, the hamming distance between 0x1F (the incoming data) and 0x1F (the encoder table value) is 0. With a hamming distance of 0, you can be fairly certain that was the original encoded value, and the original bits were "11." As a general rule, if the hamming distance is 0, that is the assigned value.
The error correction comes when one or more bits is flipped. If one bit flips, there will be no values with a hamming distance of 0. This is an example when you need to take the hamming distance of each encoder table value, and choose the minimum hamming distance pair. Since the encoder values are selected to maximize hamming distance between each other, with one bit flip there will only be one option that has a hamming distance of 1, and you can confidently choose this as your encoded value.
If two bits flip, depending on where they are located, you may or may not be able to resolve them. If they flip in parts that make the original value more closely resemble another encoder table value, then the hamming distance for both table values may be 2. This is an example of when the code should throw an error, because it does not know the original encoded value. If the bits flip in a part of the message that does not make it resemble other table values, there may only be 1 table vale with a hamming difference of 2, and you can choose this as your encoded value.
Issues arise when 3 or more bits are flipped during a transmission. In this case, the message is already so far from its original form that either the system will throw a bad data error (best case) or the data will be translated into the incorrect bits. It is important to remember that these forms of error correction are made assuming that there will rarely be 1 bit flip, and only in extreme cases should you see 2 bit flips in the same transmission. If your system is flipping more than one bit during a transmission, you have to check your setup, because bit-flips should be a rare occurrence. The FEC is put in place to make sure that on the extreme case there is a bit flip, it is still translated correctly. Your system should not rely on the FEC, but rather have it as a safety net of sorts that can help fix issues in the off chance they occur.
System SetupAs most RF systems, the overall design consists of two separate schematics. Since these devices are designed to be electrically isolated, running off of separate batteries, you can see that they do not have any common connections. Since the EV-Kits are already frequency and impedance matched, it is as simple as powering the devices and sending data.
The transmitter circuit is about as simple as can be. You power the device and send data. I've also shown the connections made for the temperature sensor, however, this can be substituted with any type of sensor. The data being sent is from a simple UART connection. The Enable pin is a simple digital input where 'high' turns the transmitter on, and 'low' puts the device in shutdown mode. The MAX30208 has a simple I2C interface.
The receiver is also extremely straightforward. It will read data as a UART signal. I have also added an interrupt pin onto the DATA_OUT of the MAX1473. This interrupt will tell the feather-board if there is incoming data. If there is data being received, the device will remain on. If there is no data to read, the device returns to a sleep mode. The PDO pin on the schematic refers to the Peak Detector output, as talked about in the "Squelch Circuitry" section above. This helps eliminate unwanted noise.
The transmission process can be setup multiple ways depending on the application. The main variable is looking at the accessibility to a reliable power source. If the project will be staying in your home or office, battery life is not as important because the transmitter and receiver can be plugged into outlets. If both transmitter and receiver are going to be battery powered, we need to make sure we have an efficient process for sending and receiving data. The two most common cases are described below.
Remote Transmitter and Powered Receiver
One common typology is having remote sensors feeding data into a powered receiver (In this context, "remote" simply means battery powered). This will be the typology used when the receiver circuit is plugged into a reliable source, such as a wall outlet.
In this situation, the transmission process is fairly straightforward. The receiver sits idle, waiting for data from the transmitters. As soon as the data is detected and read, it can be stored, processed, or passed onto another device (display, serial port, etc.).
The battery powered transmitters should only be in the active mode when they are prepared to send data. That means that if the temperature sensor will send data once every 15 minutes, then the transmitter should be active only while the system collects and sends the data. During the 15 minutes between transmissions, there is no work to be done, so the entire system should be in the lowest power mode.
Remote Transmitter and Remote Receiver
This will be the setup if you have remote sensors taking data and feeding into a remote receiver. This typology could be useful if you are working on an outdoor project, like a greenhouse or garden. You will not always have easy access to a powered outlet, so batteries are necessary to power the system.
This situation requires you to enable low power functions for both transmitter and receiver. Instead of having the receiver in the active mode, it will employ a quick-check feature. This feature will allow the reciever to turn on for a few miliseconds in order to check for data. If data is present, the reciever records a packet (about 50ms) before returning to sleep. If there is not packet, it immediatley returns to sleep. A few sample packets can be seen below:
PacketStructure
The structure of the packet is rather simple, as the amount of data be transferred during a transmission is rather small. If this were a live feed of data (like a camera), the packet structure would need modification. Since we are only sending 2 bytes of temperature data, we do not need an incredibly complex packet. There were a few features I wanted to make sure to add:
1) Starting Character - Just like GND in a circuit, we need to have some reference to the beginning of the packet
2)TransmitterID - Adding a simple 8 bit ID will allow us to use multiple sensors of the same type. It will also tell us where the data is coming from if we have multiple transmitters.
3)Device Type - This character tells the receiver what type of data is being received from the transmitter. Each transmitter may have multiple sensors, so it needs to identify what form of data is being sent (e.g 'T' for temperature sensor, 'M' for moisture sensor, etc.).
4) Data - Pretty self-explanatory... Why construct a data packet if you don't add the data?
5) End Character (Optional) - If the packet size is standard across a certain device (e.g MAX30208 Temperature Sensor always has 2 bytes of temperature data) this end character may not be required. If you have multiple types of temperature sensors being used, it may make sense to add this character.
As mentioned in the previous section, the device ID allows us to have multiple sensors actively sending data. When a transmitter sends its data, it also sends the transmitter ID, which gives the receiver information about which transmitter sent the data. You can see a sample exchange with two transmitters and one receiver below.
In the above logic analyzer sample, you can see two separate transmitters sending data, which is then received and translated to the data out pin of the receiver. Then, in the serial monitor window, you can see the microcontroller unpacking those data packets and displaying useful packet information. As shown, you see two distinct transmitter IDs ('1' and '5') as well as 2 different sensor types ('T' and 'B'). These features can be expanded to almost any application space, as it leaves room for multiple sensor types, multiple ID numbering schemes, and so on.
Data EncryptionAs with any wireless system, data security is a major concern. It is impossible to transmit data wirelessly without giving an outside party the opportunity to listen in on the transmission. While temperature data may not be a major concern for outside attacks, it is still good practice to add some level of security to the system.
For this project I implemented a simple private key cipher. The transmitter and receiver are programmed with the same shared key. Just before the transmitter is ready to send a message, it will exclusive-or (XOR) the data with the private key. A useful attribute of the XOR is that when a value is XOR'd twice by the same key, the original value will be returned. This allows us to XOR with a private key, send the data, and then XOR with the same private key to retrieve our data. If an attacker does listen in on the transmission, the message will appear to be gibberish, and unless they have access to the private key, they will not be able to read the data. If you still want more security, you could add a unique key to each transmitter, or even each sensor on a transmitter. There are also more complex mathematical encryptions that could be applied, but this should be sufficient for low-priority data.
A sample encryption and decryption are shown below. The encryption image shows how the same input could be encrypted multiple times and still have different outputs. It also shows how two separate keys give unique outputs. On the receiver end, you can see that the data is read as gibberish, but it still decrpyts back to the original values.
After code was written for both remote transmitter with remote receiver, as well as for remote transmitter with powered receiver, power tests were conducted. These tests were designed to measure the current consumption of each component individually. I decided to use the MAX9922 current sense amplifier (CSA) for this part of the project. When working with features like deep sleep and shutdown, the measured current can be incredibly low (along the order of nA). This requires an extremely precise ammeter, or it can be measured as voltage across CSA.
Another factor to consider when using these values for your own projects, is to realize that the transmitter consumes more current when sending a '1'. The data sheet has measurements of typical 1.7 mA for a '0' and 9.6 mA for a '1'. The measurements in the table below represent the average of multiple temperature data readings being sent. If your application has a significant bias towards 0's or 1's in data, you may want to remeasure the consumption here in order to record accurate average current consumption, as it could vary by almost 4 mA up or down.
Compiled Results can be found in the tables below:
*These results cover the MAX32630FTHR board and the MAX1472 or MAX1473. The MAX30208 is not included in the results, as the sensors used in this project can vary drastically.
Possible ApplicationsThere is a wide range of possible applications for these RF transmission pairs. With such a simple design, the MAX1472 can send almost any data type. Some general application areas I think would work great with RF communications could be:
1)Remote Sensor Applications - If you need to periodically check sensor data from an area that may not have easily accessible power (e.g greenhouse, open field, etc.) this is a great system to implement. These applications offer open spaces, which can improve reliability of the transmission, as well as prolonging battery life, because the data does not need to be constantly monitored.
2) In-Home Automation - This transmitter could be used as a push-button activated remote. The battery life would be great, because it would only transmit during button presses. It would also prevent extra wires being run throughout your home, which can easily be disconnected, inconvenient, or unaesthetic.
3) OutdoorSecurity System - One note about this application is that the RF signal does not do great around walls or within buildings. It is really meant for open spaces, so this will have to be an outdoor alarm system. I had a disconnected garage door monitor, or shed monitor in mind. This could wirelessly alert you if your garage or shed door was opened.
These are obviously just a few examples, as you could make any project wireless with these parts.
Future Work and ImprovementsWhile this structure can be readily implemented into any existing sensor system, there is still some work to be done of the project.
1) Implementing Data Encryption - Although this project does not use any data or information that needs to be securely encrypted, it is still a good idea to add in some encryption scheme. You never know who might be listening to that radio frequency, so it is always good practice to add in encryption.
2) Implementing Handshake Protocol - At the moment, this is a standalone transmitter and receiver. A handshake protocol could be established by having a transmitter AND receiver on both ends. This could lower the power requirements, as the receiver could send an acknowledge message once the packet is received. It could also add in features such as requesting packets, or asking for re-transmission of missed/corrupted packets. Finally, it could also help add to the encryption protocol, and you could even look at adding in some type of secret/public key encryption, or possibly even a physically uncloneable function (PUF) type encryption scheme.
3) Adding Support for Data Viewing - At this point, the data is received by the feather-board, but it does not have any usefulness afterwards. There should be some time spent developing a program to display the recorded data in a way useful to the user. This may be more applications focused, but there should be some effort put towards this.
Comments