RFM70 Arduino Shield
RFM70 ist ein billiger (3.5 bis 4 Euro) Sender/Empfänger, der im 2.4GHz Band arbeitet
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 5V4-pin SPI interface with maximum 8 MHz
clock rateDIP-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