Electrical – Using cheap RF module encoding with UART in a commercial product

433mhzencodingRFuart

For my graduation project, I need to design a system that transmits several different data packets to the computer wirelessly. It needs to have a potential to be commercial product, so both functional and inexpensive. It doesn't have to be bi-directional.

I found cheap modules RFM110W and RFM210W, transmitter and receiver, respectively. Since I am trying to write whole firmware in AVR Assembly, to make it fast and easy (to not write encoding part of code), I ended up like this: image

Edit: (in the picture, it is not 443 Mhz it is 433 Mhz)

With a little bit data handling, It works well at 1200 baudrate and data can be easily captured on serial monitor.

Because the UART is not for encoding RF signals, using it for encoding data seems like a little bit tricky. And I have concerns about using it in potentially commercial product.

Is it reliable for simple data transmission in the aspect of engineering?

If it's not, what are the potential problems I should be expecting to face with?

Edit:

FT232 USB to UART bridge datasheet

RFM110W Transmitter Module

RFM210W Receiver Module

Example romanblack.com

Best Answer

There's so far been zero information about your actual µC (microcontroller). So I'll just assume it's a super computer. If it's not then you're the one who gets to change the information so it matches.

Because the UART is not for encoding RF signals, using it for encoding data seems like a little bit tricky. And I have concerns about using it in potentially commercial product.

Using UART is alright, not the best but it works. It's like walking, rather than taking the train, to work. If anyone wonders what the train would be then it would be, for an example, 16QAM, or some other modulation.

Is it reliable for simple data transmission in the aspect of engineering?

There's absolutely zero error detection and correction happening what so ever. If you receive the value \$43_{10}\$ then that's the value you think was sent. If any bit changes sign during transit, which means that you got an error on one bit. Then you can't say that it has happened. That's awful. If your channel would've been a wire then it wouldn't have been as awful because the noise isn't as severe as in wireless channels.


Allow me to introduce you to error detection and correction, here's an answer on another question that contains some information as well.

First thing first, some notations and equations that will make this answer more compact.

Error correction code format = \$[n,k,d]\$
\$\lfloor x \rfloor\$ = round down x, if x = 5.43 then x = 5

\$n = \$ length of entire message (block length)
\$k = \$ message you want to send (message length)
\$d = \$ hamming distance (minimum number of bits that differ between two blocks)

Number of errors you can detect = \$\lfloor d-1 \rfloor\$
Number of error you can correct = \$\lfloor \frac{d-1}{2} \rfloor\$

Example: Hamming Code(3) has [7,4,3]
This means that if you want to send the information \$0110_2\$ then instead you will send \$0110110_2\$.

1 bit error:
If the receiver gets \$\color{red}{1}110110\$ then the receiver can convert it back into \$0110\$
If the receiver gets \$01\color{red}{0}0110\$ then the receiver can convert it back into \$0110\$
If the receiver gets \$011011\color{red}{1}\$ then the receiver can convert it back into \$0110\$

2 bit errors:
If the receiver gets \$0\color{red}{00}0110\$ then the receiver should ask for the message again
If the receiver gets \$\color{red}{1}11\color{red}{1}110\$ then the receiver should ask for the message again

Everyone who knows about error correction code will now be happy because I named "Hamming Code". The most famous of them all. Amusingly that's not the one I will recommend for you.


Now I know that you want an answer that "gets everything sorted", so I will attempt to do that, but I want you to know that there are many things that I'm not covering.

I assume you will send bits of 8 at a time, the hamming code is not "nice" in the sense that you will only use 7 bits out of 8, losing a whole bit's worth of information. So instead I advice you to use punctured hadamard code.

It's parameters have the following properties: [\$2^{k},k+1,2^{k-1}\$], it's base 2! Great. So let's set n equal to 8, a whole byte, and see what the d and k becomes.

\$n = 2^{k} = 8 \rightarrow k = 3 \rightarrow d = 4\$, so the actual parameters we will be using are [8,4,4]. This means that we can detect 3 errors and correct 1 error. And we will also send twice the number of bits for every bit we actually want, so we will still send things in 1500 bps, but our actual data that we want to send and read will be going at 750 bps. But we will be able to detect some errors and correct one error. I call worth (you can increase the 750 bps by compressing the data first.. like zip files does. But that's an entirely other question).

Alright, so how are these codes made? by generator matrices which will be in modulus 2. So by sending data we multiply our 4 bit data with a generator matrix that will turn it into 8 bits. On the receiving end we multiply by a parity matrix that will give us all 0's if it's a perfect block. If there's any error then we will see some 1's somewhere. You might be wondering how you will have the time to multiply matrices on the fly, and my answer to that is that you use a LUT (Look Up Table).

So the parity matrix for punctured Hadamard code looks like the following for \$k = 3\$

$$ \begin{pmatrix} 1 & 0 & 0 & 0 \\ 1 & 0 & 0 & 1 \\ 1 & 0 & 1 & 0 \\ 1 & 0 & 1 & 1 \\ 1 & 1 & 0 & 0 \\ 1 & 1 & 0 & 1 \\ 1 & 1 & 1 & 0 \\ 1 & 1 & 1 & 1 \\ \end{pmatrix} $$

As you can see it's just the regular bits for counting 0 to 7 and an extra column filled with 1's.

And the generator matrix will be the parity matrix transposed (this is not normal for block codes), the Hadamard code is special in the way it's generator matrix and parity matrix are missing the identity matrix. So I'm not sure but I think Hadamard code is one of the few (or maybe the only one?) where the generator matrix = parity matrix transposed.

So here's the generator matrix for clarity:

$$ \begin{pmatrix} 1 & 1 & 1 & 1 & 1 & 1 & 1 & 1 \\ 0 & 0 & 0 & 0 & 1 & 1 & 1 & 1 \\ 0 & 0 & 1 & 1 & 0 & 0 & 1 & 1 \\ 0 & 1 & 0 & 1 & 0 & 1 & 0 & 1 \\ \end{pmatrix} $$

So let's simulate what you will actually be doing, this way you can read this answer several times and eventually it will hit home, I hope.

On wikipedia they use \$w = sG\$ where I assume w is the codeword, aka block, s is the message to be sent and G is the Generator matrix.

So say you want to transmit the bits \$0101_2\$, then you would simply perform this multiplication:

$$ \tiny{ \begin{pmatrix} 0 & 1 & 0 & 1 \\ \end{pmatrix} × \begin{pmatrix} 1 & 1 & 1 & 1 & 1 & 1 & 1 & 1 \\ 0 & 0 & 0 & 0 & 1 & 1 & 1 & 1 \\ 0 & 0 & 1 & 1 & 0 & 0 & 1 & 1 \\ 0 & 1 & 0 & 1 & 0 & 1 & 0 & 1 \\ \end{pmatrix} = \begin{pmatrix} 0 & 1 & 0 & 1 & 1 & 0 & 1 & 0 \\ \end{pmatrix} } $$

As you can see, it's an XOR operation, aka mod 2, so 1+1 = 0, 1+0 = 1 and 1×1 = 1, 1×0 = 0. Or, you could store it in a LUT, it's just 16 possible outputs, and they are all 8 bits wide.

Then on the receiving end you just perform the multiplication by the parity matrix. Or you use a LUT, which I advice you to do if you are using a µC. If you had an FPGA then you could just calculate it in parallel. The LUT would take up 256 bytes of ram, one index for every possible combination, and inside of the registers you would say what the bits actually meant, and those that have 1 error you would convert to the correct bits in the LUT, by hand.

You can either do that for all the bits, just use a LUT and be fine with that, or maybe you want to check first if there is anything wrong with the bits, and then use the LUT.

So let's change one bit of the transmitted message to represent an error on a bit, it doesn't matter if I change a 1 to 0 or a 0 to a 1, a change is a change in XOR-world.

So say we send this:

$$ \begin{pmatrix} 0 & 1 & 0 & 1 & 1 & 0 & 1 & 0 \\ \end{pmatrix} $$

and receive this:

$$ \begin{pmatrix} 0 & 1 & 0 & 1 & \color{red}{0} & 0 & 1 & 0 \\ \end{pmatrix} $$

Let's see what happens when we multiply it with the Parity Matrix.

$$ \tiny{ \begin{pmatrix} 0 & 1 & 0 & 1 & 0 & 0 & 1 & 0 \\ \end{pmatrix} × \begin{pmatrix} 1 & 0 & 0 & 0 \\ 1 & 0 & 0 & 1 \\ 1 & 0 & 1 & 0 \\ 1 & 0 & 1 & 1 \\ 1 & 1 & 0 & 0 \\ 1 & 1 & 0 & 1 \\ 1 & 1 & 1 & 0 \\ 1 & 1 & 1 & 1 \\ \end{pmatrix} = \begin{pmatrix} \color{red}{1} & \color{red}{1} & \color{green}{0} & \color{green}{0} \\ \end{pmatrix} } $$

Had there been no errors then it would've been \$\color{green}{0000}_2\$. But since there were some error we got some 1's. So if we would've received all 0's => those 4 bits are good, otherwise use LUT. Hmm, now when I'm thinking about it, if you are using a µC then you always want to use a LUT, calculating this multiplication with the parity matrix is way too expensive time-wise. But on an FPGA or some other hardware.. it would've been cheaper memory-wise and faster time-wise.

I think I should stop this answer here, it should get you sorted. If there's anything you're unsure about, write a comment and I will update this answer.