Unattended Quad: battery saving for forever running machine

Discussion in 'UDOO QUAD' started by francescomm, Oct 4, 2017.

  1. francescomm

    francescomm Member

    Joined:
    Dec 14, 2013
    Messages:
    80
    Likes Received:
    4
    Hello, I would like to leave the UDOO Quad (udoobuntu) constantly open to perform a simple task with a connected relay. Using the Quad for this simple task instead of a smaller, simpler board, might consume more power and keep idle a full blown computer but might have advantages in term of things that can be done, if I can maximize the usage and minimize power consumption.

    EDIT
    1) Question 1 on installing a remote access software on the Quad to give me free access to my network from any place in the world was resolved in this thread: https://www.udoo.org/forum/threads/teamviewer-4-udoo.809/

    2) How do I save energy, minimize power consumption? The Due part for instance is used only to switch on/off the relay. It could be totally shut off until operation is requested. The Ubuntu part could sleep most of the time and wake up every few seconds to connect to a website to see if the relay must be activated and then go back to sleep. All sort of stuff that is not used could be deactivated (DAC, PWM?). What is the best way to save power in this scenario? (Of course I will have to wake up the board via web before remote access, that's ok).

    Any help/advice is appreciated, sorry for the long post.
    Thanks.
     
    Last edited: Oct 5, 2017
  2. fetcher

    fetcher Member

    Joined:
    Mar 9, 2014
    Messages:
    166
    Likes Received:
    20
    An Udoo Quad probably isn't your best choice for this, because it has so much on-board hardware beyond what you need, and while efficient for all that it does, it's somewhat lacking in fine-grained power control. For example, you can down-clock the CPU (echo powersave >/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor), but this gives very little power savings since the regulator for its core voltage remains fixed at 1.2V.

    If you don't need the Wifi module, definitely unplug that (after removing its retaining screw) in order to save 200-300mW.

    Although the main i.MX6 CPU can be put into sleep mode (echo mem >/sys/power/state), I never found a way to wake it back up again from this state, short of a full reset. If anyone knows, please tell!

    What you can do is halt/shutdown the i.MX6 entirely, while leaving the SAM3X (Arduino) running, and let the Arduino later power the i.MX6 back on by writing to virtual-pin 78, which Udoo connects to the i.MX6's ON_OFF signal:
    Code:
        digitalWrite(78, LOW);
        pinMode(78, OUTPUT);
        delay(250);
        digitalWrite(78, HIGH);
        delay(250);
        digitalWrite(78, LOW);
        delay(250);
        pinMode(78, INPUT);
    
    Note that the SAM3X gets reset itself as the i.MX6 is booting back up - probably due to glitches on its gpio0 output pin-- so be sure your sketch can handle this and recover from it. Also, neither CPU can keep an GPIO output driven while shut down or asleep, all going to high-impedance floating state, so be sure your circuit accomodates this with an external pull-up or pull-down.

    Running ONLY the Arduino Atmel SAM3X gets the Udoo's power consumption down to 0.2W-0.4W, which can be further reduced by turning off SAM3X peripherals, reducing its clock speed, or especially putting it in deep-sleep BACKUP mode.

    But you'd have to wake the i.MX6 based on a timer, or pin input, or some other stimulus other than remote network access, since the SAM3X doesn't have a network interface of its own (actually there is an on-board 10/100 Ethernet MAC, but as on the Arduino Due it sadly isn't brought out to pins where an RGMII could be attached).

    If you go for this, be sure to streamline the Linux boot process as much as possible, and try to set up a read-only root filesystem as well to avoid excessive wear on your SD card from all the startup cycles.

    Alternatively, if you don't want to be constantly shutting Linux down and rebooting, the Arduino SAM3X CPU can be held in RESET state by the main i.MX6 CPU via echo 0 >/gpio/gpio0/value (echo 1 to bring it back), saving another few hundred mW over letting it busy-idle. If you're only toggling a relay and not doing any other I/O via Arduino, for that you don't need the SAM3X at all - just find the corresponding i.MX6 GPIO (consult Udoo_pinout_diagram.pdf or UDOO_pinout_alternate_table.pdf, available from this site) and use that.

    For instance, Arduino D28 is tied to i.MX6 gpio134, so after making sure the Arduino isn't using that pin as an output (hold it in RESET state, or do pinMode(28, INPUT) in your sketch),
    Code:
    echo 134 >/sys/class/gpio/export
    echo out >/sys/class/gpio/gpio134/direction
    echo 1 >/sys/class/gpio/gpio134/value
    ...
    echo 0 >/sys/class/gpio/gpio134/value
    
    Udoobuntu has symlinks under /gpio to make the pin mappings easier.

    If you do choose to keep the Atmel SAM3X running (possibly by itself during idle periods, set to power on the i.MX6 periodically via "pin78" as above), note that most of that chip's sleep modes are ineffective on an Udoo since it, like the Arduino Due, ties all the various SAM3X voltage rails together-- VDDIO, VDDBU, VDDPLL, VDDANA, etc -- and so it isn't possible to supply 3.3V to one while removing power from the others.

    The Atmel's deepest-sleep "BACKUP mode" does work, however it's very limited in what remains powered-- only 8 32-bit registers, a (somewhat inaccurate) RTC and RTT (real-time timer for periodic interrupts) and handfull of "WKUP" capable input pins that can bring it out of deep sleep. All other RAM gets powered down, and on waking from this mode, the Atmel will start executing setup() as if it had been newly powered-on.

    Here's an example sketch fragment that sets the Atmel's RTT for periodic wakeups, also listening on some of the WKUP pins. If you need to save some variables in between wakeups-- hopefully 8 32-bit words is enough-- check out the gpbr_write() and gpbr_read() functions.
    Code:
    const uint32_t RTT_INTERVAL = 4;
    unsigned int rttsr1,rttsr2;
    
    void RTT_Handler () {
      rttsr1 = RTT->RTT_SR;
    }
     
    void setup() {
     int tmp;
     unsigned int key_wkup_mask=(( (1 << 3) ) << 16);
     unsigned int ser_wkup_mask=(( (1 << 4) ) << 16);
     unsigned int irc_wkup_mask=(( (1 << 15 ) ) << 16);
     unsigned int pls_wkup_mask=( 1 << 16);
    
      rttsr2=RTT->RTT_SR;
    
      RTT->RTT_MR = RTT_MR_RTTRST
                | RTT_MR_RTPRES (0x8000)  // T = 1 second
                | RTT_MR_ALMIEN;
    
      RTT->RTT_AR = RTT_AR_ALMV(RTT_INTERVAL);
     
      NVIC_DisableIRQ       ( RTT_IRQn );
      NVIC_ClearPendingIRQ  ( RTT_IRQn );
      NVIC_SetPriority      ( RTT_IRQn, 0 );
      NVIC_EnableIRQ        ( RTT_IRQn );
    
      Serial.begin(115200);
    
      sr=SUPC->SUPC_SR;
    
      if ((sr & pls_wkup_mask) != 0) {
        // handle first wakeup-pin case
      }
    
      if ((sr & key_wkup_mask) != 0) {
         // handle 2nd wakeup-pin case
      }
    
      if ((sr & irc_wkup_mask) != 0) {
         // handle 3rd wakeup-pin case
      }
    
      if ( (rttsr1 & 1) || (rttsr2 & 1) ) {
         // handle real-time timer wakeup case
      }
    
      if ( (sr & ser_wkup_mask) || Serial.available() ) {
         // handle serial input from i.MX6 host
      }
    
    // WKUP0(CANRX0) + WKUP3(pin31) + WKUP4(uart-rx) + WKUP15(pin22=IR-RX)
      tmp = ( (1 << 15) | (1 << 4 ) | (1 << 3) | 1 );
      SUPC->SUPC_WUIR = tmp;             // above sources, hi->low transition
      SUPC->SUPC_WUMR = SUPC_WUMR_RTTEN; // (+RTT) no debounce; 1 << 12 for 3 cycle
    
      pmc_enable_backupmode();
    }
    
    void loop() {
      Serial.println (F("in loop() - this should never execute!"));
      delay(500);
    }
    
    
     
    Last edited: Oct 20, 2017
  3. fetcher

    fetcher Member

    Joined:
    Mar 9, 2014
    Messages:
    166
    Likes Received:
    20
    If BACKUP mode on the SAM3X proves too limiting, you can reduce the Atmel's power consumption to a lesser degree by down-clocking it and shutting off some unnecessary peripherals. Here an example sketch fragment for doing that, taken from an old project of mine. Note that if you reduce the Atmel's clock speed, you have to multiply the Serial baud rate in inverse proportion to keep the serial rate constant. e.g. here I'm underclocking from 84MHz to 21MHz (divide by 4), which requires multiplying the Serial rate by 4, from 115200 to 460800 -- still giving an effective 115200 bps in the end.

    The power savings from some of these changes is small, and easily swamped by busy/idle state differences. Having an reasonably precise ammeter in series with the Udoo's power supply is helpful for determining what's worthwhile and what isn't.

    Code:
    void setup() {
      unsigned int i;
    
      pmc_set_writeprotect(false);
      pmc_mck_set_prescaler(48);   // 21MHz
    
       // 12MHz / 64 * 14 = 2.625MHz //  96 = 110 << 4 = /64
       // 12MHz / 32 * 14 = 5.25 MHz //  80 = 101 << 4 = /32
       // 12MHz / 16 * 14 = 10.5 MHz //  64 = 100 << 4 = /16
       // 12MHz /  8 * 14 = 21   MHz //  48 = 011 << 4 = /8
       // 12MHz /  4 * 14 = 42   MHz //  32 = 010 << 4 = /4
       // 12MHz /  2 * 14 = 84   MHz //  16 = 001 << 4 = /2 (default)
    
    // disable unused peripheral clocks to save some power
    // see p. 47-48 of SAM3X manual PDF
      pmc_disable_periph_clk(2);   // real-time clock
      pmc_disable_periph_clk(3);   // real-time timer
      pmc_disable_periph_clk(4);   // watchdog timer
      // 5 = PMC power mgmt controller
    
      pmc_disable_periph_clk(6);   // EEFC0  flash ctrl
      pmc_disable_periph_clk(7);   // EEFC1  flash ctrl
    
      // 8 = main UART, in use
    
      pmc_disable_periph_clk(9);   // SMC_SDRAMC
      pmc_disable_periph_clk(10);  // SDRAMC
    
      // 11-16 = PIO controllers (unused so far)
      pmc_disable_periph_clk(11);  // PIO A
      pmc_disable_periph_clk(12);  // PIO B
      pmc_disable_periph_clk(13);  // PIO C
      pmc_disable_periph_clk(14);  // PIO D
      pmc_disable_periph_clk(15);  // PIO E
      pmc_disable_periph_clk(16);  // PIO F
    
      pmc_disable_periph_clk(17);  // USART0
      pmc_disable_periph_clk(18);  // USART1
      pmc_disable_periph_clk(19);  // USART2
      pmc_disable_periph_clk(20);  // USART3 - using pins for GPIO
      pmc_disable_periph_clk(21);  // HSMCI (SD/MMC ctrl, N/C)
      pmc_disable_periph_clk(22);  // TWI/I2C bus 0 (i.MX6 controlling)
      pmc_disable_periph_clk(23);  // TWI/I2C bus 1
      pmc_disable_periph_clk(24);  // SPI0
      pmc_disable_periph_clk(25);  // SPI1
      pmc_disable_periph_clk(26);  // SSC (I2S digital audio, N/C)
    
      // 27-35 timer/counters; 36 = PWM
      pmc_disable_periph_clk(27);  // timer/counter 0
      pmc_disable_periph_clk(28);  // timer/counter 1
      pmc_disable_periph_clk(29);  // timer/counter 2
      pmc_disable_periph_clk(30);  // timer/counter 3
      pmc_disable_periph_clk(31);  // timer/counter 4
      pmc_disable_periph_clk(32);  // timer/counter 5
      pmc_disable_periph_clk(33);  // timer/counter 6
      pmc_disable_periph_clk(34);  // timer/counter 7
      pmc_disable_periph_clk(35);  // timer/counter 8
      pmc_disable_periph_clk(36);  // PWM
    
      // 37 = ADC, in use
    
      pmc_disable_periph_clk(38);  // DAC ctrl
      pmc_disable_periph_clk(39);  // DMA ctrl
      pmc_disable_periph_clk(40);  // USB OTG high-speed ctrl
      pmc_disable_periph_clk(41);  // random number generator
      pmc_disable_periph_clk(42);  // ethernet MAC - N/C
      pmc_disable_periph_clk(43);  // CAN controller 0
      pmc_disable_periph_clk(44);  // CAN controller 1 (N/C?)
    
      Serial.begin(460800);    // 115200 * 4 (84MHz/21MHz)
    }
     
  4. francescomm

    francescomm Member

    Joined:
    Dec 14, 2013
    Messages:
    80
    Likes Received:
    4
    Thank you Fetcher, for the extensive and detailed explanation, and for the code. I imagined the Quad was not the best choice for power saving. Of course it also has other great advantages, like fast full GUI access from the network with TeamViewer and full Linux network stack that in my case justify the power drain, and, well... that's the board I have. :)

    I will examine all the options and see if there is a way for this project to save some energy. The first will be to remove the wifi module, at least, then I might let the board go in and out from powersave according to commands from the internet (or just let it in powersave if it's fast enough). Sleep mode would be good if anyone finds how to wake up, while shutting down the i.MX6 might seem a bit extreme for what I am doing if it has to restart Linux and my script all the times, but great to know it can be done (I might even use it to issue a restart of the machine from the Arduino side in case something goes wrong). The "BACKUP mode" with an interrupt on serial input might be ok for what the Due does.

    I have really learnt a lot about the board from your post, in any case, I am grateful because now I know my board much more. Thanks!

    In case anyone is wondering what the UDOO is doing: all is up and running now (at full power, for the moment). Apart from serving as a point of access to the network, a server, and other stuff, the QUAD auto restarts my office-to-home WiFi bridge (with long distance antennas) automatically whenever either connection to the internet, or connection to the other side of the bridge fails (if peripherals with a defined MAC address are not found on the network for 10 minutes), and also every night at 4:00AM, just in case, and also when a "reset router" command is found in some table on a database on the web, so I can manually restart it from a control panel on an independent web site. Since this is up I never had to manually act on the network and never had any more web/WiFi failures. At the moment all checks are done every 10 seconds, but I might slow it down, in case, if I allow the various power save modes.
     

Share This Page