PDA

View Full Version : Problem with pin wakeup


mcervi
05-09-2010, 04:35 PM
Hello,

I'm having a problem with pin wakeup functions on the RF Engine (RF100PC6), using firmware 2.2.16.

On the SN171 proto board, there is a button attached to GPIO5. GPIO5 has its internal pullup enabled, and the button connects GPIO5 to GND when it is pressed. So, GPIO5 is low when the button is pressed, and high otherwise.

I call monitorPin(GPIO5, True) to enable monitoring of that pin. Then, I call wakeupOn(GPIO5, True, False) to enable pin wakeup on a falling edge (i.e. when the button is pressed down).

My HOOK_GPIN code pulses an LED and makes a long beep when the button goes down, and makes a short beep (no LED) when the button goes up. So, it's easy to tell if the HOOK_GPIN code has run and what type of event has occurred.

LED2 is lit whenever the device is awake (so it's easy to tell if it is sleeping).

If I put the unit to sleep from Portal by calling my function gotoSleep(), then it will sleep and wake up when the button is pressed down (falling edge). It sees the button press and executes the HOOK_GPIN code as soon as it wakes up. This all works as expected and is 100% reliable.

However, if I:
1) Press the button and keep the button held down while calling gotoSleep()
2) release the button after it's asleep
3) press the button again

it stays asleep when the button is released (step 2), which is correct, and it wakes up on the button press (step 3), but it does NOT call the HOOK_GPIN function in step 3. :confused:

If I then:
4) release the button

it does call the HOOK_GPIN function for the button release.

This is also 100% reliable - it never wakes up on the next falling edge of a monitored pin if it goes to sleep while that pin is low. I tried this on GPIO9 too just in case it was something funny with GPIO5.

I know it sees the falling edge on that pin, because it wakes itself up from sleep mode. But then why doesn't it call the HOOK_GPIN code?

My application needs to do something as soon as a user presses the button, and go to sleep immediately thereafter. If the user happens to hold the button longer than it takes for the device to complete its task and start sleeping, then the device won't work at all the next time the user presses the button - this would be bad! :(

I'm not sure how to fix this... this is my first project with these devices, so it's quite possible that I have made a mistake in my code.

Any help or suggestions would be greatly appreciated! :)

My test code is below... This can be tested using the SN171 proto board with the LED jumpers on, the switch-GPIO5 jumper set, the RS232 jumpers removed, and a beeper/buzzer between GPIO17 and GND.

from synapse.pinWakeup import *

# Initialization Code
# Pin assignments
LED1_PIN = GPIO_1
LED2_PIN = GPIO_2
BEEPER_PIN = GPIO_17
BUTTON1_PIN = GPIO_5

buttonPressed = 0
secondCounter = 0

@setHook(HOOK_STARTUP)
def startupEvent():
""" This is hooked into the HOOK_STARTUP event """
# Detect and initialize the hardware
initProtoHw()
# Set up wakeup Pin
monitorPin(BUTTON1_PIN, True)
setRate(2)
wakeupOn(BUTTON1_PIN, True, False)
lightLed2()

@setHook(HOOK_100MS)
def timer100msEvent(currentMs):
"""Hooked into the HOOK_100MS event"""
global secondCounter
global buttonPressed
secondCounter = secondCounter + 1
# If master hasn't contacted unit in 200 ticks (20s) then go to sleep to save batteries.
# Unit won't wake up again until the button is pressed or it is power-cycled.

@setHook(HOOK_GPIN)
def wakeUpOnButton(pinNum,isSet):
""" set to wake up by interrupt pin controlled by Microprocessor ... triggered falling edge """
global buttonPressed
# Buttons go to 0 when pressed and are 1 (due to internal pullup) when idle
if (isSet == False):
pulsePin(LED1_PIN, 800, True)
pulsePin(BEEPER_PIN, 250, True)
buttonPressed = 1
else:
pulsePin(BEEPER_PIN, 125, True)

# This code is called from master via RPC.
def gotoSleep(dur):
"""commands nodes to go to sleep"""
global secondCounter
if rpcSourceAddr() != localAddr():
# Reset counter when master contacts this unit.
secondCounter = 0
wakeupOn(BUTTON1_PIN, True, False)
ledsOff()
sleep(1, dur)
#afterSleep()
lightLed2()

# This code is called from master via RPC.
# It only clears the button press request if the master acknowledges receipt
# by calling this function via RPC.
def clearButtonPress():
global secondCounter
global buttonPressed
# Reset counter when master contacts this unit.
secondCounter = 0
buttonPressed = 0

# LED control functions
def ledsOff():
"""Turn off all LEDs"""
writePin(LED1_PIN, False)
writePin(LED2_PIN, False)
# Not technically an LED, but it makes sense to do this here
writePin(BEEPER_PIN, False)

def lightLed1():
"""Light the first LED"""
writePin(LED1_PIN, True)

def lightLed2():
"""Light the second LED"""
writePin(LED2_PIN, True)

# Initialization Code
def initProtoHw():
setPinDir(LED1_PIN, True)
setPinDir(LED2_PIN, True)
setPinDir(BEEPER_PIN, True)
# Button1 is input with pullup
setPinDir(BUTTON1_PIN, False)
setPinPullup(BUTTON1_PIN, True)
# Turn LEDs and beeper off
ledsOff()

RFAndy
05-09-2010, 09:07 PM
This will not answer your main question but I like to point out that the schematic of the SN171 prototype board already has a 10K pullup near the button switch and through your software code you pulled it up again.
;)

mcervi
05-09-2010, 10:39 PM
You're right - I thought someone might notice that. :)

I originally had the code / RF engine running on my own hardware (which has no external pullup) and then migrated it back to the SN171 to make sure it wasn't a problem with my board. I left the internal pullup enabled, figuring it wouldn't hurt anything.

kbanks
05-10-2010, 12:05 PM
However, if I:
1) Press the button and keep the button held down while calling gotoSleep()
2) release the button after it's asleep
3) press the button again

it stays asleep when the button is released (step 2), which is correct, and it wakes up on the button press (step 3), but it does NOT call the HOOK_GPIN function in step 3.


HOOK_GPIN events are generated by transitions in pin state that are seen by the firmware.

Since you are changing pin states while the node was asleep, it does not seen any change (it was low before it went to sleep, and is still low when it wakes back up - no transition detected).

Some applications put an explicit readPin() after the sleep() call to help deal with this, but the bottom line is that nodes do not monitor pins while asleep.

mcervi
05-10-2010, 12:24 PM
Thank you so much for the quick response. I really appreciate it!

So, is it safe to say that the mechanism that wakes the device from sleep on a pin transition is totally separate from the mechanism that detects pin transitions for HOOK_GPIN events? If so, then that helps explain things - I had assumed they were both handled together.

As you suggest, I can work around this in my script by reading the pin as soon as the device wakes up (i.e. the next line after sleep() in the script).

This leads to another question... Suppose it wakes up due to a pin transition that generates a HOOK_GPIN event, and I also have code right after the sleep() instruction to check the status of the pin when it wakes up. Which runs first? When does the HOOK_GPIN event get handled relative to the code following the sleep() instruction?

Jheath
05-10-2010, 12:59 PM
This leads to another question... Suppose it wakes up due to a pin transition that generates a HOOK_GPIN event, and I also have code right after the sleep() instruction to check the status of the pin when it wakes up. Which runs first? When does the HOOK_GPIN event get handled relative to the code following the sleep() instruction?

Good question. In SNAPpy scripts, you pick up right where you left off. In other words, the statement immediately after the sleep() command will be executed upon wakeup, then the rest of the statements within the function. The GPIN event will be executed after this function has run to completion. The GPIN event will not interrupt the function containing the sleep() call.