Jump to content
43oh

[Energia Library] Nordic nRF24L01+ library


Recommended Posts

  • 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

I read in the ENRF24 code that AutoAck is not enabled when in 250kbps mode.  Is that an implementation restriction or is that a hardware restriction?  I don't remember reading that in the data sheet and I have run the pure C implementation of the msprf24 library and I feel like I was able to use AutoAck at that speed.  But maybe I am missing something.

 

Thanks.

Link to post
Share on other sites

I read in the ENRF24 code that AutoAck is not enabled when in 250kbps mode.  Is that an implementation restriction or is that a hardware restriction?  I don't remember reading that in the data sheet and I have run the pure C implementation of the msprf24 library and I feel like I was able to use AutoAck at that speed.  But maybe I am missing something.

 

Thanks.

My understanding is it's a hardware limitation although not explicitly defined in the datasheet ... however there is a subtle wording in the datasheet that might imply it IMO.  I have never seen it work correctly with my own modules, i.e. I have never sent data at 250Kbps to a receiver turned off or out of range and actually seen it "fail", the only real indicator I have as to whether or not it works.  It always replies that TX succeeded.

 

Looks like I implemented Enrf24 to prevent you from using it at 250Kbps.  If you have a solid example of autoack actually working - i.e., you have sent data at 250Kbps with my msprf24 library with autoack enabled and found it to actually FAIL when the receiver isn't turned on - then maybe all my modules are some Chinese knockoff silicon (quite possible as I've read recently) and the real chip (expensive) actually implements it :-)

 

If that's the case then I'll make a modification to allow this in Enrf24...

Link to post
Share on other sites

Just a word about using this with interrupts... .

 

Using the interrupt to trigger a receive routine saves having to check (via SPI) on the state of the input buffer of the 24L01. However, if elsewhere in your program you transmit data, an interrupt will also occur when the transmit buffer is empty.

 

In short, your interrupt routine must check whether you are transmitting or receiving because reading the input buffer whilst transmitting really messes things up.

 

I apologise if some find this obvious, but HTH

 

Steve

Link to post
Share on other sites

Just a word about using this with interrupts... .

 

Using the interrupt to trigger a receive routine saves having to check (via SPI) on the state of the input buffer of the 24L01. However, if elsewhere in your program you transmit data, an interrupt will also occur when the transmit buffer is empty.

 

In short, your interrupt routine must check whether you are transmitting or receiving because reading the input buffer whilst transmitting really messes things up.

 

I apologise if some find this obvious, but HTH

 

Steve

Definitely something to keep in mind if you are using the interrupt function to wake the MCU out of sleep (using wakeup() in complement to having put the chip to sleep with sleep(), sleepSeconds() or suspend() previously).

 

Fwiw, take a look at the .available() function and its argument - you can pass it (true), e.g. radio.available(true) to have it "shortcut" check the transceiver by doing a digitalRead() on the IRQ pin, and going no further (no SPI I/O) if the IRQ pin isn't reading LOW.  The default argument is false, i.e. go all the way over SPI to verify there's nothing pending.  So there is no reason to employ an ISR with this library if your primary reason is to avoid extraneous SPI I/O.

Link to post
Share on other sites

The main reason I use interrupts is to transmit many more than 32 bytes. When the device has emptied its transmit buffer the IRQ only goes low very briefly, so polling for it won't work AFAIK. 

Pseudo code:

flag =1;
radio.print(block1);
radio.flush();
while (flag) ;
//.. loop/repeat ad infinitum

Int flag = 0;
 

You can do a similar thing for the RX interrupt - set a flag and let the main loop handle it later.

Link to post
Share on other sites

The main reason I use interrupts is to transmit many more than 32 bytes. When the device has emptied its transmit buffer the IRQ only goes low very briefly, so polling for it won't work AFAIK. 

Pseudo code:

flag =1;
radio.print(block1);
radio.flush();
while (flag) ;
//.. loop/repeat ad infinitum

Int flag = 0;
 

You can do a similar thing for the RX interrupt - set a flag and let the main loop handle it later.

Yeah ... Not sure though why you need to do that, flush() doesn't return until it's handled the TX interrupt.  So .flush() is a blocking call.

 

From Enrf24.cpp line 363 in Enrf24::flush():

  while (digitalRead(_irqPin) == HIGH)  // Wait until IRQ fires
    ;
  // IRQ fired
  _maintenanceHook();  // Handle/clear IRQ
Link to post
Share on other sites

Unfortunately you are absolutely correct! My problem was caused by allowing the receive routine to be triggered by the TX buffer empty signal, hence my original post.

 

Thank-you very much for that.

Hmm, do you think there is some internal flagging I should do within the library to prevent this?  Sounds like a reentrancy problem actually ... where the TX IRQ may fire an interrupt routine which may try to do some nRF24L01+ I/O that it shouldn't be doing.

Link to post
Share on other sites

Having spent some time thinking about this, I'm undecided. Simply setting a flag before transmitting and clearing it when done, does the trick. Testing this flag in the interrupt routine prevents the reading of data. It would be unnecessary if interrupts are not used. (I needed to use interrupts to minimise power.)

 

BTW, thanks for your efforts - it has saved me a lot of time despite my problems.

 

Steve

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

Spirilis,

 

Speaking on the use of low power and interrupts, I was curious why the energia library doesn't use the interrupts and instead polls the pins.  In your C library that I have used I was able to go into a low power mode and wait for the nrf24 to wake me up.  In the energia it doesn't seem to allow you do to that as easily.  Is there any reason for the difference in the way you wrote the Energia library vs the C library?

Link to post
Share on other sites

I should have read the beginning of this topic before asking the questions as it seems at the time of writing there was not a good way to handle that in Energia.  I may be wrong, but now we should be able to use suspend() with wakeup() to get the same functionality as the c library.  Is there any plans to rewrite any of this to better handle the IRQ from the nrf24l01?  

Link to post
Share on other sites

I should have read the beginning of this topic before asking the questions as it seems at the time of writing there was not a good way to handle that in Energia.  I may be wrong, but now we should be able to use suspend() with wakeup() to get the same functionality as the c library.  Is there any plans to rewrite any of this to better handle the IRQ from the nrf24l01?  

So my position on this is - The library shouldn't handle that, the user is perfectly capable of registering the nRF24 IRQ pin with their own simple handler using attachInterrupt().  That handler can then set a flag and run wakeup() to signal your main loop to check the nRF24.

 

More importantly, you DON'T want an IRQ ISR handler contacting the nRF24 over SPI - because what happens if your nRF24 receives a packet and fires the IRQ in the middle of you doing SPI I/O with, say, an LCD display? (a great example since LCD display writes often entail very lengthy and chatty SPI transactions and depending on the application, require periodic changes/updates, thus raising the probability of a conflict)

 

More on this topic here - http://dorkbotpdx.org/blog/paul/spi_transactions_in_arduino

Energia does not support Paul's new SPI Transaction feature, so there is no "safe" way to implement in-ISR SPI I/O.

 

So an idiomatic way to approach this might be something like this:

Enrf24 radio(5, 6, 7);

void setup() {
  SPI.begin();
  radio.begin();
  radio.enableRX();

  attachInterrupt(7, wake_on_rf);
}

volatile boolean rf_pending = false;

void loop() {
  // blah blah do something blah blah

  // radio.available() won't actually run if rf_pending is false
  if (rf_pending && radio.available()) {
    // blah blah do something RF-related blah blah
    rf_pending = false;
  }

  // blah blah do something else blah blah
  // go to low-power sleep
  suspend();
}

void wake_on_rf()
{
  rf_pending = true;
  wakeup();
}
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...