Jump to content
43oh

meet

Members
  • Content Count

    22
  • Joined

  • Last visited

Reputation Activity

  1. Like
    meet got a reaction from spirilis in [Energia Library] Nordic nRF24L01+ library   
    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.
  2. Like
    meet reacted to spirilis in [Energia Library] Nordic nRF24L01+ library   
    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.
  3. Like
    meet reacted to spirilis in [Energia Library] Nordic nRF24L01+ library   
    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
     
     
  4. Like
    meet reacted to spirilis in [Energia Library] Nordic nRF24L01+ library   
    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.
  5. Like
    meet reacted to Thorvard in Using interrupt   
    Try activating the internal pullup on pin P1.4:
    pinMode(P1_4, INPUT_PULLUP); and define state as boolean:
    volatile boolean state = LOW;
  6. Like
    meet got a reaction from Thorvard in Using interrupt   
    Thanks a lot! Input pullup doesn't mean anything but boolean state made it works.
  7. Like
    meet reacted to roadrunner84 in IES   
    P1.1 does not have a button connected (at the Launchpad G2), the second button is connected to the reset line, which can only be used as an edge triggered input or a physical reset.
    Would you use a button connected to P1.1, make sure to disconnect the jumper on J3 to disconnect the UART line from that pin.
×
×
  • Create New...