Timer2 does not work after including MySensors.h



  • Hi,

    I'm trying to get timer2 to work with a 32kHz crystal. I need very low power. I've made a simple sketch that works. I use the timer2 overflow to toggle an LED on pin 3.

    However, as soon as I include MySensors.h (v2.3), the LED stops blinking. Does MySensors already use timer2? Does anyone know what's going on? Some help is much appreciated!

    Thanks and Regards,
    Toby

    
    #define MY_NODE_ID 6
    #define MY_RADIO_RFM69
    #define MY_IS_RFM69HW
    
    
    #define LEDPIN 3
    
    //#include <MySensors.h>
    
    int LEDstate = 0;
    volatile byte counter;
    
    ISR(TIMER2_OVF_vect) {
    	++counter;
    }
    
    
    void setup()
    {
    	bitSet(ASSR,AS2);                // Select external clock for timer2
    	TCCR2B = bit(CS22) | bit(CS20);  // Set clock divider to 1024
    	bitSet(TIMSK2, TOIE2);           // Set timer 2 Overflow Interupt Enable (Timer Interupt Mask)
    	pinMode(LEDPIN,OUTPUT);
    
    }
    
    void loop()
    {
    	if (counter) {
    		counter = 0;
    		digitalWrite(LEDPIN,(LEDstate) ? HIGH : LOW);
    		LEDstate = !LEDstate;
    	}
    
    }
    

  • Hardware Contributor

    @tsd
    afaik mysensors is not using timer2.
    could you show us you logs plz? gw logs as well.
    also, what is your hardware for the gw and node?
    I've no time to test on my side, but what happens, for test, when you enable mysensors and blink your led from your isr (not from the loop)



  • This is the Micro Build info (excluding MySensors.h):

    Compiling 'TestSketch' for 'Arduino Nano w/ ATmega328P'
    Build Folder: "file:///C:/Users/TSD/AppData/Local/Temp/VMBuilds/TestSketch/nano_atmega328/Debug"
    Summary: Header=1 Prototypes=3 Imports=0
    Additional Defines: 
    Architecture Tools: "file:///C:/Program%20Files%20(x86)/Arduino/hardware/tools/avr/bin/"
    Api: 1.1806.1-5
    Sketch Book: "file:///C:/Users/TSD/Documents/Arduino"
    Sketch Include Paths
    Core Include Paths
    Include Path "file:///C:/Program%20Files%20(x86)/Arduino/hardware/arduino/avr/cores/arduino"
    Include Path "file:///C:/Program%20Files%20(x86)/Arduino/hardware/arduino/avr/variants/eightanaloginputs"
     
    Deep search for libraries ...
    Using previous search results: C:\Users\TSD\AppData\Local\Temp\VMBuilds\TestSketch\nano_atmega328\Debug\TestSketch.cpp
     
    Building variant ...
     
      Using previously compiled variant
     
    Building core ...
     
    Building project code ...
      Using previously compiled file: C:\Users\TSD\AppData\Local\Temp\VMBuilds\TestSketch\nano_atmega328\Debug\TestSketch.cpp.o
     
    Linking it all together ...
    # Coping cached core C:\Users\TSD\AppData\Local\Temp\VMBCore\arduino16x\1e0c139dc31076f8d2ffa4620be0d4fb\core.a to C:\Users\TSD\AppData\Local\Temp\VMBuilds\TestSketch\nano_atmega328\Debug\core.a
    
    "C:\Program Files (x86)\Arduino\hardware\tools\avr/bin/avr-gcc" -w -Os -g -flto -fuse-linker-plugin -Wl,--gc-sections -mmcu=atmega328p -o "C:\Users\TSD\AppData\Local\Temp\VMBuilds\TestSketch\nano_atmega328\Debug/TestSketch.ino.elf" "C:\Users\TSD\AppData\Local\Temp\VMBuilds\TestSketch\nano_atmega328\Debug\TestSketch.cpp.o" "C:\Users\TSD\AppData\Local\Temp\VMBuilds\TestSketch\nano_atmega328\Debug/core.a" "-LC:\Users\TSD\AppData\Local\Temp\VMBuilds\TestSketch\nano_atmega328\Debug" -lm
    ## recipe.objcopy.eep.pattern
    "C:\Program Files (x86)\Arduino\hardware\tools\avr/bin/avr-objcopy" -O ihex -j .eeprom --set-section-flags=.eeprom=alloc,load --no-change-warnings --change-section-lma .eeprom=0 "C:\Users\TSD\AppData\Local\Temp\VMBuilds\TestSketch\nano_atmega328\Debug/TestSketch.ino.elf" "C:\Users\TSD\AppData\Local\Temp\VMBuilds\TestSketch\nano_atmega328\Debug/TestSketch.ino.eep"
    ## recipe.objcopy.hex.pattern
    "C:\Program Files (x86)\Arduino\hardware\tools\avr/bin/avr-objcopy" -O ihex -R .eeprom "C:\Users\TSD\AppData\Local\Temp\VMBuilds\TestSketch\nano_atmega328\Debug/TestSketch.ino.elf" "C:\Users\TSD\AppData\Local\Temp\VMBuilds\TestSketch\nano_atmega328\Debug/TestSketch.ino.hex"
    
    Program TestSketch size: 844 bytes (used 3% of a 30.720 byte maximum) (0,97 secs)
    Minimum Memory Usage: 12 bytes (1% of a 2048 byte maximum)
     
    # Copy build result to 'Project>Property Pages>Intermediate Directory'
    # Destination: file:///C:/TestSketch/TestSketch/TestSketch/Debug
    

    There is no MySensors log, as the application does not work as soon as I include MySensors.h. The example I use here is a completely stripped version that only blinks an LED, just to show what the problem is.

    I use a custom node with an ATMEGA328PB. I use Atmel Studio 7 with Visual Micro plugin to code and AVRdude to program the hex file.

    I can blink the LED if I move the digitalWrite to the ISR (and do not include MySensors.h). I do need the counter in the loop however, because the lowest frequency of timer2 if I use a 1024 prescaler is 32768/1024=32Hz, which is too fast for my eyes to see.

    I did try to compile the code with Arduino IDE and that never works, whether I include MySensors.h or not.

    So I'm guessing there's some sort of setting or define in the Arduino software that prevents the ISR from working properly.

    Any idea what that might be?

    Thanks and regards,
    Toby


  • Mod

    @tsd could you clarify what you mean by

    the application does not work as soon as I include MySensors.h.

    Does it compile?
    Does it print anything on serial if you enable debug?



  • @mfalkvidd

    "The application" in this case is just a blinking LED. I intend to use the ISR to read out a sensor and send the data with MySensors. But because I couldn't get the ISR to work, I reduced "the application" to an LED to keep this discussion focused on the real issue.

    Yes, it always compiles, whether I include MySensors.h or not, and whether I use Arduino IDE or Atmel Studio.

    It's just that the LED doesn't always blink. In fact, the LED only blinks if I compile with Atmel Studio and don't include MySensors.h.

    I cannot use a serial monitor, because the custom node only has an ISP interface to program the MCU, there's no USB or anything like that.


  • Mod

    @tsd my guess is that there is a problem with wiring to the radio, or that MySensors is unable to connect to your gateway.

    In both those cases, MySensors will never reach setup() or loop().

    What do the logs from your gateway say?
    If you add something to presentation(), does the presentation reach your gateway?



  • @mfalkvidd
    I was testing without the radio even attached, to try and simplify the problem.

    But I reconnected the radio and expanded my example sketch to include a battery voltage measurement, that is transmitted to the GW with the RFM69 radio. The MySensors part of the sketch runs well, but the LED on pin 3 does not blink.

    #define MY_NODE_ID 6
    #define MY_RADIO_RFM69
    #define MY_IS_RFM69HW
    #define MY_DEBUG
    
    #define LEDPIN 3
    
    #include <MySensors.h>
    
    MyMessage msgVcc(1, V_VOLTAGE);
    
    
    int LEDstate = 0;
    volatile byte counter;
    ISR(TIMER2_OVF_vect) {
    
    	++counter;
    	if (counter == 0) {
    		digitalWrite(LEDPIN,(LEDstate) ? HIGH : LOW);
    		LEDstate = !LEDstate;
    	};
    }
    
    void presentation()
    {
    	sendSketchInfo("Vbat", "1.0");
    	present(1, S_MULTIMETER);
    
    }
    
    void setup()
    {
    	// Configure timer 2
    	bitSet(ASSR,AS2);                // Select external clock for timer2
    	TCCR2B = bit(CS22) | bit(CS20);  // Set clock divider to 1024
    	bitSet(TIMSK2, TOIE2);           // Set timer 2 Overflow Interupt Enable (Timer Interupt Mask)
    	
    	// Configure LED
    	pinMode(LEDPIN,OUTPUT);
    	digitalWrite(LEDPIN,HIGH);
    	
    	sei();
    }
    
    void loop()
    {
    	if (counter) {
    		counter = 0;
    //		digitalWrite(LEDPIN,(LEDstate) ? HIGH : LOW);
    //		LEDstate = !LEDstate;
    	}
    	
    	long vcc = readVcc();      // Read battery voltage
    	send(msgVcc.set(vcc, 1));  // Send battery voltage
    	sleep(2000);               // Sleep 2s
    
    }
    
    
    long readVcc() {
    	// Read 1.1V reference against AVcc
    	// set the reference to Vcc and the measurement to the internal 1.1V reference
    	#if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
    	ADMUX = _BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
    	#elif defined (__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
    	ADMUX = _BV(MUX5) | _BV(MUX0);
    	#elif defined (__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
    	ADMUX = _BV(MUX3) | _BV(MUX2);
    	#else
    	ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
    	#endif
    
    	delay(2); // Wait for Vref to settle
    	ADCSRA |= _BV(ADSC); // Start conversion
    	while (bit_is_set(ADCSRA,ADSC)); // measuring
    
    	uint8_t low  = ADCL; // must read ADCL first - it then locks ADCH
    	uint8_t high = ADCH; // unlocks both
    
    	long result = (high<<8) | low;
    
    	result = 1125300L / result; // Calculate Vcc (in mV); 1125300 = 1.1*1023*1000
    	return result; // Vcc in millivolts
    }
    

    The GW log looks as expected, and repeats every 2 seconds:

    11-8-2018 11:21:18node: b9b6269f.12ee68
    msg.payload : string[73]
    "0;255;3;0;9;2046448 TSF:MSG:READ,6-6-0,s=1,c=1,t=38,pt=7,l=5,sg=0:3319.0↵"
    11-8-2018 11:21:18node: b9b6269f.12ee68
    msg.payload : string[18]
    "6;1;1;0;38;3319.0↵"
    
    11-8-2018 11:21:20node: b9b6269f.12ee68
    msg.payload : string[73]
    "0;255;3;0;9;2048732 TSF:MSG:READ,6-6-0,s=1,c=1,t=38,pt=7,l=5,sg=0:3319.0↵"
    11-8-2018 11:21:20node: b9b6269f.12ee68
    msg.payload : string[18]
    "6;1;1;0;38;3319.0↵"
    

    However, the LED that should be toggled from the ISR, doesn't blink. The LED does blink with the code that I showed at the start of this thread (without any MySensors stuff).

    My goal is to start the measurement and send the result from the ISR and not from the main loop to save more power. The current consumption during sleep is about 3.5uA now. I hope to get to around 1uA if I use timer 2. I've seen examples of people using timer 2 with the RTC, so I don't understand why this doesn't work in my case.

    Hope the issue is more clear now. Does this make any sense to you?


  • Mod

    @tsd nice work.
    If you by "send the result from the ISR" mean sending using MySensors, it won't work. Inside an ISR, interrupts and timers are disabled so communicating with the radio is impossible. Also, sending would take way too much time. ISRs are meant to be very short.

    Are you sure timer2 will increment while the mcu is sleeping? I know millis() will never increment during sleep. Maybe the same happens to timer2? What happens if you use wait() instead of sleep()?


  • Mod

    Might be interesting to check if @ewasscher ever got around to implementing the stuff discussed in https://forum.mysensors.org/topic/2555/support-for-wake-up-by-timer2-instead-of-wd


  • Hardware Contributor

    @TSD
    it's more clear now, because with the stripped version it could have been lot of other things 🙂

    you'll need to make your own sleep function. because for the moment, powerdown mode only is available in MySensors. and as you may know it's not good for your timer2 (you need powersave mode).



  • @mfalkvidd, @scalz
    Thanks, now we're getting somewhere. When I use wait(), the LED blinks. That makes sense if sleep() uses power down mode, which turns off almost everything, including timer 2.

    I'll read the sensor and send the data (with MySensors) from the counter in the main loop. Then I'll see if I can get the MCU to sleep while leaving timer2 on with extended standby mode.

    Thanks for your help!



  • @mfalkvidd @scalz
    I tried first to disable the RFM69 with the _radio.sleep() function:

     
    
    #define MY_NODE_ID 6
    #define MY_RADIO_RFM69
    #define MY_IS_RFM69HW
    #define MY_DEBUG
    #define MY_DEBUG_VERBOSE_RFM69
    
    #define LEDPIN 3
    
    #include <MySensors.h>
    
    MyMessage msgVcc(1, V_VOLTAGE);
    
    int LEDstate = 0;
    volatile byte counter = 0;
    int PostScaler = 0;
    
    ISR(TIMER2_OVF_vect) {
    	++counter;
    }
    
    void presentation()
    {
    	sendSketchInfo("Vbat", "1.0");
    	present(1, S_MULTIMETER);
    }
    
    void setup()
    {
    	// Configure timer 2
    	bitSet(ASSR,AS2);                // Select external clock for timer2
    	TCCR2B = bit(CS22) | bit(CS20);  // Set clock divider to 1024
    	bitSet(TIMSK2, TOIE2);           // Set timer 2 Overflow Interupt Enable (Timer Interupt Mask)
    	
    	// Configure LED
    	pinMode(LEDPIN,OUTPUT);
    	digitalWrite(LEDPIN,HIGH);
    }
    
    void loop()
    {
    	if (counter) {
    		counter = 0;
    		
    		// Blink LED
    		digitalWrite(LEDPIN,(LEDstate) ? HIGH : LOW);
    		LEDstate = !LEDstate;
    		
    		// Measure battery voltage and send data to gateway
    		if (PostScaler == 2) {
    			
    			_radio.receiveDone();      // Turn on radio
    			long vcc = readVcc();      // Read battery voltage
    			send(msgVcc.set(vcc, 1));  // Send battery voltage
    			_radio.sleep();            // Sleep radio
    			
    			PostScaler = 0;
    		}
    		PostScaler++;
    		sei();
    	}
    	
    	wait(2000);
    	
    }
    
    
    long readVcc() {
    	// Read 1.1V reference against AVcc
    	// set the reference to Vcc and the measurement to the internal 1.1V reference
    	#if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
    	ADMUX = _BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
    	#elif defined (__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
    	ADMUX = _BV(MUX5) | _BV(MUX0);
    	#elif defined (__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
    	ADMUX = _BV(MUX3) | _BV(MUX2);
    	#else
    	ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
    	#endif
    
    	delay(2); // Wait for Vref to settle
    	ADCSRA |= _BV(ADSC); // Start conversion
    	while (bit_is_set(ADCSRA,ADSC)); // measuring
    
    	uint8_t low  = ADCL; // must read ADCL first - it then locks ADCH
    	uint8_t high = ADCH; // unlocks both
    
    	long result = (high<<8) | low;
    
    	result = 1125300L / result; // Calculate Vcc (in mV); 1125300 = 1.1*1023*1000
    	return result; // Vcc in millivolts
    }
    

    However, the radio doesn't turn off at all. Is there anything else that needs to be configured before this function can be used?


  • Mod

    @tsd this is way to deep for my knowledge unfortunately. Sorry.



  • @mfalkvidd Do you know anyone that might know more about this?


  • Hardware Contributor

    @TSD
    I've not digged and not time to replicate your setup, but I have a suspicion with wait()
    Does it help by using delay() instead of wait().
    you won't use wait() if you make your own sleep() I think, and maybe you'll also need to make your custom wait() if needed.
    Because wait() purpose is :

    • handle wdt, leds etc (see doYield)
    • incoming radio msg, radio link

    When you sleep radio with low level function like you do, then a few vars may be not updated in mysensors machine (like transportActive I think)
    So mysensors machine does not know you disabled/slept the radio (whereas when using mysensors and sleep in regular way it knows it of course).
    Then when you call wait(), mysensors machine will try to check link (as the state variable has not been updated), link check fails and then it reinit radio. no sleep!

    Not checked on my side, but it could be that 🙂



  • @scalz
    Your hunch was correct! When I use delay(), the current drops to 4.6mA (from >20mA). So now I can start turning off MCU peripherals to reduce the current further.

    By the way, is there good documentation to understand how all these MySensors functions work? Or do I just have to work with the Doxygen stuff and plough through all the relevant .h and .cpp files?


  • Hardware Contributor

    @TSD
    glad to hear i helped you.
    you have to work with doxygen and sources


 

282
Online

7.8k
Users

8.7k
Topics

93.1k
Posts