Accessing the RPi GPIO pins from APL
15 posts
• Page 1 of 2 • 1, 2
Accessing the RPi GPIO pins from APL
All Raspberry Pi models have a number of General Purpose Input Output (GPIO) pins.
These allow one to attach a multitude of "devices" to the RPi, allowing the RPi to read and write to them.
"Devices" can range from the simplest, a switch or button or buzzer, thru LED lights, and on to sensors to read distances, magnetic fields (compass), movement (accelerometers and Gyroscopes) temperatures, not to mention controlling motors and servos.
Many libraries already exist for accessing the GPIO pins from Python and C.
I am currently writing many of the ⎕NA calls needed to access the functions in the PIGPIO C library.
http://abyz.co.uk/rpi/pigpio/cif.html
Would any one else be interested, please let me know.
Ray
These allow one to attach a multitude of "devices" to the RPi, allowing the RPi to read and write to them.
"Devices" can range from the simplest, a switch or button or buzzer, thru LED lights, and on to sensors to read distances, magnetic fields (compass), movement (accelerometers and Gyroscopes) temperatures, not to mention controlling motors and servos.
Many libraries already exist for accessing the GPIO pins from Python and C.
I am currently writing many of the ⎕NA calls needed to access the functions in the PIGPIO C library.
http://abyz.co.uk/rpi/pigpio/cif.html
Would any one else be interested, please let me know.
Ray
Ray Cannon
Please excuse any smelling pisstakes.
Please excuse any smelling pisstakes.
-
ray - Posts: 238
- Joined: Wed Feb 24, 2010 12:24 am
- Location: Blackwater, Camberley. UK
Re: Accessing the RPi GPIO pins from APL
Hi Ray, I am just getting back into the Robot business, got myself a Pi3 and a Zero... Hope to resume blogging any day now. I am very interested in your work, please keep me posted!
-
Morten|Dyalog - Posts: 458
- Joined: Tue Sep 09, 2008 3:52 pm
Re: Accessing the RPi GPIO pins from APL
I am looking forward to reading your next blog. My robot ("PiRat bot") is still running an old model B Pi (without an Arduino), although now I am doing most of my testing on a Pi2.
So far I have written the ⎕NA calls to access the following 39 PIGPIO C programs:
"gpioInitialise" need to run before (most) of these function can work and then "gpioTerminate" before you can leave APL. (Trying to leave without running "gpioTerminate" appears to cause APL to hang.)
I am using some of the i2c* functions to read a HMC5883L Triple-axis Magnetometer (Compass) Board and the MPU6050 Six-Axis Motion Tracking Devices (Gyro + Accelerometer + thermometer),
My robot has "pan and tilt" servos controlling the "head" movements. I have just replaced calls to "Servoblaster" that I originally used, by calls to gpioServo.
Elsewhere, the gpioWave* functions are being used to produce musical notes via a buzzer connected to one of the GPIO pins.
And to read the distance via a HC-SR04 ultrasonic range finder, I am using gpioSetMode, gpioWrite, gpioRead, gpioTrigger and gpioTick. The HC-SR04 device requires you to measure the time the "echo" pin remains high. From APL I can measure distances to an accuracy of about 1cm, where as, running from C, one can achieve better than 0.5 cm accuracy (but only by using gpioSetAlertFunc).
"gpioSetAlertFunc" set up a call back function to be triggered whenever a specific pin changes state (from 0 to 3.3 volts or back). One of the arguments it passes is the clock tick when the rising or falling edge of the pulse was detected.
However, so far, I have been unable to get gpioSetAlertFunc to successfully execute the APL "call-back" function that I have tried to pass to it.
So the best APL code I have come up with to time a pulse on pin ⍵ is
Suggestion on a way of re-writing this code (in APL) with less "overhead" will be gratefully received. (Would rewriting the above as a single line help?)
So far I have written the ⎕NA calls to access the following 39 PIGPIO C programs:
- Code: Select all
bbI2CClose gpioSetWatchdog gpioWrite i2cReadWordData
bbI2COpen gpioTerminate i2cBlockProcessCall i2cSwitchCombined
bbI2CZip gpioTick i2cClose i2cWriteBlockData
gpioCfgGetInternals gpioTrigger i2cOpen i2cWriteByte
gpioDelay gpioWaveAddGeneric i2cProcessCall i2cWriteByteData
gpioHardwareRevision gpioWaveAddNew i2cReadBlockData i2cWriteDevice
gpioInitialise gpioWaveClear i2cReadByte i2cWriteI2CBlockData
gpioRead gpioWaveCreate i2cReadByteData i2cWriteWordData
gpioServo gpioWaveTxSend i2cReadDevice i2cZip
gpioSetMode gpioWaveTxStop i2cReadI2CBlockData
"gpioInitialise" need to run before (most) of these function can work and then "gpioTerminate" before you can leave APL. (Trying to leave without running "gpioTerminate" appears to cause APL to hang.)
I am using some of the i2c* functions to read a HMC5883L Triple-axis Magnetometer (Compass) Board and the MPU6050 Six-Axis Motion Tracking Devices (Gyro + Accelerometer + thermometer),
My robot has "pan and tilt" servos controlling the "head" movements. I have just replaced calls to "Servoblaster" that I originally used, by calls to gpioServo.
Elsewhere, the gpioWave* functions are being used to produce musical notes via a buzzer connected to one of the GPIO pins.
And to read the distance via a HC-SR04 ultrasonic range finder, I am using gpioSetMode, gpioWrite, gpioRead, gpioTrigger and gpioTick. The HC-SR04 device requires you to measure the time the "echo" pin remains high. From APL I can measure distances to an accuracy of about 1cm, where as, running from C, one can achieve better than 0.5 cm accuracy (but only by using gpioSetAlertFunc).
"gpioSetAlertFunc" set up a call back function to be triggered whenever a specific pin changes state (from 0 to 3.3 volts or back). One of the arguments it passes is the clock tick when the rising or falling edge of the pulse was detected.
However, so far, I have been unable to get gpioSetAlertFunc to successfully execute the APL "call-back" function that I have tried to pass to it.
So the best APL code I have come up with to time a pulse on pin ⍵ is
- Code: Select all
time←{ ⍝ Time the pulse on GPIO pin ⍵
read←{
⍺≠#.PiGpio.gpioRead ⍵:#.PiGpio.gpioTick ⍝ Return current tick
⍺ ∇ ⍵ ⍝ tail recursive call
}
(1 read ⍵)-(0 read ⍵)
}
Suggestion on a way of re-writing this code (in APL) with less "overhead" will be gratefully received. (Would rewriting the above as a single line help?)
Ray Cannon
Please excuse any smelling pisstakes.
Please excuse any smelling pisstakes.
-
ray - Posts: 238
- Joined: Wed Feb 24, 2010 12:24 am
- Location: Blackwater, Camberley. UK
Re: Accessing the RPi GPIO pins from APL
Hi Ray,
I'm really impressed by the amount of code you've got working with ⎕na - the quad-fn that raises terror in the bravest APler's heart (or mine, at any rate).
I suspect that pin change polling code is always going to be slower than you'd like.
There is a way of getting the Pi's kernel to generate a C call-back on a pin state change. I don't know if APL can be coaxed into detecting that and turning it into an APL callback. Maybe team Dyalog can comment and/or help?
Romilly
I'm really impressed by the amount of code you've got working with ⎕na - the quad-fn that raises terror in the bravest APler's heart (or mine, at any rate).
I suspect that pin change polling code is always going to be slower than you'd like.
There is a way of getting the Pi's kernel to generate a C call-back on a pin state change. I don't know if APL can be coaxed into detecting that and turning it into an APL callback. Maybe team Dyalog can comment and/or help?
Romilly
- romilly
- Posts: 6
- Joined: Tue May 03, 2016 9:51 am
Re: Accessing the RPi GPIO pins from APL
Callback support is for a callback from a ⎕NA'd function that has been invoked. There is no support for just leaving the possibility of calling back into apl whilst it is doing other things.
So you can give a callback function as an argument to a ⎕NA'd function. That function can call the callback. Once the function is finished there is no support for it calling back into apl.
Now if you run an apl thread which uses an ampersanded ⎕NA which only returns when the callback is desired - that is supported and may solve the issue.
So you can give a callback function as an argument to a ⎕NA'd function. That function can call the callback. Once the function is finished there is no support for it calling back into apl.
Now if you run an apl thread which uses an ampersanded ⎕NA which only returns when the callback is desired - that is supported and may solve the issue.
- Geoff|Dyalog
- Posts: 43
- Joined: Wed May 13, 2009 12:36 pm
Re: Accessing the RPi GPIO pins from APL
Thanks for the feedback Geoff.
The PIGPIO "C" function "gpioSetAlertFunc" requires two arguments
"f" is the call-back function.
"gpioSetAlertFunc" expect the called-back function to be passed in 3 arguments and return nothing
So for the ⎕NA statement setting up gpioSetAlertFunc I have coded:
The APL callback function I have written is
To call gpioSetAlertFunc, I
(I have tried this last line with and without the &.)
Now this all appears to be fine (APL does not crash or complaint) except that my "CallBack" function does not appear to ever be called. So the expected files are not created.
It would be nice to get this working if we could, but for now I'm stuck.
The PIGPIO "C" function "gpioSetAlertFunc" requires two arguments
- Code: Select all
int gpioSetAlertFunc(unsigned user_gpio,gpioAlertFunc_t f)
"f" is the call-back function.
"gpioSetAlertFunc" expect the called-back function to be passed in 3 arguments and return nothing
- Code: Select all
void aFunction(int gpio,int level,uint32_t tick)
{
printf("GPIO%d became%d at%d",gpio,level,tick);
}
So for the ⎕NA statement setting up gpioSetAlertFunc I have coded:
- Code: Select all
⎕NA'U4 '/home/pi/PIGPIO/libpigpio.so|gpioSetAlertFunc U ∇(P P P)'
The APL callback function I have written is
- Code: Select all
CallBack(pins level tics)
⍝ gpioSetAlertFunc sets up this function as a callback when the level changes on <pin>
(⊃,/' ',∘⍕¨pins level tics)⎕NPUT ('/home/pi/callback',⍕level) 1
To call gpioSetAlertFunc, I
- Code: Select all
echo←24
callback←⎕OR'CallBack'
rc←#.PiGpio.gpioSetAlertFunc&(echo callback)
(I have tried this last line with and without the &.)
Now this all appears to be fine (APL does not crash or complaint) except that my "CallBack" function does not appear to ever be called. So the expected files are not created.
It would be nice to get this working if we could, but for now I'm stuck.
Ray Cannon
Please excuse any smelling pisstakes.
Please excuse any smelling pisstakes.
-
ray - Posts: 238
- Joined: Wed Feb 24, 2010 12:24 am
- Location: Blackwater, Camberley. UK
Re: Accessing the RPi GPIO pins from APL
I have now written (in "C") a callback function ("afun") and linked it as an ".so" library ("libsonarEcho.so"). Once APL has imported "afun" (via an yet other ⎕NA call), it can be passed to "gpioSetAlertFunc" as a parameter.
"afun" is called twice (once on the rising pulse edge, and once on the falling pulse edge), passing the clock tick it receives as an argument from the first call to the second call via a static integer.
On the second call, "afun" calculates the distance in cm from the difference between the two clock tics, and writes the result out to a text file "sonar.txt".
Back in APL, I can then read (via ⎕MAP) the content of "sonar.txt" file.
I have now completed a 100 test runs (all at the same distance) to compare my non-callback pure APL against APl calling gpioSetAlertFunc with the new "C" callback.
The pure APL returned 76% "good" results (within about 3% of the average) while the APL with a "C" callback 81% were "good". So it just seems worth the extra effort to use gpioSetAlertFunc with the "C" callback.
"afun" is called twice (once on the rising pulse edge, and once on the falling pulse edge), passing the clock tick it receives as an argument from the first call to the second call via a static integer.
On the second call, "afun" calculates the distance in cm from the difference between the two clock tics, and writes the result out to a text file "sonar.txt".
Back in APL, I can then read (via ⎕MAP) the content of "sonar.txt" file.
- Code: Select all
⎕NA'U4 '/home/pi/PIGPIO/libpigpio.so|gpioSetAlertFunc U ∇(P P P)'
⎕NA'/home/pi/libsonarEcho.so|afun U U U4'
...
callback←⎕OR'afun'
...
rc←#.PiGpio.gpioSetAlertFunc(echo callback)
...
cm←⊃(//⎕VFI,80 ¯1 5 ⎕MAP'/home/pi/sonar.txt')
I have now completed a 100 test runs (all at the same distance) to compare my non-callback pure APL against APl calling gpioSetAlertFunc with the new "C" callback.
The pure APL returned 76% "good" results (within about 3% of the average) while the APL with a "C" callback 81% were "good". So it just seems worth the extra effort to use gpioSetAlertFunc with the "C" callback.
Ray Cannon
Please excuse any smelling pisstakes.
Please excuse any smelling pisstakes.
-
ray - Posts: 238
- Joined: Wed Feb 24, 2010 12:24 am
- Location: Blackwater, Camberley. UK
Re: Accessing the RPi GPIO pins from APL
The gpioSetAlertFunc is exactly the sort of function I said we cannot support. What this is doing is remembering a function address for later use and then returning.
Sometime later it makes a call to the supplied function address. Unfortunately, on the APL side all of the information and indeed the address only lasts until the gpioSetAlertFunc returns.
So the callbacks are useful for the sort of code that runs through a list and calls back for each element in the list.
What I was reaching for as a solution was to make a C function with the same syntax as gpioSetAlertFunc which called gpioSetAlertFunc and then went into a wait state. Lets call this function C. Each time the callback triggered it would call the APL because the C is still running. If C is invoked as a threaded call in an APL thread I think you get the effect you want.
If this works - tell me - then we might be able to provide a bit of syntax on ⎕NA to say "do not return" and thus avoid writing the C function.
Cleaning up would be an exercise. I presume there is a corresponding "unset" function. Its invocation would need to terminate the thread in which C was running. Tricky, I always dislike trying to terminate a thread from outside of the thread.
Sometime later it makes a call to the supplied function address. Unfortunately, on the APL side all of the information and indeed the address only lasts until the gpioSetAlertFunc returns.
So the callbacks are useful for the sort of code that runs through a list and calls back for each element in the list.
What I was reaching for as a solution was to make a C function with the same syntax as gpioSetAlertFunc which called gpioSetAlertFunc and then went into a wait state. Lets call this function C. Each time the callback triggered it would call the APL because the C is still running. If C is invoked as a threaded call in an APL thread I think you get the effect you want.
If this works - tell me - then we might be able to provide a bit of syntax on ⎕NA to say "do not return" and thus avoid writing the C function.
Cleaning up would be an exercise. I presume there is a corresponding "unset" function. Its invocation would need to terminate the thread in which C was running. Tricky, I always dislike trying to terminate a thread from outside of the thread.
- Geoff|Dyalog
- Posts: 43
- Joined: Wed May 13, 2009 12:36 pm
Re: Accessing the RPi GPIO pins from APL
Thanks Geoff, I'v had to read your last reply a second (or third) time before I finally understood exactly what your saying. I will give it another try and let you know the result.
Thanks
Thanks
Ray Cannon
Please excuse any smelling pisstakes.
Please excuse any smelling pisstakes.
-
ray - Posts: 238
- Joined: Wed Feb 24, 2010 12:24 am
- Location: Blackwater, Camberley. UK
Re: Accessing the RPi GPIO pins from APL
Sorry Ray. There is a reason why I am not responsible for Dyalog's documentation.
- Geoff|Dyalog
- Posts: 43
- Joined: Wed May 13, 2009 12:36 pm
15 posts
• Page 1 of 2 • 1, 2
Who is online
Users browsing this forum: No registered users and 1 guest
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group