Project

General

Profile

Jeenode micro with RFM69CW hangs in rf12_sendWait

Added by aelfric 8 months ago

I am trying to make this into a temperature node but am starting out with the radioBlip2 sketch.

I added the RF69_compat #define at the top of the file and I can receive successful packet transmissions, when it works.

The problem I have is that the code will hang in rf12_sendWait(SEND_MODE) if SEND_MODE is 2 or 3. It works OK if SEND_MODE is 0 or 1.

I have not touched the fuses yet, they are the default as shipped which reads as E:FF, H:DF, L:E2.

Should I set the fuses to e=06/h=DE/l=CE as mentioned in the sketch or something else or just leave alone?

Sorry, I am a bit new to the Tiny-84 so not that familiar with it yet.

Andrew


Replies (52)

RE: Jeenode micro with RFM69CW hangs in rf12_sendWait - Added by JohnO 8 months ago

It could be related to the fuses and processor startup time:

void rf69_sendWait (uint8_t mode) {
    while (RF69::sending())
        if (mode) {
            set_sleep_mode(mode == 3 ? SLEEP_MODE_PWR_DOWN :
#ifdef SLEEP_MODE_STANDBY
                           mode == 2 ? SLEEP_MODE_STANDBY :
#endif
                                       SLEEP_MODE_IDLE);
            sleep_mode();
        }
}

RE: Jeenode micro with RFM69CW hangs in rf12_sendWait - Added by aelfric 8 months ago

At the moment, it is still attached to the programmer so should have a reasonable supply of power so I am not sure what you mean about processor startup time.

Do you have any thoughts on what fuses might need to be changed? This is a Jeenode Micro built for direct power, no boost, bought with no RF but then a RFM69CW soldered on.

Thanks,
Andrew

RE: Jeenode micro with RFM69CW hangs in rf12_sendWait - Added by JohnO 8 months ago

The processor startup time is relevant when SLEEP_MODE_PWR_DOWN is used. It is the time allowed for the processor to be ready to do instructions again.

RE: Jeenode micro with RFM69CW hangs in rf12_sendWait - Added by aelfric 8 months ago

OK but the fuses say that the startup time is set to the maximum of 64ms already, which should be overkill. Now I have looked a bit more at the fuses they look plausible to me. But the question remains why does it hang when SEND_MODE is 2? What can I do to investigate this some more?

Andrew

RE: Jeenode micro with RFM69CW hangs in rf12_sendWait - Added by JohnO 8 months ago

I think we need a fast startup rather than slow at 64ms.

RE: Jeenode micro with RFM69CW hangs in rf12_sendWait - Added by JohnO 8 months ago

I think @martyn is saying in the above that going into power down drops the signal to the mosfet which then powers down the radio.

RE: Jeenode micro with RFM69CW hangs in rf12_sendWait - Added by martynj 8 months ago

aelfric,

If you have your soldering iron handy, connecting up the RFM69CW Vcc pin directly to the 3V supply will confirm if sleep_mode() is messing up the RF module power switching.

RE: Jeenode micro with RFM69CW hangs in rf12_sendWait - Added by aelfric 8 months ago

A startup time of 0, 4ms or 64ms makes no difference.

Connecting the Vcc pin to the 3V supply makes no difference.

In SEND_MODE = 2, it still hangs in sendWait. The RF is on at this point as it jams the receiving node from hearing any other transmissions.

Andrew

RE: Jeenode micro with RFM69CW hangs in rf12_sendWait - Added by JohnO 8 months ago

Hi Andrew,

Could you post the full sketch.

RE: Jeenode micro with RFM69CW hangs in rf12_sendWait - Added by aelfric 8 months ago

/// @dir radioBlip2
/// Send out a radio packet every minute, consuming as little power as possible.
// 2012-05-09 <jc@wippler.nl> http://opensource.org/licenses/mit-license.php

#define RF69_COMPAT 1
#include <JeeLib.h>
#include <avr/sleep.h>

#define BOOST     0   // measure battery on analog pin if 1, else vcc after

#define BLIP_NODE 22  // wireless node ID to use for sending blips
#define BLIP_GRP  210   // wireless net group to use for sending blips
#define BLIP_ID   1   // set this to a unique ID to disambiguate multiple nodes
#define SEND_MODE 1   // set to 3 if fuses are e=06/h=DE/l=CE, else set to 2

struct {
  long ping;      // 32-bit counter
  byte id :7;     // identity, should be different for each node
  byte boost :1;  // whether compiled for boost chip or not
  byte vcc1;      // VCC before transmit, 1.0V = 0 .. 6.0V = 250
  byte vcc2;      // battery voltage (BOOST=1), or VCC after transmit (BOOST=0)
} payload;

volatile bool adcDone;

// for low-noise/-power ADC readouts, we'll use ADC completion interrupts
ISR(ADC_vect) { adcDone = true; }

// this must be defined since we're using the watchdog for low-power waiting
ISR(WDT_vect) { Sleepy::watchdogEvent(); }

static byte vccRead (byte count =4) {
  set_sleep_mode(SLEEP_MODE_ADC);
  // use VCC as AREF and internal bandgap as input
#if defined(__AVR_ATtiny84__)
  ADMUX = 33;
#else
  ADMUX = bit(REFS0) | 14;
#endif
  bitSet(ADCSRA, ADIE);
  while (count-- > 0) {
    adcDone = false;
    while (!adcDone)
      sleep_mode();
  }
  bitClear(ADCSRA, ADIE);  
  // convert ADC readings to fit in one byte, i.e. 20 mV steps:
  //  1.0V = 0, 1.8V = 40, 3.3V = 115, 5.0V = 200, 6.0V = 250
  return (55U * 1024U) / (ADC + 1) - 50;
}

void setup() {
  // get the pre-scaler into a known state
  cli();
  CLKPR = bit(CLKPCE);
#if defined(__AVR_ATtiny84__)
  CLKPR = 0; // div 1, i.e. speed up to 8 MHz
#else
  CLKPR = 1; // div 2, i.e. slow down to 8 MHz
#endif
  sei();

#if defined(__AVR_ATtiny84__)
    // power up the radio on JMv3
    bitSet(DDRB, 0);
    bitClear(PORTB, 0);
#endif

  rf12_initialize(BLIP_NODE, RF12_868MHZ, BLIP_GRP);
  // see http://tools.jeelabs.org/rfm12b
  rf12_control(0xC040); // set low-battery level to 2.2V i.s.o. 3.1V
  rf12_sleep(RF12_SLEEP);

  payload.id = BLIP_ID;
  payload.boost = BOOST;
}

static byte sendPayload () {
  ++payload.ping;

  rf12_sleep(RF12_WAKEUP);
  rf12_sendNow(0, &payload, sizeof payload);
  rf12_sendWait(SEND_MODE);
  rf12_sleep(RF12_SLEEP);
}

// This code tries to implement a good survival strategy: when power is low,
// don't transmit - when power is even lower, don't read out the VCC level.
//
// With a 100 µF cap, normal packet sends can cause VCC to drop by some 0.6V,
// hence the choices below: sending at >= 2.7V should be ok most of the time.

#define VCC_OK    85  // >= 2.7V - enough power for normal 1-minute sends
#define VCC_LOW   80  // >= 2.6V - sleep for 1 minute, then try again
#define VCC_DOZE  75  // >= 2.5V - sleep for 5 minutes, then try again
                      //  < 2.5V - sleep for 60 minutes, then try again
#define VCC_SLEEP_MINS(x) ((x) >= VCC_LOW ? 1 : (x) >= VCC_DOZE ? 5 : 60)

// Reasoning is that when we're about to try sending and find out that VCC
// is far too low, then let's just send anyway, as one final sign of life.

#define VCC_FINAL 70  // <= 2.4V - send anyway, might be our last swan song

void loop() {
  byte vcc = payload.vcc1 = vccRead();

  if (vcc <= VCC_FINAL) { // hopeless, maybe we can get one last packet out
    sendPayload();
    vcc = 1; // don't even try reading VCC after this send
#if !BOOST
    payload.vcc2 = vcc;
#endif
  }

  if (vcc >= VCC_OK) { // enough energy for normal operation
#if BOOST
    payload.vcc2 = analogRead(0) >> 2;
#endif
    sendPayload();
#if !BOOST
    vcc = payload.vcc2 = vccRead(); // measure and remember the VCC drop
#endif
  }

  //byte minutes = VCC_SLEEP_MINS(vcc);
  //while (minutes-- > 0)
    Sleepy::loseSomeTime(6000);
}

RE: Jeenode micro with RFM69CW hangs in rf12_sendWait - Added by martynj 8 months ago

aelfric,

You can see from the date that this sketch was written before the RFM69 series existed - the code needs a careful review to clean up any RF module specific behaviour that is not successfully hidden by the library. E.g. this needs to be a conditional assembly - there is no low battery detector on the RFM69 series

 rf12_control(0xC040); // set low-battery level to 2.2V i.s.o. 3.1V

RE: Jeenode micro with RFM69CW hangs in rf12_sendWait - Added by JohnO 8 months ago

Which core are you using to get the ATTiny84 capability into Arduino?

Referring to the sendwait code in my first post I am trying to unravel this section:
#ifdef SLEEP_MODE_STANDBY
mode == 2 ? SLEEP_MODE_STANDBY :
#endif

I have yet to find where SLEEP_MODE_STANDBY is defined, I suspect it may be in avr/sleep.h.

Could try compiling without the ifdef and endif in the file Arduino/libraries/jeelib/RF69_compat.cpp lines 105 & 107.

I am also trying to find out which sleep modes are supported by the ATTiny84.

RE: Jeenode micro with RFM69CW hangs in rf12_sendWait - Added by JohnO 8 months ago

Wondering if there is a way that we could check that the interrupt line is soldered cleanly. The thought being that the CPU wouldn't come out of SLEEP_MODE_PWR_DOWN or SLEEP_MODE_STANDBY without the interrupt from the radio. In SLEEP_MODE_IDLE the millis tick would wake things up frequently.

@martyn I also wonder if the quick processor wake up from SLEEP_MODE_PWR_DOWN is still an issue with the RFM69 since it has a reasonable FIFO.

RE: Jeenode micro with RFM69CW hangs in rf12_sendWait - Added by JohnO 8 months ago

Yet another thought:

Referring to: https://jeelabs.org/pub/docs/jeelib/RF12_8cpp.html#af326b8c2f92239693c7477f004180280

Note that even if you only want to send out packets, you still have to call rf12_recvDone() periodically, because it keeps the RFM12B logic going. If you don't, rf12_canSend() will never return true.

Although not borne out by successful operation with SLEEP_MODE_IDLE.

RE: Jeenode micro with RFM69CW hangs in rf12_sendWait - Added by aelfric 8 months ago

To add the ATTiny-84 to Arduino I used the repository from https://github.com/jcw/ide-hardware.git

/usr/lib/avr/include/avr/iotn84.h:92:#define SLEEP_MODE_STANDBY (0x03<<3)

SLEEP_MODE_STANDBY must be defined as there is a clear difference in behaviour with SEND_MODE = 1 or = 2, so removing the #ifdef will not make any difference.

The solder joints on the IRQ line look good and solid.

RE: Jeenode micro with RFM69CW hangs in rf12_sendWait - Added by aelfric 8 months ago

I just found this comment in the datasheet about standby mode
~~~
Only recommended with external crystal or resonator selected as clock source
~~~

So SLEEP_MODE = 2 is not expected to be used with internal oscillator. So what are the thoughts about SLEEP_MODE = 3? That does not work for me either.

Andrew

RE: Jeenode micro with RFM69CW hangs in rf12_sendWait - Added by JohnO 8 months ago

From: https://jeelabs.org/2011/12/01/rf12-power-optimization/

And lastly, the rf12_sendWait(3) call does something pretty nifty: it puts the ATmega into full power down mode between each byte sent to the RFM12B while transmitting. This requires a non-standard fuse setting in the ATmega – it only works with a ceramic resonator or the internal clock oscillator, not with a crystal: wake up out of power down within a few clock cycles.

I am glad you raised this, I hadn't realised that full power down mode between each byte sent was done. I suspect that this feature is more relevant to the RFM12B since the data transfer to the RFM69 has a substantial FIFO buffer and the SPI doesn't need to wait as it does for the RFM12B radio. I'll take a look at how the RFM69 library actually deals with mode 3 - I guess it doesn't.

RE: Jeenode micro with RFM69CW hangs in rf12_sendWait - Added by JohnO 8 months ago

My take on this is as follows. Since the filling of the RFM69 transmit buffer is not handled using interrupts then the processor doesn't actually sleep until the buffer has been filled. Only then does it begin waiting for transmission completion with the enabled sleep option. This suggests to me that there isn't a substantial difference in the power saving between 2 & 3 modes when using sendwait except for perhaps a bigger hit to the millis counter when using mode 3.

RE: Jeenode micro with RFM69CW hangs in rf12_sendWait - Added by aelfric 8 months ago

Doing a little investigation suggests that the 'special' fuse settings for use with power down mode are simply using the lowest startup delay with the external crystal which is 258CK. The Jeenode Micro uses the internal oscillator which has a startup delay of 6CK in all cases, which exceeds the requirements for a quick start up and hence should be OK.

So yes, there probably is no difference in power saving between 2 and 3 for the RFM69, but neither mode is useable for me. It's as if the interrupt to signal that the packet was sent is getting lost somehow due to the power down.

RE: Jeenode micro with RFM69CW hangs in rf12_sendWait - Added by JohnO 8 months ago

We are looking at:

bool RF69::sending () {
return rxstate < TXIDLE;
}

and

void rf69_sendWait (uint8_t mode) {
while (RF69::sending())
if (mode) {
set_sleep_mode(mode == 3 ? SLEEP_MODE_PWR_DOWN :
#ifdef SLEEP_MODE_STANDBY
mode == 2 ? SLEEP_MODE_STANDBY :
#endif
SLEEP_MODE_IDLE);
sleep_mode();
}
}

there may be a logic issue.

RE: Jeenode micro with RFM69CW hangs in rf12_sendWait - Added by JohnO 8 months ago

Are you happy editing a value in the jeelib library?

Try changing to:

return rxstate > TXIDLE;

line 143 in RF69.cpp

RE: Jeenode micro with RFM69CW hangs in rf12_sendWait - Added by aelfric 8 months ago

I am happy doing so, if it makes sense. However I have gone over this code and think it is OK. I cannot easily check the source at the moment for the exact details but it goes something like this:
1) When sending a packet, rxstate is set to effectively TXIDLE - 1.
2) The interrupt routine does a rxstate++.

So rxstate is less than TXIDLE, until an interrupt is received. So the correct test to determine if the RFM69 is still sending is rxstate < TXIDLE.

Your suggested change would exit the sendWait loop immediately resulting in the RFM69 being powered down before it had finished sending the packet.

The code works with the SLEEP_MODE = 1 case, so I think the basic logic and interrupts are OK. There is something about the going into power down or standby that means the interrupt is missed.

RE: Jeenode micro with RFM69CW hangs in rf12_sendWait - Added by JohnO 8 months ago

// transceiver states, these determine what to do with each interrupt
enum { TXCRC1, TXCRC2, TXTAIL, TXDONE, TXIDLE, TXRECV };

In the main correct for RFM12B and the code was ported very much as is to support the RFM69. However, for RFM69 the send buffer fill continues:

while (rxstate < TXDONE)

and the interrupt at the end of transmission sets:

    rxstate = TXIDLE;

The end of transmission is a little distanced from the state machine for the RFM69.

(1-25/52)