chipKIT® Development Platform

Inspired by Arduino™

WF32 External Interrupt From Sleep

Created Mon, 06 Jun 2016 22:43:49 +0000 by adam.lynch


adam.lynch

Mon, 06 Jun 2016 22:43:49 +0000

Hello,

This might be an easy fix but I really can't seem to figure out what I'm doing wrong here. I am trying to put the board to sleep when the value from the on board Potentiometer goes above 3 and then wake it up by a button press attached to INT2(Pin 7). I added the digitalWrite after the "wait" function and it turns on immediately when the board goes to sleep instead of waiting for the interrupt to bring it back. I am using the WF32 board and running on the Arduino IDE. Here is my code:

#include <ChangeNotification.h>
#define pin 13
// the setup routine runs once when you press reset:
void setup() {
  // initialize serial communication at 9600 bits per second:
  Serial.begin(9600);
  attachInterrupt(2, wakeUp, FALLING);
  pinMode(pin, OUTPUT);
}


void wakeUp(){
  asm ( "eret" );
}

void loop() {
  int sensorValue = analogRead(13);
  // Convert the analog reading (which goes from 0 - 1023) to a voltage (0 - 5V):
  float voltage = sensorValue * (3.3 / 1023.0);
  // print out the value you read:
  Serial.println(voltage);

  if( voltage > 3 ){
    SYSKEY = 0xAA996655;
    SYSKEY = 0x556699AA;
    OSCCONSET = 0x10; // Enable sleep mode
    SYSKEY = 0x0;
    asm ( "wait" ); 
    digitalWrite(pin, HIGH);
  }
}

Any input is appreciated, thank you!


majenko

Tue, 07 Jun 2016 09:48:32 +0000

I'm not entirely sure why your program isn't working yet, but here are some snippets and ideas:

  1. You don't need to do anything in your interrupt handler. It's called by a wrapper function which itself does the eret, so putting your own in will confuse things. You'll end up with two erets with only one e to return from.

This is the sleep code I use successfully in another application. It runs on the MX150, not the MX695, but it should still work:

void sleep() {
    // Standard unlock sequence
    SYSKEY = 0x0;
    SYSKEY = 0xAA996655;
    SYSKEY = 0x556699AA;
    OSCCONSET = 0x10; // Enable sleep mode
    SYSKEY = 0x0;

    asm volatile("mfc0 $26, $12");
    asm volatile("ins $26, $0, 10, 3");
    asm volatile("mtc0 $26, $12");
    asm volatile("wait");
    while (OSCCONbits.SLOCK == 0);
}

Putting it to sleep, though, is only part of the story. You will only be saving some power, not lots of power. You should also disable any peripherals and set all unused IO pins to OUTPUT and LOW to prevent any floating inputs from flapping. I use this code in that same project - it will need adaption for the MX695:

// Shut down everything that can be shut down.
void savePower() {

    displayTimer.stop();

#define LOWPOWER(X) pinMode(X, OUTPUT); digitalWrite(X, LOW);

    LOWPOWER(LCD_RW)
    LOWPOWER(LCD_RS)
    LOWPOWER(LCD_E)
    LOWPOWER(LCD_CS1)
    LOWPOWER(LCD_CS2)
    LOWPOWER(LCD_D0)
    LOWPOWER(LCD_D1)
    LOWPOWER(LCD_D2)
    LOWPOWER(LCD_D3)
    LOWPOWER(LCD_D4)
    LOWPOWER(LCD_D5)
    LOWPOWER(LCD_D6)
    LOWPOWER(LCD_D7)
    LOWPOWER(PIN_LCDRES)

    LOWPOWER(MISO)
    LOWPOWER(MOSI)
    LOWPOWER(SCK)
    LOWPOWER(PIN_EXP0)
    LOWPOWER(PIN_EXP1)
    LOWPOWER(PIN_EXP2)

    pinMode(PIN_5VEN, OUTPUT);
    pinMode(PIN_LCDEN, OUTPUT);
    pinMode(PIN_BACKLIGHT, OUTPUT);
    pinMode(PIN_BTEST, OUTPUT);

    digitalWrite(PIN_BTEST, LOW);
    digitalWrite(PIN_BACKLIGHT, LOW);
    digitalWrite(PIN_LCDEN, LOW);
    digitalWrite(PIN_5VEN, HIGH);

    PMD1 = 0xFFFFFFFFUL;
    PMD2 = 0xFFFFFFFFUL;
    PMD3 = 0xFFFFFFFFUL;
    PMD4 = 0xFFFFFFFFUL;
    PMD5 = 0xFFFFFFFFUL;
    PMD6 = 0xFFFFFFFEUL;
   
    displayIsRunning = false;
}

The digitalWrite bits can be ignored - they are being used to control the power to on-board peripherals. It's the unused pins and the PMD registers that are important. You should check out the datasheet for the MX695 to look at the PMD registers to see which bits relate to which peripherals so you know which ones you can safely turn off for your application. In my case it's everything except the interrupt pins.

Using this method I have got the board down to idling at 50µA. I'm using high efficiency (TC105) switching regulators, though, and everything on the board can be turned off completely, including the 5V power supply.


adam.lynch

Tue, 07 Jun 2016 15:40:01 +0000

Wow, thank you so much for the quick response! This is all super helpful information, hopefully I'll be able to get to it by today to test it out.


adam.lynch

Wed, 08 Jun 2016 17:14:01 +0000

Okay so I was able to fix the sleep mode, all I had to do was get rid of the "eret" function. I can't believe it was so simple! As far as the LED turning on after it was put to sleep, I forgot to add the SYSKEY = 0x0 line in the beginning.

I do have just one more question. I have been looking at data sheets for a while now and I just can't seem to understand what the PMD registers even do. I'm sorry if this is a stupid question but how exactly did you know which ones to turn off? I also noticed that PMD6 is set differently than the other register, is that a typo?

Thank you again for helping me get this figured out!


majenko

Thu, 09 Jun 2016 08:37:32 +0000

The PMD registers turn the power of and disable the clocks to the built-in peripherals. A bit set to 1 turns the peripheral off. The last one is different because I need one single peripheral turned on which is the one generating the interrupt to wake up (the RTCC). You can't turn off external interrupts since they don't use a clock.

It looks like they have been introduced at the same time as the PPS functionality, so only chips with Peripheral Pin Select have the Peripheral Module Disable registers. So you can ignore them completely for the WF32 - just delete them - since the PIC32MX695 doesn't have them.


majenko

Thu, 09 Jun 2016 09:58:46 +0000

Yeah, it looks like those Peripheral Module Disable registers aren't available in the older MX5xx/6xx/7xx chips that are on the WF32 and others. The whole power management system has been improved loads in the newer MX1xx/2xx chips and their bigger PPS cousins the MX330/350/370/430/450/470.