Jump to content
43oh

nrf24L01+ wake-up after powerdown


Recommended Posts

I am trying to do exactly what spirilis describes in the hypothetical remote sensing application on his wiki for the nrf24L01+ library:

 

"A typical application of the nRF24L01+ which takes full advantage of the MSP430's touted low-power modes is remote sensing with periodic wakeup involving an MSP430 circuit attached to sensors in a remote location. An MSP430 using either the VLO or LFXT1 driving ACLK to wake up the device periodically will switch on the nRF24, take sensor measurements and once the nRF24 is ready (5ms Standby-I wakeup time has elapsed), transmit those to a base station, followed by deep powerdown of the nRF24 chip and any sensors involved. LPM3 is an appropriate sleep mode for this application."

 

 This is how far I have gotten:

#include <msp430.h>
#include "msprf24.h"
#include "nrf_userconfig.h"
#include "stdint.h"

volatile unsigned int user;

unsigned int delay;

unsigned int delay = 0;

void main(){
char addr[5];
char buf[32];

WDTCTL = WDTHOLD | WDTPW;
DCOCTL = CALDCO_1MHZ;
BCSCTL1 = CALBC1_1MHZ;
BCSCTL2 = DIVS_2;  // SMCLK = DCOCLK/2
// SPI (USCI) uses SMCLK, prefer SMCLK < 10MHz (SPI speed limit for nRF24 = 10MHz)

BCSCTL3 |= LFXT1S_2;

TACCR0 = 50000;
TACTL = TASSEL_1 + ID1 + MC_1;    // ACLCK, 1/8 DIVIDER, upmode to TCCR0 value
TACCTL0 = CCIE;
TACCR1 = 0;

//setup pins
P1DIR |= BIT0;// Red used for status

user = 0xFE;

/* Initial values for nRF24L01+ library config variables */
rf_crc = RF24_EN_CRC | RF24_CRCO; // CRC enabled, 16-bit
rf_addr_width      = 5;
rf_speed_power     = RF24_SPEED_1MBPS | RF24_POWER_MAX;
rf_channel         = 120;

msprf24_init();  // All RX pipes closed by default
msprf24_set_pipe_packetsize(0, 32);
msprf24_open_pipe(0, 1);  // Open pipe#0 with Enhanced ShockBurst enabled for receiving Auto-ACKs
msprf24_set_retransmit_count(15);

// Transmit to 'rad01' (0x72 0x61 0x64 0x30 0x31) F0F0F0F0E4
msprf24_standby();
user = msprf24_current_state();
addr[0] = 0xDE; addr[1] = 0xAD; addr[2] = 0xBE; addr[3] = 0xEF; addr[4] = 0x00;
w_tx_addr(addr);
w_rx_addr(0, addr);  // Pipe 0 receives auto-ack's, autoacks are sent back to the TX addr so the PTX node
            // needs to listen to the TX addr on pipe#0 to receive them.

while(1){
if(delay == 2){
msprf24_standby();
_delay_cycles(5000);
P1OUT |= BIT0;  // Red LED on
flush_tx();
buf[0] = '1';
w_tx_payload(32, buf);
msprf24_activate_tx();
delay=0;
//msprf24_powerdown();
LPM3;
}
if (rf_irq & RF24_IRQ_FLAGGED) {
msprf24_get_irq_reason();
if (rf_irq & RF24_IRQ_TX){
flush_tx();
buf[0] = '0';
w_tx_payload(32, buf);
msprf24_activate_tx();
P1OUT &= ~BIT0; //Red LED off
}
}
msprf24_irq_clear(rf_irq);
user = msprf24_get_last_retransmits();

}
}

// Timer A0 interrupt service routine
#pragma vector=TIMER0_A0_VECTOR
__interrupt void Timer_A (void)
{
  delay++;
}

As you can see I send an initial TX then enter LPM3 mode. I use timera to wake up the MSP430 every 25 seconds or so, increment the delay variable, check to see if the delay variable is equal to the predefined value and if so it send another TX and go back into LPM3. The  goal is achieve the lowest power consumption possible so I would also like to powerdown the nrf24 as spirilis suggests. The problem is when I try to use the msprf24_powerdown function I can't seem to wake the nrf24 back up. I thought from reading the documentation that I only needed to issue the msprf24_standby function then wait 5ms. I have tried a number of different things including calling the standby function and checking the transceiver states. Can't seem to get it to work. Thoughts?   

 

Link to post
Share on other sites

Ah so I suspect you read & implemented my blurb a bit too literally :D  I should revise that at some point for exactness.

 

Problems:

if(delay == 2){
    msprf24_standby();
    _delay_cycles(5000);
    P1OUT |= BIT0;  // Red LED on
    flush_tx();
    buf[0] = '1';
    w_tx_payload(32, buf);
    msprf24_activate_tx();
    delay=0;
    //msprf24_powerdown();
    LPM3;

Yes, you certainly wouldn't want to power down the transceiver the moment it *started transmitting*.  The msprf24_powerdown() would be at the very end of your TX IRQ handler, unless you want to continuously transmit and transmit and transmit toggling the pin each time.  That LPM3 would last in practice only until the transceiver was done transmitting and had either successfully transmitted (msprf24_get_irq_reason() setting rf_irq to RF24_IRQ_TX) or unsuccessfully (RF24_IRQ_TXFAILED).  The latter could indeed happen, because you are using 1Mbps (1Mbps and 2Mbps are eligible for AutoACK) and have autoack enabled in msprf24_open_pipe().  Need to make sure you catch that IRQ.

 

 

Here's a typical while() loop that has worked for me, now that I have a bit of experience under my belt with these transceivers:

        while(1) {
                // Handle RF acknowledgements
                if (rf_irq & RF24_IRQ_FLAGGED) {
                        msprf24_get_irq_reason();

                        // Handle TX acknowledgements
                        if (rf_irq & RF24_IRQ_TX) {
                                // Acknowledge
                                msprf24_irq_clear(RF24_IRQ_TX);
                                msprf24_powerdown();
                                P2OUT &= ~LED_POT;
                        }

                        if (rf_irq & RF24_IRQ_TXFAILED) {
                                msprf24_irq_clear(RF24_IRQ_TXFAILED);
                                flush_tx();
                                msprf24_powerdown();
                                P2OUT &= ~LED_POT;
                        }

                        if (rf_irq & RF24_IRQ_RX) {
                                // Really no reason we should be receiving anything.
                                flush_rx();
                                msprf24_irq_clear(RF24_IRQ_RX);
                        } /* rf_irq & RF24_IRQ_RX */
                }  /* rf_irq & RF24_IRQ_FLAGGED */

                if (rotbtn) {
                        // Process rotary encoder button press
                        if (saturation == 1.0)
                                saturation = 0.2;
                        else
                                saturation = 1.0;
                        // Do update
                        if (msprf24_queue_state() & RF24_QUEUE_TXEMPTY) {
                                HSV_to_RGB(dmx512_buffer, (float)rotenc, saturation, (float) (pot / POT_UPPER_VALUE) );
                                dmx512_output_channels(P2IN & 0x03, 1, dmx512_buffer, 3);
                        }

                        rotbtn = 0;
                }
                if (!sleep_counter) {  // ADC conversion timer
                        ADC10CTL0 = SREF_1 | ADC10SHT_3 | REFBURST | REFON | REFOUT | ADC10ON;
                        ADC10CTL1 = INCH_3 | ADC10DIV_1;
                        ADC10AE0 |= BIT3;

                        ADC10CTL0 |= ENC | ADC10SC;
                        while (ADC10CTL1 & ADC10BUSY)
                                ;
                        pot = ADC10MEM >> 3;
                        ADC10CTL1 &= ~ENC;
                        ADC10CTL0 &= ~(ADC10ON | ADC10IFG);

                        if (pot != pot_old) {
                                // Do update
                                if (msprf24_queue_state() & RF24_QUEUE_TXEMPTY) {
                                        HSV_to_RGB(dmx512_buffer, (float)rotenc, saturation, (float) (pot / POT_UPPER_VALUE) );
                                        dmx512_output_channels(P2IN & 0x03, 1, dmx512_buffer, 3);
                                        pot_old = pot;
                                }
                        }

                        sleep_counter = ADC_SLEEP_INTERVAL;
                }

                if (rotenc != rotenc_old) {
                        // Do update
                        if (msprf24_queue_state() & RF24_QUEUE_TXEMPTY) {
                                HSV_to_RGB(dmx512_buffer, (float)rotenc, saturation, (float) (pot / POT_UPPER_VALUE) );
                                dmx512_output_channels(P2IN & 0x03, 1, dmx512_buffer, 3);
                                rotenc_old = rotenc;
                        }
                }

                if (packet_task_next() != NULL) {
                        packet_process_txqueue();
                        P2OUT |= LED_POT;
                }

        LPM3;
        } /* while(1) */

Note the program flow; Handle RF IRQs at the top of the loop, then process other events, deciding whether to wake it up & transmit again.  FYI, the packet_process_txqueue() function does some stuff that ultimately results in doing a w_tx_addr(), followed by w_tx_payload() and msprf24_activate_tx() before returning.  (There's a simplistic logical link layer-type of protocol I developed for my own purposes that sits on top of the nRF24L01+'s packets, using the dynamic payload size feature too)

 

Then it goes into LPM3, waking up eventually by the transceiver firing the RF24_IRQ_TX or RF24_IRQ_TXFAILED IRQs.  Only when the handler code sees & acknowledges those IRQs, will it issue msprf24_powerdown().  Between the issuing of msprf24_activate_tx() and the TX or TXFAILED IRQs being "handled", the transceiver should be powered up and it will be going through its process of sending the packet.

 

The chip may also wake up from LPM3 due to the WDT ISR timing out (sleep_counter reaching 0), either way, the whole loop runs and events are addressed as they come.  It's a good idea to have the RF IRQ handlers up top so they're the first thing that runs after LPM3 exits.

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