Pages

Showing posts with label Send data using RLE and Cheap RF Modules. Show all posts
Showing posts with label Send data using RLE and Cheap RF Modules. Show all posts

Saturday, 20 April 2024

Throw out those Cheap Chinese RF Modules

I previously discussed how the receiver can benefit from better hardware. As part of my shed door monitor project I replaced the SAW based transmitter and prebuilt receiver modules with something I built up around IC's designed for this purpose. The difference was outstanding.

Previously I had measured the reliable line of sight range at 35m. I am now getting over twice that range with the receiver sitting in the car near the gear shift lever. That's a dramatic improvement and if the unit is sitting on the dashboard it works intermittently out to over 120m. We're not talking LORA ranges. But we are getting a meaningful coverage with simple very low cost hardware that lends itself to a host of projects.

As a result I'll no longer be tagging these blogs with "Cheap RF Modules". You are simply far better off by avoiding SAW based transmitters and pre-built receivers with unknown IC's.

Saturday, 23 March 2024

Serial Data Transmission with RF - Improvements

The "pipe-lining" fix in the transmitter was still bugging me.

Fortunately I came up with a solution. With the CPU clock slowed down to 62.5kHz, half what I had been required to use, and NOP instructions in both _TXOn and _TXOff, I achieved the jitter free waveform I was after.

I assume that with enough NOP instructions the pipeline was being forced to reload more often and the jitter caused by random reloading was gone. 

In my first application, a shed door monitor, I expect a single D cell will last over 4 years. The maths suggest 11 years but can an alkaline battery last that long without leaking and self discharge reducing the life?

Briefly,

: _TXon  [ 1 PC_ODR _TxEn ]B!  ;
: _TXoff  [ 0 PC_ODR _TxEn ]B! NOP NOP NOP NOP NOP NOP ; \ 8 bytes 

was changed to

: _TXon  [ 1 PC_ODR _TxEn ]B! NOP NOP NOP NOP ;
: _TXoff  [ 0 PC_ODR _TxEn ]B! NOP NOP NOP NOP ; 

I then used the ]M! command to build up the assembly bytes for a complete On and Off packet without any calls.

Sunday, 18 February 2024

Serial Data Transmission with RF - Improved Hardware and Range Testing

A better receiver is justified. 

The build quality of these super regenerative receivers, like most of the Aliexcrement or Crapbay stuff from China, is woeful and I have little confidence will work on an extended basis. I had two receivers. After getting them working due to manufacturing faults one stopped working again very quickly. The second unit works but appears to suffer from dry joints because the performance is inconsistent.

During development I discovered that the receiving module is a super-regenerative type. I was able to confirm, as expected, that it generates noise on 433.2MHz which prevents multiple receivers from being located close together. But the biggest concern I have is temperature stability. While it doesn't matter so much when located in-side a house, it does have implications for being located outside. As ambient temperatures change, say from 0 Celsius to 35 Celsius, the frequency to which the receiver is tuned will shift. That will reduce the sensitivity since the transmitter is in comparison stable. So not only do receivers need to be physically spaced apart they also need to be in a relatively stable temperature. 

Search for 433MHz receiving modules on your favourite site and there will be plenty to chose from. Get one with a crystal like this one and you should be far better off for the few extra cents.

 


However, not all modules work. The one pictured above was purchased from LCSC. A mediocre datasheet did not help get it working. A typical decoded data stream is shown below:



I gave up trying to work out why these didn't work when the second one I pulled from the packet had an aerial that was swinging in the breeze.  My suspicion is the data rate was too fast for the receiver chip.

I trawled my junkbox and found another receiver module. The MPN was RX520. Like the module discussed above, the output also tended to idle in a high state. So I altered my code slightly to account for this.

Then, in a real twist, I discovered that the for this second superheterodyne module the first pulse following the start pulse is slightly longer than you would expect. Perhaps an artifact of AGC action since logging strong pulses and weaker pulses showed a clear difference. This is not an ideal situation. However, adjusting the 1/0 threshold allowed range testing to begin.

A preliminary range test was made. The transmitter used a vertical antenna, but no ground plane, and was located on the ground. The receiver used a 13cm piece of wire. Neither was ideal. But this combination would work reliably at 35m line of sight when no interference was present. The interference was evidenced by the flashing led cycling on and off correctly for up to 4 seconds, then it would "freeze" for a random length of time before working again. 

On balance I'm satisfied with the result. I have a list of further potential enhancements which might improve the robustness of a link. My first real application may not require them so I'll push on with that application.



Sunday, 11 February 2024

Serial Data Transmission with RF - Range Testing


To recap, I now have a receiver with very little noise on the data out pin between actual packets. I have a transmitter alternatively sending two characters 500ms apart. And I modified the receiver board to toggle a LED depending on which character was received.

My thinking was that I could walk away from the transmitter and watch for the LED to start blinking erratically or cease blinking at all. Then I could make some changes and see if the range got better or worse.

I had done something similar with nRF24L01 modules some years ago and that had convinced me 2.4GHz wasn't suitable because in real life the range was too short to be useful.

My initial test showed a range of only 11m across the workshop. The decoding was reliable right up to the doorway. The following day I put the TX unit on the ground near the door and the RX unit back on the bench to look at the data stream. Rock solid. So I iteratively moved the transmitter out of the workshop. At the property boundary it was now, according to Google Maps, 27m from the receiver and down a decline. But still in a direct line through the doorway.

The blinking was steady indicating no errors. 

 

What is noticeable is that as the signal strength drops with increasing range the pulses get narrower. 

The edge of range was when the transmitter was about 32m from the receiver and now screened by the workshop wall. At this point the light began blinking erratically. Looking at the received data stream it was obvious why this was. 


The pulses were getting so narrow that either the start pulse is outside the allowed range weak or, as seen from the second last pulse above only just hitting 2V, the pulses are not hitting a logic high level.

A quick check: Assume Vcc=3.7V. Logic high for the micro is say 70% of Vcc or 2.59V. The LM358 can swing to perhaps 1.2V of Vcc, or 2.5V. So logic high is not being met. 

At 5v the problem goes away. 

Three possible fixes: 

  1. Replace the LM358 with a R2R output opamp.
  2. Add a pull-up resistor to the data line.
  3. Use two LiPo batteries and the onboard regulator.

The third option is expedient for range testing purposes but adding a pull up resistor is no harder and maybe relevant to a battery powered receiver.

I added a 10k resistor from the data line to Vcc and the high logic level is now being met. I didn't persist with this because the following day when I went to do the range testing the noise was again present. Given the hardware issues with this receiver model I decided to suspend work since I now have a better receiver board.

 

 

Footnote for those landing here via Google Search:

My suspicion is that a lot of people trying to get these receivers to work on a LiPo battery had issues with this. This problem is exacerbated when both the ATMega and Rx unit are running at 3.3V. So if you landed here trying to work out why your Arduino project isn't working now you have a hardware issue to consider.






Sunday, 4 February 2024

Serial Data Transmission with RF - Receiving Notes Part 3

In preparation for range testing I made a leap of faith and decided to improve the speed of the receiver code with still more assembly code. I felt the code was fast enough. However, but I wanted to be sure that if I sent two packets with a short gap, say 2ms, that the receiver would be ready 2ms after the previous packet finished

It was a relatively smooth exercise. That's testament to how the design choices in STM8 eForth set it apart. And the power of Forth itself. Interactively testing at the console is so far in front of a "compile upload debug" model many languages require.

So after fetching 9 pulse lengths (PL) I did a thumb suck on how long it would take:

9 PL x 10 clock cycles to process each PL = 270 clock cycles.

Say 20 clock cycles to use the byte received

Clock speed of 16MHz means 290 clock cycles equates to ~18uS

So even if the next byte starts 50uS after one finishes then the micro should be ready. Now I'm comfortable that I can send multiple bytes with a short delay and missed packets are the result of being out of range.

 

Lesson learned - the preamble should never be a start pulse.

I had a hunch, given the strange stuff going on today, that the soldering of the receiver to the base board needed touching up. That seemed to transform the receiver and now there was no noise between bytes on the data pin.  I thought that was a real win. 

While the noise returned, which really annoys me, it turned out to be masking another issue. As it turn out, grabbing the 9th pulse when there was no noise meant the preamble from the following packet was grabbed. So the time it took to  process the 9 pulses, while short, meant that the measured pulse length for the next start byte was just outside the window I had allowed. So that byte was skipped altogether.

It took me some time to work this out. The grabbing of 9 pulses was a relic of when a packet commenced with 2 start pulses. Far better, in my opinion, to simplify the processing of received pulses to only have one START pulse. That way you don't have to deal with the possibility of an extra start pulse.  So far better that the preamble is nothing like a start pulse.

Sunday, 21 January 2024

Serial Data Transmission with RF - Receiving Notes Part 1

 

What follows is some preliminary detail on how I receive the data stream.

The STM8 chips have multiple timers. The simplest timer is 8 bits which is sufficient and was unused by STM8 eForth. I ended up using a lot of assembly code in STM8 eForth to measure the pulse timing. 

Update - with the benefit of hindsight now that it is working I didn't need to use as much assembly code as I used.

I clocked the 8 bit TIMER4 at 250kHz to avoid overflowing when a start pulse was received.

 In pseudo code then a word like: 

: PULSE@ ( -- ) \ measure the time from now till falling edge of pulse
         Turn on the timer      
         Wait for falling edge
         Turn off timer
;

 actually becomes when you can only test for logic levels:

: PULSE@ ( -- ) \ measure the time from now till falling edge of pulse

   TimOn \ turn on the timer
   [ $7200 _RX 2* + 1+ , PD_IDR , $FB C, ] \ wait till _rx is high
   [ $7200 _RX 2* +   , PD_IDR , $FB C, ] \ wait till _rx is LOW
   TimOff \ turn off the timer

This worked really well and could easily handle higher data rates.

However, I later worked out how to  copy the assembly code from a compiled word into a new word avoiding the need for CALLS and RETURNS. This gave me a smoother coding experience and avoided  repeating the assembly code whenever I wanted to incorporate it in a high level word. A bit like a macro in AVR assembler but the destination for the macro is a high level word.

: Pulse@ \ ( -- )  time, now to falling edge
   [ ' TimOn ]M! \ Turn on TIM4
   [ ' _RX=1 ]M! \ wait till _rx is high
   [ ' _RX=0 ]M! \ wait till _rx is LOW
   [ ' TimOff ]M! \ Turn off TIM4
;

While it is not obvious Pulse@ is now just pure assembly with no call's or return instructions. If I decide to use a different timer I only have to change the definition of TimOn and TimOff in one place. Later when I post the full code it will hopefully be clearer.

At this point the code now easily meets any time constraints.  But a better receiver, still to be tested, might allow much faster data transmission so I'm leaving the assembly code in place because I might want to push the data rate still faster one day.

And while all of this only takes a few clock cycles, the longest pulse length we want to measure is a start pulse of around 640uS. If all we were doing was measuring one pulse it would be simpler. But I planned to measure up to 10 pules in succession. My plan is to do some error checking takes after the pulses following a start pulse have been received. 

 




Sunday, 14 January 2024

Serial Data Transmission with RF - Transmtting Notes Part 1

I was so easily deceived. All those byes flying around and not being decoded reliably. I spent a long time on the receiver and in frustration checked the transmitter data stream.

You could have heard a pin drop. 

When it was transmitting two good start pulses the data was being ruined by timing errors:


The shaded areas above show where the delay in changing state was recorded. There were also examples of start pulses being mistimed. 

There was no reason for the missing clock cycles. Op codes which were supposed to take 1 cycle were sometimes times taking longer. No interrupts were firing. After days of testing Thomas, author of STM eForth, and I think this is caused by the pipe-lining of execution instructions. The programming manuals makes an off hand reference to this by pointing out "In some cases, depending on the instruction sequence, the cycle taken could be more than that number." Add to that the fact that the pipeline fills differently for RAM compared to Flash.

Which could explain why, when sending a string of high/low instructions which should have produced a nice 50:50 duty cycle waveform I got the following when executing from RAM



And this when executing from flash.




Same code. I didn't zoom in as close on the flash version but you should see that when the code was executed in RAM every second pulse lost a time unit during the low period, but when executed from flash the lost time unit occurred during every second high period.  

This was eventually traced to the way the pipeline fetches code. Fixed by changing the code so that the pipeline was always reloading. Consistent outcome but slower. Required an 8fold increase in the CPU clock to 125kHz to compensate for this.


Sunday, 7 January 2024

Serial Data Transmission with RF - Overview

What follows is some background information to sending data via RF. I will fully expand on this in coming weeks.  This is working across the workbench but I have yet to explore the range that can be achieved.

I stumbled across Roman Black's article on using cheap RF modules for transmitting data. While the world has come a long way in the 10 years since Roman wrote about his findings those modules, and more modern ones at similar modest cost, are widely available. 

The concept had my hooked immediately.

  • It uses RF
  • It was really well written and comprehensive
  • Seemed like an ideal project that will enable other projects.
  • I get a thrill out of using STM8 eForth. You should try it too.

My broad goal was a burst transmission of one to three bytes of data with long off periods. This required some maths to understand the tradeoff between battery life, data speed and preamble length. At present I am using a "pedestrian" data rate, (uS shown is measured):

  • Start pulse is 3 units low, 2 units high. (560uS)
  • Zero is one unit low, one unit high,and (298uS)
  • One is two units low, one unit high       (410uS)

Each byte takes about 4ms to send and for testing I spaced them 500ms apart. In practice I expect I will send a packet of 1-3 bytes, repeated several times before going into a long sleep.

With some modules on the workbench and my digital scope set up it was no time before I had a transmitter sending  $AA or $55 for testing purposes.

Then the heartache started. One of my two receiver's didn't work. That was traced down to a through hole via not being connected. 

But with all the hardware working it was time to finesse the software. While it took me ages to work this out it was all down to hardware and software timing. And some weird seemingly random timing errors in the transmitter which took a really long time to track down. 

I will try to explain in coming articles, perhaps once per week, how I moved from concept to finished RF link, or indeed if I couldn't get it to work. This will definitely not be some superficial clap trap telling you to wire this pin to this, load this library and your done series of posts. I'll be sharing what I learned and hopefully inspire you to improve my code and hardware choices.

Plenty to talk about next time.

Conclusion

I wish more projects were written up to the standard of Roman Black's article. I gave up looking at other articles on these modules because it was clear they were factually wrong. From the solid foundation Roman's article gave me I expect I can send bursts of data with long battery life for the transmitter.

This now enables me to pursue some projects I had never progressed beyond being a possibility. Monitoring my workshop door will be the first real application. I can't see it from anywhere in the house meaning I have to walk up there to confirm I have locked it.

The github for this project will be open soon.