Sunday 28 August 2016

Raspberry Pi GPIO: Gambas + pigpio library

There are now a number of ways of controlling the Raspberry Pi general purpose I/O.


Libraries such as wiringPi and pigpio are written in the C programming language, but can also be used with other languages including Gambas.


I have covered wiringPi previously, and this short post is just a basic introduction to using the pigpio library with Gambas.

The pigpio library has dozens of functions enabling the Gambas programmer to interface and control simple serial comms, I2C, SPI and PWM, in addition to the basic digital inputs and outputs.

Download...


But before we can use this functionality, we need to download the source files and build the library.

Open a terminal on your Pi and type:-

wget abyz.co.uk/rpi/pigpio/pigpio.zip

Locate the pigpio.zip file in the file manager (pcmanfm) then right-click and Extract.

Open the extracted folder in file manager, then hit F4 to open a terminal (within this folder) and type:-

make -j4

Once completed, type:-

sudo make install

If there are no errors, this completes the installation.

Using the library in Gambas


Open Gambas and create a new project.

Add a button and two labels to the form.

In the Form class, declare the pigpio library:-

Library "/usr/local/lib/libpigpio"

Declare the initialise and terminate functions:-

Public Extern gpioInitialise() As Integer   'call at start of program to initialise
 

Public Extern gpioTerminate()    'call at end of program to release resources and terminate threads

Add functions to return library version and hardware revision details:-

Public Extern gpioVersion() As Integer
Public Extern gpioHardwareRevision() As Integer


Add digital I/O set mode, read and write functions:-

Public Extern gpioSetMode(iPin As Integer, iMode As Integer) As Integer
Public Extern gpioRead(iPin As Integer) As Integer
Public Extern gpioWrite(iPin As Integer, iLevel As Integer) As Integer


Declare mode constants:-

Const PI_INPUT As Integer = 0
Const PI_OUTPUT As Integer = 1


We need to initialise pigpio when our program starts...

Public Sub Form_Open()
Dim intReply As Integer

  intReply = gpioInitialise()
  If intReply < 0 Then
    Label1.Text = "Failed: must be run as root"
    Button1.Enabled = False
  Else
    Label1.Text = "Initialised: pigpio version no: " & intReply
    Me.Text = "Pi hardware rev: " & Hex$(gpioHardwareRevision())
    Me.Text &= ",  pigpio vers: " & gpioVersion()
    Me.Tag = 0
  Endif
 
End


...and terminate properly when the program stops...

Public Sub Form_Close()
 
  gpioTerminate()
 
End


Now we can use the button click event to write values to the output pins and read them back:-

Public Sub Button1_Click()
'write then read digital IO
Dim intPin As Integer
Dim intMode As Integer
Dim intLevel As Integer
Dim intOut As Integer
 
  Label2.Text = ""
  If Me.tag = 0 Then
    Me.Tag = 1
  Else
    Me.Tag = 0
  Endif
  intOut = Me.Tag     'alter 1's & 0's sequence each time button pressed
  For intPin = 0 To 31
    intMode = gpioSetMode(intPin, PI_OUTPUT)
    If intOut = 0 Then      'alternate 1's and 0's outputs
      intOut = 1
    Else
      intOut = 0 
    Endif
    gpioWrite(intPin, intOut)
    intLevel = gpioRead(intPin)
    Label2.Text &= intLevel & ", "
  Next

End


Now try to run the project in the Gambas IDE. It will probably report:-

"Failed: must be run as root"

...because you are not running as root. So close Gambas and restart by opening a terminal and typing:-

gksu gambas3

Hopefully, the program will now run properly.




Conclusion


In this basic example I've illustrated how to reference the pigpio library, and declare & implement a few simple library functions. Please refer to the pigpio website for a full list of functions.

At first glance, the pigpio library has more functionality and is easier to use than wiringPi.



20 comments:

  1. Hi, This code works well. I have looked around for advice on what condition is best state to leave the GPIO pins at the end of a program but I can't seem to find any definitive answer. Most of the pins are left 'Open' when this program exits, If you run my GPIO program next to yours you will see what I mean. Is this ideal?

    ReplyDelete
    Replies
    1. Hi Cogier, not sure I understand the question, but if you are asking what state the gpio should be returned to after use by a program like yours (i.e. not a program that runs as a gpio controller the whole time the system is powered-up) then there may be 2 sensible options; 1) return gpio to state it was in before your program started, 2) set all pins as inputs (which may be the safest and more practical option).

      A third alternative is not to worry about it. If a second (different design) gpio program is started after yours is closed, the second program will intialise pins to suit its own purpose.

      Here are a couple of threads which discuss what happens (and what should happen) to the gpio when the Pi starts: https://www.raspberrypi.org/forums/viewtopic.php?f=29&t=47965 ...and... https://www.raspberrypi.org/forums/viewtopic.php?f=44&t=24491

      Not sure this is very helpful, but do come back if I've missed the point.

      Delete
    2. Hi SteveDee, Here is what I was trying to explain.

      http://www.cogier.com/stevedee/

      Delete
    3. Hi Cogier,
      OK, that makes sense, my test program has set all pins as outputs, and that's how they stay after the program ends.

      I notice that the pigpio library has a gpioGetMode method, so it looks like we could read & store the pin modes, and then set them back to their initial settings at the end of the program...I'll try this when I get a moment.

      Delete
    4. Have another look at the same link above. I have added a few lines of code that will fix this.

      Delete
    5. Yes, that should do it.

      I just checked one of my Pi boards (a Pi3 with up-to-date software) and it seems to default all pins to inputs each time it is re-booted. Although I don't think all previous versions have worked this way.

      Delete
    6. This is not the correct place for this but I could not find a private email contact. Due to the loss of Gambas Guru I thought I would try my hand at this forum lark so check out
      www.gambas.cogier.com
      It's all new to me but I am having a go!

      Delete
  2. Hi, I'm using Gambas 3.9.2 under raspbian jessie kernel 4.4. My prog is getting -1 from gpioInitialise(), both with executable and under IDE. I carefully followed installation steps in abyz.co.uk "Download & Install" Method-1. After failing with this, I tried to follow your steps up here but "make -j4" gives me "make: Nothing to be done for 'all'.". This command was run in a terminal while being in the /Home/pi/PIGPIO folder. By the way, gpioVersion() is giving 61. Thanks for you help.

    ReplyDelete
    Replies
    1. Hi, sorry that you are having problems with this.

      I have just set up a Pi3 to my instructions above.

      If I run Gambas as user Pi, then I get the same result as you (i.e. gpioVersion = 61, but gpioInitialise returns -1).

      If I then close Gambas, then open a terminal and type: gksu gambas3
      ...I can run the program OK (...and gpioInitialise also returns 61).

      So are you running Gambas as root using these instructions?

      NOTE: I'm using Gambas 3.5.4 on Pi

      NOTE: The first time I tried to run as root my Pi3 hung. This is because I seem to be suffering some sort of file permission problem which is unrelated to Gambas or pigpio (I think there may be a bug in a recent version of Raspbian). So just check that you can use the file manager to view folders in the root directory. If the system shows an hour-glass and hangs, then you have the same problem, and will need to fix using fsck (http://captainbodgit.blogspot.co.uk/2017/01/file-system-repair-forcing-fsck-on.html).

      Delete
  3. Right! Running gambas as root now all goes well. I really appreciate your help Steve, thank you very much. I'll try to run Pi3 as root.

    ReplyDelete
    Replies
    1. Great stuff! But I don't recommend you run the Pi3 as user "root".

      You can run your Gambas executable from the terminal like this: sudo /home/pi/your_exe.gambas
      ...obviously using your path and file name, but including the .gambas extention. Or if you open terminal at the required folder: sudo ./your_exe.gambas.

      To run your pigpio application as user Pi, you could edit the /etc/sudoers file to give user Pi the required permissions.

      Or you could use wiringPi instead of pigpio, as this can now be used without admin/root permissions.

      Delete
    2. I'll give PI permissions. Than you again.

      Delete
  4. Hi steve. My raspberry OS is jessie. I use gambas 3.9.2. I have a problem when I want run as root gambas3. I use sudo gambas3 in terminal for root gambas. But when I enter this program, the comment is client is not authorized to connect to server gambas3: cannot connect to X server :1.0. Can you resolved for this problem? thank you

    ReplyDelete
    Replies
    1. Hi Terry, it sounds like you are trying to start Gambas from the command line without running the Raspbian desktop GUI (X server), or maybe trying to remote connect to the Pi via SSH.

      Can you confirm how you are running your Pi and whether you can run gambas as user Pi - i.e. does it work if you just type "gambas3" into a terminal window while running the desktop?

      Delete
  5. Hi, I really don't want to run gambas apps as root, Can I run the initialize portion as a root gambas app at startup.
    Then run the rest of my gambas apps as normal user io commands as they don't seem to require root after initialization
    Then run the terminate as a separate root gambas app?
    thanks

    ReplyDelete
    Replies
    1. Try adding your user as a member of the gpio group. If user is "pi" then type in a terminal the command:-

      sudo adduser pi gpio

      If this does not work then see the question above from JaimeDrn. I'd probably either modify 'sudoers' so that only my program would run as root (i.e. you would type sudo {program} but not have to supply a password) or use wiringPi instead.

      Delete
  6. I am attempting to get an ADS1115 A/D chip working on the I2C port. I'm reading the pigpio page cover to cover but I'm missing something with the HANDLE. I have the following defined in the header of my program...

    Public Extern i2cOpen(i2cBus As Integer, i2cAddress As Integer, i2cFlags As Integer)
    Public Extern i2cClose(Handle As Integer)
    Public Extern i2cWriteByte(i2cBus As Integer, i2cByte As Byte)
    Public Extern i2cReadByte(i2cBus As Integer)
    Public Extern i2cWriteWordData(i2cBus As Integer, i2cReg As Integer, i2cWord As Integer)
    Public Extern i2cReadWordData(i2cBus As Integer, i2cReg As Integer)

    This is below all the GPIO statements which are working just dandy thank you very much!

    Anyway... I made a button with the attached code... presuming the ADS1115 is addressed as HEX &48 or decimal 72...

    Public Sub BTN_12c_Test_A_Click()
    Print "Open"
    i2cOpen(0, 72, 0)
    Print "Close"
    i2cClose(0)
    Print "Done."
    End

    It opens fine, or at least there is no error showing. When it hits the i2cClose(0) command however... it fails with a BAD HANDLE(0)

    I thought, Ok... maybe this is the first device, so I tried i2cClose(0) which also fails.

    I am obviously missing the point on how to read/interact with a handle.
    Can you help me out? All the SERVO, GPIO IN/OUT, and PWM are fine... I just can't seem to get around HANDLE.

    Thanks,
    Jerry

    ReplyDelete
    Replies
    1. Hi Jerry, you seem to be ignoring "Return" values from some or all of the pigpio commands that you are using. For example the Open command should be declared as:-
      Public Extern i2cOpen(i2cBus As Integer, i2cAddress As Integer, i2cFlags As Integer) As Integer

      Then in the code:-
      Dim intHandle as Integer
      ...
      intHandle = i2cOpen(0, 72, 0)
      ...
      i2cClose(intHandle)

      I think that should work, but if not come back to me.

      You can also ask questions on https://forum.gambas.one where it may be easier to give longer code answers than in the small Comments section here.

      Delete
    2. You are correct... I had the "As Integer" on the other commands, totally missed it on this one. I installed that iand now I get the OPEN and CLOSE print commands with no bad handles.

      Thank you for that. I found another video explaining how to set the register bits to write (setup) then read an answer... hopefully I now have enough data to get this chip to read a sensor.

      Thank you very much!
      Jerry

      Delete
  7. First up... after reading this blog and related info more carefully... I discovered that the i2cBus -> MUST <- be 1 (not 0) for it to work in a Raspberry Pi... and after changing the code to be...

    Public Sub BTN_12c_Test_A_Click()
    Print "Open"
    i2cOpen(1, 72, 0)
    Print "Close"
    i2cClose(1)
    Print "Done."
    End

    It oddly gives an error the first time, but subsequently... runs just fine, Now I need to figure out the proper buffers, registers, and so forth... then program it to make a TEXTBOX or PRINT to show the value returned on a button click. When I get that... I'll put it in a TIMER function and finally be able to read my wind-speed indicator. (Pitot Tube - https://en.wikipedia.org/wiki/Pitot_tube)

    ReplyDelete