cpmame
Posts: 6
Joined: Sun Jan 19, 2014 6:19 am

Multithreaded Callback Interrupt Problem with GPIO 0.5.4

Sun Jan 19, 2014 7:07 am

Please help, I am having problem with multi-threaded callback interrupt with RPi.GPIO 0.5.4. The problem can be demonstrated in the sample code below. If you try my setup I believe you should see the same problem.

Basically I have 6 push buttons setup as HIGH input, with internal pull up resistor enabled through software. On the breadboard, each GPIO pin are connected -> push button -> GND (no external resistor/capacitor). So below the button is pushed, it is HIGH (3.3V), when it is pushed, the signal will sink to LOW. So when you release the button, the RISING edge detection will trigger the callback interrupt. I also added 100ms to debounce the switch, which can be seen in the code below.

Code: Select all

import RPi.GPIO as GPIO
b11_count = 0

def callback_11(channels):
  global b11_count
  b11_count += 1
  print 'b11_count = %d' %(b11_count)

def callback_x(channels):
  print 'other buttons'


print 'start'
GPIO.setmode(GPIO.BOARD)
GPIO.setup(11, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(13, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(15, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(16, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(18, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(12, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.add_event_detect(11, GPIO.RISING, callback=callback_11, bouncetime=100)
GPIO.add_event_detect(13, GPIO.RISING, callback=callback_x, bouncetime=100)
GPIO.add_event_detect(15, GPIO.RISING, callback=callback_x, bouncetime=100)
GPIO.add_event_detect(16, GPIO.RISING, callback=callback_x, bouncetime=100)
GPIO.add_event_detect(18, GPIO.RISING, callback=callback_x, bouncetime=100)

GPIO.wait_for_edge(12, GPIO.FALLING)
print 'bye'

When I push button #11 once, I expect the screen would just print the counter once. And when I keep pushing the same button multiple times the counter on the screen will increment in proper order. However in my test when I pushed button #11 once (press-release within 1 second), I found multiple lines of counter were printed on the screen and the values are out of order. Please see the attached picture.

Increasing the bounce time to 500ms help sometimes, but once in a while I still get the same problem. I had also tried 1000ms, the system become sluggish but still I cannot eliminate the problem completely. What else can I do? Please advice
Attachments
Screen Shot 2014-01-18 at 10.55.38 PM.png
Screen Shot 2014-01-18 at 10.55.38 PM.png (30.72 KiB) Viewed 1958 times

User avatar
croston
Posts: 708
Joined: Sat Nov 26, 2011 12:33 pm
Location: Blackpool
Contact: Website

Re: Multithreaded Callback Interrupt Problem with GPIO 0.5.4

Sun Jan 19, 2014 12:44 pm

I think what is happening is that the switch bounces when it is pressed, giving both a rising and falling edge. When you release it, you will get some switch bounce as well.

The way RPi.GPIO switch bounce handling works is that it ignores edges for a certain time after an edge is initially detected. As you are trying to detect a button release rather than a button press, the algorithm does not quite fit what you are trying to do.

A better way of doing it in your code might be to GPIO.input() the value of the button a short time (100ms?) after the event is called. If the input() is HIGH, then it is probably a button release rather than a button press.

I also suggest you put a 0.1uF capacitor around your switch to reduce the bounce effect.

cpmame
Posts: 6
Joined: Sun Jan 19, 2014 6:19 am

Re: Multithreaded Callback Interrupt Problem with GPIO 0.5.4

Sun Jan 19, 2014 3:10 pm

Thanks for your reply croston. I will try out your suggestion. Beside, why the execution of the code was out of order? Any idea how to fix that? Thanks

cpmame
Posts: 6
Joined: Sun Jan 19, 2014 6:19 am

Re: Multithreaded Callback Interrupt Problem with GPIO 0.5.4

Sun Jan 19, 2014 11:39 pm

Croston your suggestion really works. You had mentioned a few key points that really nailed the root cause of the problem. Thanks.

1. This are two separate bounces for each "press" and "release" of the button. Since each bounce has multiple "mini" FALLING & RISING edge, my algorithm catches the wrong part of the RISING edge (suppose to catch the "release" part). So even with 100nF capacitor or software debounce could minimize the bouncing effect it would still catch the wrong part of the RISING edge. So you are right, the algorithm is still not appropriate.

2. Use GPIO.input(11) to ensure that the callback function is run on the button "release" really fix the problem. Thanks. That really stabilize the algorithm even without software/hardware debounce. A short software debounce 50-100ms stabilize the algorithm even more. For those who is interested, here is the revised callback function

Code: Select all

def callback_11(channels):
  if GPIO.input(11):    #run only when button is released
    global b11_count
    b11_count += 1
    print 'b11_count = %d %d' %(b11_count, GPIO.input(11))
Thanks

Return to “Raspberry Pi OS”