In this example we are going to connect the Raspberry PI with a button, and then make Xojo programs where the first one will read from the button without interrupts and the second will be doing the same using interrupts.
We do not take any responsibility for possible errors in the guide or errors that you might do wiring it up. Incorrect wiring can result in damaged sensor or damaged Raspberry PI.
Pieces we use are:
- Raspberry PI 2
- Cobbler and Cobbler cable
- Bread board
- 1 K-ohm resistor
- A button
- Wiring PI Xojo module from Paul Lefebvre (Note we will be making modifications for the interrupts example)
If you are not familiar with working with a breadboard or on how to place a cobbler on the breadboard then click here bellow
If you don’t know resistor color codings to find correct resistors then you can click the link bellow
First thing is understanding the wiring of the button:
My button looked like this:
The button had 4 pins, 2 and 2 are same. At first I was not sure how its internal wiring was, as in which two poles were the same and which were the opposite. So I used digital multimeter to get to know its internal wiring.
Do not worry if you don’t know which pins are what on your button, if you get it wrong then worst thing that can happen is the reading of your application will just be always pressed down.
You will want to protect the GPIO pin from mistakes, like if you were to program it as output instead of input then without protection you likely would damage the Raspberry PI. So we use 1K resistor to protect the pin.
1 KOhm resistor in 4 stripe system = Brown – Black – Red (Read towards the golden stripe)
If you have 5 or 6 stipe system on your resistors then you can 5 and 6 stripe resistors to get help on reading their values if you do not know how.
Now once the resistor is in place then if doing programming error it should not damage the pin.
On the breadboard it looked like this:
So basically red is connected to 3,3 V on the Cobbler, and the other end to the button. From the output of the button we connect the 1K resistor, and from the other end of the button we connect Green which goes from the resistor to the GPIO 6 (which is pin 31) which we choose to use for this example.
The Xojo code without interupts:
An input gpio will float between 0 and 1 if it’s not connected to a voltage. So we will need to take care of that by giving it determined state. We do that by using the GPIO.PullUpDnControl function.
The open event of a window:
Sub Open() Const kPin = 6 GPIO.SetupGPIO GPIO.PinMode(kPin,GPIO.INPUT) GPIO.PullUpDnControl(kPin,GPIO.PUD_DOWN) Timer1.Mode = Timer.ModeMultiple Timer1.Enabled = true End Sub
The timer action event:
Sub Action() Const kPin = 6 for n as Integer = 1 to 10 if GPIO.DigitalRead(kPin) <> 0 then Listbox1.AddRow "Button was clicked" end if App.DoEvents(1) next End Sub
This works…… and completes the example without interrupts……
But this is not really great since no matter how tight your timer or loop runs then you will be able to miss clicks.
So here is how we do it with interrupts:
When using interrupts then we must be really careful to not call anything from within the interrupt since Xojo does not support that. So the idea is we have a safe function that only logs the interrupt then we poll the log. That way event is never lost and timer or whatever method you use to poll does not need to be very intensive.
First thing is we need to patch Paul’s GPIO module, adding the following to the module (the function we are adding likely already exists but is not fully implemented so verify that or just blindly override it) and remember to add the four constants also:
Protected Const EDGE_FALLING = 1 Protected Const EDGE_BOTH = 3 Protected Const EDGE_RISING = 2 Protected Const EDGE_SETUP = 0 Protected Function WIringPiISR(pin as integer,edgeType as integer, p as ptr) As Integer //This function registers a function to received interrupts on the specified pin. // The edgeType parameter is either INT_EDGE_FALLING, INT_EDGE_RISING, // INT_EDGE_BOTH or INT_EDGE_SETUP. If it is INT_EDGE_SETUP then no // initialisation of the pin will happen – it’s assumed that you have already // setup the pin elsewhere (e.g. with the gpio program), but if you specify one // of the other types, then the pin will be exported and initialised as specified. // This is accomplished via a suitable call to the gpio utility program, // so it need to be available. // // The pin number is supplied in the current mode – native wiringPi, BCM_GPIO, // physical or Sys modes. // // This function will work in any mode, and does not need root privileges to work. // // The function will be called when the interrupt triggers. // When it is triggered, it’s cleared in the dispatcher before calling your // function, so if a subsequent interrupt fires before you finish your handler, // then it won’t be missed. (However it can only track one more interrupt, // if more than one interrupt fires while one is being handled then they will be ignored) // // This function is run at a high priority (if the program is run // using sudo, or as root) and executes concurrently with the main program. // It has full access to all the global variables, open file handles and so on. // // See the isr.c example program for more details on how to use this feature. #If TargetARM And TargetLinux Then Soft Declare Function wpISR Lib "libwiringPi.so" Alias "wiringPiISR" (pin As Integer, mode As Integer, p as ptr) as Integer return wpISR(pin, edgeType,p) #Endif End Function
Next we create a module which we will call InteruptModule and this module will contain the following things:
Private DownEventCount As Integer Protected Sub ButtonDownInterupt() // We need some pragmas here to make this safe since this is called from interupt. #Pragma StackOverflowChecking False #Pragma DisableBackgroundTasks // NOTE since we are in interupt then we may not call any methods here it is not safe // however we can count the number of occurances and poll this module with a timer or by other means, and by doing that we can be sure that no clicks were missed. DownEventCount = DownEventCount + 1 End Sub Protected Function GetDetectedClicks() As Integer Dim tmp as Integer = DownEventCount DownEventCount = 0 return tmp End Function
Then the Window open event will look like this:
Sub Open() Const kPin = 6 GPIO.SetupGPIO GPIO.PinMode(kPin,GPIO.INPUT) GPIO.PullUpDnControl(kPin,GPIO.PUD_DOWN) if GPIO.WIringPiISR(kPin,GPIO.EDGE_RISING,Addressof InteruptModule.ButtonDownInterupt) = -1 then MsgBox "Could not register interupt for pin number " + Str(kPin) end if Timer1.Mode = Timer.ModeMultiple Timer1.Enabled = true End Sub
And the timer action event will look like this:
Sub Action() Dim clicks as Integer clicks = InteruptModule.GetDetectedClicks() if clicks > 0 then Listbox1.AddRow "Button was clicked" end if End Sub
No button clicks should ever get missed now.
Thats it for now !