RF Data Link Using Si4021 And Si4311

Among the many commercial ISM band RF transmitter and receiver ICs, I have found that Silicon LabsSi4021 (transmitter IC) and Si4311 (receiver IC) are surprisingly easy to work with. Only a few commonly available external components are needed to build a fully functional circuit. The integrated automatic antenna tunning circuit in Si4021 makes building transmitters an easy task. The Si4311 receiver IC is highly integrated, more so than many other ISM band RF ICs, and is quite tolerate to the variance of the required few external capacitors. No special tuning is required.

To test their effectiveness, I built a transmitter and a receiver using the reference designs in the data sheets. The transmitter is controlled by an ATmega328p MCU and the receiver is linked to another ATmega328p.

Here is a picture of the transmitter:

Si4021 Transmitter

Si4021 Transmitter

Si4021 can be used in either EPROM mode or MCU mode. In this particular application, I am using the MCU mode and the transmitter is controlled by ATmega328p. The Si4021 transmitter chip is soldered onto a SSOP breakout board, which is shown on the left. I made a simple loop antenna using magnetic wire and the power is fed through the top middle section. If you are designing a PCB based antenna, I would recommend you read this antenna design guide provided by Silicon Labs. The transmitter circuit is powered with +5V supply.

The following shows a picture of the receiver:

Si4311 Receiver

Si4311 Receiver

And here is a closeup of the Si4311 portion. The QFN Si4311 chip is extremely small, you can see that in my prototype I used magnetic wire to connect the solder pads to the PCB pads. I have been using this soldering technique with QFN chips to build prototypes for a while and it has been working quite well. The jumpers to the right are for the frequency deviation range settings (DEV0 and DEV1) and bit time settings (BT0 and BT1). The performance of the receiver can be fine tuned using these jumpers depending on the bit rate used. When the communication range is low, all these pins can be grounded without affecting performance too much. You can refer to the datasheet for more details.

Si4311 Receiver Close Up

Si4311 Receiver Close Up

Since S4311’s maximum supply voltage is 3.6V, we cannot use the typical 5V power supply. So the Si4311 and the ATmega chip are powered using a 3.3V supply.

The receiver side of the code is fairly straight forward. Besides DEV0, DEV1, BT0 and BT1 pin settings (which are done in hardware), the receiver is totally configuration free. I used NewSoftSerial library in the code below. The main loop simply print out the incoming bit stream. You may also use Arduino’s built-in hardware serial library if you do not need the serial port for program uploading (e.g. using ICSP).

#define __AVR_ATmega328P__

#include <binary.h>
#include <HardwareSerial.h>
#include <pins_arduino.h>
#include <WConstants.h>
#include <wiring.h>
#include <wiring_private.h>
#include <WProgram.h>
#include <EEPROM/EEPROM.h>
#include <NewSoftSerial/NewSoftSerial.h>

const int PIN_RECV = 8;
const int PIN_TRAN = 7;

NewSoftSerial mySerial(PIN_RECV, PIN_TRAN);
byte b;

void setup() {
    pinMode(PIN_RECV, INPUT);
    pinMode(PIN_TRAN, OUTPUT);
    Serial.begin(9600);
    mySerial.begin(4800);
}

void loop() {
    while (mySerial.available() > 0) {
        b = mySerial.read();
        Serial.print(b);
    }
}

The transmitter side of the code is a bit more complex. As you can see in the code below, we first setup the transmitter using 433.92 Mhz frequency band, and then set the data transfer rate to 4800 bps. In the main loop, the transmitter is turned on and data is transfered using the baud rate setup earlier. For simplicity, I only used a small fraction of the available commands. Please refer to the datasheet for the full command listings.

#define __AVR_ATmega328P__

#include <binary.h>
#include <HardwareSerial.h>
#include <pins_arduino.h>
#include <WConstants.h>
#include <wiring.h>
#include <wiring_private.h>
#include <WProgram.h>
#include <EEPROM/EEPROM.h>
#include <NewSoftSerial/NewSoftSerial.h>

/** <editor-fold desc="Pin Definitions"> */
#define DATAOUT 11//1 SDI
#define DATAIN  12//
#define SPICLOCK  13//2 SCK
#define CS 10// 3

#define FSK 8
#define nIRQ 9
/** </editor-fold> */

NewSoftSerial mySerial(7, FSK);

byte spiTransfer(volatile byte data) {
    SPDR = data;

    while (!(SPSR & _BV(SPIF)));

    return SPDR;
}

void initSys() {
    pinMode(DATAOUT, OUTPUT);
    pinMode(DATAIN, INPUT);
    pinMode(SPICLOCK, OUTPUT);
    pinMode(CS, OUTPUT);
    pinMode(FSK, OUTPUT);
    pinMode(nIRQ, INPUT);

    //initialize SPI
    digitalWrite(CS, HIGH);
    SPCR = _BV(SPE) | _BV(MSTR) | _BV(CPOL);

    mySerial.begin(4800);
}

void setup() {
    initSys();

    delay(1000);

    //status registerread command
    digitalWrite(CS, LOW);
    spiTransfer(0xCC);
    spiTransfer(0x00);
    spiTransfer(0x0); // status ready at nIRQ pin
    digitalWrite(CS, HIGH);

    //configuration setting command
    //frequency band: 433
    //clock output: 10 MHz
    digitalWrite(CS, LOW);
    spiTransfer(0x8F);
    spiTransfer(0x80);
    spiTransfer(0x0);
    digitalWrite(CS, HIGH);

    //frequency setting command
    //frequency set to 433.92 MHz
    digitalWrite(CS, LOW);
    spiTransfer(0xA6);
    spiTransfer(0x20);
    spiTransfer(0x0);
    digitalWrite(CS, HIGH);

    //data rate command
    //data rate set to 4800bps
    digitalWrite(CS, LOW);
    spiTransfer(0xC8);
    spiTransfer(0x47);
    spiTransfer(0x0);
    digitalWrite(CS, HIGH);

    //low battery detector command
    //note we set the ebs bit to enable TX synchronization
    digitalWrite(CS, LOW);
    spiTransfer(0xC2);
    spiTransfer(0x20);
    spiTransfer(0x0);
    digitalWrite(CS, HIGH);

    //power management command
    //set to default: 0xC000
    digitalWrite(CS, LOW);
    spiTransfer(0xC0);
    spiTransfer(0x00);
    spiTransfer(0x0);
    digitalWrite(CS, HIGH);
}

void loop() {
    //power management command
    //turn on the crystal oscillator and the sythesizer
    //ex = 1
    //es = 1
    //turn on the power amplifier
    //ea=1
    //enable clock output buffer
    //dc=0
    digitalWrite(CS, LOW);
    spiTransfer(0xC0);
    spiTransfer(0x38);
    spiTransfer(0x0);
    digitalWrite(CS, HIGH);

    while (1) {
        mySerial.println("Hello World!");
        delay(100);
    }
}

The receiver’s output conforms to the RS232 waveform standard. By default, the NewSoftSerial library uses 8 data bit 1 stop bit no parity bit and flow control is set to none. Here is the output wave form for letter “A” (B1000001).

Receiver Serial Output For "A"

The picture below shows the receiver’s output over the serial console at 4800 kps. As you can see, the result is actually pretty good, only a few bytes are garbled. With a little bit of processing (e.g. using message checksums) the data link can be made much more reliable. Slower bit rate can also reduce error rate. If your application does not require a high data rate, you can get much less data error by simply lower the transfer data rate.

Receiver Serial Output For "Hello World!" at 4800 kps

Receiver Serial Output For "Hello World!" at 4800 kps

Be Sociable, Share!

21 Comments

  1. Mike Cook says:

    Hi,

    This is a great project! I have a project where I’ll be trying to pull information from an existing application. The current solution consists of a uController and a Ti4021 wireless transmitter chip. Connected between the exiting uController and the wireless chip are SCK, SDI, nSEL, iIRQ, CLK, and FSK.

    I want to capture the data being sent to the SDI on the Si4021 chip. I’m figuring I’ll solder on a connection wire to the SDI pin on the Si4021 and use it to take a look at the signal on an oscilloscope to see whether it is RS232 data or whether it is sychrononous.

    If asynchronous (RS232?), I figure I can hook it up straight away to an Arduino. This should allow me to record all the serial data being sent to the Si4021 chip.

    On the other hand, if it’s synchronous data, I’m a bit at a loss, as I’ve not faced this challenge before. I think I’d need to somehow use the SPI feature of Arduino. Does this sound right? I notice on another of your postings you are using this functionality… Can you provide any guidance as to how I’d set up the Arduino to receive synchronous data from the current uController? I’m confused because the naming conventions don’t seem to be matching up… For example, SPI has MOSI and MISO and Slave Select. Does MOSI map to SDI; MISO to CLK and nSel to Slave Select?

    As you can see I’m confused. Any help would be appreciated :-)

    Thanks,
    Mike

  2. kwong says:

    Hi Mike,

    The SPI interface is only used to setup the transmitter (e.g. band, baud rate, etc.) The actual data transmission portion is quite simple, it basically just follows the UART standards. So the data is being sent asynchronously.

    For the pin mappings, please take a look at the transmitter side of the code.

    SDI -> MOSI
    SCK -> SCK
    nSEL -> SS

    Let me know if you have any other questions.

  3. Mike Cook says:

    Hi Kerry,

    Thanks for the response and help. I think my uController may be using the CLK to set up a synchronous data feed. I say this because, after attaching a wire to the SDI and feeding this into the Arduino, I don’t see valid data being delivered from the uController to the Si4021 chip on the SDI feed. At least at 300, 1200, 2400, 4800, 9600, 19200, 28800, and 57600 baud… I’m guessing that the original developer decided not to use a standard UART asynch serial stream… So, I guess I’ll need to hook it up to the scope and see what’s happening on the SCK and SDI pins? Any suggestions on how to hook it up to the Arduino if the above is the case?

    Mike

  4. Mike Cook says:

    Hi Kerry,

    Thank you again. I read through the datasheet for the 4021 again. Now I get it… The CLK is only used for the setup of the transmission. After that, it’s async. Guess you can tell I’m more of a software geek… Having fun learning about hardware in my old age.

    I’ve monitored the traffic on the SDI input, and it does not appear to contain the data I need. So, I guess the next step is to take a look at the FSK interface. Maybe data is being transmitted across it…

    Anyway, thanks again for your suggestions. Figured I’d close the loop here.

    Mike

  5. Mike Cook says:

    Yep… soldered a wire onto pin 16 on the 4021 chip and sure enough, that’s where the ‘correct’ information was located…. I was thinking that the data would be on the SDI pin. Like I said, this is all new to me. Next time, I’ll know to check the FSK pin first!

    Cheers,
    Mike

  6. CaeJae says:

    Can you provide the schematics used in your project?

  7. Mike Cook says:

    Hi,

    Since last December, I’ve been using my hardwired serial interface which I connected to the FSK input on the 4021 chip. That works fine. I continue to be able to pull data from the chip.

    But, I figured I’d try to receive the data via Wireless. This would make it much easier for me. To that end, I figure I could do what you did in this experiment. Although in my case, I’d be receiving at 961.68 MHz.

    I was wondering how you set the receive frequency on the 4311 chip. Your code simply reads data from the chip. Wouldn’t I need to set the receiving frequency? For example, it appears as if you are setting the transmitter frequency to 433.92 MHz. How does the receiver know to listen on this frequency?

    Thank you,
    Mike

  8. Lee says:

    I want to wirelessly monitor two devices that are not easily accessible. If one continues to function and the other goes off-line, it makes a mess. The office I want to monitor them from is not far from the devices. I have worked out how to interface the devices so that when they are operating, they will cause the RF transmitter to come on. Can someone help me design a monitor that would receive the 2 RF signals, interface their output to an AND gate and sound a buzzer if either device goes off-line. Please be patient. I can make PCB’s and solder well, but not a strong designer. I only need a schematic and brief explanation.

    Thanks for your help

  9. John says:

    Hi Kerry!
    1) Do you try to connect SI4311 output directly to USB-UART dongle and observe signals on terminal?
    2) How do you configured BT0 , BT1 and DEV0, DEV1 pins?

    • kwong says:

      Hi John,

      1) The output of SI4311 is UART compatible so you could use a UART-USB chip (e.g. FT232R) for this purpose.
      2) BT0 BT1 DEV0 DEV1 are set according to datasheet. You can start from a low bit rate and set all of these pins to 0 to start with (it should work in this configuration). The settings mainly affect the bit time and frequency deviation and thus affect the range.

  10. Abhay says:

    Hi Kerry,
    Could you please explain me how to read data from Si4311 receiver?
    Thanks,
    Abhay

    • kwong says:

      Sure thing. You read from the receiver output as you would from an UART output. So if you are testing this with an Arduino, you can simply connect the output from Si4311 to the Rx pin on ATmega328 and use Serial Monitor to see the received data (you will have to set the baud rate to be the same as the transmitter side).

  11. Chris T says:

    Hi, I am using the exact same chips for a radio link. I have quite some experience with the SI4320 rx and moved to the SI4311 due to its small size. I am running both receivers in parallel for comparison and see some strange behavior on the SI4311. First the radio link is established, after a while it seems to loose the signal, I see some errors in the signal sometimes it is gone completely and all of a sudden it shows up inverted. I asume the afc is scanning for the optimium frequency and is going crazy, maybe pushing one tone out of band. Either my input signal is not to spec, but I tried to detune in both directions and didn’t find a better operating point. Or, some settings on the 4311 need to be changed. I will make a new board to fool around with the afc bw and deviation pins. The 4320 has the afc activated as well and there it is working well. I need about 100 meters of save range for a model airplane. I am using a printed loop antenna on the tx and just a wire on the rx pin without the LC. The LC should only be required for 50Ohm impedance matching. A lambda/4 dipole antenna should connect directly, correct? I am doing this on the 4320 as well and have good range. With the 4311 I get into trouble at 5 meters already. Any ideas? Any experience with range? Thanks a lot for the help. Maybe a smaller deviation, deactivated afc with manually tuned tx and probably one step lower bw might do it. I will try.

    Cheers,

    Chris

    • kwong says:

      Hi Chris,

      It has been a while…. if I remember correctly, you might need to adjust pin 14 and pin 15 settings depending on the bit rate you are using. Other than that, I don’t recall having an issue with the receiver performance.

      • Chris T says:

        Hi Kerry,

        thanks a lot for your quick response. This seems like the only place in the web, where experience with the 4311 is shared. I made a new board yesterday with jumpers for configuration. However, I didn’t find a setting, that improves the range. The signal qualtity seems more stable. Maybe it’s not changing over time anymore, but is only a function of distance. The range is still bad. My question this time is, could it be related to a different thing than the setting. Here are the specs: I am running driectly from a lipo, so the supply voltage is around 4V. This is above the rating, but since they write there is a LDO inside, it should be ok. Second, The antenna is a wire directly connected to the pin, No L and C there. Also, I am using only a 4.7uF ceramic cap. Is the 22n so essential. I am doing all this with the 4320 as well, and it works fine (on 915MHz) I have been flying models with this setup for a while, reliable radio link. Maybe there is a difference in the design of the 4311 and it is reacting differently to changes of the recommended setup. Any input is welcome. I am really interested what range you got. Would you please let me know?

        Thanks again.

        Chris

        • kwong says:

          Hi Chris, I don’t believe the value of the 22nF bypassing capacitor is that critical. But if you are using a larger capacitor, it probably would be helpful to put a smaller value one in parallel for better bypassing. Using a simple antenna, I had no problem of reaching 100 feet with a Si4311 transmitter (power set to max) in open space.

Leave a Reply