Accessing the RPi GPIO pins from APL
15 posts
• Page 2 of 2 • 1, 2
Re: Accessing the RPi GPIO pins from APL
Update on the PIGPIO "C" library to APL interface:
I have NOT tried yet to code those marked as "EXPERT - Not intended for general use".
I have attempted to code up all the rest (149 of them) and I have managed to get 146 defined as complied functions available in APL.
However, I know that the syntax I have supplied is incorrect for the following 5 functions:
I have NOT tried yet to code those marked as "EXPERT - Not intended for general use".
I have attempted to code up all the rest (149 of them) and I have managed to get 146 defined as complied functions available in APL.
However, I know that the syntax I have supplied is incorrect for the following 5 functions:
- Code: Select all
#.NAbscXfer #.NAgpioSetTimerFunc #.NAgpioSetTimerFuncEx #.NAgpioStartThread #.NAgpioStopThread
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
Just saw your post. Are you distributing your code?
Just saw your post. Are you distributing your code?
- bwyork67
- Posts: 13
- Joined: Tue Nov 12, 2013 7:01 pm
Re: Accessing the RPi GPIO pins from APL
Hi,
>Just saw your post. Are you distributing your code?
So far, I have just about managed to put the interface to the PIGPIO code on to GITHUB:
https://github.com/RayCannon/gpio
Currently, there is very little documentation, as I am struggling to get to grips with GITHUB, and I am NOT a fan of Dyalog Scripts as I love the old fashion workspace, and simple namespaces.
Part of the problem is I am having too much fun using the code in Robot ANT project and have no time to bother with Githib.
To give you something to get on with, here is some code for "Ant_1" my robot ant.
The ant uses a modified tripod gait.
It uses 3 servos connected to a PCA9685 (an I2C device to control up to 16 PWM devices) to drive the 6 legs.
The Right front and back legs are controlled by the first servo.
The Left front and back legs are controlled by the second servo.
The two middle legs "see-saw" the ant from side to side and use the third servo.
(See https://diyhacking.com/hexapod-walker-raspberry-pi/)
>Just saw your post. Are you distributing your code?
So far, I have just about managed to put the interface to the PIGPIO code on to GITHUB:
https://github.com/RayCannon/gpio
Currently, there is very little documentation, as I am struggling to get to grips with GITHUB, and I am NOT a fan of Dyalog Scripts as I love the old fashion workspace, and simple namespaces.
Part of the problem is I am having too much fun using the code in Robot ANT project and have no time to bother with Githib.
To give you something to get on with, here is some code for "Ant_1" my robot ant.
The ant uses a modified tripod gait.
It uses 3 servos connected to a PCA9685 (an I2C device to control up to 16 PWM devices) to drive the 6 legs.
The Right front and back legs are controlled by the first servo.
The Left front and back legs are controlled by the second servo.
The two middle legs "see-saw" the ant from side to side and use the third servo.
(See https://diyhacking.com/hexapod-walker-raspberry-pi/)
- Code: Select all
Ant_1;LeftLegs;MiddleLegs;RightLegs;centzero;dl;hand;i;leftFor;leftUp;leftup;legzero;liftmov;llegaft;llegfor;rightup;rlegaft;rlegfor;shand;stepmov;center_nums
⍝ Code to drive a robotic ant
⍝ connected via PCA9685
⍝ Channel 0=left back and forward
⍝ Channel 1=right back and forward
⍝ Channel 2=middle up and down
Close
Init
shand←Open_I2C'40' ⍝ Open I2C device PCA9685 on 0x40 (16 servo controller)
InitServos shand ⍝ Initialise the 16 servos channels
dl←0.6 ⍝ delay for servos to complete movement
RightLegs←0 ⍝ right legs channel
LeftLegs←1 ⍝ left side front and back legs channel
MiddleLegs←2 ⍝ center legs channel
centzero←54 ⍝ MiddleServos at center position 50%
legzero←56 ⍝ legs at central positin
stepmov←20 ⍝ Step movement 25 % (initially)
liftmov←7 ⍝ Step lift movement 10 % (initially)
leftup←centzero+liftmov ⍝ move left side up
rightup←centzero-liftmov ⍝ move right side up
llegfor←legzero+stepmov ⍝ Left Leg forward
llegaft←legzero-stepmov ⍝ Left Leg back
rlegfor←legzero-stepmov ⍝ right Leg forward
rlegaft←legzero+stepmov ⍝ right Leg back
center_nums←shand centzero legzero leftup rightup
CenterServos center_nums ⍝ Center all servos
⎕DL dl
:For i :In ⍳3 ⍝ Move 3 steps forward
Breast shand ⍝ Breast-stroke movement rather than Crawl
:End
CenterServos center_nums ⍝ Center all servos
MoveServos shand ¯1 ¯1 ⍝ stop all servos
CancelServo shand ⍝ Switches all PWM channels off
Close ⍝ close the PIGPIO interface
- Code: Select all
Close;⎕TRAP;a;b
⍝ Close down PiGpio and any open I2C devices
⎕TRAP←0 'E' '→⎕LC+1'
:If 9=#.⎕NC'PiGpio'
:If ×⍴,#.PiGpio.Handles
a←#.PiGpio.i2cClose¨#.PiGpio.Handles
:End
#.PiGpio.Handles←⍬
#.PiGpio.Devices←⍬
b←#.PiGpio.gpioTerminate
:End
- Code: Select all
version←Init;so;hex2int
⍝ Initialise the PIGPIO library calls
version←'Init I2C failed'
hex2int←{⊃16⊥('0123456789abcde'⍳⍵)-⎕IO}
⍝ Create a namespace for PIGPIO objects
:If 0=#.⎕NC'PiGpio'
'PiGpio'#.⎕NS''
:End
#.PiGpio.Devices←⍬ ⍝ Numeric Address of I2C devices
#.PiGpio.Handles←⍬ ⍝ Handles of open I2C devices
⍝ define APL "cover" function in #.PiGpio
so←'/home/pi/PIGPIO/libpigpio.so' ⍝ Location of the PIGPIO DLL
#.PiGpio NA.Init_PiGpio_via_NA so ⍝ set up the functions in NS #.PiGpio
⎕NA'/home/pi/libsonarEcho.so|afun U U U4'
⎕NA'I /home/pi/libsonarEcho.so|mySetAlertFunc U ∇(P P P)'
⍝ Initialises the library
#.PiGpio.(version←gpioInitialise) ⍝ Returns the pigpio version number if OK, otherwise ¯1
:If #.PiGpio.version<0
'PIGPIO ERROR'⎕SIGNAL 711
:Else
version←'PIGPIO version #',⍕#.PiGpio.version
:End
- Code: Select all
{id}←Open_I2C add;dev;han;bo
⍝ Open an I2C devive on hex address <add>, returning a handle to the device
dev←#.hex2int add ⍝ Numeric address
bo←#.PiGpio.Devices∊dev ⍝ where device is in list
han←⍬
:If ∨/bo ⍝ Is the I2C device already open?
id←bo/#.PiGpio.Handles ⍝ handle of open device
:Else
han←#.PiGpio.i2cOpen 1 dev 0 ⍝ Open the device returning a handle (1←→bus number)
:If han≥0 ⍝ Check it opened OK
#.PiGpio.Devices,←dev ⍝ Add to the list
#.PiGpio.Handles,←han
id←han
:Else
'I2C OPEN ERROR'⎕SIGNAL 711
:End
:End
- Code: Select all
InitServos handle;mode;reg;buf;rc;val;restart;ai;sleep;allcall;och;outdrv;b2ui;shift;m1;m2
⍝ Initialise the frequency to drive the named <servos> on device with <handle>
⍝ Set the frequency to about 55 Hz
⍝
b2ui←{⎕UCS 80 ⎕DR ⍵} ⍝ Convert bit string to unsigneg int
shift←{⍵⌽¯8↑1} ⍝ shift by ⍵ 1<<⍵
m1←0 ⍝ _MODE1 = 0x00
m2←1 ⍝ _MODE2 = 0x01
⍝ At first, we call for initialize() method which restarts the device by
⍝ first setting the SLEEP_BIT to ‘0’ in MODE1 register
⍝ and then setting the RESTART_BIT to ‘1’ in the same register.
⍝ Also, it sets the AI_BIT to ‘1’ which allows to perform multi byte I2C operations for faster data transfer.Auto Increment
⍝ Bits in mode 1
restart←shift 7 ⍝ _RESTART=1<<7
ai←shift 5 ⍝ _AI=1<<5
ai=Auto Increment
sleep←shift 4 ⍝ _SLEEP=1<<4
allcall←shift 0 ⍝ _ALLCALL=1<<0
⍝ Bits in Mode 2
och←shift 3 ⍝ _OCH=1<<3
Outputs change on: STOP command (0) or on ACK (1)
outdrv←shift 2 ⍝ _OUTDRV=1<<2 The 16 LEDn outputs are configured with: an open-drain structure (0), a totem pole structure (1)
⍝ Reseting PCA9685 MODE1 (without SLEEP) and MODE2
val←b2ui ai∨allcall ⍝ self._AI | self._ALLCALL
rc←#.PiGpio.i2cWriteByteData handle m1 val ⍝ self._write_reg(self._MODE1, self._AI | self._ALLCALL)
val←b2ui och∨outdrv ⍝ self._OCH | self._OUTDRV
rc←#.PiGpio.i2cWriteByteData handle m2 val ⍝ self._write_reg(self._MODE2, self._OCH | self._OUTDRV)
⎕DL 0.005 ⍝# wait for oscillator
⍝ Read the current mode
mode←#.PiGpio.i2cReadByteData handle m1 ⍝ mode = self._read_reg(self._MODE1)
⍝ # wake up (reset sleep)
val←b2ui(11 ⎕DR mode)∧~sleep ⍝ mode & ~self._SLEEP
rc←#.PiGpio.i2cWriteByteData handle m1 val
⎕DL 0.005 ⍝# wait for oscillator
CancelServo handle ⍝ Switches all PWM channels off
⍝ handle ServoFreq 200 ⍝ self.set_frequency(200)
handle ServoFreq 50 ⍝ self.set_frequency(50)
- Code: Select all
CenterServos(shand centzero legzero leftup rightup)
⍝ Center all servos
⍝ Lift up left legs
MoveServos shand MiddleLegs leftup
⎕DL dl
⍝ Center left legs
MoveServos shand LeftLegs legzero
⍝ Lift up right legs
MoveServos shand MiddleLegs rightup
⎕DL dl
⍝ Center right legs
MoveServos shand RightLegs legzero
⎕DL dl
⍝ Center middle leg
MoveServos shand MiddleLegs centzero
⎕DL dl
- Code: Select all
MoveServos(handle channel pc);reg;steps;rc;on;off;min;max;range;mid;minl;maxl;percent;hi_on;low_on;hi_off;low_off;Check
⍝ Move <servo> to position (pc%) 0%=-90 50%=0 100%=+90
⍝ Channel←→0-15 or ¯1 for all
⍝ if pc -ve STOP the servo
⍝ Channel ←→0-15 or ¯1 for all
Check←{⍺←0 ⍝ ⍺ ←→ count retries
rc←⍺⍺ ⍵ ⍝ ⍺⍺←→#.PiGpio.i2cWriteByteData
rc=0:0 ⍝ if it worked return 0=OK
{}⎕DL 0.01 ⍝ it failed, wait a mo
count←1+⍺ ⍝ increment count
count=10:rc ⍝ exit if cont exceeded max
rc=-82:count(⍺⍺ ∇∇)⍵ ⍝ and re-try
rc}
min←2.5 ⍝ 50000÷19988.48 ⍝ minimum % for 500micro sec with pulse width 19988.48
max←12.5 ⍝ 250000÷19988.48 ⍝ maximum % for 2500micro sec with pulse width 19988.48
range←max-min
⍝ Calculate the required percentage
:If pc≤0 ⍝ if -ve Stop the servo
on←0
off←0
steps←0
:Else
percent←min+range×pc÷100
steps←⌊percent×4096÷100
:If steps>4095
on←4096
off←0
:Else
on←0
:Select steps
:CaseList ⍳81
off←82
:CaseList 81↓⍳490
off←steps
:CaseList 490↓4096
off←490
:Else
off←0
:End
:End
:End
:If channel=¯1
⍝ all channels _ALL_LED_ON_L = 0xFA 250
reg←hex2int'fa'
:Else
⍝_LED0_ON_L = 0x06
reg←6+4×channel
:End
hi_on low_on←256 256⊤on
hi_off low_off←256 256⊤off
rc←#.PiGpio.i2cWriteByteData Check handle(reg+0)(low_on)
rc←#.PiGpio.i2cWriteByteData Check handle(reg+1)(hi_on)
rc←#.PiGpio.i2cWriteByteData Check handle(reg+2)(low_off)
rc←#.PiGpio.i2cWriteByteData Check handle(reg+3)(hi_off)
:If rc<0
('I2C WRITE BYTE ERROR ',⍕rc)⎕SIGNAL 711
:End
- Code: Select all
Breast shand
⍝ Move forward using Breast stroke movement
MoveServos shand MiddleLegs leftup
⎕DL dl
MoveServos shand LeftLegs llegfor
⎕DL dl
MoveServos shand MiddleLegs rightup
⎕DL dl
MoveServos shand RightLegs rlegfor
⎕DL dl
MoveServos shand MiddleLegs centzero
⎕DL dl
MoveServos shand LeftLegs llegaft
MoveServos shand RightLegs rlegaft
⎕DL dl
- Code: Select all
CancelServo handle;reg;buf;rc
⍝ Switches all PWM channels off set_duty_cycle(-1, 0)
reg←hex2int'fa' ⍝ all channels _ALL_LED_ON_L = 0xFA 250
buf←⎕UCS 0 0 0 0 ⍝ on=0 off=0
rc←⊃PiGpio.i2cWriteI2CBlockData handle reg buf 4 ⍝ self.set_duty_cycle(-1, 0)
:If rc<0
('I2C WRITE BLOCK ERROR ',⍕rc)⎕SIGNAL 711
:End
- Code: Select all
handle ServoFreq freq;mode;val;restart;ai;sleep;allcall;och;outdrv;rc;b2ui;shift;ps;m1;m2;bits;mod;pulse_width;prescaleval
⍝ setFrequency() method is used to control the output frequency in Hz.
⍝ It calculates the prescale value based on the required frequency and writes it to the PRE_SCALE register.
⍝ freq←→ frequency in Hz Between 50 and 60 for servos
ps←hex2int'fe' ⍝ _PRESCALE = 0xFE 254 prescale register number
m1←0 ⍝ _MODE1 = 0x00
m2←1 ⍝ _MODE2 = 0x01
b2ui←{⎕UCS 80 ⎕DR ⍵} ⍝ Convert bit string to unsigneg int
shift←{⍵⌽¯8↑1} ⍝ shift by ⍵ 1<<⍵
⍝ Bits in mode 1
restart←shift 7 ⍝ _RESTART=1<<7
ai←shift 5 ⍝ _AI=1<<5
sleep←shift 4 ⍝ _SLEEP=1<<4
allcall←shift 0 ⍝ _ALLCALL=1<<0
⍝ Bits in Mode 2
och←shift 3 ⍝ _OCH=1<<3
Outputs change on: STOP command (0) or on ACK (1)
outdrv←shift 2 ⍝ _OUTDRV=1<<2 The 16 LEDn outputs are configured with: an open-drain structure (0), a totem pole structure (1)
⍝ "Sets the PWM frequency."
prescaleval←25000000 ⍝ prescaleval = 25000000.0 # 25MHz internal oscillator (requires no external components)
prescaleval÷←4096 ⍝ prescaleval /= 4096.0 # 12-bit
prescaleval÷←freq ⍝ prescaleval /= float(freq)
prescaleval-←1 ⍝ prescaleval -= 1.0 ⍝ Estimated pre-scale 121.0703125 @ 50hz
prescaleval←3⌈255⌊⌊0.5+prescaleval ⍝ as an int between 3 and 255
⍝ Read the current mode
mod←#.PiGpio.i2cReadByteData handle m1 ⍝ mode=self._read_reg(self._MODE1);
⍝ Go to sleep
⍝⍝// disable restart, sleep, set prescale and reset
⍝⍝ this->pBus->WriteRegisterByte(this->devAddress, MODE1, (mode & ~RESTART) | SLEEP);
⍝⍝ this->pBus->WriteRegisterByte(this->devAddress, PRESCALE, prescale);
⍝⍝ this->pBus->WriteRegisterByte(this->devAddress, MODE1, mode);
mode←11 ⎕DR mod
⍝⍝ bits←mode∧~sleep ⍝ mode & ~self._SLEEP
bits←mode∧~restart ⍝ mode & ~self._RESTART
val←b2ui bits∨sleep ⍝ (mode&~self._SLEEP)|self._SLEEP
rc←#.PiGpio.i2cWriteByteData handle m1 val ⍝ self._write_reg(self._MODE1,(mode&~self._SLEEP)|self._SLEEP)
⍝ Set prescaleval (can only be done while asleep)
rc←#.PiGpio.i2cWriteByteData handle ps prescaleval ⍝ self._write_reg(self._PRESCALE,prescale)
⍝ reset the mode
rc←#.PiGpio.i2cWriteByteData handle m1 mod ⍝ self._write_reg(self._MODE1,mode)
⎕DL 0.005 ⍝ time.sleep(0.0005)
⍝ Restart it
val←b2ui mode∨restart ⍝ mode|self._RESTART
rc←#.PiGpio.i2cWriteByteData handle m1 val ⍝ self._write_reg(self._MODE1,mode|self._RESTART)
⍝
freq←(25000000÷4096)÷(prescaleval+1) ⍝ self._frequency=(25000000/4096)/(prescale+1) freq←50.0288166 ⍕ 50
pulse_width←(1000000÷freq) ⍝ self._pulse_width=(1000000/self._frequency)
pw←19988.48
- Code: Select all
hex2int←{16⊥('0123456789abcde'⍳(819⌶)⍵)-⎕IO}
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
Many thanks. This is really helpful. If I get something going that is worth seeing,
you will be gratefully acknowledged.
you will be gratefully acknowledged.
- bwyork67
- Posts: 13
- Joined: Tue Nov 12, 2013 7:01 pm
Re: Accessing the RPi GPIO pins from APL
An update on this topic.
With the help of Peter Cyriax and others, I have now got the C Callback process working.
A small C callback routine that is triggered when the selected pin changes level, (set up via gpioSetAlertFunc), simply writes the GPIO pin number, Level, and clock tick, to a named pipe (a FIFO file) for each interrupt.
At the APL end within a child process thread, ⎕ARBIN runs in a loop reading the named pipe, adding a token to the token pool for each interrupt read. The value of the token is set to include the GPIO pin number, Level, and clock tick.
This allows other APL threads to access the data from the interrupt via the token pool.
Using this process, I have managed (albeit under a very light load on a RPi model 3) to read distances via a HC-SR04 ultrasonic distance sensor often with an accuracy of +/- 1 tick (+/- 1.7 mm).
I hope to update GITHUB with this over the next few weeks.
With the help of Peter Cyriax and others, I have now got the C Callback process working.
A small C callback routine that is triggered when the selected pin changes level, (set up via gpioSetAlertFunc), simply writes the GPIO pin number, Level, and clock tick, to a named pipe (a FIFO file) for each interrupt.
At the APL end within a child process thread, ⎕ARBIN runs in a loop reading the named pipe, adding a token to the token pool for each interrupt read. The value of the token is set to include the GPIO pin number, Level, and clock tick.
This allows other APL threads to access the data from the interrupt via the token pool.
Using this process, I have managed (albeit under a very light load on a RPi model 3) to read distances via a HC-SR04 ultrasonic distance sensor often with an accuracy of +/- 1 tick (+/- 1.7 mm).
I hope to update GITHUB with this over the next few weeks.
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
15 posts
• Page 2 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