diff --git a/README.md b/README.md index a71fb6b..cc7b97f 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ Design Goals: This library is designed to be... -* More complianct with the manufacturer specified operation of the chip +* More compliant with the manufacturer specified operation of the chip * More reliable and feature rich * Easy for beginners to use * Consumed with a public interface that's similiar to other Arduino standard libraries @@ -14,6 +14,7 @@ April 2014: Optimization nearing completion * Changes to read() functionality have increased reliability and response * Extended timeout periods have been added to aid in noisy or otherwise unreliable environments * Delays have been removed where possible to ensure maximum efficiency +* Arduino Due fully supported with extended SPI functions * More! See the links below and class documentation for more info. Please refer to: diff --git a/RF24.cpp b/RF24.cpp index e171883..5297c63 100644 --- a/RF24.cpp +++ b/RF24.cpp @@ -12,29 +12,29 @@ /****************************************************************************/ -void RF24::csn(int mode) +void RF24::csn(bool mode) { // Minimum ideal SPI bus speed is 2x data rate // If we assume 2Mbs data rate and 16Mhz clock, a // divider of 4 is the minimum we want. // CLK:BUS 8Mhz:2Mhz, 16Mhz:4Mhz, or 20Mhz:5Mhz #ifdef ARDUINO - #if !defined( __AVR_ATtiny85__ ) && !defined( __AVR_ATtiny84__) - SPI.setBitOrder(MSBFIRST); - SPI.setDataMode(SPI_MODE0); - #ifdef __arm__ // Shouldn't need to set the clock divider on DUE - SPI.setClockDivider(21); - #else - SPI.setClockDivider(SPI_CLOCK_DIV4); - #endif + #if !defined( __AVR_ATtiny85__ ) && !defined( __AVR_ATtiny84__) && !defined (__arm__) + SPI.setBitOrder(MSBFIRST); + SPI.setDataMode(SPI_MODE0); + SPI.setClockDivider(SPI_CLOCK_DIV2); + #endif #endif + +#ifndef __arm__ + digitalWrite(csn_pin,mode); #endif - digitalWrite(csn_pin,mode); + } /****************************************************************************/ -void RF24::ce(int level) +void RF24::ce(bool level) { digitalWrite(ce_pin,level); } @@ -45,13 +45,23 @@ uint8_t RF24::read_register(uint8_t reg, uint8_t* buf, uint8_t len) { uint8_t status; +#if defined (__arm__) + status = SPI.transfer(csn_pin, R_REGISTER | ( REGISTER_MASK & reg ), SPI_CONTINUE ); + while ( len-- > 1 ){ + *buf++ = SPI.transfer(csn_pin,0xff, SPI_CONTINUE); + } + *buf++ = SPI.transfer(csn_pin,0xff); + +#else csn(LOW); status = SPI.transfer( R_REGISTER | ( REGISTER_MASK & reg ) ); - while ( len-- ) + while ( len-- ){ *buf++ = SPI.transfer(0xff); - + } csn(HIGH); +#endif + return status; } @@ -59,11 +69,18 @@ uint8_t RF24::read_register(uint8_t reg, uint8_t* buf, uint8_t len) uint8_t RF24::read_register(uint8_t reg) { + + #if defined (__arm__) + SPI.transfer(csn_pin, R_REGISTER | ( REGISTER_MASK & reg ) , SPI_CONTINUE); + uint8_t result = SPI.transfer(csn_pin,0xff); + #else csn(LOW); SPI.transfer( R_REGISTER | ( REGISTER_MASK & reg ) ); uint8_t result = SPI.transfer(0xff); csn(HIGH); + #endif + return result; } @@ -73,6 +90,14 @@ uint8_t RF24::write_register(uint8_t reg, const uint8_t* buf, uint8_t len) { uint8_t status; + #if defined (__arm__) + status = SPI.transfer(csn_pin, W_REGISTER | ( REGISTER_MASK & reg ), SPI_CONTINUE ); + while ( len-- > 1){ + SPI.transfer(csn_pin,*buf++, SPI_CONTINUE); + } + SPI.transfer(csn_pin,*buf++); + #else + csn(LOW); status = SPI.transfer( W_REGISTER | ( REGISTER_MASK & reg ) ); while ( len-- ) @@ -80,6 +105,8 @@ uint8_t RF24::write_register(uint8_t reg, const uint8_t* buf, uint8_t len) csn(HIGH); + #endif + return status; } @@ -91,11 +118,18 @@ uint8_t RF24::write_register(uint8_t reg, uint8_t value) IF_SERIAL_DEBUG(printf_P(PSTR("write_register(%02x,%02x)\r\n"),reg,value)); + #if defined (__arm__) + status = SPI.transfer(csn_pin, W_REGISTER | ( REGISTER_MASK & reg ), SPI_CONTINUE); + SPI.transfer(csn_pin,value); + #else + csn(LOW); status = SPI.transfer( W_REGISTER | ( REGISTER_MASK & reg ) ); SPI.transfer(value); csn(HIGH); + #endif + return status; } @@ -112,6 +146,31 @@ uint8_t RF24::write_payload(const void* buf, uint8_t len) //printf("[Writing %u bytes %u blanks]",data_len,blank_len); + #if defined (__arm__) + + status = SPI.transfer(csn_pin, W_TX_PAYLOAD , SPI_CONTINUE); + + if(data_len == 32 || dynamic_payloads_enabled){ + while ( data_len-- > 1){ + SPI.transfer(csn_pin,*current++, SPI_CONTINUE); + } + SPI.transfer(csn_pin,*current++); + }else{ + while ( data_len-- ){ + SPI.transfer(csn_pin,*current++, SPI_CONTINUE); + } + } + + if(blank_len){ + while ( blank_len-- > 1){ + SPI.transfer(csn_pin,0, SPI_CONTINUE); + } + SPI.transfer(csn_pin,0); + } + + + #else + csn(LOW); status = SPI.transfer( W_TX_PAYLOAD ); while ( data_len-- ) @@ -120,6 +179,8 @@ uint8_t RF24::write_payload(const void* buf, uint8_t len) SPI.transfer(0); csn(HIGH); + #endif + return status; } @@ -135,6 +196,30 @@ uint8_t RF24::read_payload(void* buf, uint8_t len) //printf("[Reading %u bytes %u blanks]",data_len,blank_len); + #if defined (__arm__) + + status = SPI.transfer(csn_pin, R_RX_PAYLOAD, SPI_CONTINUE ); + + if(data_len == 32 || dynamic_payloads_enabled){ + while ( data_len-- > 1 ){ + *current++ = SPI.transfer(csn_pin,0xff, SPI_CONTINUE); + } + *current++ = SPI.transfer(csn_pin,0xff); + }else{ + while ( data_len-- > 1 ){ + *current++ = SPI.transfer(csn_pin,0xff, SPI_CONTINUE); + } + + } + if(blank_len){ + while ( blank_len-- ){ + SPI.transfer(csn_pin,0xff, SPI_CONTINUE); + } + SPI.transfer(csn_pin,0xff); + } + + #else + csn(LOW); status = SPI.transfer( R_RX_PAYLOAD ); while ( data_len-- ) @@ -143,6 +228,8 @@ uint8_t RF24::read_payload(void* buf, uint8_t len) SPI.transfer(0xff); csn(HIGH); + #endif + return status; } @@ -152,10 +239,15 @@ uint8_t RF24::flush_rx(void) { uint8_t status; + #if defined (__arm__) + status = SPI.transfer(csn_pin, FLUSH_RX ); + #else csn(LOW); status = SPI.transfer( FLUSH_RX ); csn(HIGH); + #endif + return status; } @@ -165,10 +257,16 @@ uint8_t RF24::flush_tx(void) { uint8_t status; + #if defined (__arm__) + status = SPI.transfer(csn_pin, FLUSH_TX ); + #else + csn(LOW); status = SPI.transfer( FLUSH_TX ); csn(HIGH); + #endif + return status; } @@ -178,9 +276,14 @@ uint8_t RF24::get_status(void) { uint8_t status; + #if defined (__arm__) + status = SPI.transfer(csn_pin, NOP ); + #else + csn(LOW); status = SPI.transfer( NOP ); csn(HIGH); + #endif return status; } @@ -305,8 +408,8 @@ static const char * const rf24_crclength_e_str_P[] PROGMEM = { }; static const char rf24_pa_dbm_e_str_0[] PROGMEM = "PA_MIN"; static const char rf24_pa_dbm_e_str_1[] PROGMEM = "PA_LOW"; -static const char rf24_pa_dbm_e_str_2[] PROGMEM = "LA_MED"; -static const char rf24_pa_dbm_e_str_3[] PROGMEM = "PA_HIGH"; +static const char rf24_pa_dbm_e_str_2[] PROGMEM = "PA_HIGH"; +static const char rf24_pa_dbm_e_str_3[] PROGMEM = "PA_MAX"; static const char * const rf24_pa_dbm_e_str_P[] PROGMEM = { rf24_pa_dbm_e_str_0, rf24_pa_dbm_e_str_1, @@ -330,10 +433,17 @@ void RF24::printDetails(void) print_byte_register(PSTR("CONFIG"),CONFIG); print_byte_register(PSTR("DYNPD/FEATURE"),DYNPD,2); +#if defined(__arm__) + printf_P(PSTR("Data Rate\t = %s\r\n"),pgm_read_word(&rf24_datarate_e_str_P[getDataRate()])); + printf_P(PSTR("Model\t\t = %s\r\n"),pgm_read_word(&rf24_model_e_str_P[isPVariant()])); + printf_P(PSTR("CRC Length\t = %s\r\n"),pgm_read_word(&rf24_crclength_e_str_P[getCRCLength()])); + printf_P(PSTR("PA Power\t = %s\r\n"),pgm_read_word(&rf24_pa_dbm_e_str_P[getPALevel()])); +#else printf_P(PSTR("Data Rate\t = %S\r\n"),pgm_read_word(&rf24_datarate_e_str_P[getDataRate()])); printf_P(PSTR("Model\t\t = %S\r\n"),pgm_read_word(&rf24_model_e_str_P[isPVariant()])); printf_P(PSTR("CRC Length\t = %S\r\n"),pgm_read_word(&rf24_crclength_e_str_P[getCRCLength()])); printf_P(PSTR("PA Power\t = %S\r\n"),pgm_read_word(&rf24_pa_dbm_e_str_P[getPALevel()])); +#endif } #endif @@ -343,13 +453,22 @@ void RF24::begin(void) { // Initialize pins pinMode(ce_pin,OUTPUT); - pinMode(csn_pin,OUTPUT); - // Initialize SPI bus - SPI.begin(); + #if defined(__arm__) + SPI.begin(csn_pin); // Using the extended SPI features of the DUE + SPI.setClockDivider(csn_pin, 9); // Set the bus speed to 8.4mhz on Due + SPI.setBitOrder(csn_pin,MSBFIRST); // Set the bit order and mode specific to this device + SPI.setDataMode(csn_pin,SPI_MODE0); + ce(LOW); + //csn(HIGH); + #else + pinMode(csn_pin,OUTPUT); + SPI.begin(); + ce(LOW); + csn(HIGH); + #endif + - ce(LOW); - csn(HIGH); // Must allow the radio time to settle else configuration bits will not necessarily stick. // This is actually only required following power up but some settling time also appears to @@ -483,14 +602,14 @@ bool RF24::write( const void* buf, uint8_t len ) /****************************************************************************/ //For general use, the interrupt flags are not important to clear -bool RF24::writeBlocking( const void* buf, uint8_t len, unsigned long timeout ) +bool RF24::writeBlocking( const void* buf, uint8_t len, uint32_t timeout ) { //Block until the FIFO is NOT full. //Keep track of the MAX retries and set auto-retry if seeing failures //This way the FIFO will fill up and allow blocking until packets go through //The radio will auto-clear everything in the FIFO as long as CE remains high - unsigned long timer = millis(); //Get the time that the payload transmission started + uint32_t timer = millis(); //Get the time that the payload transmission started while ( (read_register(FIFO_STATUS) & _BV(FIFO_FULL))){ //Blocking only if FIFO is full. This will loop and block until TX is successful @@ -510,9 +629,13 @@ bool RF24::writeBlocking( const void* buf, uint8_t len, unsigned long timeout ) void RF24::reUseTX(){ write_register(STATUS,_BV(MAX_RT) ); //Clear max retry flag - csn(LOW); - SPI.transfer( REUSE_TX_PL ); - csn(HIGH); + #if defined (__arm__) + SPI.transfer(csn_pin, REUSE_TX_PL ); + #else + csn(LOW); + SPI.transfer( REUSE_TX_PL ); + csn(HIGH); + #endif ce(LOW); //Re-Transfer packet ce(HIGH); } @@ -587,9 +710,9 @@ bool RF24::txStandBy(){ return 1; } -bool RF24::txStandBy(unsigned long timeout){ +bool RF24::txStandBy(uint32_t timeout){ - unsigned long start = millis(); + uint32_t start = millis(); while( ! (read_register(FIFO_STATUS) & _BV(TX_EMPTY)) ){ if( get_status() & _BV(MAX_RT)){ @@ -605,6 +728,12 @@ bool RF24::txStandBy(unsigned long timeout){ return 1; } +/****************************************************************************/ + +void RF24::maskIRQ(bool tx, bool fail, bool rx){ + + write_register(CONFIG, ( read_register(CONFIG) ) | fail << MASK_MAX_RT | tx << MASK_TX_DS | rx << MASK_RX_DR ); +} /****************************************************************************/ @@ -612,11 +741,17 @@ uint8_t RF24::getDynamicPayloadSize(void) { uint8_t result = 0; + #if defined (__arm__) + SPI.transfer(csn_pin, R_RX_PL_WID, SPI_CONTINUE ); + result = SPI.transfer(csn_pin,0xff); + #else csn(LOW); SPI.transfer( R_RX_PL_WID ); result = SPI.transfer(0xff); csn(HIGH); + #endif + if(result > 32) { flush_rx(); return 0; } return result; } @@ -735,10 +870,16 @@ void RF24::openReadingPipe(uint8_t child, uint64_t address) void RF24::toggle_features(void) { + + #if defined (__arm__) + SPI.transfer(csn_pin, ACTIVATE, SPI_CONTINUE ); + SPI.transfer(csn_pin, 0x73 ); + #else csn(LOW); SPI.transfer( ACTIVATE ); SPI.transfer( 0x73 ); csn(HIGH); + #endif } /****************************************************************************/ @@ -800,14 +941,26 @@ void RF24::writeAckPayload(uint8_t pipe, const void* buf, uint8_t len) { const uint8_t* current = reinterpret_cast(buf); - csn(LOW); - SPI.transfer( W_ACK_PAYLOAD | ( pipe & B111 ) ); const uint8_t max_payload_size = 32; uint8_t data_len = min(len,max_payload_size); + + #if defined (__arm__) + SPI.transfer(csn_pin, W_ACK_PAYLOAD | ( pipe & B111 ), SPI_CONTINUE); + while ( data_len-- > 1 ){ + SPI.transfer(csn_pin,*current++, SPI_CONTINUE); + } + SPI.transfer(csn_pin,*current++); + + #else + csn(LOW); + SPI.transfer(W_ACK_PAYLOAD | ( pipe & B111 ) ); + while ( data_len-- ) SPI.transfer(*current++); csn(HIGH); + + #endif } /****************************************************************************/ diff --git a/RF24.h b/RF24.h index dfb0ff9..609124d 100644 --- a/RF24.h +++ b/RF24.h @@ -54,7 +54,6 @@ private: bool dynamic_payloads_enabled; /**< Whether dynamic payloads are enabled. */ uint8_t ack_payload_length; /**< Dynamic size of pending ack payload. */ uint64_t pipe0_reading_address; /**< Last address set on pipe 0 for reading. */ - bool avail; public: @@ -360,7 +359,7 @@ public: * @return True if transmission is successful * */ - bool txStandBy(unsigned long timeout); + bool txStandBy(uint32_t timeout); /** * Write an ack payload for the specified pipe @@ -699,7 +698,7 @@ private: * * @param mode HIGH to take this unit off the SPI bus, LOW to put it on */ - void csn(int mode); + void csn(bool mode); /** * Set chip enable @@ -707,7 +706,7 @@ private: * @param level HIGH to actively begin transmission or LOW to put in standby. Please see data sheet * for a much more detailed description of this pin. */ - void ce(int level); + void ce(bool level); /** * Read a chunk of data in from a register diff --git a/RF24_config.h b/RF24_config.h index 5d62655..946586b 100644 --- a/RF24_config.h +++ b/RF24_config.h @@ -24,9 +24,9 @@ //#define MINIMAL // Define _BV for non-Arduino platforms and for Arduino DUE - #if ! defined(ARDUINO) || (defined(ARDUINO) && defined(__arm__)) - #define _BV(x) (1<<(x)) - #endif + + + #undef SERIAL_DEBUG #ifdef SERIAL_DEBUG @@ -35,27 +35,29 @@ #define IF_SERIAL_DEBUG(x) #endif - // Avoid spurious warnings - #if 1 - #if ! defined( NATIVE ) && defined( ARDUINO ) && ! defined(__arm__) - #undef PROGMEM - #define PROGMEM __attribute__(( section(".progmem.data") )) - #undef PSTR - #define PSTR(s) (__extension__({static const char __c[] PROGMEM = (s); &__c[0];})) - #endif - #endif +// Avoid spurious warnings +// Arduino DUE is arm and uses traditional PROGMEM constructs +#if 1 +#if ! defined( NATIVE ) && defined( ARDUINO ) && ! defined(__arm__) +#undef PROGMEM +#define PROGMEM __attribute__(( section(".progmem.data") )) +#undef PSTR +#define PSTR(s) (__extension__({static const char __c[] PROGMEM = (s); &__c[0];})) +#endif +#endif - // Progmem is Arduino-specific - #if defined(ARDUINO) && ! defined(__arm__) - #include - #define PRIPSTR "%S" - #else +// Progmem is Arduino-specific +// Arduino DUE is arm and does not include avr/pgmspace +#if defined(ARDUINO) && ! defined(__arm__) +#include +#define PRIPSTR "%S" +#else +#if ! defined(ARDUINO) // This doesn't work on Arduino DUE +typedef char const char; +#else // Fill in pgm_read_byte that is used, but missing from DUE +#define pgm_read_byte(addr) (*(const unsigned char *)(addr)) +#endif - #if ! defined(ARDUINO) - typedef char const char; - else // Fill in pgm_read_byte that is used, but missing from DUE - #define pgm_read_byte(addr) (*(const unsigned char *)(addr)) - #endif typedef uint16_t prog_uint16_t; #define PSTR(x) (x) #define printf_P printf @@ -66,14 +68,18 @@ #endif - +// Define _BV for non-Arduino platforms and for Arduino DUE +#if ! defined(ARDUINO) || (defined(ARDUINO) && defined(__arm__)) +#define _BV(x) (1<<(x)) +#endif // Stuff that is normally provided by Arduino - #if !defined ARDUINO + #if !defined (ARDUINO) #include #include #include extern HardwareSPI SPI; + #define _BV(x) (1<<(x)) #else #if !defined( __AVR_ATtiny85__ ) || defined( __AVR_ATtiny84__) diff --git a/examples/GettingStarted_CallResponse/GettingStarted_CallResponse.ino b/examples/GettingStarted_CallResponse/GettingStarted_CallResponse.ino index d491a83..5f09ad2 100644 --- a/examples/GettingStarted_CallResponse/GettingStarted_CallResponse.ino +++ b/examples/GettingStarted_CallResponse/GettingStarted_CallResponse.ino @@ -61,10 +61,10 @@ void loop(void) { if (role == role_ping_out){ // Radio is in ping mode byte gotByte; // Initialize a variable for the incoming response - unsigned long time = micros(); // Record the current microsecond count radio.stopListening(); // First, stop listening so we can talk. printf("Now sending %d as payload. ",counter); // Use a simple byte counter as payload + unsigned long time = micros(); // Record the current microsecond count if ( radio.write(&counter,1) ){ // Send the counter variable to the other radio if(!radio.available()){ // If nothing in the buffer, we got an ack but it is blank