MySensors on ATTiny84 and RFM69CW



  • I try to get MySensors working on an ATtiny 84 with RFM69CW module. I use the Tiny TX 3 Sensor board. I know, because of little memory, I can use this for reel simple nodes, at the best.

    First I do some changes to get MYSensors to compile with the ATTiny core.

    I have to disable serialEventRun in MySensors main (MyMainAVR.cpp) because there is no serial interface on ATtiny:

    int main(void)
    {
    	init();
    #if defined(USBCON)
    	USBDevice.attach();
    #endif
    	_begin(); // Startup MySensors library
    	for(;;) {
    		_process();  // Process incoming data
    		if (loop) {
    			loop(); // Call sketch loop
    		}
    // MCU like ATtiny don't support serial
    #if defined(HAVE_HWSERIAL0) || defined(HAVE_HWSERIAL1) || defined(HAVE_HWSERIAL2) || defined(HAVE_HWSERIAL3)
    		if (serialEventRun) {
    			serialEventRun();
    		}
    #endif
    	}
    	return 0;
    }
    

    I also have to change clearPendingInterrupt (MyHWAVR.cpp) because ATtiny 84 only have on interrupt and use an other register:

    void clearPendingInterrupt(const uint8_t interrupt)
    {
    #ifdef ATTINY_CORE
    	// Flag for INT0 / ATtiny84 is on Bit 6 in GIFR
    	if (interrupt == 0)
    		GIFR = _BV(interrupt + 6);
    #else	
    	EIFR = _BV(interrupt);
    #endif
    }
    

    I also have to change hwUniqueID (MyHWAVR.cpp). I know this code don't really return a unique ID. At the moment I have no idea how to do this for ATtiny. But I think also that souldn't prevent MySensors from working.

    bool hwUniqueID(unique_id_t *uniqueID)
    {
    	// padding
    	(void)memset(uniqueID, MY_HWID_PADDING_BYTE, sizeof(unique_id_t));
    #ifndef ATTINY_CORE	
    	// no unique ID for non-PB AVR, use HW specifics for diversification
    	*((uint8_t *)uniqueID) = boot_signature_byte_get(0x00);
    	*((uint8_t *)uniqueID + 1) = boot_signature_byte_get(0x02);
    	*((uint8_t *)uniqueID + 2) = boot_signature_byte_get(0x04);
    	*((uint8_t *)uniqueID + 3) = boot_signature_byte_get(0x01); //OSCCAL
    #endif	
    #if defined(__AVR_ATmega328PB__)
    	// ATMEGA328PB specifics, has unique ID
    	for(uint8_t idx = 0; idx < 10; idx++) {
    		*((uint8_t *)uniqueID + 4 + idx) = boot_signature_byte_get(0xE + idx);
    	}
    	return true; // unique ID returned
    #else
    	return false;	// no unique ID returned
    #endif
    }
    

    With this little changes, which I think aren't completely wrong, MySensors compile for ATtiny. At least after this changes it compiles for the Attiny 84 on TinyTX3 and for my Arduino Nano which I also use for testing.

    I got also message sent to my gateway from the ATiny. But it seems, it never receives the incoming message because I get this log:

    TSF:MSG:READ,5-5-255,s=255,c=3,t=7,pt=0,l=0,sg=0:
    TSF:MSG:BC
    TSF:MSG:FPAR REQ,ID=5
    TSF:PNG:SEND,TO=0
    TSF:CKU:OK
    TSF:MSG:GWL OK
    TSF:MSG:SEND,0-0-5-5,s=255,c=3,t=8,pt=1,l=1,sg=0,ft=0,st=OK:0
    TSF:MSG:READ,5-5-255,s=255,c=3,t=7,pt=0,l=0,sg=0:
    TSF:MSG:BC
    TSF:MSG:FPAR REQ,ID=5
    TSF:CKU:OK,FCTRL
    TSF:MSG:GWL OK
    TSF:MSG:SEND,0-0-5-5,s=255,c=3,t=8,pt=1,l=1,sg=0,ft=0,st=OK:0
    TSF:MSG:READ,5-5-255,s=255,c=3,t=7,pt=0,l=0,sg=0:
    TSF:MSG:BC
    TSF:MSG:FPAR REQ,ID=5
    TSF:CKU:OK,FCTRL
    TSF:MSG:GWL OK
    TSF:MSG:SEND,0-0-5-5,s=255,c=3,t=8,pt=1,l=1,sg=0,ft=0,st=OK:0
    TSF:MSG:READ,5-5-255,s=255,c=3,t=7,pt=0,l=0,sg=0:
    TSF:MSG:BC
    TSF:MSG:FPAR REQ,ID=5
    TSF:CKU:OK,FCTRL
    TSF:MSG:GWL OK
    TSF:MSG:SEND,0-0-5-5,s=255,c=3,t=8,pt=1,l=1,sg=0,ft=0,st=OK:0
    ...
    

    An endless I_FIND_PARENT_REQUEST / I_FIND_PARENT_RESPONSE sequence The same program on Arduino Nano works.

    My first idea was, that the interrupt on ATtiny don't work (because I changes the code for clearPendingInterrupt how you can see above ๐Ÿ™‚ ). But I set an output pin to debug (because I have no serial on ATtiny) in the interrupt routine and it seems that at least it is called.

    By check the output pins I also see the (Arduino) pin 8 and 9 is set to high. I don't know why. I don't set thess in my program but I also don't see at the moment that they are set in the MySensors code.

    Does anyone have an idea why pin 8 and 9 is high? Or why incoming messages aren't processed?



  • OK I now know why Pin 8 and 9 is not 0V. It was used for a software serial interface on ATtiny. I could disable this with "#define MY_DISABLED_SERIAL". I also now use "#define MY_PASSIVE_NODE", because for my intended use as temperature/humidity sensor its OK.

    The following test program no works on ATtiny84 with my changes to MySensor lib:

    #include <Arduino.h>
    
    // ATMEL ATTINY84 / ARDUINO Pin map
    //
    //                           +-\/-+
    //                     VCC  1|    |14  GND
    //             (D  0)  PB0  2|    |13  AREF (D 10)
    //             (D  1)  PB1  3|    |12  PA1  (D  9) 
    //                     PB3  4|    |11  PA2  (D  8) 
    //  PWM  INT0  (D  2)  PB2  5|    |10  PA3  (D  7) 
    //  PWM        (D  3)  PA7  6|    |9   PA4  (D  6) 
    //  PWM        (D  4)  PA6  7|    |8   PA5  (D  5)        PWM
    //                           +----+
    
    #define MY_PASSIVE_NODE
    
    #define MY_SPLASH_SCREEN_DISABLED
    
    #ifdef ATTINY_CORE
      #define MY_DISABLED_SERIAL
      #define MY_NODE_ID 5
      #define MY_RFM69_CS_PIN 1
    #else
      #define MY_DEBUG
      #define MY_DEBUG_VERBOSE_RFM69
      #define MY_NODE_ID 1
    #endif
    
    #define MY_RADIO_RFM69
    #define MY_RFM69_NEW_DRIVER
    #define MY_RFM69_FREQUENCY RFM69_433MHZ
    #include <MySensors.h>
    
    
    // Sleep time between sensor updates (in milliseconds)
    // Must be >1000ms for DHT22 and >2000ms for DHT11
    static const uint64_t UPDATE_INTERVAL = 60000;
    
    // Force sending an update of the temperature after n sensor reads, so a controller showing the
    // timestamp of the last update doesn't show something like 3 hours in the unlikely case, that
    // the value didn't change since;
    // i.e. the sensor would force sending an update every UPDATE_INTERVAL*FORCE_UPDATE_N_READS [ms]
    static const uint8_t FORCE_UPDATE_N_READS = 10;
    
    #define CHILD_ID_HUM 0
    #define CHILD_ID_TEMP 1
    
    float lastTemp;
    float lastHum;
    uint8_t nNoUpdatesTemp;
    uint8_t nNoUpdatesHum;
    
    MyMessage msgHum(CHILD_ID_HUM, V_HUM);
    MyMessage msgTemp(CHILD_ID_TEMP, V_TEMP);
    
    // Set this offset if the sensor has a permanent small offset to the real temperatures.
    // In Celsius degrees (as measured by the device)
    #define SENSOR_TEMP_OFFSET 0
    
    void presentation()  
    { 
      // Send the sketch version information to the gateway
    #ifdef ATTINY_CORE  
      sendSketchInfo("TinyTest", "1.1");
    #else
      sendSketchInfo("NanoTest", "1.1");
    #endif
      delay(3000);
    
      // Register all sensors to gw (they will be created as child devices)
      present(CHILD_ID_HUM, S_HUM);
      delay(3000);
    
      present(CHILD_ID_TEMP, S_TEMP);
      delay(3000);
    }
    
    
    void setup()
    {
    #ifdef ATTINY_CORE  
      pinMode(0, OUTPUT);
      pinMode(3, OUTPUT);
      pinMode(7, OUTPUT);
      pinMode(8, OUTPUT);
      pinMode(9, OUTPUT);
      pinMode(10, OUTPUT);
    #else
      Serial.begin(9600);
    #endif  
    }
    
    
    void loop()      
    {
      // Get temperature from DHT library
      float temperature = 11.11f;
      // if (temperature != lastTemp || nNoUpdatesTemp == FORCE_UPDATE_N_READS)
      // {
      //   // Only send temperature if it changed since the last measurement or if we didn't send an update for n times
      //   lastTemp = temperature;
    
      //   // apply the offset before converting to something different than Celsius degrees
      //   temperature += SENSOR_TEMP_OFFSET;
    
      //   // Reset no updates counter
      //   nNoUpdatesTemp = 0;
      //   send(msgTemp.set(temperature, 2));
      // } 
      // else 
      // {
      //   // Increase no update counter if the temperature stayed the same
      //   nNoUpdatesTemp++;
      // }
      if (send(msgTemp.set(temperature, 2)))
        digitalWrite(0, HIGH);
      else
        digitalWrite(3, HIGH);
      delay(3000);
      // Get humidity from DHT library
      float humidity = 55.55f;
      send(msgHum.set(humidity, 2));
      // if (humidity != lastHum || nNoUpdatesHum == FORCE_UPDATE_N_READS)
      // {
      //   // Only send humidity if it changed since the last measurement or if we didn't send an update for n times
      //   lastHum = humidity;
      //   // Reset no updates counter
      //   nNoUpdatesHum = 0;
      //   send(msgHum.set(humidity, 2));
      // } 
      // else 
      // {
      //   // Increase no update counter if the humidity stayed the same
      //   nNoUpdatesHum++;
      // }
    
      // Sleep for a while to save energy
      delay(3000);
    }
    

    But some problems still remaining. The biggest one, sleep don't work. If I replace delay by sleep in the program above, the program really behaves strange. So I think I must rewrite this function for ATtiny84. Has anyone tips how to do this?


  • Hardware Contributor

    @blachner said in MySensors on ATTiny84 and RFM69CW:

    If I replace delay by sleep in the program above, the program really behaves strange

    Hello, you should not use delay() with MySensors but wait(), which will poll the NRF24 regularly to receive incoming messages.



  • @nca78 said in MySensors on ATTiny84 and RFM69CW:

    Hello, you should not use delay() with MySensors but wait(), which will poll the NRF24 regularly to receive incoming messages.

    You are surely right, that using delay isn't normally a good idea for a MySensors program. In my case I only want to implement a passive node to measure temperature and humidity. So my program don't wait for any incoming messages and delay wouldn't be a problem for this reason. But for the final version delay wouldn't be a good solution for another reason: battery life. But I have now a working sleep function for the ATTiny84 which needs only approximately 6ยตA during sleep.

    In the meantime I found the reasons for my problems. My program just uses to much RAM (only 512 Byte on ATTiny84 available), so the stack destroys other variables and the program behaves strange. But I now found a solution for a working passive MySensors Node for temperature and humidity on ATTiny84 with RFM69 radio module and the BME280 as temperature/humidity sensor. I will show my solution here anytime soon, maybe it is of interest for others who try something similar.


 

191
Online

8.8k
Users

9.6k
Topics

100.4k
Posts