RF communication with the RFM12B module

 

(For the working code scroll all the way to the bottom!)

I free-formed a simple RFM12B atmega168 temperature sensor circuit using a 3.7 lithium ion battery I would one day like to solar recharge. Behold!:

Notes: DO for Data Out and DI for Data In, from the perspective of the RFM12B. I’m using a 7cm long antenna because these modules are 868MHz (you can tell the frequency based on the existence or not of a certain capacitor).

The MISO line is dead, the RFM12B is not responding to anything I’m sending it…

The RFM works with 16 bit data and I am currently trying to squeeze two 8 bit data transmissions, this is why I think things are not currently working. This project might be the limit of where it is easy to make one’s own code and when one must rely on code produced by the manufacturer of the chip in question.

An additional problem with the particilar project is the poor documentation by the manufacturer of the RFM12B module. Even the numbering of the registers is not consistent and there are errors in example code.

Here is the (not yet working) TX side code:


// *
// * Atmega168 RFM12B TX
// *
// * Created:
// * Author : FablabDigiscope
// */

#define F_CPU 8000000

#include <avr/io.h>
#include <util/delay.h>

#define NIRQ PB0 // input for nIRQ which goes low after a transmit is received?


void SPI_Init();
void SPI_Transmit(char dataout);
void SPI_Stop();
void rfInit();


int main(void)
{
		SPI_Init();
		SPDR = (0x00); // byte to send
		SPDR = (0x00); // byte to send
		rfInit();
		DDRD = 0b10000000; //LED for RX/TX rec/sent

	while (1)
	{
		char dataout = 0b10011001; // 0x99 //
		

		
		SPI_Transmit(0xB8); //this must precede data, it is the transmit register write command.		
		SPI_Transmit(0xAA); // PREAMBLE
		
		SPI_Transmit(0xB8); //this must precede data, it is the transmit register write command.
		SPI_Transmit(0xAA);
		
		SPI_Transmit(0xB8); //this must precede data, it is the transmit register write command.		
		SPI_Transmit(0xAA);
		
		SPI_Transmit(0xB8); //this must precede data, it is the transmit register write command.		
		SPI_Transmit(0x2D); // SYNC
		
		SPI_Transmit(0xB8); //this must precede data, it is the transmit register write command.
		SPI_Transmit(0xD4); // Network ID


		SPI_Transmit(0xB8); //this must precede data, it is the transmit register write command.
		SPI_Transmit(dataout);
		
		SPI_Transmit(0x00); //
		SPI_Transmit(0xAA); // DUMMY BYTES, optional?
		
		SPI_Transmit(0x00); //
		SPI_Transmit(0xAA);
		
		SPI_Transmit(0x00); //
		SPI_Transmit(0xAA);
		
		SPI_Stop();

		_delay_ms(1);
		
		PORTD = 0b10000000; // turn on LED

	}
}



void SPI_Init()
{
	DDRB = ((1<<DDB2)|(1<<DDB5)|(1<<DDB3)); //SPI pins on port B: SS, SCK, MOSI outputs
	//set MISO as input
	PORTB |= (1<<DDB2); //start with SS high (slave not selected). DO THIS BEFORE BEGINING ISP
	PORTB |= (1<<DDB4); //MISO pull-up activated
	SPCR = ((1<<SPE)|(1<<MSTR)|(1<<SPR1));  // SPI enable, Master enable, f/64. DO THIS AFTER DDR!
}

void SPI_Transmit(char dataout)
{
	//SPI_Transmit
	PORTB &= ~(1<<DDB2); // pull slave select low
	while(PINB & (1<<NIRQ)); // wait until ready signal (low)
	SPDR = (dataout); // byte to send
	while(!(SPSR & (1<<SPIF))); // wait for SPIF transmit flag to be set. After this, SPDR will contain the received byte!
}


void SPI_Stop()
{
	PORTB |= (1<<DDB2); //slave select high
}

void rfInit()
{
	SPI_Transmit(0x80);
	SPI_Transmit(0xE7); //EL (turn on internal data reg.),EF (FIFO rx mode enabled, data and dclk used for data and data clock output),868band,12.0pF
	
	SPI_Transmit(0x82);
	SPI_Transmit(0x39); //er (for rec. mode),!ebb,ET(for rec. mode),ES,EX,!eb,!ew,DC for receiver mode//
	
	SPI_Transmit(0xA6);
	SPI_Transmit(0x40); //frequency select
	
	SPI_Transmit(0xC6);
	SPI_Transmit(0x47); //4.8kbps
	
	SPI_Transmit(0x94);
	SPI_Transmit(0xA0); //VDI,FAST,134kHz,0dBm,-103dBm
	
	SPI_Transmit(0xC2);
	SPI_Transmit(0xAC); //AL,!ml,DIG,DQD4
	
	SPI_Transmit(0xCA);
	SPI_Transmit(0x81); //FIFO8,SYNC,!ff,DR ***** (this must be set to 0xCA83 to rx)
	
	SPI_Transmit(0xCE);
	SPI_Transmit(0xD4); //SYNC=2DD4 ,AG
	
	SPI_Transmit(0xC4);
	SPI_Transmit(0x83); //@PWR,NO RSTRIC,!st,!fi,OE,EN
	
	SPI_Transmit(0x98);
	SPI_Transmit(0x50); //!mp,90kHz,MAX OUT
	
	SPI_Transmit(0xCC);
	SPI_Transmit(0x17); //OB1 , ACOB0, LPX,Iddy,CDDIT,CBW0
	
	SPI_Transmit(0xE0);
	SPI_Transmit(0x00); //NOT USED
	
	SPI_Transmit(0xC8);
	SPI_Transmit(0x00); //NOT USED
	
	SPI_Transmit(0xC0);
	SPI_Transmit(0x40); //1.66MHz,2.2V
}


Here is the (not yet working) RX side of the code:


// *
// * Atmega168 RFM12B RX
// *
// * Created:
// * Author : FablabDigiscope
// */


		#define F_CPU 8000000

		#include <avr/io.h>
		#include <util/delay.h>

		#define NIRQ PB0 // input for nIRQ which goes low after a transmit is received?
		
		void FIFO_Reset();
		void SPI_Transmit(char dataout);
		void SPI_Init();
		void rfInit();
		void SPI_Stop();
		char SPI_Receive();

		int main(void)
		{
		DDRD = 0b10000000; //LED for RX/TX rec/sent
		
		SPI_Init();
		rfInit();


		
	
		
		while (1)
		{
		char storage; 
		SPI_Transmit(0x00);
		SPI_Transmit(0x00);
		
		FIFO_Reset();
		storage = SPI_Receive(); //should get only last byte of message?	
			
		if(storage == 0b10011001) // 0x99
		{
		PORTD = 0b10000000; //turn on LED
		FIFO_Reset();
		}
		SPI_Stop();
		_delay_us(1);
		}
		}




void SPI_Init()
{
	DDRB = ((1<<DDB2)|(1<<DDB5)|(1<<DDB3)); //SPI pins on port B: SS, SCK, MOSI outputs
	//set MISO as input
	PORTB |= (1<<DDB2); //start with SS high (slave not selected). DO THIS BEFORE BEGINING ISP
	PORTB |= (1<<DDB4); //MISO pull-up activated
	SPCR = ((1<<SPE)|(1<<MSTR)|(1<<SPR1));  // SPI enable, Master enable, f/64. DO THIS AFTER DDR!
}

char SPI_Receive() //must be in receive mode for this to work//
{
	char received;
	//SPI_Receive
	PORTB &= ~(1<<DDB2); // pull slave select low
	while(PINB & (1<<NIRQ)); // wait until ready signal (low)
	SPDR = (0xB0); // byte to send
	while(!(SPSR & (1<<SPIF))); // wait for SPIF transmit flag to be set. After this, SPDR will contain the received byte!
	
	while(PINB & (1<<NIRQ)); // wait until ready signal (low)
	SPDR = (0x00); // byte to send
	while(!(SPSR & (1<<SPIF))); // wait for SPIF transmit flag to be set. After this, SPDR will contain the received byte!
	
	received = SPDR;
	return received;
}

void SPI_Transmit(char dataout)
{
	//SPI_Transmit
	PORTB &= ~(1<<DDB2); // pull slave select low
	while(PINB & (1<<NIRQ)); // wait until ready signal (low)
	SPDR = (dataout); // byte to send
	while(!(SPSR & (1<<SPIF))); // wait for SPIF transmit flag to be set. After this, SPDR will contain the received byte!
}

void FIFO_Reset()
{
	SPI_Transmit(0xCA);
	SPI_Transmit(0x81);

	SPI_Transmit(0xCA);
	SPI_Transmit(0x83);
}


void rfInit()
{
	SPI_Transmit(0x80); 
	SPI_Transmit(0xE7); //EL (turn on internal data reg.),EF (FIFO rx mode enabled, data and dclk used for data and data clock output),868band,12.0pF
	
	SPI_Transmit(0x82); 
	SPI_Transmit(0x99); //er (for rec. mode),!ebb,ET(for rec. mode),ES,EX,!eb,!ew,DC for receiver mode//
	
	SPI_Transmit(0xA6); 
	SPI_Transmit(0x40); //frequency select
	
	SPI_Transmit(0xC6); 
	SPI_Transmit(0x47); //4.8kbps
	
	SPI_Transmit(0x94); 
	SPI_Transmit(0xA0); //VDI,FAST,134kHz,0dBm,-103dBm
		
	SPI_Transmit(0xC2); 
	SPI_Transmit(0xAC); //AL,!ml,DIG,DQD4	
	
	SPI_Transmit(0xCA); 
	SPI_Transmit(0x81); //FIFO8,SYNC,!ff,DR ***** (this must be set to 0xCA83 to rx)	
	
	SPI_Transmit(0xCE); 
	SPI_Transmit(0xD4); //SYNC=2DD4 ,AG
		
	SPI_Transmit(0xC4); 
	SPI_Transmit(0x83); //@PWR,NO RSTRIC,!st,!fi,OE,EN	
	
	SPI_Transmit(0x98); 
	SPI_Transmit(0x50); //!mp,90kHz,MAX OUT
		
	SPI_Transmit(0xCC); 
	SPI_Transmit(0x17); //OB1 , ACOB0, LPX,Iddy,CDDIT,CBW0	
	
	SPI_Transmit(0xE0); 
	SPI_Transmit(0x00); //NOT USED	
	
	SPI_Transmit(0xC8); 
	SPI_Transmit(0x00); //NOT USED	
		
	SPI_Transmit(0xC0); 
	SPI_Transmit(0x40); //1.66MHz,2.2V
}

void SPI_Stop()
{
	PORTB |= (1<<DDB2); //slave select high
}



This code works (most of the time!), it’s from http://dlehard.narod.ru/quick_start.pdf, dlehard did a wonderful job making this clear and legible, thank you for your work!

I think the main reason it is working is the fact that it does not rely on the AVR USI but has its own custom 16 bit Write(Cmd) function. This function is straight forward, it takes a 16 bit input and bit bangs the SDO (Microchip input from RFM12B output) one bit at a time while also reading the SDI (Microchip output to RFM12B input) and writing it to the recv variable. It manually does the basic SPI stuff, pulling Chip Select (CS) low and pulling the clock low before putting SDI in the appropriate state and ticking the clock up. The part I had difficulty understanding was the ANDing with 0x8000, now I understand this is a bitmask which looks only at the highest bit in the 16 bit value (0x8000 = 0b1000000000000000) while the loop bitshifts the Cmd to the left each time, ANDing the next bit with 1. ANDing produces a 1 only if A and B are both 1 and otherwise produces a 0, this is why it is useful as a bitmask.

I don’t know how the timing of this SPI setup is controlled but I guess it’s not critical.

The TX side turns on an LED everytime it transmits, the RX side turns on an LED if it receives the byte 0x30.

I was too lazy to get the USART to work with the Atmega168 (I have a previous post on getting it going with an Attiny2313) so that part of the code is commented out.

Here is the RX side:

/*
 * Atmega168 RFM12B rev.2 RX.c
 *
 * Created: 4/30/2019 2:56:31 PM
 * Author : FablabDigiscope
 */ 


#include <avr/io.h>

/* RFM12B INTERFACE */
#define SCK 5 // SPI clock
#define SDO 4 // SPI Data output (RFM12B side)
#define SDI 3 // SPI Data input (RFM12B side)
#define CS 2 // SPI SS (chip select)
#define NIRQ 2 // (PORTD)

/* IO CONTROL */
#define HI(x) PORTB |= (1<<(x))
#define LO(x) PORTB &= ~(1<<(x))


/* LED */
#define LED 6
#define LED_OFF() PORTD &= ~(1<<LED)
#define LED_ON() PORTD |= (1<<LED)

/* USART */
//#define BAUDRATE 25 // 19200 at 8MHz

void portInit() {
	HI(CS);
	HI(SDI);
	LO(SCK);
	DDRB = (1<<CS) | (1<<SDI) | (1<<SCK);
	DDRD = (1<<LED);
}

unsigned int writeCmd(unsigned int cmd) {
	unsigned char i;
	unsigned int recv;
	recv = 0;
	LO(SCK);
	LO(CS);
	
	for(i=0; i<16; i++) {
		if(cmd&0x8000) HI(SDI); else LO(SDI);
		HI(SCK);
		recv<<=1;
		if( PINB&(1<<SDO) ) {
			recv|=0x0001;
		}
		LO(SCK);
		cmd<<=1;
	}
	HI(CS);
	return recv;
}


/* 
void rsInit(unsigned char baud) {
	UBRRL = baud;
	UCSRC = (1<<UCSZ0) | (1<<UCSZ1); // 8N1
	UCSRB = (1<<RXEN) | (1<<TXEN); // enable tx and rx
}
void rsSend(unsigned char data) {
	while( !(UCSRA & (1<<UDRE)));
	UDR = data;
}
unsigned char rsRecv() {
	while( !(UCSRA & (1<<RXC)));
	return UDR;
}
 */

void rfInit() {
	writeCmd(0x80E7); //EL,EF,868band,12.0pF
	writeCmd(0x8299); //er,!ebb,ET,ES,EX,!eb,!ew,DC (bug was here)
	writeCmd(0xA640); //freq select
	writeCmd(0xC647); //4.8kbps
	writeCmd(0x94A0); //VDI,FAST,134kHz,0dBm,-103dBm
	writeCmd(0xC2AC); //AL,!ml,DIG,DQD4
	writeCmd(0xCA81); //FIFO8,SYNC,!ff,DR (FIFO level = 8)
	writeCmd(0xCED4); //SYNC=2DD4;
	writeCmd(0xC483); //@PWR,NO RSTRIC,!st,!fi,OE,EN
	writeCmd(0x9850); //!mp,90kHz,MAX OUT
	writeCmd(0xCC17); //!OB1,!OB0, LPX,!ddy,DDIT,BW0
	writeCmd(0xE000); //NOT USE
	writeCmd(0xC800); //NOT USE
	writeCmd(0xC040); //1.66MHz,2.2V
}

/*
void rfSend(unsigned char data){
	while(PIND&(1<<NIRQ));
	writeCmd(0xB800 + data);
}
*/

unsigned char rfRecv() {
	unsigned int data;
	while(1) {
		data = writeCmd(0x0000);
		if ( (data&0x8000) ) {
			data = writeCmd(0xB000);
			return (data&0x00FF);
		}
	}
}
void FIFOReset() {
	writeCmd(0xCA81);
	writeCmd(0xCA83);
}

int main(void) {

	unsigned char data, i;
	LED_OFF();
	portInit();
	rfInit();
//	rsInit(BAUDRATE); 
	FIFOReset();
	while(1) {
		//waitForData();
		
		for (i=0; i<16; i++) {
			data = rfRecv();
			if (data == 0x30){
			LED_ON(); //delete this
			}
		}
		FIFOReset();
		LED_OFF();
	}
	return 0;
}



Here is the TX side:

/*
 * Atmega168 RFM12B rev.2.c
 *
 * Created: 4/25/2019 5:27:15 PM
 * Author : FablabDigiscope
 */ 

#include <avr/io.h>

/* RFM12B INTERFACE */
#define SCK 5 // SPI clock
#define SDO 4 // SPI Data output (RFM12B side)
#define SDI 3 // SPI Data input (RFM12B side)
#define CS 2 // SPI SS (chip select)
#define NIRQ 2 // (PORTD)

/* IO CONTROL */
#define HI(x) PORTB |= (1<<(x))
#define LO(x) PORTB &= ~(1<<(x))


/* LED */
#define LED 6
#define LED_OFF() PORTD &= ~(1<<LED)
#define LED_ON() PORTD |= (1<<LED)

void portInit() {
	HI(CS);
	HI(SDI);
	LO(SCK);
	DDRB = (1<<CS) | (1<<SDI) | (1<<SCK);
	DDRD = (1<<LED);
}

unsigned int writeCmd(unsigned int cmd) {
	unsigned char i;
	unsigned int recv;
	recv = 0;
	LO(SCK);
	LO(CS);
	
	for(i=0; i<16; i++) {
		if(cmd&0x8000) HI(SDI); else LO(SDI);
		HI(SCK);
		recv<<=1;
		if( PINB&(1<<SDO) ) {
			recv|=0x0001;
		}
		LO(SCK);
		cmd<<=1;
	}
	HI(CS);
	return recv;
}

void rfInit() {
	writeCmd(0x80E7); //EL,EF,868band,12.0pF
	writeCmd(0x8239); //!er,!ebb,ET,ES,EX,!eb,!ew,DC
	writeCmd(0xA640); //frequency select
	writeCmd(0xC647); //4.8kbps
	writeCmd(0x94A0); //VDI,FAST,134kHz,0dBm,-103dBm
	writeCmd(0xC2AC); //AL,!ml,DIG,DQD4
	writeCmd(0xCA81); //FIFO8,SYNC,!ff,DR
	writeCmd(0xCED4); //SYNC=2DD4,AG
	writeCmd(0xC483); //@PWR,NO RSTRIC,!st,!fi,OE,EN
	writeCmd(0x9850); //!mp,90kHz,MAX OUT
	writeCmd(0xCC17); //OB1,ACOB0, LPX,Iddy,CDDIT,CBW0
	writeCmd(0xE000); //NOT USED
	writeCmd(0xC800); //NOT USED
	writeCmd(0xC040); //1.66MHz,2.2V
}


void rfSend(unsigned char data){
	while(PIND&(1<<NIRQ));
	writeCmd(0xB800 + data);
}


int main() {
	volatile unsigned int i,j;
	asm("cli");
	for(i=0;i<1000;i++)for(j=0;j<123;j++);
	portInit();
	rfInit();
	while(1){
		LED_ON();
		writeCmd(0x0000);
		rfSend(0xAA); // PREAMBLE
		rfSend(0xAA);
		rfSend(0xAA);
		rfSend(0x2D); // SYNC
		rfSend(0xD4);
		for(i=0; i<16; i++) {
			rfSend(0x30+i);
		}
		rfSend(0xAA); // DUMMY BYTES
		rfSend(0xAA);
		rfSend(0xAA);
		LED_OFF();
		for(i=0; i<10000; i++) // some not very
		for(j=0; j<123; j++); // sophisticated delay
	}
}


And here’s a photo of the two modules communicating when each is battery powered from two 1.5 watch battery cells. They continue to be able to communicate after a shortish but not insignificant walk to the coffee machine (50 meters or so).

Here is the code for one RFM12B taking an analog measurement and sending it to the other which is printing the result via USART to a serial port.

TX side:


/*
 * Atmega168 RFM12B TX rev.2.c
 *
 * Created: 4/25/2019 5:27:15 PM
 * Author : FablabDigiscope
 */ 

#include <avr/io.h>

/* RFM12B INTERFACE */
#define SCK 5 // SPI clock
#define SDO 4 // SPI Data output (RFM12B side)
#define SDI 3 // SPI Data input (RFM12B side)
#define CS 2 // SPI SS (chip select)
#define NIRQ 2 // (PORTD)

/* IO CONTROL */
#define HI(x) PORTB |= (1<<(x))
#define LO(x) PORTB &= ~(1<<(x))


/* LED */
#define LED 6
#define LED_OFF() PORTD &= ~(1<<LED)
#define LED_ON() PORTD |= (1<<LED)

void analogInit() {
	ADMUX |= (1 << REFS0); // AREF ref voltage connected to power
	// PC0 input select
	ADCSRA |= (1 << ADPS2) | (1 << ADPS0); // set clock to 32 divisions for 8MHz
	ADCSRA |= (1 << ADEN); /* enable ADC */
	
	
}

unsigned int analogRead() {
	uint16_t adcValue; //16 bit variable because the ADC on the Attiny84 is 10 bits.
	ADCSRA |= (1 << ADSC); /* start conversion */
	adcValue = ADC; /* store high byte into adcValue */
	return adcValue;
}


void portInit() {
	HI(CS);
	HI(SDI);
	LO(SCK);
	DDRB = (1<<CS) | (1<<SDI) | (1<<SCK);
	DDRD = (1<<LED);
}

unsigned int writeCmd(unsigned int cmd) {
	unsigned char i;
	unsigned int recv;
	recv = 0;
	LO(SCK);
	LO(CS);
	
	for(i=0; i<16; i++) {
		if(cmd&0x8000) HI(SDI); else LO(SDI);
		HI(SCK);
		recv<<=1;
		if( PINB&(1<<SDO) ) {
			recv|=0x0001;
		}
		LO(SCK);
		cmd<<=1;
	}
	HI(CS);
	return recv;
}

void rfInit() {
	writeCmd(0x80E7); //EL,EF,868band,12.0pF
	writeCmd(0x8239); //!er,!ebb,ET,ES,EX,!eb,!ew,DC
	writeCmd(0xA640); //frequency select
	writeCmd(0xC647); //4.8kbps
	writeCmd(0x94A0); //VDI,FAST,134kHz,0dBm,-103dBm
	writeCmd(0xC2AC); //AL,!ml,DIG,DQD4
	writeCmd(0xCA81); //FIFO8,SYNC,!ff,DR
	writeCmd(0xCED4); //SYNC=2DD4,AG
	writeCmd(0xC483); //@PWR,NO RSTRIC,!st,!fi,OE,EN
	writeCmd(0x9850); //!mp,90kHz,MAX OUT
	writeCmd(0xCC17); //OB1,ACOB0, LPX,Iddy,CDDIT,CBW0
	writeCmd(0xE000); //NOT USED
	writeCmd(0xC800); //NOT USED
	writeCmd(0xC040); //1.66MHz,2.2V
}


void rfSend(unsigned char data){
	while(PIND&(1<<NIRQ));
	writeCmd(0xB800 + data);
}


int main() {
	volatile unsigned int i,j;
	asm("cli");
	for(i=0;i<1000;i++)for(j=0;j<123;j++);
	portInit();
	analogInit();
	rfInit();
	while(1){
		LED_ON();
		writeCmd(0x0000);
		rfSend(0xAA); // PREAMBLE
		rfSend(0xAA);
		rfSend(0xAA);
		rfSend(0x2D); // SYNC
		rfSend(0xD4);
		for(i=0; i<16; i++) {
			rfSend(analogRead());
		}
		rfSend(0xAA); // DUMMY BYTES
		rfSend(0xAA);
		rfSend(0xAA);
		LED_OFF();
		for(i=0; i<10000; i++) // some not very
		for(j=0; j<123; j++); // sophisticated delay
	}
}

RX side:


/*
 * Atmega168 RFM12B rev.2 RX.c
 *
 * Created: 4/30/2019 2:56:31 PM
 * Author : FablabDigiscope
 */ 


#include <avr/io.h>

/* RFM12B INTERFACE */
#define SCK 5 // SPI clock
#define SDO 4 // SPI Data output (RFM12B side)
#define SDI 3 // SPI Data input (RFM12B side)
#define CS 2 // SPI SS (chip select)
#define NIRQ 2 // (PORTD)

/* IO CONTROL */
#define HI(x) PORTB |= (1<<(x))
#define LO(x) PORTB &= ~(1<<(x))


/* LED */
#define LED 6
#define LED_OFF() PORTD &= ~(1<<LED)
#define LED_ON() PORTD |= (1<<LED)

/* USART */
#define BAUDRATE 25 // 19200 at 8MHz

void portInit() {
	HI(CS);
	HI(SDI);
	LO(SCK);
	DDRB = (1<<CS) | (1<<SDI) | (1<<SCK);
	DDRD = (1<<LED);
}



unsigned int writeCmd(unsigned int cmd) {
	unsigned char i;
	unsigned int recv;
	recv = 0;
	LO(SCK);
	LO(CS);
	
	for(i=0; i<16; i++) {
		if(cmd&0x8000) HI(SDI); else LO(SDI);
		HI(SCK);
		recv<<=1;
		if( PINB&(1<<SDO) ) {
			recv|=0x0001;
		}
		LO(SCK);
		cmd<<=1;
	}
	HI(CS);
	return recv;
}

void rsInit(unsigned char baud) {
	UBRR0L = baud;
	UCSR0C = (1<<UCSZ00) | (1<<UCSZ01); // 8N1
	UCSR0B = (1<<RXEN0) | (1<<TXEN0); // enable tx and rx
}

void rsSend(unsigned char data) {
	while( !(UCSR0A & (1<<UDRE0)));
	UDR0 = data;
}


unsigned char rsRecv() {
	while( !(UCSR0A & (1<<RXC0)));
	return UDR0;
}

/*    FOR ATTINY 2313
void rsInit(unsigned char baud) {
	UBRRL = baud;
	UCSRC = (1<<UCSZ0) | (1<<UCSZ1); // 8N1
	UCSRB = (1<<RXEN) | (1<<TXEN); // enable tx and rx
}
void rsSend(unsigned char data) {
	while( !(UCSRA & (1<<UDRE)));
	UDR = data;
}
unsigned char rsRecv() {
	while( !(UCSRA & (1<<RXC)));
	return UDR;
}
 */

void rfInit() {
	writeCmd(0x80E7); //EL,EF,868band,12.0pF
	writeCmd(0x8299); //er,!ebb,ET,ES,EX,!eb (low batt detector disabled),!ew,DC (bug was here)
	writeCmd(0xA640); //freq select
	writeCmd(0xC647); //4.8kbps
	writeCmd(0x94A0); //VDI,FAST,134kHz,0dBm,-103dBm
	writeCmd(0xC2AC); //AL,!ml,DIG,DQD4
	writeCmd(0xCA81); //FIFO8,SYNC,!ff,DR (FIFO level = 8)
	writeCmd(0xCED4); //SYNC=2DD4;
	writeCmd(0xC483); //@PWR,NO RSTRIC,!st,!fi,OE,EN
	writeCmd(0x9850); //!mp,90kHz,MAX OUT
	writeCmd(0xCC17); //!OB1,!OB0, LPX,!ddy,DDIT,BW0
	writeCmd(0xE000); //NOT USE
	writeCmd(0xC800); //NOT USE
	writeCmd(0xC040); //1.66MHz,2.2V
}


void rfSend(unsigned char data){
	while(PIND&(1<<NIRQ));
	writeCmd(0xB800 + data);
}


unsigned char rfRecv() {
	unsigned int data;
	while(1) {
		data = writeCmd(0x0000); // I think I would add here responses to Status 
		if ( (data&0x8000) ) {
			data = writeCmd(0xB000);
			return (data&0x00FF);
		}
	}
}
void FIFOReset() {
	writeCmd(0xCA81);
	writeCmd(0xCA83);
}

int main(void) {

	unsigned char data, i;
	LED_OFF();
	portInit();
	rfInit();
	rsInit(BAUDRATE); 
	//analogInit();
	FIFOReset();
	while(1) {
		//waitForData();
	for (i=0; i<16; i++) {
		data = rfRecv();
		rsSend(data);
		}
		FIFOReset();
		LED_OFF();
	}
	return 0;
}