RFM70 Arduino Shield

RFM70 ist ein billiger (3.5 bis 4 Euro) Sender/Empfänger, der im 2.4GHz Band arbeitet

Datenblatt

http://www.hoperf.com/rf_fsk/rfm70.htm


Features:

  •  2400-2483.5 MHz ISM band operation

  •  Support 1 and 2 Mbps air data rate

  •  Programmable output power
    (-40dBm to 5dBm)

  •  Low power consumption

  •  Variable payload length from 1 to 32bytes

  •  Automatic packet processing

  •  6 data pipes for 1:6 star networks

  •  1.9V to 3.6V power supply
    Control Signals up to 5V

  •  4-pin SPI interface with maximum 8 MHz
    clock rate

  •  DIP-8pin and SMD-8pin Package

Beispielcode (Original auf http://www.ise.pw.edu.pl/~wzab/wireless_guitar_system/index.html)

Sender

/* Arduino Duemilanove    kner 2011
    ein kleines erstes Testprogramm
*/

extern "C" void __cxa_pure_virtual(void); //for C++ defines

void __cxa_pure_virtual(void) {};


#include "../../libraries/Arduino328p/WProgram.h" //import main Arduino header file
#include "../../libraries/Arduino328p/Spi.h" //import Arduino Spi function
#include "../../libraries/Arduino328p/rfm70.h"
#include <avr/io.h>

#define ACTIVATE 0x50
#define SWITCH_BANK 0x53
#define READ_REGISTER 000A AAAA
#define READ_STATUS_REGISTER 7
#define NOP 0xFF
#define FLUSH_TX 0b11100001

const PROGMEM uint8_t cmd_activate[]={0x50,0x73};
const PROGMEM uint8_t cmd_tog1[]={0xd9 | 0x06, 0x9e, 0x86, 0x0b}; //assosciated with set1[4]!
const static PROGMEM uint8_t cmd_tog2[]={0xd9 & ~0x06, 0x9e, 0x86, 0x0b};
const static PROGMEM uint8_t cmd_flush_rx[]={0xe2,0x00};
const static PROGMEM uint8_t cmd_flush_tx[]={0xe1,0x00};
const static PROGMEM uint8_t cmd_switch_cfg[]={0x50,0x53};

const static PROGMEM uint8_t adr0[]={0x21,'K','N'};   //
//static PROGMEM uint8_t adr1[]={SET_NUMBER,'W','G'};



void SendString(uint8_t* s,uint8_t size);
int main(){

    uint16_t dataNr=0;
    init();
    rfm70_hw_setup();
    set_ce(0);
    Serial.begin(9600);
    Serial.println("RFM70 Transmitter Kner 2011");
    delay(100);

    //switch RFM70 to Standby;  all SPI Registers available


    Spi.mode(1<<SPR0);                // set SPI clock to system clock / 16
    Spi.transfer(FLUSH_TX);

    Serial.println("Kennung:");
    switch_cfg(1);

    uint8_t readBuffer[4];
    read_reg_pbuf(8,readBuffer,sizeof(readBuffer)); //read ID from RFM70[8]
    SendString(readBuffer,4);
    switch_cfg(0);
    Serial.println("start init");
    rfm70_init(0);
    Serial.println("end init");
    uint8_t status = read_reg(29);
    Serial.print(status,HEX);


    _delay_ms(500);
    set_ce(1);
    uint8_t b1=read_reg(0x07);
    write_pcmd(cmd_switch_cfg,sizeof(cmd_switch_cfg));
    uint8_t b2=read_reg(0x07);
    if ((b1 ^ b2) != 0x80){
          Serial.println("Umschalten der Registerbank funktioniert nicht");
          exit(1);
    }
    rfm70_init(0x50);  //channel = 0x50
    switch_to_tx_mode();


    while(1){
      b1=read_reg(0x07);
      if(b1 & 0x10) {
          //Maximum number of retransmissions occured!
          //set_ce(0);
          write_reg(0x07,0x10); //clear maximum-number-of-retransmits-interrupt
          //set_ce(1); //retry transfer!
          Serial.println("Max. Anzahl von Retransmits");
      }
      if((b1 & 0x01) == 0) { //TX Fifo not full
        Spi.setSS(0);
        Spi.transfer(0xa0); //Start of the packet!
        for (uint8_t i=0; i<32; i++){
           Spi.transfer(dataNr%256);
           dataNr++;
        }
        Spi.setSS(1);  //end of Data
      }
      else {
        Serial.print("Tx Fifo full DataNr:");
        Serial.println(dataNr,DEC);

      }
    }
}
void SendString(uint8_t* s,uint8_t size){
    for( int i=0; i<size; i++){
      Serial.print(s[i], HEX);
      }

}

Empfänger

/* Arduino Duemilanove    kner 2011
   RFM70 Modul Receiver
*/

extern "C" void __cxa_pure_virtual(void); //for C++ defines

void __cxa_pure_virtual(void) {};


#include "../../libraries/Arduino328p/WProgram.h" //import main Arduino header file
#include "../../libraries/Arduino328p/Spi.h" //import Arduino Spi function
#include "../../libraries/Arduino328p/rfm70.h"
#include <avr/io.h>

#define ACTIVATE 0x50
#define SWITCH_BANK 0x53
#define READ_REGISTER 000A AAAA
#define READ_STATUS_REGISTER 7
#define NOP 0xFF
#define FLUSH_TX 0b11100001

const PROGMEM uint8_t cmd_activate[]={0x50,0x73};
const PROGMEM uint8_t cmd_tog1[]={0xd9 | 0x06, 0x9e, 0x86, 0x0b}; //assosciated with set1[4]!
const static PROGMEM uint8_t cmd_tog2[]={0xd9 & ~0x06, 0x9e, 0x86, 0x0b};
const static PROGMEM uint8_t cmd_flush_rx[]={0xe2,0x00};
const static PROGMEM uint8_t cmd_flush_tx[]={0xe1,0x00};
const static PROGMEM uint8_t cmd_switch_cfg[]={0x50,0x53};

const static PROGMEM uint8_t adr0[]={0x21,'K','N'};   //
//static PROGMEM uint8_t adr1[]={SET_NUMBER,'W','G'};



void SendString(uint8_t* s,uint8_t size);

ISR(INT0_vect, ISR_BLOCK)
{
  Serial.println("juhuu, endlich ein Interrupt");
  //Disable the INT0 interrupt
  EIMSK &= ~(1<<INT0);
  EIFR  = (1<<INTF0);

  while(1) {  //get all packets: reading all bytes from rx fifo stops this loop
    write_reg(0x7,0x40);  //clear rx interrupt flag
    if((read_reg(0x17) & 0x01) == 1) { //only one more byte in buffer
      break;
    }
    Spi.setSS(0);
    Spi.transfer(0x61);         //read rx payload
    for (uint8_t i=0; i<32; i++){
      uint8_t pkt=Spi.transfer(0x00); //read packet number
      Serial.println(pkt,HEX);
    }
    Spi.setSS(1);

  }
  EIMSK |= (1<<INT0); //enable again
}
int main(){
    init();
    EIMSK |= (1<<INT0);   //allow Interrupt
    //PD2 ist Input (INT0); no Pullup needed
    rfm70_hw_setup();  //CE=OUTPUT
    set_ce(0);
    Serial.begin(9600);
    Serial.println("RFM70 Receiver Kner 2011");
    delay(100);

    //switch RFM70 to Standby;  all SPI Registers available


    Spi.mode(1<<SPR0);                // set SPI clock to system clock / 16
    Spi.transfer(FLUSH_TX);

    Serial.println("Kennung:");
    switch_cfg(1);

    uint8_t readBuffer[4];
    read_reg_pbuf(8,readBuffer,sizeof(readBuffer)); //read ID from RFM70[8]
    SendString(readBuffer,4);
    switch_cfg(0);
    Serial.println("start init");
    rfm70_init(0);
    Serial.println("end init");
    uint8_t status = read_reg(29);
    Serial.print(status,HEX);


    _delay_ms(500);
    set_ce(0);
    _delay_us(10);
    write_pcmd(cmd_flush_tx,sizeof(cmd_flush_tx));
    write_pcmd(cmd_flush_rx,sizeof(cmd_flush_rx));
    write_reg(7,0x70); //cancel all possible interrupts

    set_ce(1);
    uint8_t b1=read_reg(0x07);
    write_pcmd(cmd_switch_cfg,sizeof(cmd_switch_cfg));
    uint8_t b2=read_reg(0x07);
    if ((b1 ^ b2) != 0x80){
          Serial.println("Umschalten der Registerbank funktioniert nicht");
          exit(1);
    }
    rfm70_init(0x50);  //channel = 0x50
    switch_to_rx_mode();

    sei();
    while(1){


    }
}
void SendString(uint8_t* s,uint8_t size){
    for( int i=0; i<size; i++){
      Serial.print(s[i], HEX);
      }

}

rfm70.cpp Bibliothek

/* FREEWARE
   Original: Wojciech M. Zabolotny wzab<at>ise.pw.edu.pl)
   kner 2011
 */
#include "rfm70.h"
#include "Spi.h"

#ifdef PROGMEM
#undef PROGMEM
#define PROGMEM __attribute__((section(".progmem.data")))
#endif

static PROGMEM uint8_t cmd_activate[]={0x50,0x73};
static PROGMEM uint8_t cmd_tog1[]={0xd9 | 0x06, 0x9e, 0x86, 0x0b}; //assosciated with set1[4]!
static PROGMEM uint8_t cmd_tog2[]={0xd9 & ~0x06, 0x9e, 0x86, 0x0b};
static PROGMEM uint8_t cmd_flush_rx[]={0xe2,0x00};
static PROGMEM uint8_t cmd_flush_tx[]={0xe1,0x00};
static PROGMEM uint8_t cmd_switch_cfg[]={0x50,0x53};

static PROGMEM uint8_t adr0[]={0x21,'K','N'};   //
//static PROGMEM uint8_t adr1[]={SET_NUMBER,'W','G'};


static PROGMEM uint8_t set1[][4]={
  {0x40, 0x4b, 0x01, 0xe2},//0
  {0xc0, 0x4b, 0x00, 0x00},
  {0xd0, 0xfc, 0x8c, 0x02},//2
  {0x99, 0x00, 0x39, 0x41},
  {0xd9, 0x9e, 0x86, 0x0b},//4 #?? d9 oder f9? POWER
  {0x24, 0x06, 0x7f, 0xa6},
  {0x00, 0x00, 0x00, 0x00},//6
  {0x00, 0x00, 0x00, 0x00},
  {0x00, 0x00, 0x00, 0x00},//8
  {0x00, 0x00, 0x00, 0x00},
  {0x00, 0x00, 0x00, 0x00},//10
  {0x00, 0x00, 0x00, 0x00},
  {0x00, 0x12, 0x73, 0x00},//12
  {0x36, 0xB4, 0x80, 0x00},
};
static PROGMEM uint8_t set1_14[]={0x41,0x20,0x08,0x04,0x81,0x20,0xCF,0xF7,0xFE,0xFF,0xFF};
static PROGMEM uint8_t set0[][2]={
  {0,0x3F}, //mask RX_DR\TX_DS\MAX_RT (we do not use IRQ!),Enable CRC ,2byte,POWER UP,PRX
  {1,0x01}, //Enable AACK only in pipe 0! Was:{1,0x3F}, //Enable auto acknowledgement data pipe5\4\3\2\1\0
  {2,0x01}, //Enable only RX pipe 0 //Enable RX Addresses pipe5\4\3\2\1\0
  {3,0x01}, //RX/TX address field width 3 bytes
  {4,0x0f}, //up to 15 retransmissions 250#,A5#(Bs delay! Was: {4,0xff}, //auto retransmission dalay (4000us),auto retransmission count(15)
  {5,0x17}, // ?????? (5,0x17), #32 channel
  {6,0x3f}, //6,0x17), #air data rate-1M,out power 0dbm,setup LNA gain
  {7,0x07}, //
  {8,0x00}, //
  {9,0x00}, //
  {12,0xc3},// only LSB Receive address data pipe 2, MSB bytes is equal to RX_ADDR_P1[39:8]
  {13,0xc4},// only LSB Receive address data pipe 3, MSB bytes is equal to RX_ADDR_P1[39:8]
  {14,0xc5},// only LSB Receive address data pipe 4, MSB bytes is equal to RX_ADDR_P1[39:8]
  {15,0xc6},// only LSB Receive address data pipe 5, MSB bytes is equal to RX_ADDR_P1[39:8]
  {17,0x20},// Number of bytes in RX payload in data pipe0(32 byte)
  {18,0x20},// Number of bytes in RX payload in data pipe1(32 byte)
  {19,0x20},// Number of bytes in RX payload in data pipe2(32 byte)
  {20,0x20},// Number of bytes in RX payload in data pipe3(32 byte)
  {21,0x20},// Number of bytes in RX payload in data pipe4(32 byte)
  {22,0x20},// Number of bytes in RX payload in data pipe5(32 byte)
  {23,0x00},// fifo status
  {28,0x00},// No dynamic payload length! {28,0x3F},// Enable dynamic payload length data pipe5\4\3\2\1\0
  {29,0x07},// Enables Dynamic Payload Length,Enables Payload with ACK,Enables the W_TX_PAYLOAD_NOACK command
};


void write_pcmd(const uint8_t * cmd, uint8_t len)
{
  Spi.setSS(1);
  Spi.setSS(0);
  while(len--) {
    Spi.transfer(pgm_read_byte(cmd++));
  };
  Spi.setSS(1);
}

void write_reg(uint8_t reg, uint8_t val)
{
  Spi.setSS(1);
  Spi.setSS(0);
  Spi.transfer(reg | 0x20);
  Spi.transfer(val);
  Spi.setSS(1);
}
__attribute__ ((always_inline))

uint8_t read_reg(uint8_t reg)
{
  uint8_t res;
  Spi.setSS(0);
  Spi.transfer(reg);
  res=Spi.transfer(0);
  Spi.setSS(1);
  return res;
}

void switch_cfg(uint8_t cnum)
{
  uint8_t tmp = read_reg(0x07) & 0x80;
  if(cnum) {
    if(!tmp)
      write_pcmd(cmd_switch_cfg,sizeof(cmd_switch_cfg));
  } else {
    if(tmp)
      write_pcmd(cmd_switch_cfg,sizeof(cmd_switch_cfg));
  }
}

void switch_to_rx_mode(void)
{
  uint8_t val;
  write_pcmd(cmd_flush_rx,sizeof(cmd_flush_rx));
  val = read_reg(0x07);
  write_reg(0x07,val);
  set_ce(0);
  val=read_reg(0x00);
  val |= 0x01;
  write_reg(0x00,val);
  set_ce(1);
}

void switch_to_tx_mode(void)
{
  uint8_t val;
  write_pcmd(cmd_flush_tx,sizeof(cmd_flush_tx));
  set_ce(0);
  val=read_reg(0x00);
  val &= ~0x01;
  write_reg(0x00,val);
  set_ce(1);
}

void set_channel(uint8_t cnum)
{
  write_reg(5, cnum);
}


void write_reg_pbuf(uint8_t reg, uint8_t * buf, uint8_t len)
{
  Spi.setSS(1);
  Spi.setSS(0);
  Spi.transfer(reg | 0x20);
  while(len--)
    Spi.transfer(pgm_read_byte(buf++));
  Spi.setSS(1);
}
void read_reg_pbuf(uint8_t reg, uint8_t * buf, uint8_t len)
//len Byte von Register reg lesen
{
  Spi.setSS(1);
  Spi.setSS(0);
  Spi.transfer(reg);
  while(len--){
    *buf=Spi.transfer(0);
    buf++;
  }
  Spi.setSS(1);
}

uint8_t send_packet(uint8_t * data, uint8_t len)
{
   uint8_t status;
   switch_to_tx_mode();
   status = read_reg(0x17); //FIFO_STATUS
   if (status & 0x20) return 0xff; //Error?
   Spi.setSS(0);
   Spi.transfer(0xb0);
   while(len--) {
     Spi.transfer(*(data++));
   }
   Spi.setSS(1);
   return 0;
}

void rfm70_init(uint8_t channel)
{
  uint8_t i;
  switch_cfg(0);
  for(i=0;i<20;i++) {
    write_reg(pgm_read_byte(&set0[i][0]),pgm_read_byte(&set0[i][1]));
    }
  write_reg_pbuf(10,adr0,sizeof(adr0)); //PIPE 0 read address
  //write_reg_pbuf(11,adr1,sizeof(adr1)); // PIPE 1 not used!
  write_reg_pbuf(16,adr0,sizeof(adr0));
  set_channel(channel);
  if(!read_reg(29))
    write_pcmd(cmd_activate,sizeof(cmd_activate));
  write_reg(pgm_read_byte(&set0[22][0]),pgm_read_byte(&set0[22][1]));
  write_reg(pgm_read_byte(&set0[21][0]),pgm_read_byte(&set0[21][1]));
  switch_cfg(1);
  for(i=0;i<14;i++) {
    write_reg_pbuf(i,set1[i],sizeof(set1[i]));
    }
  write_reg_pbuf(14,set1_14,sizeof(set1_14));
  write_reg_pbuf(4,cmd_tog1,sizeof(cmd_tog1));
  write_reg_pbuf(4,cmd_tog2,sizeof(cmd_tog2));
  //delay 50 ms
  _delay_ms(50);
  switch_cfg(0);
  switch_to_rx_mode();
}

rfm70.h

#ifndef _RFM70_H_
#define _RFM70_H_



/* Includes: */
#include <ctype.h>
#include <avr/io.h>
#include <avr/wdt.h>
#include <avr/power.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <util/delay.h>
#include "Spi.h"


#define PORT_CE PORTD
#define DDR_CE DDRD
#define PIN_CE 3



static inline void set_ce(uint8_t val)
{
  if(val)
    PORT_CE |= (1<<PIN_CE);
  else
    PORT_CE &= ~(1<<PIN_CE);
}

static inline void rfm70_hw_setup(void)
{
  DDR_CE |= (1<<PIN_CE);
}


void switch_cfg(uint8_t cnum); // switch to Register Bank cnum
void write_reg(uint8_t reg, uint8_t val);
uint8_t read_reg(uint8_t reg);
void write_pcmd(const uint8_t * cmd, uint8_t len);                    //Kommando und Parameter schreiben
void write_reg_pbuf(uint8_t reg, uint8_t * buf, uint8_t len);   // auf Register reg die Daten in buf schreiben
void read_reg_pbuf(uint8_t reg, uint8_t * buf, uint8_t len);
void rfm70_init(uint8_t channel);
void switch_to_tx_mode(void);

void switch_to_rx_mode(void);
void show_error(uint8_t msg);
void set_channel(uint8_t cnum);



#endif