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

That's strange, I tried the code below and it doesn't work

//PIR input on port P1_1
volatile int state = LOW;

void setup()
{
 
  pinMode(P1_1, INPUT);
  pinMode(RED_LED, OUTPUT);
  attachInterrupt(P1_1, A, RISING);
}

void loop()
{
  digitalWrite(RED_LED, state);
}

void A(){
  state = !state;
  
}

I checked the output pin of PIR and see that it give 3.4V when motion detected, so PIR is working. But I can't get P1_1 read this voltage and fire its flag to blink the red led on launchpad.

Link to post
Share on other sites

That's strange, I tried the code below and it doesn't work

//PIR input on port P1_1
volatile int state = LOW;

void setup()
{
 
  pinMode(P1_1, INPUT);
  pinMode(RED_LED, OUTPUT);
  attachInterrupt(P1_1, A, RISING);
}

void loop()
{
  digitalWrite(RED_LED, state);
}

void A(){
  state = !state;
  
}

I checked the output pin of PIR and see that it give 3.4V when motion detected, so PIR is working. But I can't get P1_1 read this voltage and fire its flag to blink the red led on launchpad.

Gotcha; Can you post a new thread about this in the Energia subforum?  Just don't want this issue cluttering up the nRF24L01+ thread too much :)

Thanks

Link to post
Share on other sites

I fixed it, now it works but I can't run radio.begin inside the interrupt vector. It's working when it's defined on setup(), but as you said it means that radio is not sleeping.

I can get the radio connection with code below, my PIR sensor trigger P1_4 and this cause interrupt  fires, inside the interrupt vector I use the radio.print to send data to always wakened receiver. receiver read this data and blink a led. It works.

// TX part

#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 txaddr[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0x01 };
 
const char *str_on = "ON_A";

 
void setup() {
  SPI.begin();
  SPI.setDataMode(SPI_MODE0);
  SPI.setBitOrder(1); // MSB-first
  
  P1DIR &= ~BIT4;		
  P1REN |= BIT4 ;
  P1OUT &= ~BIT4;
  P1IE |=  BIT4; 		
  P1IES &= ~BIT4;
  P1IFG &= ~BIT4 ;
  
  radio.begin();  // Defaults 1Mbps, channel 0, max TX power
  radio.setTXaddress((void*)txaddr);

 _BIS_SR(GIE + LPM4_bits);   
  
}
 
void loop() {

  LPM4;
 
}


#pragma vector = PORT1_VECTOR
__interrupt void A(void){
   P1IFG &= ~BIT4;
  
  // radio.begin doesn't work here.
 
  radio.print(str_on);
  radio.flush();  // Force transmit (don't wait for any more data)
  delay(1000);
	
       
        
       

}

Do you have an idea how to awaken the radio inside the interrrupt service routine and make it sleep till a new interrup comes ? 

Thanks in advance spirilis.

Link to post
Share on other sites

Actually this loop things in energia confuse me, I can't use it efficiently.

 

Another thing, it seems like TX radio sends continuosly data when triggered inside the interrupt vector, how can I make it stop ?

 

#pragma vector = PORT1_VECTOR
__interrupt
void A(void){
P1IFG &= ~BIT4;

radio.print(str_on);
radio.flush(); // Force transmit (don't wait for any more data)
delay(1000);

// sends data continuously, I want to stop it.
    

Link to post
Share on other sites

I can't say I have ever tried using any radio functions inside an ISR, because as a matter of design principle it's a terrible idea. ISRs are meant for flagging that some event has occurred so your main loop knows that it needs to process the results, or to do very light tasks like flipping an LED or whatnot. So I can't be of much help here.

 

Sent from my Galaxy Note II with Tapatalk 4

 

 

Link to post
Share on other sites

You don't want to run begin() inside the interrupt routine, just inside setup(). Set another attachInterrupt for the radio's IRQ line and do an LPM4_exit inside that to fully wake up the chip. Then in your loop() process the radio message.

 

Sent from my Galaxy Note II with Tapatalk 4

 

I would do if I know how to do, but clearly I don't know how. Maybe it's a simple thing for you but I don't have enough information about it and that's why I'm asking here, to improve my knowledge. Maybe you can help more clear to me. Thanks a lot. 

Link to post
Share on other sites

I would do if I know how to do, but clearly I don't know how. Maybe it's a simple thing for you but I don't have enough information about it and that's why I'm asking here, to improve my knowledge. Maybe you can help more clear to me. Thanks a lot. 

Ah okay, looks like you were a bit confused on what loop() et al is...

 

Anyway, first off, Energia in its present form doesn't really "cater" to the use of LPM properly, imo.  That may change in the future but I get the impression that using the LPMx commands as they are seems sufficient for most people, even though the millis() and micros() counters don't get correctly updated during that sleep mode.

 

Take a look at the Getting Started tutorial so you know what setup() and loop() are there for- http://energia.nu/Tutorial_Sketch.html

 

The problem with running lots of code inside an interrupt routine is that your code may affect peripherals that were in the midst of being modified by your loop() function... e.g. if you had a more complex app that updated an SPI LCD display, having nRF24L01+ radio commands inside an ISR could totally bomb if the ISR began and tried doing SPI communication with the radio while your main loop() code was in the middle of doing SPI I/O with an LCD display.  That doesn't seem to be the case here, as your app is quite simple, but it's a very important thing to keep in mind when designing your sketches.  Interrupts literally pull the CPU out of whatever it was working on, and branches it off to execute your interrupt routine code, with no regards to properly "cleaning up" the state of the system.

 

So in general, a flag ISR should do something simple like update a "flag variable", and your main loop() should be where all the action is.

 

Let me try rewriting your sketch to illustrate what I'm talking about:

// TX part

#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 txaddr[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0x01 };
 
const char *str_on = "ON_A";

 
void setup() {
  SPI.begin();
  SPI.setDataMode(SPI_MODE0);
  SPI.setBitOrder(1); // MSB-first
  
  P1DIR &= ~BIT4;		
  P1REN |= BIT4 ;
  P1OUT &= ~BIT4;
  P1IE |=  BIT4; 		
  P1IES &= ~BIT4;
  P1IFG &= ~BIT4 ;
  
  radio.begin();  // Defaults 1Mbps, channel 0, max TX power
  radio.setTXaddress((void*)txaddr);
}

volatile boolean pir_flag = FALSE;  // Flag variable
 
void loop() {
  if (pir_flag == TRUE) {
    // PIR event detected; send radio message!
    radio.print(str_on);
    radio.flush();  // force transmission
    pir_flag = FALSE;
  }

  if (pir_flag == FALSE) {  // probably not necessary but can't hurt
                            // to put this conditional in there
    LPM4;
  } 
}


#pragma vector = PORT1_VECTOR
__interrupt void A(void){
  P1IFG &= ~BIT4;
  // Signal to the main loop() that a PIR event has occurred.
  pir_flag = TRUE;
  // Exit LPM.
  LPM4_exit;
}

It's important to use the "volatile" keyword for the flag variable because that instructs the compiler to always pull its value from RAM; never try to rely on "saving" or "caching" a copy of it in registers and referencing that when the variable is read.

 

Energia only runs setup() once, but it keeps re-running loop() forever.  In this example, when no PIR event has been detected, the loop() function pauses in LPM4.  When the ISR runs, LPM4 gets cancelled and when the ISR exits, the code after LPM4 in the loop() function is run; which is nothing, and so loop() just exits.  But then Energia's core code re-runs loop(), where it will check that pir_flag variable and act on it if it's TRUE, or skip it and go back into LPM4 if it's FALSE.

 

In this case your ISR is incredibly simple; it clears the P1IFG bit, sets a flag variable, and exits LPM4.  In reality the flag might not actually be necessary since there is only 1 event that is capable of cancelling LPM.

 

Also note I haven't done anything with the nRF24's IRQ.  This is because this code is for the transmitter only; after radio.flush() completes, there is no reason to watch the radio's IRQ line.  Your RX code will look different here; you'll need an ISR for the radio that sets a flag variable and some code in loop() to handle incoming radio data.

Link to post
Share on other sites

I was thinking that you didn't write a response of my last post, I just find it out now.

 

That codes make it all clear now, it's so explicit and very simple but incisive. Thanks for your guide, I'm going to apply this method to my nrf sensor nodes and hope it will work :)

 

About the IRQ, is that something I need to use when I received data and want to close the connection with the transceiver pair?

Because I observe that when TX sends data to RX, it latched connected each other(I prove that with powering rf on/off) and I don't know how to disconnect them.

 

My code for RX is below;

#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);
 
  
  radio.enableRX();  // Start listening
}
 
void loop() {
  char inbuf[33];
  
  while (!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);

  }
}

Thanks in advance, you improve my viewpoint.

Link to post
Share on other sites

By the way, LPM4_exit gives the error "was not declared on this scope". And I think it's a must to use it to start void loop() and check if flag is TRUE.

 

edit: I used  __bic_SR_register_on_exit(LPM4_bits)  and it's solved. PIR node works perfectly!

 

My question about the IRQ is still valid :)

Link to post
Share on other sites

By the way, LPM4_exit gives the error "was not declared on this scope". And I think it's a must to use it to start void loop() and check if flag is TRUE.

 

edit: I used  __bic_SR_register_on_exit(LPM4_bits)  and it's solved. PIR node works perfectly!

 

My question about the IRQ is still valid :)

I'm a little puzzled by what you mean here. "Latched"? Does the TX side just continuously transmit? Or is the RX side reading the same thing over and over with it not flushing the results from the transceiver? I.e. does this issue stop if you only remove power from the TX side?
Link to post
Share on other sites

Yes, before it was like you described (stop if you only remove power from the TX side). 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. 

 

And still wondering about IRQ you mentioned above.

if (pir_flag == FALSE) { 

void deepsleep();// here it is

LPM4;
} 
}
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...