From defe3e47dd837f9f2ae8447b7148893af8e8f1d0 Mon Sep 17 00:00:00 2001 From: Daniel Friesel Date: Mon, 24 Jun 2019 12:48:14 +0200 Subject: import nRF24 TX code --- include/driver/nrf24l01.h | 251 +++++++++++++++++++++++++++++------ src/app/nrf24l01test/main.cc | 2 + src/arch/msp430fr5994lp/Makefile.inc | 2 +- src/driver/nrf24l01.cc | 198 +++++++++++++++++++++++++-- 4 files changed, 402 insertions(+), 51 deletions(-) diff --git a/include/driver/nrf24l01.h b/include/driver/nrf24l01.h index 911ef58..c10332d 100644 --- a/include/driver/nrf24l01.h +++ b/include/driver/nrf24l01.h @@ -5,63 +5,236 @@ #include "driver/gpio.h" #include "arch.h" -class Nrf24l01 { - private: - Nrf24l01(const Nrf24l01 ©); - unsigned char txbuf[2]; - unsigned char rxbuf[2]; - - uint8_t writeRegister(uint8_t reg, uint8_t value); - uint8_t readRegister(uint8_t reg); - - inline void csnHigh() { - gpio.write(NRF24L01_CS_PIN, 1); - arch.delay_us(5); - } - inline void csnLow() { - gpio.write(NRF24L01_CS_PIN, 0); - arch.delay_us(5); - } - inline void beginTransaction() { - csnLow(); - } - inline void endTransaction() { - csnHigh(); - } - - public: - Nrf24l01() {} - - /** +#define rf24_max(a, b) ((a) > (b) ? (a) : (b)) +#define rf24_min(a, b) ((a) < (b) ? (a) : (b)) + +class Nrf24l01 +{ +private: + Nrf24l01(const Nrf24l01 ©); + unsigned char txbuf[2]; + unsigned char rxbuf[2]; + + bool p_variant; /* False for RF24L01 and true for RF24L01P */ + uint8_t payload_size; /**< Fixed size of payloads */ + bool dynamic_payloads_enabled; /**< Whether dynamic payloads are enabled. */ + uint8_t pipe0_reading_address[5]; /**< Last address set on pipe 0 for reading. */ + uint8_t addr_width; /**< The address width to use - 3,4 or 5 bytes. */ + uint32_t txRxDelay; /**< Var for adjusting delays depending on datarate */ + + uint8_t writeRegister(uint8_t reg, uint8_t value); + uint8_t readRegister(uint8_t reg); + uint8_t writePayload(const void *buf, uint8_t data_len, const uint8_t writeType); + + inline void csnHigh() + { + gpio.write(NRF24L01_CS_PIN, 1); + arch.delay_us(5); + } + inline void csnLow() + { + gpio.write(NRF24L01_CS_PIN, 0); + arch.delay_us(5); + } + inline void beginTransaction() + { + csnLow(); + } + inline void endTransaction() + { + csnHigh(); + } + +public: + Nrf24l01() : payload_size(32), dynamic_payloads_enabled(false), addr_width(5) {} + + /** * Power Amplifier level. * * For use with setPALevel() */ - enum rf24_pa_dbm_e { RF24_PA_MIN = 0,RF24_PA_LOW, RF24_PA_HIGH, RF24_PA_MAX, RF24_PA_ERROR }; + enum rf24_pa_dbm_e + { + RF24_PA_MIN = 0, + RF24_PA_LOW, + RF24_PA_HIGH, + RF24_PA_MAX, + RF24_PA_ERROR + }; - /** + /** * Data rate. How fast data moves through the air. * * For use with setDataRate() */ - enum rf24_datarate_e { RF24_1MBPS = 0, RF24_2MBPS, RF24_250KBPS }; + enum rf24_datarate_e + { + RF24_1MBPS = 0, + RF24_2MBPS, + RF24_250KBPS + }; - /** + /** * CRC Length. How big (if any) of a CRC is included. * * For use with setCRCLength() */ - enum rf24_crclength_e { RF24_CRC_DISABLED = 0, RF24_CRC_8, RF24_CRC_16 }; + enum rf24_crclength_e + { + RF24_CRC_DISABLED = 0, + RF24_CRC_8, + RF24_CRC_16 + }; + + /** + * Enter low-power mode + * + * To return to normal power mode, call powerUp(). + * + * @note After calling startListening(), a basic radio will consume about 13.5mA + * at max PA level. + * During active transmission, the radio will consume about 11.5mA, but this will + * be reduced to 26uA (.026mA) between sending. + * In full powerDown mode, the radio will consume approximately 900nA (.0009mA) + * + * @code + * radio.powerDown(); + * avr_enter_sleep_mode(); // Custom function to sleep the device + * radio.powerUp(); + * @endcode + */ + void powerDown(void); + + /** + * Leave low-power mode - required for normal radio operation after calling powerDown() + * + * To return to low power mode, call powerDown(). + * @note This will take up to 5ms for maximum compatibility + */ + void powerUp(void); + + /** + * Empty the transmit buffer. This is generally not required in standard operation. + * May be required in specific cases after stopListening() , if operating at 250KBPS data rate. + * + * @return Current value of status register + */ + uint8_t flushTx(void); + + /** + * Empty the receive buffer + * + * @return Current value of status register + */ + uint8_t flushRx(void); + + void setup(); + /** + * Set Power Amplifier (PA) level to one of four levels: + * RF24_PA_MIN, RF24_PA_LOW, RF24_PA_HIGH and RF24_PA_MAX + * + * The power levels correspond to the following output levels respectively: + * NRF24L01: -18dBm, -12dBm,-6dBM, and 0dBm + * + * SI24R1: -6dBm, 0dBm, 3dBM, and 7dBm. + * + * @param level Desired PA level. + */ + void setPALevel(uint8_t level); // 0 (-18B), 1 (-12dB), 2 (-6dB), 3 (0dB) + + /** + * Set the address width from 3 to 5 bytes (24, 32 or 40 bit) + * + * @param a_width The address width to use: 3,4 or 5 + */ + + void setAddressWidth(uint8_t a_width); + + /** + * Set the number and delay of retries upon failed submit + * + * @param delay How long to wait between each retry, in multiples of 250us, + * max is 15. 0 means 250us, 15 means 4000us. + * @param count How many retries before giving up, max 15 + */ + void setRetries(uint8_t delay, uint8_t count); + + /** + * Set RF communication channel + * + * @param channel Which RF channel to communicate on, 0-125 + */ + void setChannel(uint8_t channel); + + /** + * Get RF communication channel + * + * @return The currently configured RF Channel + */ + uint8_t getChannel(void); + + /** + * Set Static Payload Size + * + * This implementation uses a pre-stablished fixed payload size for all + * transmissions. If this method is never called, the driver will always + * transmit the maximum payload size (32 bytes), no matter how much + * was sent to write(). + * + * @todo Implement variable-sized payloads feature + * + * @param size The number of bytes in the payload + */ + void setPayloadSize(uint8_t size); + + /** + * Get Static Payload Size + * + * @see setPayloadSize() + * + * @return The number of bytes in the payload + */ + uint8_t getPayloadSize(void); + + /** + * Set the transmission data rate + * + * @warning setting RF24_250KBPS will fail for non-plus units + * + * @param speed RF24_250KBPS for 250kbs, RF24_1MBPS for 1Mbps, or RF24_2MBPS for 2Mbps + * @return true if the change was successful + */ + bool setDataRate(rf24_datarate_e speed); + /** + * The radio will generate interrupt signals when a transmission is complete, + * a transmission fails, or a payload is received. This allows users to mask + * those interrupts to prevent them from generating a signal on the interrupt + * pin. Interrupts are enabled on the radio chip by default. + * + * @code + * Mask all interrupts except the receive interrupt: + * + * radio.maskIRQ(1,1,0); + * @endcode + * + * @param tx_ok Mask transmission complete interrupts + * @param tx_fail Mask transmit failure interrupts + * @param rx_ready Mask payload received interrupts + */ + void maskIRQ(bool tx_ok, bool tx_fail, bool rx_ready); - void setup(); - void powerOn(); - void powerOff(); + /** + * Turn on or off the special features of the chip + * + * The chip has certain 'features' which are only available when the 'features' + * are enabled. See the datasheet for details. + */ + void toggleFeatures(void); - void setRetries(uint8_t delay, uint8_t count); - void setPALevel ( uint8_t level ); // 0 (-18B), 1 (-12dB), 2 (-6dB), 3 (0dB) + uint8_t write(const void *buf, uint8_t len, bool blocking); - uint8_t getStatus(); + uint8_t getStatus(); }; extern Nrf24l01 nrf24l01; diff --git a/src/app/nrf24l01test/main.cc b/src/app/nrf24l01test/main.cc index 2f65a7c..c12cbf5 100644 --- a/src/app/nrf24l01test/main.cc +++ b/src/app/nrf24l01test/main.cc @@ -7,6 +7,8 @@ void loop(void) { gpio.led_toggle(1); kout << "status: " << hex << nrf24l01.getStatus() << endl; + kout << "write: "; + kout << nrf24l01.write("foo", 3, true) << endl; } int main(void) diff --git a/src/arch/msp430fr5994lp/Makefile.inc b/src/arch/msp430fr5994lp/Makefile.inc index 6498597..535e01b 100644 --- a/src/arch/msp430fr5994lp/Makefile.inc +++ b/src/arch/msp430fr5994lp/Makefile.inc @@ -3,7 +3,7 @@ CPU = 430x MCU = msp430fr5994 -cpu_freq ?= 16000000 +cpu_freq ?= 8000000 MSP430_FLASHER_DIR ?= /home/derf/var/projects/msp430/MSP430Flasher_1.3.15 diff --git a/src/driver/nrf24l01.cc b/src/driver/nrf24l01.cc index 144158c..ff19240 100644 --- a/src/driver/nrf24l01.cc +++ b/src/driver/nrf24l01.cc @@ -21,6 +21,7 @@ void Nrf24l01::setup() { spi.setup(); + gpio.input(NRF24L01_IRQ_PIN, true); gpio.output(NRF24L01_EN_PIN); gpio.output(NRF24L01_CS_PIN); gpio.write(NRF24L01_EN_PIN, 0); @@ -28,34 +29,167 @@ void Nrf24l01::setup() arch.delay_ms(5); // Reset NRF_CONFIG and enable 16-bit CRC. - writeRegister( NRF_CONFIG, 0b00001100 ) ; + writeRegister(NRF_CONFIG, 0b00001100); // Set 1500uS (minimum for 32B payload in ESB@250KBPS) timeouts, to make testing a little easier // WARNING: If this is ever lowered, either 250KBS mode with AA is broken or maximum packet // sizes must never be used. See documentation for a more complete explanation. - setRetries(5,15); + setRetries(5, 10); // Reset value is MAX - setPALevel( RF24_PA_MAX ) ; + setPALevel(RF24_PA_MAX); + setDataRate(RF24_1MBPS); + + toggleFeatures(); + writeRegister(FEATURE, 0); + writeRegister(DYNPD, 0); + dynamic_payloads_enabled = false; + + // Reset current status + // Notice reset and flush is the last thing we do + writeRegister(NRF_STATUS, (1 << RX_DR) | (1 << TX_DS) | (1 << MAX_RT)); + + // Set up default configuration. Callers can always change it later. + // This channel should be universally safe and not bleed over into adjacent + // spectrum. + setChannel(76); + + // Flush buffers + flushRx(); + flushTx(); + + maskIRQ(true, false, false); + + powerUp(); //Power up by default when begin() is called + + // 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 ) + // PTX should use only 22uA of power + writeRegister(NRF_CONFIG, (readRegister(NRF_CONFIG)) & ~(1 << PRIM_RX)); +} + +//Power up now. Radio will not power down unless instructed by MCU for config changes etc. +void Nrf24l01::powerUp(void) +{ + uint8_t cfg = readRegister(NRF_CONFIG); + + // if not powered up then power up and wait for the radio to initialize + if (!(cfg & (1 << PWR_UP))) + { + writeRegister(NRF_CONFIG, cfg | (1 << PWR_UP)); + + // For nRF24L01+ to go from power down mode to TX or RX mode it must first pass through stand-by mode. + // There must be a delay of Tpd2stby (see Table 16.) after the nRF24L01+ leaves power down mode before + // the CEis set high. - Tpd2stby can be up to 5ms per the 1.0 datasheet + arch.delay_us(5); + } } void Nrf24l01::setRetries(uint8_t delay, uint8_t count) { - writeRegister(SETUP_RETR,(delay&0xf)< 3){ // If invalid level, go to max PA - level = (RF24_PA_MAX << 1) + 1; // +1 to support the SI24R1 chip extra bit - }else{ - level = (level << 1) + 1; // Else set level as requested + if (level > 3) + { // If invalid level, go to max PA + level = (RF24_PA_MAX << 1) + 1; // +1 to support the SI24R1 chip extra bit + } + else + { + level = (level << 1) + 1; // Else set level as requested + } + + writeRegister(RF_SETUP, setup |= level); // Write it to the chip +} + +bool Nrf24l01::setDataRate(Nrf24l01::rf24_datarate_e speed) +{ + bool result = false; + uint8_t setup = readRegister(RF_SETUP); + + // HIGH and LOW '00' is 1Mbs - our default + setup &= ~((1 << RF_DR_LOW) | (1 << RF_DR_HIGH)); + + txRxDelay = 85; + if (speed == RF24_250KBPS) + { + // Must set the RF_DR_LOW to 1; RF_DR_HIGH (used to be RF_DR) is already 0 + // Making it '10'. + setup |= (1 << RF_DR_LOW); + txRxDelay = 155; } + else + { + // Set 2Mbs, RF_DR (RF_DR_HIGH) is set 1 + // Making it '01' + if (speed == RF24_2MBPS) + { + setup |= (1 << RF_DR_HIGH); + txRxDelay = 65; + } + } + writeRegister(RF_SETUP, setup); + + // Verify our result + if (readRegister(RF_SETUP) == setup) + { + result = true; + } + return result; +} + +void Nrf24l01::toggleFeatures(void) +{ + beginTransaction(); + txbuf[0] = ACTIVATE; + txbuf[1] = 0x73; + spi.xmit(2, txbuf, 0, rxbuf); + endTransaction(); +} - writeRegister( RF_SETUP, setup |= level ) ; // Write it to the chip +void Nrf24l01::setChannel(uint8_t channel) +{ + writeRegister(RF_CH, rf24_min(channel, 125)); +} + +uint8_t Nrf24l01::write(const void *buf, uint8_t len, bool blocking) +{ + writePayload(buf, len, W_TX_PAYLOAD); + + gpio.write(NRF24L01_EN_PIN, 1); + arch.delay_us(10); + gpio.write(NRF24L01_EN_PIN, 0); + + if (!blocking) + { + return 0; + } + + while (!(getStatus() & ((1 << TX_DS) | (1 << MAX_RT)))) + ; + uint8_t status = writeRegister(NRF_STATUS, ((1 << TX_DS) | (1 << MAX_RT))); + + if (status & (1 << MAX_RT)) + { + // flush_tx(); //Only going to be 1 packet int the FIFO at a time using this method, so just flush + return 0; + } + return 1; +} + +void Nrf24l01::maskIRQ(bool tx, bool fail, bool rx) +{ + + uint8_t config = readRegister(NRF_CONFIG); + /* clear the interrupt flags */ + config &= ~(1 << MASK_MAX_RT | 1 << MASK_TX_DS | 1 << MASK_RX_DR); + /* set the specified interrupt flags */ + config |= fail << MASK_MAX_RT | tx << MASK_TX_DS | rx << MASK_RX_DR; + writeRegister(NRF_CONFIG, config); } uint8_t Nrf24l01::getStatus() @@ -70,7 +204,7 @@ uint8_t Nrf24l01::getStatus() uint8_t Nrf24l01::readRegister(uint8_t reg) { - txbuf[0] = R_REGISTER | ( REGISTER_MASK & reg ); + txbuf[0] = R_REGISTER | (REGISTER_MASK & reg); txbuf[1] = NOP; beginTransaction(); @@ -92,4 +226,46 @@ uint8_t Nrf24l01::writeRegister(uint8_t reg, uint8_t value) return rxbuf[0]; } -Nrf24l01 nrf24l01; +uint8_t Nrf24l01::writePayload(const void *buf, uint8_t data_len, const uint8_t writeType) +{ + data_len = rf24_min(data_len, payload_size); + uint8_t blank_len = dynamic_payloads_enabled ? 0 : payload_size - data_len; + + //printf("[Writing %u bytes %u blanks]",data_len,blank_len); + //IF_SERIAL_DEBUG( printf("[Writing %u bytes %u blanks]\n",data_len,blank_len); ); + + beginTransaction(); + txbuf[0] = writeType; + spi.xmit(1, txbuf, 1, rxbuf); + spi.xmit(data_len, (unsigned char *)buf, 0, NULL); + txbuf[0] = 0; + while (blank_len--) + { + spi.xmit(1, txbuf, 0, NULL); + } + endTransaction(); + + return rxbuf[0]; +} + +uint8_t Nrf24l01::flushRx(void) +{ + txbuf[0] = FLUSH_RX; + beginTransaction(); + spi.xmit(1, txbuf, 1, rxbuf); + endTransaction(); + return rxbuf[0]; +} + +/****************************************************************************/ + +uint8_t Nrf24l01::flushTx(void) +{ + txbuf[0] = FLUSH_TX; + beginTransaction(); + spi.xmit(1, txbuf, 1, rxbuf); + endTransaction(); + return rxbuf[0]; +} + +Nrf24l01 nrf24l01; \ No newline at end of file -- cgit v1.2.3