Posts Tagged ‘spi’

RFM12 programming

October 7, 2010 12 comments

I know that I wouldn’t rediscover a wheel here, but there are many problems with these modules. Generally, problems arises from lacks in documentations.

Here is short tutorial, describing basics of SPI transmittion & RFM12 module behavior.

    SPI transmition

SPI comes from Serial Peripheral Interface. In hardware appears as 4 main lines :
SDO – data coming out from host (microcontroller) to module
SDI – data coming in from module into host
SCK – data clock, timing the transfer
and more or less optional :
SS – chip select, indicates that transmittion is going to occur on the lines

The definition here is host-centric, but any will do when you remember to connect host’s SDO to module’s SDI and host’s SDI to module’s SDO.
In interface IDLE state – when you don’t want to transmit anything – SS should be LOGIC HIGH. When you want to start the transmittion pull SS down to logic LOW, and keep it low during the transmittion.

There are two different kind of SPI operation – Master and Slave mode, assuming host-centric (the clock generation is provided by host) interface. Connecting RFM12 we will consider only Master mode – that is, the microcontroller is providing SCK signal and is responsible for helding SS line at appropriate level, short – master is controlling the transmittion.

Writing is started by pulling SS low. SCK should be low when inactive. Rising edge on SCK is defining moment when module is “reading” its SDI line (the host’s SDO line). Simultaneously, module is sending data through its SDO (host’s SDI line) !!! This is the most important thing, considering SPI interface.
Of course, during the host writing data, module is sending previously requested data, or default register defined in hardware as a feature (eg. RFM12 is sending its STATUS register).

Example 1. Writing data to RFM12 module :
should be executed as follows :
1) pull down SS to select RFM12 module
2) pump out bits of data (x8209) through hosts’ SDO line, clocking the SCK simultaneously (high indicates data ready at SDO)
3) pull up SS to deselect RFM12 module

In the example above, we’re discarding the information RFM12 is sending back during SCK clocking.

Example 2. Reading STATUS register of RFM12 :

status = WriteCMD(0x0000);

this code should be performed as follows :
1) pull down SS
2) pull down host’s SDO (we’re sendind all zeroes)
3) clock 16 times the SCK, listening host’s SDI before SCK is going high. This is feature of RFM12 module – it is sending its STATUS register MSB bit (FFIT) before first SCK pulse!
4) pull up SS to indicate end of transmittion

Accumulating SDI bits in a variable, we will obtain RFM12 status register value after 16 clocks on SCK line.

int cnt = 16;
int result = 0;
while (cnt--)
result = result | SDI;
result = result << 1;
SCK = 1;
SCK = 0;

Example 3. Reading from FIFO register of RFM12

 unsigned char data = WriteCMD(0xB000); 

That code should be executed in this way :
1) SS low
2) clocking out the command 0xB000 (16 bits), simultaneously accumulating SDI into result variable
RFM12 will accept the 0xB0 command during the first 8 clocks (Read FIFO command) and will spit out the FIFO register during the last 8 clocks, so the FIFO contents will be held into lower byte of result variable.
3) variable ‘data’ will be filled with only 8 lower bits of ‘result’.
4) SS high

RFM12 SPI Interface
There is nothing strange here, except 16-bit mode of interface. It means that each transfer is 16 bit wide, consists of 16 clock changes on SCK line.

RFM12 vs RFM12B
RFM12 is 5V tolerant device – it can be powered with +5V and accepts +5V as HIGH level on SPI lines.
RFM12B is 3.3V device ONLY !!! That means, you should provide +3.3V as power to RFM12B module, and you should translate (if necessary) levels at SPI interface to 3V3 level on the side of RFM12B.

RFM12 Interface
RFM12 Interface consists of 4 SPI lines (SDI,SDO,SCK,SS) and optional connections (eg. nIRQ, nRES, etc).
OPTIMAL way is to connect SPI & nIRQ line.
nIRQ is an Interrupt ReQuest line, informing host (microcontroller (MCU)), about an event occured in the RFM12 module.
It is strongly recomended to connect this line to your MCU, especially to some kind of External Interrupt pin (INT0, INT1, and so on…).

nRES is a hardware RESET signal. It can be connected to provide HW reset ability. To reset RFM12 module, you should held nRES LOW for about 5ms, and then release it HIGH and waits for about 50ms.

nIRQ is logic HIGH, when there is no event to respond (module is calm and quiet). RFM12 is pulling nIRQ LOW, when it wants to say something, eg. the data is received and ready at FIFO register to be read, the module is ready to transmit next byte…

Power-Up condition
After applying power to your circuit, RFM12 will assert nIRQ line LOW because of POR (Power-On-Reset) interrupt. You should read status register (WriteCMD(0x0000)) of RFM12 to CLEAR this condition. After reading STATUS, RFM12 will release nIRQ HIGH -> idle state.
In readed status, you will find POR bit set (0x4000). That indicates your SPI connections is running smooth, and RFM12 is working correctly.

RFM12 Initial configuration
According to many sources in the Internet, esp. RFM12 Datasheet, RF12 Datasheet, RF12 Programming Guide, the first thing you’d do with the RFM12 is sending initial configuration setup. It would sets the internal RFM12′ registers to desired values, eg. frequency of operation, speed of transmittion, modulation deviation, etc…

Consider this code :

    WriteCMD(0x80D8); //EL,EF,433band,12.0pF
    WriteCMD(0x8201); // Sleep
    WriteCMD(0xC611); // Speed of transmittion = 19200 bauds
    WriteCMD(0x9460); // frequency

This commands should be sent to RFM12 after applying power to the device. For detailed information about each command I’ll send you to datasheet. After all, the first 4 commands are the most important.

After this step, your RFM12 is at SLEEP state (it is not receving nor transmitting anything), and is awaiting your further commands.

RFM12 – Transmitting data
RFM12 data transmition is all about FIFO and STATUS register.
FIFO holds data to be sent when your RFM12 is in TX mode, and holds data received in RX mode.

BEFORE entering TX mode, RFM12 should be at IDLE (0x8209) or SLEEP (0x8201) mode. nIRQ line should be high – there can not be any unhandled IRQ left.

RFM12 is designed to provide interrupting transmittion, it means, TX mode should be entered only when you want to transmit data, and over immediately after the transmittion completes.
RX mode can be switched ON all the time.

RFM12 is designed to send packet of data, consisting of :
1) PREAMBLE (one or more 0xAA or 0x55 bytes)
2) SYNC WORD ( default 0x2DD4 )
3) user packet data…

Preamble is required to synchronize the other RFM12 receiver circuit clock with the transmitting signal, the longer the better, but usually 2 bytes of 0xAA (alternating 1010101….) is sufficient.
Sync word is required to indicate start of transmittion. Data sent AFTER SYNC WORD would be pumped into FIFO register.

Transmittion should be performed with these steps :
1) Assume the RFM12 is IDLE (you should provide in your code simple state machine, describing current mode of RFM12)
2) Fill the FIFO with 2 bytes of PREAMBLE ( 0xB8AA, 0xB8AA )
3) Enter TX mode ( 0x8239 )
4) Watch nIRQ line while it is HIGH (when it falls low, that would indicate FIFO is ready to accept next byte)
5) Send next byte of transmittion ( sync word 0xB82D, 0xB8D4, then your own data … 0xB800 | data )
6) go to 4) while there is something to send
7) Leave TX mode by entering IDLE (0x8209) or RX (0x82D9) ….

RFM12 – Reception of data
Reception starts when you command the RFM12 to enter RX mode (0x82D9). After or before that command you should clear FIFO ( subsequent 0xCA83, 0xCA81).

Receiving should be performed like this :
1) Enter RX mode (0x82D9)
2) Waits for nIRQ LOW -> it means that RFM12 received preamble , syncword and 1st byte of transmitted user data. FIFO would now contain 1st byte of our data.
3) Read FIFO (0xB000) and store lower byte of result as in your RX buffer.
The Read FIFO command would restore HIGH on nIRQ.
4) Go to 2) while you want to receive more data
5) Clear FIFO

The packet transmitted over the aether should looks like :
0xAA, 0xAA, 0x2D, 0xD4, data_len, chksum, data[0], data[1] …. data[n]
so : preamble, syncword, data length to be received, checksum of data, subsequent data bytes.
That would ease the reception, and allow to control correctness of received data.

I hope that this short brief would help you in your fun with RFM12.

Categories: microcontrollers Tags: , ,