spirilis 1,265 Posted March 18, 2014 Author Share Posted March 18, 2014 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 meet 1 Quote Link to post Share on other sites
meet 2 Posted March 18, 2014 Share Posted March 18, 2014 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. Quote Link to post Share on other sites
spirilis 1,265 Posted March 18, 2014 Author Share Posted March 18, 2014 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. meet and gssmahadevan 2 Quote Link to post Share on other sites
meet 2 Posted March 18, 2014 Share Posted March 18, 2014 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. spirilis 1 Quote Link to post Share on other sites
theb 0 Posted April 14, 2014 Share Posted April 14, 2014 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 Quote Link to post Share on other sites
SloMusti 2 Posted April 14, 2014 Share Posted April 14, 2014 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"); } } Quote Link to post Share on other sites
SloMusti 2 Posted April 14, 2014 Share Posted April 14, 2014 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 Quote Link to post Share on other sites
SloMusti 2 Posted April 15, 2014 Share Posted April 15, 2014 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. Quote Link to post Share on other sites
spirilis 1,265 Posted April 15, 2014 Author Share Posted April 15, 2014 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. Quote Link to post Share on other sites
SloMusti 2 Posted April 15, 2014 Share Posted April 15, 2014 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. } Quote Link to post Share on other sites
spirilis 1,265 Posted April 15, 2014 Author Share Posted April 15, 2014 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? Quote Link to post Share on other sites
SloMusti 2 Posted April 15, 2014 Share Posted April 15, 2014 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"); } } Quote Link to post Share on other sites
SloMusti 2 Posted April 15, 2014 Share Posted April 15, 2014 CE disconnected equals to pulling it high permanently. Quote Link to post Share on other sites
spirilis 1,265 Posted April 15, 2014 Author Share Posted April 15, 2014 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); Quote Link to post Share on other sites
SloMusti 2 Posted April 15, 2014 Share Posted April 15, 2014 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. Quote Link to post Share on other sites
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.