RF Transceiver using the MRF49XA


Transceiver breakout boards

I’m just finishing up my last class ever!!!  (for credit, anyway.)  It was a really fun, mostly because I decided to have fun with my last class, and make it a 4/5 (undergrad/graduate).  This meant that it was much easier and less theory-heavy than those that I’m used to.  Anyway, as a grad student, I was expected to do something extra, and I decided to make a RF transceiver module.  I looked around for a little while, and I settled on the Microchip MRF49XA.  In general, it’s a nice chip.  It has about the same capability as the Micrel MICRF6xx modules that I’ve used in the past.  The Micrel modules cost $20/ea. and the Microchip IC is around $3.  I was able to make the whole breakout board for the MRF49XA for less than the Micrel module alone.  One of these days, I should dig out my notes from the Micrel project and post them, but I digress.  I noticed a distinct lack of programming information using the MRF49XA, so I’m posting not only my schematic and PCB, but the software library I wrote for the Atmel AVRmega.

Breakout board schematic

The schematic I created for the breakout board is, in large part, copied from the reference schematic from the datasheet.  There are a few parts that make up the complete schematic, including power regulation, microcontroller interface, RF balun, and the IC.  Everything but the balun is really easy to understand, the power input can be +5 volts or more (probably up to about 14 volts) while using the LM317, or if the LM317 is omitted, +3.3 volts.  The MRF49XA is really a 3.3 volt part, and expects 3.3 volt I/0.  Originally, and on the PCB I had made, I had 2 ground pins.  Since then I realized it would be useful to output regulated 3.3 volt output, so I changed one of the grounds for that.  The only other major portion of the circuit is the balun.  This is used to transform the balanced RF input/output from the IC to the unbalanced antenna connector.  This circuit also provides power to the RF power amplifier inside the IC.

Breakout board top

Breakout board top

The PCB designed from the schematic is also fairly straight-forward.  A few things are worth noting, however.  I’ve added some silkscreen between 2 of the pins on the LM317.  These are to indicate where you could jumper if the breakout board is supplied with regulated power.  I used a 0805 0-ohm resistor (see the image below).  The voltage output of the LM317 is selected with R1 and R2.  I decided not to include the “stop” layer on this image so as to not clutter it, but near the word “Fence” there is a strip without solder mask over the vias.  If you wanted to isolate the RF from the outside, you could build a fence out of copper foil (or something).  The Antenna connector is a end-launch SMA, though it could also be raw coax if you want to save some money.

Close up

The only pins necessary for complete functioning of the device are the standard SPI set (MOSI, MISO, SCK, !CS), and IRO (interrupt request out).  The IRO pin is not strictly necessary, but HIGHLY recommended.  The MRF module uses the IRO pin to notify the microcontroller of a few time-sensitive events, such as FIFO full/empty conditions.

MCU interface while transmitting (click to enlarge)

The diagram included above (from the MRF49XA datasheet) provides a useful overview for the transmitting process.  The take-away message is that you first send the “Transmit data enable” (TXDEN) command, which loads 0xAAAA into the transmit FIFO.  You can either leave this in there, as a preamble, or replace it with data of your choice.  Then, you send the “Transmit carrier enable” (TXCEN) command.  At this point, the PLL starts, and the PA turns on, then transmission starts.  When the first full byte leaves the FIFO the IRO asserts.  Hopefully this forces the MCU to jump to your interrupt service routine.  Once there, if the CS pin is held low, the MRF will bring SDO (MISO) high.  This is a clear signal that the FIFO needs attention.  You can continue this process for as long as you have data.  Once you’re done, you need to load a “dummy byte” into the FIFO so your last data byte makes it out.  Finally, on the next interrupt, shut down the transmitter by sending TXCEN and TXDEN = 0.

Receiving FIFO usage (click to enlarge)

This diagram illustrates another detail of the interface to the MRF.  Also borrowed from the datasheet, it describes the way to access the receive FIFO using SPI.  Typically, SPI interfaces don’t have a notion of registers quite like I2C does, but the MRF does.  To get access to the receive FIFO you initiate an SPI transfer to the MRF module with the contents equal to the address of the receive FIFO.  In this case it’s 0xA000.  Once the first byte of the transfer is complete, the MRF begins outputting the FIFO value on the SDO pin.  It is also possible to gain access to the receive FIFO using FSEL (FIFO Select, called “Data” on the schematic) pin.

Baseband Bandwidth calculation (click for full size)

Before going into some details on the implementation of the library, I’d like to talk briefly about the RF frequency, deviation, and bit rate determination.  I’ve attached another snippet from the datasheet (hopefully the last one), and I’m going to go through the math quickly with numbers for my application.  I’m using 434 Mhz band, with 9600 baud, using a 10ppm crystal.  This means that fxerror = 10 * (434000/1000000) = 4.34 Khz.  Then, our deviation must be 9.6 + 2*fxerror + 10 = 28.28; the closest modulation is 30 Khz.  Therefore, BBBW = 30*2 – 10 = 50 Khz.  The closest BBBW is 67 Khz.

Spectrum plot from alternating 1s and 0s

I recently gained access to a spectrum analyzer courtesy of the OSU Robotics Club.  This is a spectrum plot of 0xAA, or alternating 1’s and 0’s.  It’s a little strange that the distance between peaks is about 90 Khz, as it should be more like 60 Khz.  The comb-like appearance on the flanks is probably from the transceiver switching from 1 to 0 across the scan.

Transmitting ‘1’

This plot is while transmitting all 1’s.  It’s obvious this is much cleaner, but very little information is actually being transmitted here.

With respect to the Atmel AVR library that I wrote, it includes a header file devoted entirely to defining the registers and bits as defined in the datasheet.  Each section includes a comment block description, and in the cases where some bit values need to be calculated, the equations used.  On the occasions where a bitfield is used for some integer value, I include a mask to ensure that if the derived values overrun the width of the bitfield they don’t pollute unrelated settings.  Below, I’ve included an example.

/*******************************************************************************
 * Convenience definitions for band setting
 *
 * These defines are provided for use configuring the MRF49XA module.
 * Select the frequency band for the given hardware by uncommenting the
 * appropriate line.  Set the crystal load capacitance using the MRF_XTAL_LD_CAP
 * value.
 *
 * The load capacitance is given by the following equation:
 *
 * Cap pF = 8.5 + (LCS / 2)
 * LCS = (10 - 8.5) * 2
 *
 * For 10pF: LCS = (10 - 8.5) * 2 = 1.5 * 2 = 3
 *
 ******************************************************************************/
#pragma mark General Configuration Register
#define MRF_GENCREG		0x8000		// General config. register
#define MRF_TXDEN		0x0080		// TX Data Register enable bit
#define MRF_FIFOEN		0x0040		// FIFO enable bit
#define MRF_FBS_MASK		0x0030		// Mask for the band selection
#define MRF_LCS_MASK		0x000F		// Load capacitance mask
// 10pF Crystal load capacitance
#define MRF_LCS			3		// Crystal Load capacitance
// Frequency band settings
#define MRF_FBS_434		0x0010		// 434 mHz band
#define MRF_FBS_868		0x0020		// 868 mHz band
#define MRF_FBS_915		0x0030		// 915 mHz band

All of the files in the library depend on a “hardware.h” file that defines the qualities of the hardware.  The hope is that this file is the only place that implementation-specific code lives.  There are some holes still, however.  Finally, the mrf49xa.c and mrf49xa.h files behave the way you would expect.  The module requires a total of 5 pins and one interrupt.  Some of those pins may be shared with other SPI devices.

void MRF_init(void);

uint8_t MRF_is_idle();
uint16_t MRF_statusRead(void);

// Packet structures
// the maximum payload size
#define MRF_PAYLOAD_LEN 40
// Space for preamble, sync, length and dummy
#define MRF_TX_PACKET_LEN	MRF_PAYLOAD_LEN + 5

typedef struct {
	uint8_t	length;
	char		payload[MRF_PAYLOAD_LEN];
} MRF_packet_t;

// Packet based functions
void MRF_transmit_packet(MRF_packet_t *packet);
MRF_packet_t* MRF_receive_packet();

I’ve included a snippet of the header file above so I could mention the basic process for using the MRF module.  The MRF_init function expects the SPI bus to be configured, and it performs the basic initialization of the device.  Once it’s started, the interrupts on the AVR must be enabled.  In the main loop (or at least as often as a packet can be transmitted) you should call MRF_receive_packet.  This function will return NULL if no packet was received, and a pointer to a packet structure if it was.  MRF_transmit_packet takes a packet structure and transmits it.  This is an asynchronous operation, and you may use the packet structure (or it’s memory) once it returns.  This is useful if you want to use a packet structure created on the stack.  It is possible to get yourself into trouble with MRF_packet_transmit, as it spin-loops on a lock set in the ISR.  If for whatever reason that lock isn’t unlocked at some point you can hardlock.  I’ve done my best to ensure that it doesn’t happen, but beware.

And, finally, links to the files.  If there seems to be sufficient interest, I’ll open up a SVN (maybe Google Code, who knows) with these files and a main program useful for telemetry and the like.  Post in the comments if you’re interested, or send me a line.

hardware.h

MRF49XA_definitions.h

MRF49XA.c

MRF49XA.h

spi.h

spi.c

Also, the PCB is available as a public design from BatchPCB.  I’ll include a bill of materials if necessary, though the components are clearly printed on the silkscreen.

Oh!  before you ask: No, I don’t know what the range is.  The longest I’ve tried is about 20 feet, and there weren’t any errors, but it was only about 100 bytes.  The chip is rated to 7dBm, I think, so go from there. 🙂

Update:

Here is a simple bill of materials, I used the Eagle export feature, and attempted to place digikey part numbers for each part.  I’m not saying they’re all right, you may want to make sure you’re getting what you think is correct.

partlist.txt

Also, here are the eagle files.  They aren’t necessarily finalized

eagle_files.zip

, , , , , , , ,

  1. #1 by hpux735 on October 13, 2011 - 9:38 am

    Right you are! Luckily for you, I’ve sent a combined transceiver/avr combo board with USB to the PCB house. I’ll be posting about it before too long.

    As an aside, I’m thinking of offering a kit or assembled board. Any interest?

  2. #2 by Samwise on October 13, 2011 - 11:52 pm

    Hi
    Just a short question, would it be possible to use a wire antenna?

  3. #3 by aiqon on October 14, 2011 - 3:09 am

    Im very interested. can we stay in touch by mail? stas.stelle ( at ) gmail ( dot ) com

  4. #4 by hpux735 on October 14, 2011 - 6:06 am

    Sure, a wire antenna is just like any other antenna. Do your best to match it to 50 ohms at 434 Mhz, and you should be all set.

  5. #5 by aiqon on October 16, 2011 - 1:43 am

    what are the values for R1 and R2? and do u by chance have a supplier that can send all parts? digikey kinda lacks the LM317 in SOT223 :/

  6. #6 by hpux735 on October 16, 2011 - 7:00 am

    I bought everything from DigiKey. This is the exact part I used: 296-12602-1-ND. As far as R1 and R2, I usually don’t specify it because I make it up with the actual resistors I have on hand. Using the LM317 calculator it looks like you want 240 for R1 and about 400 for R2.

  7. #7 by Pankil on September 13, 2012 - 10:15 pm

    I want to design pcb with on board antenna using mrf49xa. For designing of antenna i can not understand which type of antenna i can use for 915MHz. If yuu have guideline then help me..

  8. #8 by hpux735 on September 14, 2012 - 6:11 am

    You have quite a few options. The datasheet discusses these in more detail, but you can use a monopole, dipole, or loop antenna. The caveat is that you’ll need to calculate new values for the matching components, and this isn’t a trivial exercise.

  9. #9 by Tyger on October 5, 2012 - 6:37 am

    The MRF49XA Breakout board has other values on it. so what should we use? the once on the board or the schematic?

  10. #10 by hpux735 on October 6, 2012 - 6:38 am

    Sorry it took so long to reply, I’ve been out of the country.

    Anyway, I don’t remember 100%. The values are exactly the same as the datasheet for the MRF49XA in the 400 Mhz example schematic. Make sure you don’t use the 900 MHz values.

  11. #11 by Nayab on December 5, 2012 - 12:35 pm

    hi hpux735 ..
    am also making RFID boar using MRF49xa and i need your help imidiatly..can you contact me by mail?
    nayab.khan@gmail.com

  12. #12 by hpux735 on December 6, 2012 - 8:14 am

    Sorry, I don’t address questions ‘off line’. If you have a specific question, feel free to ask here. I’ll answer it if I can. Thanks.

  13. #13 by Nayab on December 8, 2012 - 6:06 am

    @hpux735
    OK thats fine..i am using PIC18F452 as host UC and i wrote my code in Mikro c pro..but try hard i am unable to transmit the RF signal correctly. i dnt know why?
    i have already read your whole post and all comments as well.you have done good work an i think you can help me..

    am using external crystal for host UC of 24MHZ and SCK of 1.5MHZ i.e FOS/16
    -> i have also rad AN1552.
    can you figur out problem areas?

  14. #14 by hpux735 on December 8, 2012 - 11:43 pm

    If you’re using a PIC it may be easier to use the microchip provided sample code. That’s what I based mine off of. I ported it to atmel. No sense in you porting it back to microchip. I don’t remember where to find it, but the microchip code is publicly available.

  15. #15 by Nayab on December 9, 2012 - 3:10 am

    @hpux735
    yes am using that code but i think i have some hardware problem.but i am unable to sort it out.
    mrf is giving all other responses as expected but not transmitting Rf signal…?

  16. #16 by hpux735 on December 9, 2012 - 1:33 pm

    @Nayab

    Check the interrupt line with a logic analyzer or something. If you don’t service the MRF49XA appropriately then it won’t work.

  17. #17 by Nayab on December 14, 2012 - 9:41 am

    @hpux735
    what do you mean by service?

  18. #18 by hpux735 on December 14, 2012 - 9:52 am

    I mean that when the MRF49XA requests an interrupt of the microcontroller, it actually requires that the microcontroller do something about it. For example, if you don’t respond when trying to start transmitting it won’t do it. (If I remember correctly).

    RegisterSet(MRF_PMCREG); // Turn everything off
    RegisterSet(MRF_GENCREG_SET | MRF_TXDEN); // Enable TX FIFO
    // Reset value of TX FIFO is 0xAAAA

    RegisterSet(MRF_PMCREG | MRF_TXCEN); // Begin transmitting
    // Everything else is handled in the ISR

    Then, in the ISR:

    RegisterSet(MRF_TXBREG | transmit_buffer[counter++]);

    If you don’t respond by providing additional data (TXBREG is the transmit byte register) it won’t transmit.

  19. #19 by Nayab on December 14, 2012 - 10:25 am

    am axactly doing the same..
    here is my code
    plz have a look
    SPI_Command(PMCREG); // turn off the transmitter and receiver
    SPI_Command(GENCREG | 0x0080); // Enable the Tx register
    //—- Packet transmission
    // Reset value of the Tx regs are [AA AA], we can start transmission
    //—- Enable Tx
    SPI_Command(PMCREG |0x0020); // turn on tx

    Slave_Select=0;
    Chip_Select=0;
    //Delay_Ms(200); // chip select low
    while(!RF_SDO);//{led2=~led2;Delay_Ms(100);};

    SPI_Write16(TXBREG | 0xAA); // preamble
    while(!RF_SDO);

    SPI_Write16(TXBREG | 0x2D); // sync pattern 1st byte
    while(!RF_SDO);

    SPI_Write16(TXBREG | 0xD4); // sync pattern 2nd byte
    while(!RF_SDO);

    SPI_Write16(TXBREG | length);

    for (a=0;a<length;a++){

    SPI_Write16(TXBREG | data1[a]); // write a byte to tx register

    }

    while(!RF_SDO){}

    SPI_Write16(TXBREG |0x00); // write a dummy byte since the previous byte is still in buffer
    while (!RF_SDO){}
    // wait for the last byte transmission end
    Slave_Select=1;
    Chip_Select=1;
    Delay_Ms(200);

  20. #20 by hpux735 on December 14, 2012 - 10:35 am

    @Nayab

    In that case, it’s possible that you’re doing something wrong in your configuration. I would still analyze the state of the interrupt out pin while doing this routing to see if the MRF is requesting interrupts. That’s a good indication that it’s working and is actively requesting data.

  21. #21 by Nayab on December 14, 2012 - 11:08 am

    yes..fine..
    am gona read stsreg..
    but it also sends RF_SDO down when a byte is transmitted sucseesfully..isnt it?

  22. #22 by hpux735 on December 14, 2012 - 11:18 am

    @Nayab

    Yes, but I don’t know what’s happening in your application. You simply say that you’re “unable to transmit” I don’t know where your results deviate from what is expected. I recommend buying a MRF49XA device (either mine of microchips) that has known-working behavior. Then use a logic analyzer to capture all the communication between the MRF and the uC. Do the same with yours and try to see where things start changing.

  23. #23 by Nayab on December 14, 2012 - 11:45 am

    hmm

    am using spi or seril clock of 1.5mhz is it fine?

  24. #24 by Nayab on December 14, 2012 - 11:46 am

    dear i dnt have access to spectrum analyzer and logic analyzer am using an oscilloscope to troble shoot all of these..

  25. #25 by hpux735 on December 14, 2012 - 11:50 am

    @Nayab

    I’ve been using the saleae logic analyzer. It’s relatively inexpensive. It’s almost a must-have instrument. Without knowing what’s going on between the devices it’s very difficult to debug.

    http://www.saleae.com

  26. #26 by Nayab on December 14, 2012 - 11:50 am

    @hpux735

    what should be its out put power at RFP and RFN while transmitting corecltly?

  27. #27 by hpux735 on December 14, 2012 - 11:54 am

    @Nayab

    I actually don’t really know. I’ve always tested it with the balun. The output power with the balun and matching circuitry was very near what was published in the datasheet.

  28. #28 by Nayab on December 14, 2012 - 12:22 pm

    @hpux735

    i wana send you a view of my schematic.Can i?
    for point out any thing missed

  29. #29 by hpux735 on December 15, 2012 - 1:44 pm

    @Nayab

    I received it. It looks normal. I don’t really have time to provide support at this level. There is a forum on the microchip website that may be able to provide more help.

  30. #30 by Tyger on April 26, 2013 - 2:36 pm

    Can you please add what your code does? it does not say that on the page.

  31. #31 by hpux735 on April 29, 2013 - 4:20 pm

    This code is basically only a library intended to be used with this module. What it does is up to you.

  32. #32 by Tirpeh on October 23, 2013 - 11:37 am

    Have you got any idea how much those libraries use mCu program memory?

  33. #33 by hpux735 on October 23, 2013 - 1:34 pm

    I’m not exactly sure, but the main.hex file (intel HEX) is ~7kB

  34. #34 by Emil on December 5, 2013 - 10:52 am

    Hi.
    Firstly i must thank you for this design and tutorial. Im building ma PCB based on your example.
    I do have few questions…

    1.) Do i need to use RF balun and is there some ready made part for it ?
    2.) I have connected CS line to GND. Should this be OK ?
    3.) I was planning to make somekind of frequency switcher so i can cnage from 433 to 868mhz range. Any idea how to make this ?

    Please be so kind and share some light on this questions because am stuck in this part.

    Emil

  35. #35 by hpux735 on December 5, 2013 - 11:43 am

    Hi,

    If you wanted to make a frequency switcher… I think that’s possible. You’d want to switch between the balun and the main IC. I believe the best way to do that would be through a PIN diode. I think it _may_ be possible to use an analog switch or MOSFET, but I’m not as sure. If it’s possible, a MOSFET would be a lot easier. I think that you could attach both baluns to the MRF and switch between them.

    I’m honestly not sure if you can tie CS low. I know that when you pull CS low, you can check whether there’s data in the FIFO. UPDATE I’m pretty sure you can’t do that. I think the device applies the register load when CS goes high.

    The RF balun isn’t necessary if you use a balanced antenna system. The balun lets you interface to an unbalanced 50 ohm load. It’s probably possible to buy a balun transformer from minicircuits or coilcraft. That could also be an option for wideband operation (433-868Mhz).

    Good luck! I’m interested in how things go. Keep me posted if you can.

  36. #36 by Emil on December 5, 2013 - 12:26 pm

    Thank you very much for your fast replay !.

    Ok, i will do as you have suggested.

    Am planning to use external directional antenna to get cca 100 m range.
    Do i need to design something extra or is your schematics enough ?

    The end project is to set 5 nodes and one master PCB.
    There will be duplex communication in between.
    So, basically , small one to many network…

    E.

  37. #37 by hpux735 on December 5, 2013 - 12:33 pm

    @Emil

    With a good antenna system 300′ (100m) should be no problem. I’ve tested it further than that with some bit loss. I’d recommend some kind of error correction (or at least detection and retransmission). You should achieve better than .10% bit error rate.

  38. #38 by Emil on December 5, 2013 - 1:42 pm

    OK will do that.

    What kind of balun transformer and pin diode do you suggest ?

    E.

  39. #39 by hpux735 on December 5, 2013 - 2:25 pm

    @Emil

    Unfortunately, I can’t recommend products in either case. I don’t have experience designing circuits with PIN diodes, I’m just familiar with the technology and think it would work. With the balun transformers, I can’t help there either. It may not be a bad idea to contact Microchip’s design support team with these questions. Choosing a balun transformer is easy if you know the source and destination impedance (destination is well known: 50 ohms), but the data sheet doesn’t specify source impedance. It’s possible that the impedance would be different with 400 and 800 MHz.

    http://www.microchip.com/support/SupportContact.aspx

  40. #40 by Emil on December 6, 2013 - 12:57 am

    OK. So basically, the schematics for this ( without balun part for now ) should look like this ? :
    http://oi44.tinypic.com/2uqc83k.jpg

    1.) connection to RF
    2.) connection to PC over max3232

    Is this OK ?

  41. #41 by Emil on December 6, 2013 - 1:02 am

    Uppps, wrong one…
    This is the latest version:

    http://oi42.tinypic.com/r2lwye.jpg

  42. #42 by hpux735 on December 6, 2013 - 9:18 am

    @Emil

    That looks pretty good. I would caution you to provide some provision for connecting the CS line to the MRF49XA. Also, It’s a good idea, I think to connectorize the antenna ports. Just make sure that you use short, low inductance connections to your balun solution. At 433MHz it’s not as critical, but at 800MHz it matters more. The rule of thumb is that you want things to be wonky no more than 1/2 the wavelength of the frequency you’re using. That would be about 30cm at 800mhz.

  43. #43 by Emil on December 7, 2013 - 3:57 am

    The CS line is left from the old schematics. I will remove it.
    I was planning to use some antenna connector as you suggested and this will be in end design.
    Thank you for additional info and help 🙂 !

    I will send the new schematic when am done.

    E.

  44. #44 by Emil on December 9, 2013 - 9:16 am

    Hi !

    Ok. please look at final version of the device.
    It should be working on 433 mhz and i guess it will 🙂
    http://oi42.tinypic.com/8wa740.jpg
    E.

  45. #45 by hpux735 on December 9, 2013 - 10:01 am

    It looks pretty good to me.

  46. #46 by askemb on January 23, 2014 - 9:58 am

    hi

    I am trying to use this transceiver for building automation for a requirement, what is the maximum range for this transceiver.

  47. #47 by hpux735 on January 23, 2014 - 11:14 am

    This is a common question asked about any transceiver. Unfortunately, it’s almost impossible to answer. It depends. Is it indoors or outdoors, what kind of antenna, what data rate? All I can say is that the output power is +7dBm. Add that to your antenna system gain (or loss). The receiver sensitivity for 433 MHz, 2.4 kbps, ΔfFSK: 45 kHz, BW: 67 kHz is about -110dBm. This means that your path losses can’t be more than 117dB. This will vary greatly according to your environment. There is no guaranteed maximum, I’ve had signal (albeit with bit errors) with a distance of 2000-3000 feet. Good luck.

  48. #48 by Emil on February 23, 2014 - 2:25 am

    Hi.
    I finally finished the boards. I have one master board and 3 slave.
    First part of the project will be to put your firmware to the master board and to connect this board on PC ( over serial ). When this is done am going to try the board to board communication.

    Tell me what programming language did you use on the PC side. I know that java has some problems serial comm but i was thinking on using c++ or php.

    E.

  49. #49 by hpux735 on February 23, 2014 - 2:28 pm

    Depending on what firmware you use, they’re in various stages of completion. I recommend using them as a framework and guideline…

    That said, I typically use C and Objective-C. I have a Objective-C serial library on Github https://github.com/hpux735/SerialPort-Framework that could adapt to C++. I’m sure there are other libraries you could use. It’s not that hard to do, but the ioctl interface can be a bit weird. I’m assuming you’re using a UNIX-based operating system. If you’re on windows, you’ll have to find something else.

(will not be published)

Please complete this capcha. I get almost 1000 spam comments a day! * Time limit is exhausted. Please reload CAPTCHA.