High Speed Data Transfers/Optimization
Changes: - Enable PTX at radio begin, in standby-I mode - Enable PTX at radio stopListening(); in standy-I mode - Radio startListening - removed delay. What is there to wait for when the radio will just be listening anyway? - Radio powerUp - radio will need to be powered up after configuration - radio will not power down unless instructed to - need to issue radio.txStandBy(); when finished transmitting to engage standby-I mode - Added txStandBy() to drop to standBy-I mode if not switching to RX mode - Radio Write: Sped up - radio previously did not use standby mode effectively, after TX sending of each packet, the radio is powered down introducing a 1.5ms delay in addition to the 130us delay from standby. - No observe-tx code, a simple NOP cmd is sent to get the status info - No millis() timeout, hanging condition should only occur because of faulty code - Simplified whatHappened() code - Flush TX FIFO if MAX_RT met as lib does not support re-transmit instead of flush every time. - Remove ack size monitoring - No powerdown needed, - Added writeClear() function for writes that need the interrupt flags cleared (ack payloads, etc). Same as write() otherwise - Radio startWrite: Sped up - Enable PTX mode is now done in stopListening() code. Enter TX mode by writing CE high. This brings the data transfer capabilities up to a reasonable level - No need to power up, already in Standby-I mode - No need for delayMicroseconds() in write functon. - No need for delay after writing CE high - Does not enter Standby-I mode be default. It is up to the MCU to call the new txStandBy() function to enter standby-I mode from PTX if not switching back to PRX - Radio available: - Now checks the FIFO buffer instead of the interrupt flag (no missed data) - Moved clearing of interrupt flags to Read() - Radio read: - No longer returns any value - use available to check for more data - Radio isAckPayloadAvailable() now checks the FIFO directly - Radio getDynamicPayloadSize() - Per the datasheet, added fix to flush corrupted packets
This commit is contained in:
@@ -389,6 +389,11 @@ void RF24::begin(void)
|
|||||||
// Flush buffers
|
// Flush buffers
|
||||||
flush_rx();
|
flush_rx();
|
||||||
flush_tx();
|
flush_tx();
|
||||||
|
|
||||||
|
//Enable PTX, do not write CE high so radio will remain in standby I mode ( 130us max to transition to RX or TX instead of 1500us from powerUp )
|
||||||
|
write_register(CONFIG, ( read_register(CONFIG) ) & ~_BV(PRIM_RX) );
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
@@ -409,8 +414,6 @@ void RF24::startListening(void)
|
|||||||
// Go!
|
// Go!
|
||||||
ce(HIGH);
|
ce(HIGH);
|
||||||
|
|
||||||
// wait for the radio to come up (130us actually only needed)
|
|
||||||
delayMicroseconds(130);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
@@ -420,6 +423,8 @@ void RF24::stopListening(void)
|
|||||||
ce(LOW);
|
ce(LOW);
|
||||||
flush_tx();
|
flush_tx();
|
||||||
flush_rx();
|
flush_rx();
|
||||||
|
write_register(CONFIG, ( read_register(CONFIG) ) & ~_BV(PRIM_RX) );
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
@@ -431,6 +436,7 @@ void RF24::powerDown(void)
|
|||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
|
//Power up now. Radio will not power down unless instructed by MCU for config changes etc.
|
||||||
void RF24::powerUp(void)
|
void RF24::powerUp(void)
|
||||||
{
|
{
|
||||||
write_register(CONFIG,read_register(CONFIG) | _BV(PWR_UP));
|
write_register(CONFIG,read_register(CONFIG) | _BV(PWR_UP));
|
||||||
@@ -438,84 +444,68 @@ void RF24::powerUp(void)
|
|||||||
|
|
||||||
/******************************************************************/
|
/******************************************************************/
|
||||||
|
|
||||||
bool RF24::write( const void* buf, uint8_t len )
|
//Similar to the previous write, clears the interrupt flags
|
||||||
|
bool RF24::writeClear( const void* buf, uint8_t len )
|
||||||
{
|
{
|
||||||
bool result = false;
|
//Start Writing
|
||||||
|
|
||||||
// Begin the write
|
|
||||||
startWrite(buf,len);
|
startWrite(buf,len);
|
||||||
|
|
||||||
// ------------
|
//Wait until complete or failed
|
||||||
// At this point we could return from a non-blocking write, and then call
|
//ACK payloads that are handled improperly will cause this to hang
|
||||||
// the rest after an interrupt
|
//If autoAck is ON, a payload has to be written prior to reading a payload, else write after reading a payload
|
||||||
|
while( ! ( get_status() & ( _BV(TX_DS) | _BV(MAX_RT) ))) { }
|
||||||
|
|
||||||
// Instead, we are going to block here until we get TX_DS (transmission completed and ack'd)
|
uint8_t status = write_register(STATUS,_BV(RX_DR) | _BV(TX_DS) | _BV(MAX_RT) );
|
||||||
// or MAX_RT (maximum retries, transmission failed). Also, we'll timeout in case the radio
|
|
||||||
// is flaky and we get neither.
|
|
||||||
|
|
||||||
// IN the end, the send should be blocking. It comes back in 60ms worst case, or much faster
|
//Max retries exceeded
|
||||||
// if I tighted up the retry logic. (Default settings will be 1500us.
|
if( status & _BV(MAX_RT)){
|
||||||
// Monitor the send
|
//Flush the FIFO since this is a single-packet-write function, and FIFO is NOT cleared when MAX_RT is reached
|
||||||
uint8_t observe_tx;
|
|
||||||
uint8_t status;
|
|
||||||
uint32_t sent_at = millis();
|
|
||||||
const uint32_t timeout = 500; //ms to wait for timeout
|
|
||||||
do
|
|
||||||
{
|
|
||||||
status = read_register(OBSERVE_TX,&observe_tx,1);
|
|
||||||
IF_SERIAL_DEBUG(Serial.print(observe_tx,HEX));
|
|
||||||
}
|
|
||||||
while( ! ( status & ( _BV(TX_DS) | _BV(MAX_RT) ) ) && ( millis() - sent_at < timeout ) );
|
|
||||||
|
|
||||||
// The part above is what you could recreate with your own interrupt handler,
|
|
||||||
// and then call this when you got an interrupt
|
|
||||||
// ------------
|
|
||||||
|
|
||||||
// Call this when you get an interrupt
|
|
||||||
// The status tells us three things
|
|
||||||
// * The send was successful (TX_DS)
|
|
||||||
// * The send failed, too many retries (MAX_RT)
|
|
||||||
// * There is an ack packet waiting (RX_DR)
|
|
||||||
bool tx_ok, tx_fail;
|
|
||||||
whatHappened(tx_ok,tx_fail,ack_payload_available);
|
|
||||||
|
|
||||||
//printf("%u%u%u\r\n",tx_ok,tx_fail,ack_payload_available);
|
|
||||||
|
|
||||||
result = tx_ok;
|
|
||||||
IF_SERIAL_DEBUG(Serial.print(result?"...OK.":"...Failed"));
|
|
||||||
|
|
||||||
// Handle the ack packet
|
|
||||||
if ( ack_payload_available )
|
|
||||||
{
|
|
||||||
ack_payload_length = getDynamicPayloadSize();
|
|
||||||
IF_SERIAL_DEBUG(Serial.print("[AckPacket]/"));
|
|
||||||
IF_SERIAL_DEBUG(Serial.println(ack_payload_length,DEC));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Yay, we are done.
|
|
||||||
|
|
||||||
// Power down
|
|
||||||
powerDown();
|
|
||||||
|
|
||||||
// Flush buffers (Is this a relic of past experimentation, and not needed anymore??)
|
|
||||||
flush_tx();
|
flush_tx();
|
||||||
|
}
|
||||||
return result;
|
//TX OK 1 or 0
|
||||||
|
return status & _BV(TX_DS);//tx_ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
void RF24::startWrite( const void* buf, uint8_t len )
|
//For general use, the flags are not important to clear
|
||||||
|
bool RF24::write( const void* buf, uint8_t len )
|
||||||
{
|
{
|
||||||
// Transmitter power-up
|
//Start Writing
|
||||||
write_register(CONFIG, ( read_register(CONFIG) | _BV(PWR_UP) ) & ~_BV(PRIM_RX) );
|
startWrite(buf,len);
|
||||||
delayMicroseconds(150);
|
|
||||||
|
|
||||||
// Send the payload
|
//Wait until complete or failed
|
||||||
write_payload( buf, len );
|
//ACK payloads that are handled improperly will cause this to hang
|
||||||
|
//If autoAck is ON, a payload has to be written prior to reading a payload, else write after reading a payload
|
||||||
|
uint8_t status;
|
||||||
|
while( ! ( status = get_status() & ( _BV(TX_DS) | _BV(MAX_RT) ))) { }
|
||||||
|
|
||||||
// Allons!
|
//Max retries exceeded
|
||||||
|
if( status & _BV(MAX_RT)){
|
||||||
|
//Flush the FIFO since this is a single-packet-write function, and FIFO is NOT cleared when MAX_RT is reached
|
||||||
|
flush_tx();
|
||||||
|
}
|
||||||
|
//TX OK 1 or 0
|
||||||
|
return status & _BV(TX_DS);//tx_ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
//Per the documentation, we want to set PTX Mode when not listening. Then all we do is write data and set CE high
|
||||||
|
//In this mode, if we can keep the FIFO buffers loaded, packets will transmit immediately (no 130us delay)
|
||||||
|
//Otherwise we enter Standby-II mode, which is still faster than standby mode
|
||||||
|
//Also, we remove the need to keep writing the config register over and over and delaying for 150 us each time if sending a stream of data
|
||||||
|
|
||||||
|
void RF24::startWrite( const void* buf, uint8_t len ){ //TMRh20
|
||||||
|
|
||||||
|
write_payload( buf,len);
|
||||||
ce(HIGH);
|
ce(HIGH);
|
||||||
delayMicroseconds(15);
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void RF24::txStandBy(){
|
||||||
ce(LOW);
|
ce(LOW);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -530,6 +520,7 @@ uint8_t RF24::getDynamicPayloadSize(void)
|
|||||||
result = SPI.transfer(0xff);
|
result = SPI.transfer(0xff);
|
||||||
csn(HIGH);
|
csn(HIGH);
|
||||||
|
|
||||||
|
if(result > 32) { flush_rx(); return 0; }
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -544,45 +535,35 @@ bool RF24::available(void)
|
|||||||
|
|
||||||
bool RF24::available(uint8_t* pipe_num)
|
bool RF24::available(uint8_t* pipe_num)
|
||||||
{
|
{
|
||||||
uint8_t status = get_status();
|
|
||||||
|
|
||||||
// Too noisy, enable if you really want lots o data!!
|
//Check the FIFO buffer to see if data is waitng to be read
|
||||||
//IF_SERIAL_DEBUG(print_status(status));
|
|
||||||
|
|
||||||
bool result = ( status & _BV(RX_DR) );
|
if (!( read_register(FIFO_STATUS) & _BV(RX_EMPTY) )){
|
||||||
|
|
||||||
if (result)
|
|
||||||
{
|
|
||||||
// If the caller wants the pipe number, include that
|
// If the caller wants the pipe number, include that
|
||||||
if ( pipe_num )
|
if ( pipe_num ){
|
||||||
|
uint8_t status = get_status();
|
||||||
*pipe_num = ( status >> RX_P_NO ) & B111;
|
*pipe_num = ( status >> RX_P_NO ) & B111;
|
||||||
|
|
||||||
// Clear the status bit
|
|
||||||
|
|
||||||
// ??? Should this REALLY be cleared now? Or wait until we
|
|
||||||
// actually READ the payload?
|
|
||||||
|
|
||||||
write_register(STATUS,_BV(RX_DR) );
|
|
||||||
|
|
||||||
// Handle ack payload receipt
|
|
||||||
if ( status & _BV(TX_DS) )
|
|
||||||
{
|
|
||||||
write_register(STATUS,_BV(TX_DS));
|
|
||||||
}
|
}
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return 0;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
bool RF24::read( void* buf, uint8_t len )
|
void RF24::read( void* buf, uint8_t len ){
|
||||||
{
|
|
||||||
// Fetch the payload
|
// Fetch the payload
|
||||||
read_payload( buf, len );
|
read_payload( buf, len );
|
||||||
|
|
||||||
// was this the last of the data available?
|
//Clear the two possible interrupt flags with one command
|
||||||
return read_register(FIFO_STATUS) & _BV(RX_EMPTY);
|
write_register(STATUS,_BV(RX_DR) | _BV(TX_DS) );
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
@@ -736,9 +717,10 @@ void RF24::writeAckPayload(uint8_t pipe, const void* buf, uint8_t len)
|
|||||||
|
|
||||||
bool RF24::isAckPayloadAvailable(void)
|
bool RF24::isAckPayloadAvailable(void)
|
||||||
{
|
{
|
||||||
bool result = ack_payload_available;
|
if (!( read_register(FIFO_STATUS) & _BV(RX_EMPTY) )){
|
||||||
ack_payload_available = false;
|
return 1;
|
||||||
return result;
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|||||||
@@ -54,6 +54,7 @@ private:
|
|||||||
bool dynamic_payloads_enabled; /**< Whether dynamic payloads are enabled. */
|
bool dynamic_payloads_enabled; /**< Whether dynamic payloads are enabled. */
|
||||||
uint8_t ack_payload_length; /**< Dynamic size of pending ack payload. */
|
uint8_t ack_payload_length; /**< Dynamic size of pending ack payload. */
|
||||||
uint64_t pipe0_reading_address; /**< Last address set on pipe 0 for reading. */
|
uint64_t pipe0_reading_address; /**< Last address set on pipe 0 for reading. */
|
||||||
|
bool avail;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/**
|
/**
|
||||||
@@ -219,6 +220,11 @@ protected:
|
|||||||
/**@}*/
|
/**@}*/
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
//TMRh20
|
||||||
|
void txStandBy();
|
||||||
|
bool writeClear( const void* buf, uint8_t len );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @name Primary public interface
|
* @name Primary public interface
|
||||||
*
|
*
|
||||||
@@ -301,7 +307,7 @@ public:
|
|||||||
* @param len Maximum number of bytes to read into the buffer
|
* @param len Maximum number of bytes to read into the buffer
|
||||||
* @return True if the payload was delivered successfully false if not
|
* @return True if the payload was delivered successfully false if not
|
||||||
*/
|
*/
|
||||||
bool read( void* buf, uint8_t len );
|
void read( void* buf, uint8_t len );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Open a pipe for writing
|
* Open a pipe for writing
|
||||||
|
|||||||
Reference in New Issue
Block a user