DIY RC System.‎ > ‎

RC System Firmware.

This is an overview of the Transmitter and Receiver firmware for my DIY Radio Control system.
To make use of this page you will need some understanding of electronics, microcontroller programming and radio control model components.

The firmware on the RC system is an ongoing project.
What is presented here is Version 2. This has all of the functionality of a conventional RC system plus the ability to receive data from the aircraft.
This version of the firmware run on all published previous versions of the hardware.

The ground station will be referred to as the "Transmitter" and the aircraft mounted board which will be referred to as the "Receiver".
As this is a 2 way radio system the terms "Transmitter" and "Receiver" are not 100% correct as both stations can transmit and receive a signal. It does however match conventional RC terminology though and from the users perspective the name fits.

Programing Environment.

The code here was written for the AVR GCC compiler. I am going to presume anyone reading this is familiar with programming AVRs under GCC.
In this version of the firmware i rewrote everything to make use of the excellent WebbotLib library.
WebbotLib has AVR code for many different hardware peripherals as well as providing a framework for timing and other aspects of program control.

WebbotLib has a bit of a different approach to programming AVRs than normal but here is a 3 line introduction:
  1. Note that there is no main() function in the user code. This has been replaced by the appInitHardware() and appInitSoftware() which run at power on and appControl() which runs as the main program loop.
  2. Unlike conventional libraries, WebbotLib's various components needs the underlying WebbotLib framework to work. You can't just copy the bits you want into your existing project.
  3. The easiest way to use WebbotLib is to link to the pre-compiled version that matches your processor. This project will build by linking to the pre-built libWebbot-ATMega2561.a object.
So when you first look at my code, start with the contents of the appControl() function.

WebbotLib has been used to do much of the hard work in this project. It manages program timing as well as driving the various hardware components, eg, servos, PS2 controller, UARTs, etc.
There are 2 areas where i did not rely on WebbotLib though.
  1.  At the time of writing WebbotLib does not interface with INT pins. (It has support for PCINT pins though.) The RF modules in this project use INT pin interrupts at the Receiver end to deal with incoming transmissions. As a result i have resorted to writing my own ISR to deal with this. ISR(INT7_vect)
  2. This project makes heavy use of the hardware SPI bus to communicate with the CYRF6936 RF modules.
    It is possible to use either WebbotLib or this project's native code for SPI communications. The line #define USE_WEBBOTLIB_SPI can be commented out to disable WebbotLib (and so use the native SPI).
    WebbotLib's SPI code has been developed to be extendable and robust but this comes at the price of speed. This project's native SPI code allows RF transmissions to be executed around 30% quicker than WebbotLibs.
    If you have no plans to add other devices to your SPI but i advise you to use this project's native SPI code as it allows time for a 3rd re-transmission of any failed packets. If on the other hand you want to add other devices to the SPI bus and don't plan to operate at the limit of the CYRF6936 range then use the WebbotLib code. (Look at the WebbotLib documentation to see what other SPI devices are supported.)


The firmware operates on a 20ms loop to match the servos update time. This loop is controlled is controlled on the Transmitter node and implemented using the inbuilt scheduling of WebbotLib's main appControl() function. Once every 20ms the Transmitter sends a RF data frame and then waits for a reply data frame from the Receiver.
The Receiver doesn't need to keep such precise control of timing as that is done on the Transmitter.
The RF module's IRQ pin is connected to an AVR I/O pin which triggers a hardware interrupt when an incoming data frame is detected. This way the main loop on the Receiver can be free running with all receiving and reply transmitting done during the ISR (Interrupt Service Routine). This allows the Receiver to reply to the Transmitter with very low latency.
When the Receiver detects an incoming data frame it replies to the Transmitter with it's own data frame.

The main program loop goes like this:
  1. Every 20ms execute this loop.
  2. Transmitter reads data from controller. (PS2 controller or connected PC.)
  3. Transmitter sends a data frame to the Receiver.
  4. The Transmitter waits for the reply to it's transmission.
  5. The Receiver's ISR is triggered by the incoming data frame so it pauses it's program to deal with the incoming data frame.
  6. The Receiver validates the incoming data frame and if it is valid replies to the Transmitter with it's own data frame.
  7. The Transmitter receives the reply data frame. (If for what ever reason a reply frame is not received within a giver timeout interval, return to step 3 providing 20ms time frame has not been exceeded.)
  8. The Transmitter executes any non critical tasks (including transmitting and receiving non critical data frames.)
  9. Transmitter exits WebbotLib's main appControl() function. (Return to 1.)

The one tricky part in this is the Transmitter knowing how long to wait for a reply packet before it should time out and retry the transmission.
This value is set by #define REPLY_TIME value in the Transmitter code. The exact value should be determined by trial and error and varies depending on which SPI code is used. (WebbotLib or native SPI.) Values between 2500us and 3500us are typical but go larger (~5000us+) while debugging.

RF Transmission.

RF Module.

The radio Unigen UGWJ4US modules used in this project have already been discussed in the RC System Hardware section. As they are based on the Cypress CYRF6936 chipset the firmware described here should work on any CYRF6936 based module with a little modification.

It is worth mentioning the Unigen UGWJ4US datasheet is basically just a copy of the Cypress CYRF6936 datasheet. Read this datasheet all the way through thoroughly before you start.
It is also worth noting that the Unigen datasheet does not contain all the information you need to make the module work.
On the Unigen UGWJ4US to have the module correctly controll the TX amplifier the CYRF6936 register 0x0C (XTAL_CTRL), Bits 7,6 should be set "01 = Active LOW PA Control" for correct operation.

Little other online information is available for working with the Unigen modules so be prepaired for lots of difficult debugging and when all else fails a bit of trial and error. (Please send links to other CYRF6936 resources if you have them.)

The Artaflex modules ( require the AVR to control the TX and RX amplifier using thePACTLn and PACTL pins. If you are using these modules instead the firmware would need some minor modifications.
This is at least documented in the Artaflex data sheets though which (unlike the Unigen data sheets) are adequate.

The Artaflex modules have changed to using the CYRF7936 chip.
While the CYRF7936 should be similar to the CYRF6936 i can't say for sure if my code will work with it or not.
At the time of writing there does not appear to be a full datasheet available for the CYRF7936 that documents the configuration registers.

Transmission Mode.

The CYRF6936 has several different transmission modes. In this version of the firmware the controller will use 8DR mode data packets (discussed in the datasheet). This mode allows 250 kbps data transfer with a 16bit CRC (Cyclic Redundancy Check) making false packet detection very unlikely and allowing multiple systems to be used on the same channel. It is also the fastest mode the chipset supports with DSSS spreading/despreading, giving excellent immunity to interference and will theoretically allow many (hundreds?) of these systems to operate within range of each other providing unique Pseudo Noise (PN) codes are chosen for each system.

At face value the simplest method of using the CYRF6936 would be to make use of ATS (Automatic Transaction Sequencer) mode which automatically handles acknowledge packets and retransmissions.
Unfortunately ATS mode does not play very well with the power amplifiers all these modules need to get the desired range. ATS mode does not work with the Artaflex modules and would require a lot of messing with timing registers to work with the Unigen UGWJ4US module (if it would work at all). Note that it would work with the low power UGWG4US if you only needed limited range.

For us though it is better not to use ATS mode in this application even if it was possible as it is better to send a data frame as an acknowledge packet. ATS mode just replies with an empty packet but we want to reply with useful data.

Packet Format.

The CYRF6936 only has a packet buffer of 16bytes. It is possible to send packets longer than this but the TX buffer must be loaded as a transmission occurs and the RX buffer must be emptied as a receive occurs greatly increasing the complexity of the receive code.
For this reason the maximum size of any packet will be 16 bytes. At this length no special attention need be taken to timing when a packet comes in. The microcontroller can just read the RX buffer any time after the packet arrives.

There is an array defined on both the Transmitter and the Receiver called data[]. The packet sent by the Transmitter and it's reply from the Receiver are used to synchronise the data[] array on both Transmitter and Receiver.
The Transmitter decides which segment of data[] to send and which segment to request from the Receiver. Packets arriving at either end update the relevant section of the data[] array with data from the other end.

The segment of data[] used to control the RC vehicle gets transmitted every 20ms but other segments of data[] are optional. By default 2 14byte packets are sent every frame but this could easily be modified so far larger data structures were syncronised over a longer time interval. (For a RC system the 1st packet should always contain control data but subsequent packets could be for any address in the data[] structure.)

Transmitters Packet:
 Byte Name Description
 0 Data address
 Address of this data (in data[]).
 1 Requested data address
 Request Receiver sends this data (from data[]) in reply packet.
  tx_chan[0] First data byte.
 3  tx_chan[1] Second data byte.
 4  tx_chan[2] Third data byte.
 5  tx_chan[3] etc...
 6  tx_chan[4] 
 7  tx_chan[5] 
 8  tx_chan[6] 
 9  tx_chan[7] 
 10  tx_chan[8] 
 11  tx_chan[9] 
 12  tx_chan[0x0A]
 13  tx_chan[0x0B] 
 15  tx_chan[0x0D] 14th data byte.

Receivers Packet (sent as reply to Transmitters packet):
 Byte Name Description
 0 Data address
 Address of this data (in data[]).
 1 Unused
  tx_chan[0] First data byte.
 3  tx_chan[1] Second data byte.
 4  tx_chan[2] Third data byte.
 5  tx_chan[3] etc...
 6  tx_chan[4] 
 7  tx_chan[5] 
 8  tx_chan[6] 
 9  tx_chan[7] 
 10  tx_chan[8] 
 11  tx_chan[9] 
 12  tx_chan[0x0A]
 13  tx_chan[0x0B] 
 15  tx_chan[0x0D] 14th data byte.

Error Checking.

One of the advantages of using a chip like the CYRF6936 is it already has 16bit CRC checks built in so any received packet without an error flag is presumed good. It is theoretically possible to get an errored packet pass the checks but this will happen for a tiny percentage of packets so can be ignored as it will have little effect on performance.

Dual RF Modules on Receiver.

By the nature of 2.4GHz RF communications occasionally the signal will be blocked by parts of the RC vehicle or various reflections cause multi path interference.
Dual RF modules on the receiver greatly improve reliability at medium and long range.

Version 2.2 of the firmware works with either one or two modules connected to the receiver with no software configuration changes required.

The RF modules on the receiver trigger an interrupt on the microcontroller when an incoming packet arrives. When dual RF modules are used very occasionally this causes a race condition on the microcontroller which leads to the microcontroller firmware locking. To deal with this the watchdog timer on the receiver microcontroller must be enabled when dual modules are used.

These firmware lockups will cause brief (< 100ms) jitters in the RX servo output. The exact timing of these lockups are by their nature difficult to predict but once every 30 minutes might be average.

User Interface.

PS2 Controller.

For this prototype a Sony PS2 controller is being used as an input device. While it may not be to everybody's taste it does provide a nice ergonomic easy to interface way to input data at the Controller end.
After a bit of heckling from me, PS2 controllers are now supported under WebbotLib (thanks Webbot!) so refer to the documentation there for more info.

Other UI Options.

With 6 spare analogue inputs on the AVR it would be trivial to add more conventional joystick controllers.
Many conventional RC Controllers have trainer ports. It may be possible to provide input from one of these as well. (Suggestions on the viability of this option welcome.)
I will also be adding USB input so the device can be controlled by a PC or laptop, including any connected USB joystick.


Controller Mixing.

Conventional RC systems control the mixing of control channels on the Controller. The servo positions then transmitted and acted on by the Receiver.
This firmware version does not yet allow for this. The controller's joystick and button positions are transmitted "at is" and the mixing is done at the Receiver end.
Future versions of the firmware will allow for mixing of channels at the Controller end as well as at the Receiver end allowing for more complicated input device combinations without adversely affecting latency.

Receiver Mixing.

At present all mixing is done on the Receiver. Control positions are received over the RF link and hard coded rules in the Receiver's firmware work out servo position.
Settings can be saved to EEPROM according to button presses and included in the mixing rules.
Sensors attached to analogue inputs and the i2c bus can be read and included in the mixing rules but this will require some programming at present.

Future versions of the firmware will allow mixing rules to be uploaded from a PC without having to modify the firmware.

With such complex mixing options possible at the receiver end full UAV operation should be possible eventually.


This code is written for the AVR atMega2561, needs to be linked with WebbotLib and will compile under AVR GCC.

Please note, i am not a professional programmer.
The code also has not yet been tidied up and properly commented. I'm only posting it here because i have been asked for it.
This an OpenSource project so if any one is willing to collaborate on this code please contact me.

The current version of the firmware can be found on the Downloads page.
Everything (Transmitter and Receiver firmware as well as PCB files) can be found in the file "".

Cravats and Future development.

At present there is nothing in this code to change the channel or CRC checksum of the RF modules.
Anyone who needs to operate more than one pair of this system within a few kilometers of each other will need to hard code either different RF channel numbers of different CRC checksums into the code.
Happily this is fairly straight forward and can be worked out from the CYRF6936 datasheet.
Unique pairing of Transmitter and Receivers will be included in a future revision of the firmware.

As already mentioned, there are rare firmware lockups when using dual RF modules on the receiver. Future revisions of the firmware should either solve this completely or at least minimise the reset time.

Future firmware versions will add additional input devices as well as improved ways to log data on an (optional) attached PC.

Future firmware versions will also include my (currently experimental) code for mixing onboard sensor data with flight control data, creating a fully functional autopilot.

Thanks for the Code Guys!

This project could not have been made without numerous open source projects involved in the AVR_GNU and AVR_LIBC projects.
Of particular help in the early days were the numerous helpful PS2 hacking pages online, some of which i link to on
More recent versions od this code use the WebbotLib library for much of the AVR hardware interfacing (including the PS2 controller).
Also a lot of help on RC aircraft in general were the archives of
And of continuous inspiration in all things automation related:
Thanks Guys!

About the License.

My work, as i have already covered in the previous section, is based partly on the work of others.
Any changes i have made or code i have written are licensed under the GNU General Public License (GPL). The others work, are licensed under the GNU General Public License (GPL).

A copy of the GPL is included in License.txt.

<<  RC System Hardware.                            Sensors and Autopilot.  >>

Duncan Law,
20 Dec 2008, 10:13