Jump to content
43oh

[Energia Library] Nordic nRF24L01+ library


Recommended Posts

Yes, it was like you described before. But with the new code I tried it and it's fixed. Thanks again.

 

I found deepsleep on your library, and used it before LPM4 line inside void loop(), and it works fine. I wonder what deepsleep realy do? I'm just trying to lower power consumption.

if (pir_flag == FALSE) { 

void deepsleep();// here it is

LPM4;
} 
}
Take a look at the nRF24L01+ datasheet sometime; deepsleep puts the transceiver in POWERDOWN mode with 0.9uA power consumption; this is what you want for the TX node during its LPM4 state. Otherwise the chip sits in Standby-I mode, where power consumption is around 30uA I think... or maybe 200uA, can't remember offhand. The Enrf24 library will automatically wake up the transceiver from deepsleep before performing an actual transmit or entering RX mode.

 

Sent from my Galaxy Note II with Tapatalk 4

 

 

Link to post
Share on other sites
  • Replies 352
  • Created
  • Last Reply

Top Posters In This Topic

Top Posters In This Topic

Popular Posts

Hi folks... So I'm a little new to Energia, but since I wrote a library for the nRF24L01+ digital transceivers for native C-based apps I figured it'd be a great idea to port this to Energia.   I'm r

Ok, so I ported the Enrf library over so that it works with both MSP430 and Stellaris.  Seems to work great.  I am watching the tx rx demo between msp430g2553 (on the RX side), and the StellarPad doin

Okie doke - https://github.com/spirilis/Enrf24   The examples are the same as the ones I posted... I'll write up the API in a wiki page soon.  Alternately, I put documentation in the Enrf24.h file f

Posted Images

That's so cool, what I really needed to lower power consumption.

And the thing you mentioned about IRQ on the receiver part, can you make it clear if you have time. Thanks a lot spirillis.

 

Sure ... On the RX side, the transceiver is actually the event-producing piece; whereas the PIR sensor was in your TX example, the RX example is quite different.

 

The nRF24L01+ will signal an IRQ on any of 3 conditions: TX succeeded, TX failed, RX event (successful receive of a packet with valid CRC, if CRC is enabled, which it is by default with my library).

 

The former 2 are handled entirely within the context of Enrf24 when you run radio.flush(), so you never need to know about those.

The last, however, is what you're looking for.

 

The loop() should enter LPM4 when it's done handling any radio events, and then the nRF24L01+'s IRQ line should trigger an ISR that raises a flag and tells the chip to exit LPM4.

Rewriting your example:

#include <Enrf24.h>
#include <nRF24L01.h>
#include <string.h>
#include <SPI.h>
 
Enrf24 radio(P2_0, P2_1, P2_2);  // P2.0=CE, P2.1=CSN, P2.2=IRQ
 
const uint8_t rxaddr[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0x01 };
 
const char *str_ona = "ON_A";
const char *str_onb = "ON_B";
const char *str_onc = "ON_C";

void setup() {
 
  SPI.begin();
  SPI.setDataMode(SPI_MODE0);
  SPI.setBitOrder(1); // MSB-first
  
  radio.begin();  // Defaults 1Mbps, channel 0, max TX power
  radio.setRXaddress((void*)rxaddr);
  
  pinMode(P2_3, OUTPUT);
  digitalWrite(P2_3, LOW);
  pinMode(P1_0, OUTPUT);
  digitalWrite(P1_0, LOW);
  pinMode(P2_4, OUTPUT);
  digitalWrite(P2_4, LOW);

  // IRQ config
  P2IFG &= ~BIT2;
  P2IES |= BIT2;  // trigger P2.2 IRQ on High-To-Low transition
  P2IE |= BIT2;
 
  radio.enableRX();  // Start listening
}

volatile boolean radio_flag = FALSE;

void loop() {
  char inbuf[33];

  if (radio_flag) {  
    if (radio.available(true)) {
      if (radio.read(inbuf)) {
        if (!strcmp(inbuf, str_ona))
          digitalWrite(P2_3, HIGH);
        if (!strcmp(inbuf, str_onb))
          digitalWrite(P1_0, HIGH);
        if (!strcmp(inbuf, str_onc))
          digitalWrite(P2_4, HIGH);
      }
    }
    radio_flag = FALSE;  // reload flag for next event
  }

  if (!radio.available(true)) {  // Any more packets waiting?
    LPM4;  // Assuming no more packets are pending, go to sleep.
  } else {
    radio_flag = TRUE;  /* If a new packet arrived in the middle of us handling
                         * the old one, manually re-trigger the radio_flag and
                         * let loop() re-start so our code will handle the next
                         * packet waiting in the transceiver's RX FIFO.
                         */
  }
}

// P2 ISR; should only be concerned with P2.2 here
#pragma vector=PORT2_VECTOR
__interrupt void P2ISR()
{
  if (P2IFG & BIT2) {
    radio_flag = TRUE;
    __bic_SR_register_on_exit(LPM4_bits);
    P2IFG &= ~BIT2;
  }
}

As a side note, the fact that we have to go behind Energia's back and declare our own PORT2 ISR is another point of contention as to why Energia doesn't "properly cater to" LPM modes.  We shouldn't have to do this; there should be a special flag to attachInterrupt() that tells Energia "When this ISR runs, exit LPM" or perhaps some way for the ISR to inform the Energia PORT2 ISR that it should issue __bic_SR_register_on_exit(LPM4_bits) before exiting.  This is something I'd like to see changed in future versions of Energia.

 

edit: Although, if your ISR runs long enough to let the Watchdog timer trigger, then it will exit LPM3; but I believe it'll still keep the ACLK disabled, so that's not really a proper & graceful exit.

Link to post
Share on other sites

That's so clever. Now I understood how to use IRQ properly and how is the logical coding structure to transceive and receive data efficiently with less power. I'm really appreciated of your help. Hope someone else besides me will benefit from all these explanations.

Best regards spirillis.

 

And about the side note, there is a topic about it. Here is a quotation;

 

If you will be using low power modes, I recommend going into the Energia "cores" folder, finding the file WInterrupts.c, and adding the command "LPM4_EXIT;" to the end of each of the interrupt handlers in that file. This will guarantee that the processor will always be left in the "awake" state after an interrupt runs, and doesn't make it dependent on Energia's timer. Without this change, if for some reason Energia's timer was stopped when you go into LPM4, there is no way to leave the processor awake after an interrupt.

 

topic(second post)=> http://forum.43oh.com/topic/4984-low-power-mode-first-sketch/

 

I found WInterrupts.c but couldn't be sure where to print LPM4_EXIT. So I gave up as it is.

Link to post
Share on other sites
  • 4 weeks later...

Thanks for this library spirilis.

 

I would like to use 250Kbps for the extra range, and I know that auto-ack will not work. But I was wondering, is it possible to use custom ack packets at 250Kbps using your library?

 

Thanks 

Link to post
Share on other sites

Hi folks,

I am trying to use enrf24 library with Tiva C lm4f120 launchpad on Windows and latest energia 0101E0012, lates library release. Using TX demo and RX demo, modifying only the pinout for the three pins.

 

The problem arises with TX demo, that gets stuck in Actively transmitting mode and does not transmit anything. After about 15 transmissions like these, it returns NO TRANSCEIVER PRESENT and crashes until reset. Playing around with different configurations and setups produced no results.

 

The RX demo was tested to work with MSP430G2452 based TX demo, no problems.

 

What could be the cause of this problem. Just to be sure, I am attaching the problematic TX demo code, which is really the same as the example, just pins changed and added SPI.setModule(2), for more rigurous port selection. Any ideas?

#include <Enrf24.h>
#include <nRF24L01.h>
#include <string.h>
#include <SPI.h>


  // radio
  #define ENRF24L_CE PC_7
  #define ENRF24L_CSN PA_5
  #define ENRF24L_IRQ PB_5
  
Enrf24 radio(ENRF24L_CE, ENRF24L_CSN, ENRF24L_IRQ);


const uint8_t txaddr[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0x01 };

const char *str_on = "ON";
const char *str_off = "OFF";

void dump_radio_status_to_serialport(uint8_t);

void setup() {
  Serial.begin(9600);

  SPI.setModule(2);
  SPI.begin();
  SPI.setDataMode(SPI_MODE0);
  SPI.setBitOrder(1); // MSB-first

  radio.begin();  // Defaults 1Mbps, channel 0, max TX power
  dump_radio_status_to_serialport(radio.radioState());

  radio.setTXaddress((void*)txaddr);
}

void loop() {
  Serial.print("Sending packet: ");
  Serial.println(str_on);
  radio.print(str_on);
  radio.flush();  // Force transmit (don't wait for any more data)
  dump_radio_status_to_serialport(radio.radioState());  // Should report IDLE
  delay(1000);

  Serial.print("Sending packet: ");
  Serial.println(str_off);
  radio.print(str_off);
  radio.flush();  //
  dump_radio_status_to_serialport(radio.radioState());  // Should report IDLE
  delay(1000);
}

void dump_radio_status_to_serialport(uint8_t status)
{
  Serial.print("Enrf24 radio transceiver status: ");
  switch (status) {
    case ENRF24_STATE_NOTPRESENT:
      Serial.println("NO TRANSCEIVER PRESENT");
      break;

    case ENRF24_STATE_DEEPSLEEP:
      Serial.println("DEEP SLEEP <1uA power consumption");
      break;

    case ENRF24_STATE_IDLE:
      Serial.println("IDLE module powered up w/ oscillators running");
      break;

    case ENRF24_STATE_PTX:
      Serial.println("Actively Transmitting");
      break;

    case ENRF24_STATE_PRX:
      Serial.println("Receive Mode");
      break;

    default:
      Serial.println("UNKNOWN STATUS CODE");
  }
}
Link to post
Share on other sites

Hi folks,

I am trying to use enrf24 library with Tiva C lm4f120 launchpad on Windows and latest energia 0101E0012, lates library release. Using TX demo and RX demo, modifying only the pinout for the three pins.

 

The problem arises with TX demo, that gets stuck in Actively transmitting mode and does not transmit anything. After about 15 transmissions like these, it returns NO TRANSCEIVER PRESENT and crashes until reset. Playing around with different configurations and setups produced no results.

 

The RX demo was tested to work with MSP430G2452 based TX demo, no problems.

 

What could be the cause of this problem. Just to be sure, I am attaching the problematic TX demo code, which is really the same as the example, just pins changed and added SPI.setModule(2), for more rigurous port selection. Any ideas?

#include <Enrf24.h>
#include <nRF24L01.h>
#include <string.h>
#include <SPI.h>


  // radio
  #define ENRF24L_CE PC_7
  #define ENRF24L_CSN PA_5
  #define ENRF24L_IRQ PB_5
  
Enrf24 radio(ENRF24L_CE, ENRF24L_CSN, ENRF24L_IRQ);


const uint8_t txaddr[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0x01 };

const char *str_on = "ON";
const char *str_off = "OFF";

void dump_radio_status_to_serialport(uint8_t);

void setup() {
  Serial.begin(9600);

  SPI.setModule(2);
  SPI.begin();
  SPI.setDataMode(SPI_MODE0);
  SPI.setBitOrder(1); // MSB-first

  radio.begin();  // Defaults 1Mbps, channel 0, max TX power
  dump_radio_status_to_serialport(radio.radioState());

  radio.setTXaddress((void*)txaddr);
}

void loop() {
  Serial.print("Sending packet: ");
  Serial.println(str_on);
  radio.print(str_on);
  radio.flush();  // Force transmit (don't wait for any more data)
  dump_radio_status_to_serialport(radio.radioState());  // Should report IDLE
  delay(1000);

  Serial.print("Sending packet: ");
  Serial.println(str_off);
  radio.print%2
Link to post
Share on other sites

Further investigation of my problems described above shows, that the TX queue is not being transmitted and the sketch loops until the TX buffer is of 40bytes in length (32B is max). The reason for this behaviour is unknown to me just yet, maybe someone with more in depth knowledge? I suppose the problem lies within flush function or some sub-function.

Link to post
Share on other sites

Further investigation of my problems described above shows, that the TX queue is not being transmitted and the sketch loops until the TX buffer is of 40bytes in length (32B is max). The reason for this behaviour is unknown to me just yet, maybe someone with more in depth knowledge? I suppose the problem lies within flush function or some sub-function.

CE pin hooked up right?  It has to pulse that in order to transmit.

Link to post
Share on other sites

Yes, CE is hooked up, checked with an oscilloscope, bunches of 5 or 6 sequential CE pulses are occuring regularly with TX demo scipt. I will go into dumping it and comparing to MSP430.

 

Tracking the problem through the library brings me to this point, meeting this condition that should never happen. Any ideas?

  reg = _readReg(RF24_FIFO_STATUS);
  if (reg & BIT5) {  // RF24_TX_FULL #define is BIT0, which is not the correct bit for FIFO_STATUS.
	Serial.println("Fail return.");
    return;  // Should never happen, but nonetheless a precaution to take.
  }
Link to post
Share on other sites

Ok so yeah, that's just confirming that indeed the TX fifo is full.

Strange...

Can you post your whole sketch?  I noticed it got cut off at the end.

 

Anyway, I do think it's odd my code just returns when the TX FIFO is full, although I'm aware why; the write() function called by print(), println() et al normally forces a flush if its buffer is full so this situation should never really happen, but I think there's a more graceful way it can handle that.

If you comment out that whole if() block, does it work?

Link to post
Share on other sites

Wow, it starts working if CE wire is disconnected after getting into TX mode, when the whole thing is in loop(). Interestingly enough, it works without CE pulses then.

 

Commenting out this if() block does indeed stop the buffer from filling up, but the transmission does not occur untill CE cable is disconnected.

 

The whole sketch re-posted:

#include <Enrf24.h>
#include <nRF24L01.h>
#include <string.h>
#include <SPI.h>


  // radio 
  #define ENRF24L_CE PC_7
  #define ENRF24L_CSN PA_5
  #define ENRF24L_IRQ PB_5

Enrf24 radio(ENRF24L_CE, ENRF24L_CSN, ENRF24L_IRQ);

const uint8_t txaddr[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0x01 };

const char *str_on = "ON";
const char *str_off = "OFF";

void dump_radio_status_to_serialport(uint8_t);

void setup() {
  Serial.begin(9600);

  SPI.begin();
  SPI.setDataMode(SPI_MODE0);
  SPI.setBitOrder(1); // MSB-first

  radio.begin();  // Defaults 1Mbps, channel 0, max TX power
  radio.autoAck(false);  // no auto ack
  dump_radio_status_to_serialport(radio.radioState());

  radio.setTXaddress((void*)txaddr);
}

void loop() {
  Serial.print("Sending packet: ");
  Serial.println(str_on);
  radio.print(str_on);
  radio.flush();  // Force transmit (don't wait for any more data)
  dump_radio_status_to_serialport(radio.radioState());  // Should report IDLE
  delay(1000);

  Serial.print("Sending packet: ");
  Serial.println(str_off);
  radio.print(str_off);
  delay(100);
  radio.flush();  //
  dump_radio_status_to_serialport(radio.radioState());  // Should report IDLE
  delay(1000);
}

void dump_radio_status_to_serialport(uint8_t status)
{
  Serial.print("Enrf24 radio transceiver status: ");
  switch (status) {
    case ENRF24_STATE_NOTPRESENT:
      Serial.println("NO TRANSCEIVER PRESENT");
      break;

    case ENRF24_STATE_DEEPSLEEP:
      Serial.println("DEEP SLEEP <1uA power consumption");
      break;

    case ENRF24_STATE_IDLE:
      Serial.println("IDLE module powered up w/ oscillators running");
      break;

    case ENRF24_STATE_PTX:
      Serial.println("Actively Transmitting");
      break;

    case ENRF24_STATE_PRX:
      Serial.println("Receive Mode");
      break;

    default:
      Serial.println("UNKNOWN STATUS CODE");
  }
}
Link to post
Share on other sites

Ok, that's strange but at least we're getting somewhere.

 

1. Is this a genuine nRF24L01+ module, or one of those newfangled SI24R1 taiwanese-nRF24L01+-knockoff-silicon modules?  I have a whole order of the latter on my desk at home but haven't played with them yet & haven't properly vetted them with this library yet.

 

2. In the flush() function, can you change my delayMicroseconds(100); to something like delay(1); ?

Talking about this:

  _issueCmdPayload(RF24_W_TX_PAYLOAD, txbuf, txbuf_len);
  digitalWrite(_cePin, HIGH);
  delayMicroseconds(100);
  digitalWrite(_cePin, LOW);
Link to post
Share on other sites

I believe it is genuine nRF24L01+, green board, 10pin connector. Chip markings state NRF 0 24L01+ (1423CC date?).

 

Increasing the delay to any time, or even removing the digitalWrite(_cePin, LOW) does not make a change. Even permanently changing all of the CE writes to HIGH does nothing. So I have investigated further and something strange is going on.

 

Chooring a random pin for CE does not change anything, say PE_2. Setting pin PD_0 to output and HIGH prevents the module to be found.

 

So this part of the problem may have nothing to do with the library as such.

Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


×
×
  • Create New...