Sunday, 29 January 2012

Wireless sensor node - turning off subsystems (5)

In my last post I spoke about the watchdog timer which can be used to enter a deep sleep on the ATtiny85. This time I want to take a quick look at the other power saving options available on the ATtiny85.

The ATtiny has several subsystems which can be separately turned on and off. The datasheet describes all of these systems but we just want to find out how to turn them off! Thankfully, you can skip straight to looking at power.h. This header exposes some methods which make power management more straightforward. From this header file you can quickly find all the subsystems on the ATTiny85 which can be switched off. 
  • power_adc_disable()
  • power_timer0_disable()
  • power_timer1_disable()  
  • power_usi_disable() 
In practice, I can't actually switch all of these off in my project.
  • Timer1 - used by Manchester lib. The datasheet says that timer1 is always stopped while we are asleep
  • ADC - used to read analog value from sensor. ATTINYWATCHDOG already explicitly turns off the ADC when we sleep. 
The ATtiny datasheet has a section on power saving. This recommends that when not in use, pins should be set to input mode so that they are not driving anything. 

The wiring of my project currently connects the VCC of my TX module to the battery VCC line. However, I can improve power use by connecting TX VCC to a pin on the ATtiny. This allows me to power down the TX while the ATtiny sleeps. 

There is one change which I should make which will actually consume more power. I am planning to run an ATtiny from battery power for long periods of time. At some point the battery will start to run out and the battery voltage will drop. The ATtiny can operate over a fairly wide range of voltages. However, but the voltage drops too low the ATtiny can actually be damaged. To avoid this happening, we can enable a Brown Out Detection (BOD) circuit. This is enabled by setting a fuse on the ATtiny. 

The details about how to set the fuse are listed on this page. I used the command line approach which involved the following steps.
  1. Open a command line in: \path\to\arduino-0022\hardware\tools\avr
  2. Run the following command to read the current fuses

    avrdude -C "\path\to\arduino-0022\hardware\tools\avr\etc\avrdude.conf" -p ATtiny85 -c stk500v1 -b 19200 -p COM3 -v


    Note that the stk500v1 works fine when using the Arduino as an ISP. Also note that the fuse values get output twice. For example:

    avrdude: Device signature = 0x1e930b
    avrdude: safemode: lfuse reads as E2
    avrdude: safemode: hfuse reads as DD
    avrdude: safemode: efuse reads as FF

    avrdude: safemode: lfuse reads as E2
    avrdude: safemode: hfuse reads as DD
    avrdude: safemode: efuse reads as FF
    avrdude: safemode: Fuses OK

  3. Use this site to work out your new fuse values. Select "ATtiny85", the default features value is correct. The "current settings" section will likely show fuse values matching what you read from your chip.
  4. To enable BOD, select your desired level, in my case "Brown-out detection level at VCC=2.7 V; [BODLEVEL=101]". Click "Apply feature settings". The updated fuse settings are shown in the "Current settings" section. In my case, the default of DF changed to DD. In binary this means 0b11011111 changes to 0b11011101.
  5. To apply this change, run the following command:

    avrdude -C "\path\to\arduino-0022\hardware\tools\avr\etc\avrdude.conf" -p ATtiny85 -c stk500v1 -b 19200 -p COM3 -U hfuse:w:0xDD:m


    The output of this command should include the following lines:

    avrdude: 1 bytes of hfuse written
    avrdude: 1 bytes of hfuse verified
    avrdude: safemode: Fuses OK
    avrdude done.  Thank you.

The results after making all of these changes are as follows. 
  • Sleep current - 0.025mA (up from 0.006mA). This makes it clear how much current the Brown Out Detection support requires.
  • Wake current - 7.8mA (down from 8.5mA). This is a rough figure - the reading on the multimeter jumps around as the RF TX happens and the ATtiny sleeps between transmits. 7.8mA is about the highest reading I saw so I am going to use that for now.
Finally, there is one mode thing which I could do in software to improve power usage. This would be to rewrite my code to be interrupt driven. This would allow the ATtiny to spend more time asleep. However, the resulting code would be more complex and I don't need the extra power savings at the moment.