Commit defe3e47 authored by Daniel Friesel's avatar Daniel Friesel
Browse files

import nRF24 TX code

parent 0dbe2001
Loading
Loading
Loading
Loading
+212 −39
Original line number Diff line number Diff line
@@ -5,61 +5,234 @@
#include "driver/gpio.h"
#include "arch.h"

class 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 &copy);
	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() {
	inline void csnHigh()
	{
		gpio.write(NRF24L01_CS_PIN, 1);
		arch.delay_us(5);
	}
		inline void csnLow() {
	inline void csnLow()
	{
		gpio.write(NRF24L01_CS_PIN, 0);
		arch.delay_us(5);
	}
		inline void beginTransaction() {
	inline void beginTransaction()
	{
		csnLow();
	}
		inline void endTransaction() {
	inline void endTransaction()
	{
		csnHigh();
	}

public:
		Nrf24l01() {}
	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();
		void powerOn();
		void powerOff();
	/**
   * 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);
		void setPALevel ( uint8_t level ); // 0 (-18B), 1 (-12dB), 2 (-6dB), 3 (0dB)

	/**
   * 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);

	/**
   * 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);

	uint8_t write(const void *buf, uint8_t len, bool blocking);

	uint8_t getStatus();
};
+2 −0
Original line number Diff line number Diff line
@@ -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)
+1 −1
Original line number Diff line number Diff line
@@ -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

+187 −11
Original line number Diff line number Diff line
@@ -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);
@@ -33,11 +34,55 @@ void Nrf24l01::setup()
	// 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);

	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)
@@ -49,15 +94,104 @@ void Nrf24l01::setPALevel(uint8_t level)
{
	uint8_t setup = readRegister(RF_SETUP) & 0b11111000;

	if(level > 3){  						// If invalid level, go to max PA
	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{
	}
	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();
}

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()
{
	txbuf[0] = NOP;
@@ -92,4 +226,46 @@ uint8_t Nrf24l01::writeRegister(uint8_t reg, uint8_t value)
	return rxbuf[0];
}

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