Jump to content
spirilis

[Energia Library] Nordic nRF24L01+ library

Recommended Posts

Thanks!!!!!!!!  :biggrin:

Now function very well with 2553 and 2452

 

Things what I do not  made:

2553 ---> jumper "HW UART"  - MISO P1.6 - MOSI P1.7

2452----> jumper "SW UART"  - MISO P1.7 - MOSI P1.6

 

Thank you very much for your help!

Share this post


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.

Share this post


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...

Share this post


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

Share this post


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.

Share this post


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.

Share this post


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

Share this post


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.

Share this post


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.

Share this post


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

Share this post


Link to post
Share on other sites

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?

Share this post


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?  

Share this post


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();
}

Share this post


Link to post
Share on other sites

Awesome, thanks for the reply and the example code.  My only thought on this would be in any type of ISR handler you should only be doing the bare minimum.  I would hope no libraries would do a SPI transaction from inside an interrupt routine.  

Share this post


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...