Go Back   Home > Forums > >
Home Forums Rules Articles diyAudio Store Blogs Gallery Wiki Register Donations FAQ Calendar Search Today's Posts Mark Forums Read

PC Based Computer music servers, crossovers, and equalization

Adding GPIO functionality to a Linux desktop computer
Adding GPIO functionality to a Linux desktop computer
Please consider donating to help us continue to serve you.

Ads on/off / Custom Title / More PMs / More album space / Advanced printing & mass image saving
Reply
 
Thread Tools Search this Thread
Old 17th October 2018, 02:23 PM   #1
CharlieLaub is offline CharlieLaub  United States
diyAudio Member
 
Join Date: Mar 2007
Location: Michigan
Default Adding GPIO functionality to a Linux desktop computer

I have recently been using some low powered "CPU Onboard" (Intel) linux system in the mITX form factor for audio work. This hardware runs mainstream linux, which seems to provide much better OS and software reliability. Compared to systems like the Raspberry Pi and other SBCs there is more computing power on tap. What is sorely lacking, however, is GPIO functionality.

I like to build active DSP loudspeakers where the DSP is done on a small computer, in software. These systems are intended to be clients in a streaming audio system (software that I wrote) and can be turned on and off remotely. I would like to use GPIO that is triggered through user space as explained here:
Access GPIO from Linux user space
This approach is common on eg the Raspberry Pi, either done directly from the command line or through an application like WiringPi. The GPIO pin can, for example, be connected to a relay that toggles 12V connected to an amplifier's remote trigger input, or a relay could switch the AC mains itself. This would allow the system to be turned on and off remotely.

There are some USB GPIO boards available online, however, they are relatively expensive and use custom software (from the vendor) to operate. I finally found how to interface with a very inexpensive (<$5) Serial interface + GPIO board based on the CH341 IC and I finally got it up and running. I thought I would share my experience here in case anyone else is looking for this kind of solution.

Essentially I followed the info posted here by "Zoobab":
CH341 USB SPI I2C UART ISP dongle - .[ZooBaB].
Which refers to this linux kernel driver for the CH341:
GitHub - gschorcht/i2c-ch341-usb: A Linux kernel driver for ch341 emulating the I2C bus
I followed the instructions in the section "Installation of the driver" on a BayTrail (J1900) system having a fresh installation of Ubuntu 18.04. I plugged in the board and voila, 8 new GPIOs were now available to me through the operating system in the directory "/sys/class/gpio". Cool!

There was one problem: I needed to be superuser to toggle the GPIO pins. I realized that all the newly available GPIOs were owned by user "root". So I changed user to become root (via sudo su) and then changed the owner of each GPIO folder and the files within them to be owned by my regular user account. This eliminated the need to use sudo when toggling the value or changing the in/out pin mode.

Unfortunately, after I unplugged the Serial board and plugged it back in, the GPIOs were again created with root as the owner. I will need to figure out how to work around this, perhaps writing a udev rule that runs when the board is plugged in that will change the ownership. The board will always appear as a USB device with id "1a86:5512" so I should be able to launch a script off of that property upon plug-in. There is some info on the web about this that I have used to write custom scripts that run when an Arduino was plugged into the computer for another application. One good example is found here:
How to Write udev Rules for USB Devices
Other pages on this topic can be found here:
Tutorial on how to write basic udev rules in Linux - LinuxConfig.org
and here:
https://wiki.debian.org/udev

Here is a link to the boards I am using:
CH341 USB Programmer (USB, TTL, IIC, SPI, Printer, etc) - ElectroDragon
__________________
Visit my Audio Web Page <<--CLICK TO LEARN MORE-->> Get my LADSPA plugins

Last edited by CharlieLaub; 17th October 2018 at 02:56 PM.
  Reply With Quote
Old 17th October 2018, 02:52 PM   #2
CharlieLaub is offline CharlieLaub  United States
diyAudio Member
 
Join Date: Mar 2007
Location: Michigan
I was able to identify the USB Serial + GPIO board on my computer. It appears as a new device: /dev/gpiochip0. Using some udev tools I found:
Code:
charlie@BayTrail-2:/sys/class/gpio$ udevadm info --name=/dev/gpiochip0 --attribute-walk | grep 1a
    ATTRS{idVendor}=="1a86"
charlie@BayTrail-2:/sys/class/gpio$ udevadm info --name=/dev/gpiochip0 --attribute-walk | grep 5512
    ATTRS{idProduct}=="5512"
The attributes idVendor and idProduct will remain the same for all such boards from this vendor (Electrodragon). These will let me identify the board when it is plugged into the computer and, hopefully, change the owner of the GPIO pin directories and their contents so I do not need to toggle the pins as root or using sudo.
__________________
Visit my Audio Web Page <<--CLICK TO LEARN MORE-->> Get my LADSPA plugins
  Reply With Quote
Old 17th October 2018, 03:04 PM   #3
phofman is offline phofman  Czech Republic
diyAudio Member
 
Join Date: Apr 2005
Location: Pilsen
Very useful, thanks! Great thing about the Gunar's ch341 driver are the software interrupts - polling in a kernel thread is much more efficient than polling from user space.
  Reply With Quote
Old 17th October 2018, 11:46 PM   #4
CharlieLaub is offline CharlieLaub  United States
diyAudio Member
 
Join Date: Mar 2007
Location: Michigan
OK, based on my previous experience using udev and the info I found about the device via udev (see post #2 above) I came up with the following approach that allows a normal (non root) user to change the GPIO pin value (high/low) or set the direction (input/output) of the pin.

First, it is important to note that the code below will only work with the Electrodragon board that I linked to in post #1. The same approach will work for other boards but you will need to find out the unique attribute(s) to use in udev to identify the board when it is connected to the computer.

The solution consists of:
  • a udev rule that can identify the board and take action
  • a shell script that is called by udev when the board is plugged in
  • using chown in the shell script to change the owner of the value and direction files for the GPIOs associated with the Electrodragon board

UDEV RULE:
udev rules reside in the directory /etc/udev/rules.d (yes that is a directory). On my system with a clean Ubuntu install this directory was empty. Edit/create a new file by typing:
Code:
sudo nano /etc/udev/rules.d/z21_persistent-local.rules
If you do not like nano you can use vi, etc.
Now paste this code into the newly created file:
Code:
ACTION=="add" \
,ATTRS{idVendor}=="1a86" \
,ATTRS{idProduct}=="5512" \
,RUN+="/usr/local/bin/on_gpio_plugin.sh"
Save the file and exit.
This rule will execute the file "/usr/local/bin/on_gpio_plugin.sh" on the addition of a device with the listed vendor and product IDs. We will create this file next.

SHELL SCRIPT:
We will now create the script that makes the ownership changes. In a terminal window type:
Code:
sudo nano /usr/local/bin/on_gpio_plugin.sh
Then paste in the following script:
Code:
#!/bin/bash
#this script changes the ownership of the files 'value' and
#  'direction' within directories used to control GPIO pins
#  of an Electrodragon CH341 USB-to-Serial+GPIO board
#Substitue your own user name below for NEW_OWNER
#  then put the script in the directory /usr/local/bin/
#Call the script using a udev rule

NEW_OWNER=charlie

i=0
for f in /sys/class/gpio/gpio*; do
   if [[ $f =~ "gpio$i" ]]; then
      cd $f
      if [ -e value ]; then chown $NEW_OWNER value; fi
      if [ -e direction ]; then chown $NEW_OWNER direction; fi
      cd ..
      ((i++))
   fi
done
Next, change the value of the variable NEW_OWNER (on line 9) to your username, or the username of the user you would like to be able to use the GPIO pins. Save the file. Now you need to make this text file executable, so type:
Code:
sudo chmod +x /usr/local/bin/on_gpio_plugin.sh
With this change the shell script can be executed by the udev rule.

On my system there were no other GPIO pins, so the Electrodragon board GPIOs appeared as gpio0 through gpio7. You can check on your own system. GPIOs are exposed to userspace in the directory /sys/class/gpio, in which each GPIO pin appears as a directory named "gpioXXX" where XXX is a number starting with 0. The script will look through all the directories in /sys/class/gpio starting with gpioXXX=gpio0 and increasing XXX until all GPIOs present have their ownership changed to NEW_OWNER. If there were any other GPIOs present from other devices on the system, they will also have their ownership changed. This should not break anything.

In each gpioXXX directory, you will find some files and directories. Ignore the directories. The most pertinent files are "value" and "direction". The file "value" contains the current GPIO state, as a 0 (low) or 1 (high). The file "direction" should contain either the word "in" or "out" and sets whether the pin is configured as an output pin or an input pin. You should not write to the file "value" unless the direction is set to "out" ("out" was the default direction on my board as obtained from the MFG). When the direction is "in" you read the file instead to get the pin state.

USING THE ELECTRODRAGON BOARD GPIOs
With the udev rule and shell script in place, once the Electrodragon board is plugged in you can start using the GPIOs. It's always a good idea to set the direction first. Let's assume we want gpio0 to be an output. When logged in as the user you set for NEW_OWNER, type:
Code:
echo "out" > /sys/class/gpio/gpio0/direction
That's it!
Now let's set the pin high. Type:
Code:
echo 1 > /sys/class/gpio/gpio0/value
So easy!
Likewise, to set the pin low, type
Code:
echo 0 > /sys/class/gpio/gpio0/value
You can even blink an LED by putting these commands in a loop, like this:
Code:
#!/bin/bash
while :
do
   echo 0 > /sys/class/gpio/gpio1/value
   sleep 0.5
   echo 1 > /sys/class/gpio/gpio1/value
   sleep 1.5
done
Who doesn't want to blink an LED???

AUDIO USES:
So, this is a DIYaudio forum, so what are the audio uses? Answer: for triggering relays or signaling. The Electrodragon board can be set to 3.3V or 5V levels for GPIO. The current is limited to (guessing here) a couple of milliamps at best. So you will need a transistor and some other circuitry connected to a relay. You can buy these kinds of board on the web - they will have the appropriate interfacing circuitry. Then you can switch power on and off, do input switching, or anything you might come up with.
__________________
Visit my Audio Web Page <<--CLICK TO LEARN MORE-->> Get my LADSPA plugins
  Reply With Quote
Old 18th October 2018, 10:06 PM   #5
phofman is offline phofman  Czech Republic
diyAudio Member
 
Join Date: Apr 2005
Location: Pilsen
Actually I will need several GPIOs on x86 for controlling relays for automated calibration of Virtual balanced in/out from regular soundcard in linux - results in my Headless Amplifier Measurement Workstation

Another alternative to specialized driver/chip is using a regular arduino board with built-in USB-serial chip for 2USD Mini USB CH340 Nano 3.0 ATmega328P Controller Board Compatible For Arduino Nano CH340 USB Driver Nano V3.0 ATmega328-in Integrated Circuits from Electronic Components & Supplies on Aliexpress.com | Alibaba Group programmed with standard firmata firmware arduino/StandardFirmata.ino at master * firmata/arduino * GitHub . This will turn the arduino into a slaved device remotely controllable from the PC via standard firmata protocol. There are lots of firmata clients and libraries available Download - Firmata , my choice would be https://github.com/MrYsLab/PyMata , e.g. example https://github.com/MrYsLab/PyMata/bl...ymata_blink.py (outline):


Code:
BOARD_LED = 13
# Create a PyMata instance
board = PyMata("/dev/ttyUSB0", verbose=True)
# Set digital pin 13 to be an output port
board.set_pin_mode(BOARD_LED, board.OUTPUT, board.DIGITAL)
board.digital_write(BOARD_LED, 1)
# Wait a half second between toggles.
time.sleep(.5)
# Set the output to 0 = Low
board.digital_write(BOARD_LED, 0)
Apart of GPIOs all arduino features are available, such as reading analog inputs, controlling motors/steppers for turning analog volume controls (pots), reading encoders for manual digital volume control, etc.
  Reply With Quote
Old 18th October 2018, 10:53 PM   #6
CharlieLaub is offline CharlieLaub  United States
diyAudio Member
 
Join Date: Mar 2007
Location: Michigan
Yes, you can use an Arduino in a similar way and have all of its functionality available to you. I used an Arduino in this project:
Linux USB Preamp project
Using the arudino to interface with buttons and rotary encoders, and using udev to recognize it when it plugged in and launch a script to talk to it, I created a physical "control" interface for the computer, with code that could also launch DSP processing on my computer in response to control input by the user (e.g. changing "input" and volume settings of alsa controls).

I got it working and demoed it at a Burning Amp, but there wasn't much interest. I decided that a physical interface was not what I wanted to do, so I put it aside and worked more on my GSASysCon code, which can basically do the same thing via a software interface that I can access via WiFi from anywhere in my home.

I still have all the code on both sides (Linux on computer and Arduino code) that I could post or share. I learned a lot of neat stuff while developing the project. Like how to debounce buttons using a running average of the polled input state (works like a LP filter).

For my current needs the CH341 is better because it appears as a GPIO pin in the OS. Using it is very simple. For the Arduino I would need to create and call scripts to do stuff, and it's a little more involved and error prone. I will take a look at the Firmata stuff. That sounds interesting and might make using the Arduino more straightforward.
__________________
Visit my Audio Web Page <<--CLICK TO LEARN MORE-->> Get my LADSPA plugins

Last edited by CharlieLaub; 18th October 2018 at 11:04 PM.
  Reply With Quote
Old 19th October 2018, 05:51 AM   #7
phofman is offline phofman  Czech Republic
diyAudio Member
 
Join Date: Apr 2005
Location: Pilsen
I tried to find a simple command line firmata client to call from a script, unfortunately to no avail. That makes using CH341 definitely simplier.

My project is controlled by a python daemon where using firmata is just a single include of pymata. I actually enjoy I will not have to code arduino for this case, the standard firmata firmware is widely used and likely well tested.

Just note the sys gpio interface is slowly being replaced by the new /dev/gpiochip approach Learn More About Linux's New GPIO User Space Subsystem & Libgpiod , with current drivers in linux/drivers/gpio at master * torvalds/linux * GitHub . But it will take a while before that CH341 driver gets incompatible (unless converted to the new style).
  Reply With Quote
Old 19th October 2018, 01:19 PM   #8
CharlieLaub is offline CharlieLaub  United States
diyAudio Member
 
Join Date: Mar 2007
Location: Michigan
Quote:
Originally Posted by phofman View Post
Just note the sys gpio interface is slowly being replaced by the new /dev/gpiochip approach Learn More About Linux's New GPIO User Space Subsystem & Libgpiod , with current drivers in linux/drivers/gpio at master * torvalds/linux * GitHub . But it will take a while before that CH341 driver gets incompatible (unless converted to the new style).
Thanks for mentioning that! It seems like a positive development. Hopefully the old way will be available for a few more years.

On my system with kernel 4.15 the gpiod is not installed by default but can be if you want to try it.
__________________
Visit my Audio Web Page <<--CLICK TO LEARN MORE-->> Get my LADSPA plugins
  Reply With Quote
Old 1st November 2018, 09:54 PM   #9
CharlieLaub is offline CharlieLaub  United States
diyAudio Member
 
Join Date: Mar 2007
Location: Michigan
I was installing some software on another mini-ITX linux machine and I decided to add the USB-GPIO functionality. It didn't work! Whaaaa? Oops, I forgot to actually install the kernel module for the Electrodragon board (see post 1). Once I did that it worked perfectly. Nice!

So, for emphasis and since I sometimes refer back to these posts myself, here are the steps for getting this up and running:
  1. Buy one or more Electrodragon Serial+GPIO USB boards (they cost a mere $3 each!):
    Electrodragon CH341 USB Programmer (USB, TTL, IIC, SPI, Printer, etc)
  2. Install the kernel module for the CH341a by following the instructions under the heading "Installation of the driver" on this page:
    GitHub - gschorcht/i2c-ch341-usb: A Linux kernel driver for ch341 emulating the I2C bus
  3. Follow my instructions in post 4 for making the GPIO pin "value" and "direction" files accessible to non-root users (no need to use sudo after that!).

This makes is possible to combine a relay driver board, relays, and some mains AC sockets to switch external equipment on and off right from the command line. This was something I really missed from ARM-SBC platforms like the Raspberry Pi but I wanted access to more computing power and more mainstream kernel support that I have when using AMD/Intel CPUs in compact, fanless mITX systems.
__________________
Visit my Audio Web Page <<--CLICK TO LEARN MORE-->> Get my LADSPA plugins
  Reply With Quote
Old 1st December 2018, 05:11 AM   #10
booomerang is offline booomerang  United States
diyAudio Member
 
Join Date: Jan 2013
I bought an CH341A board hoping to replicate this USB gpio functionality. On my machine I could not see gpio files populated in /sys/class/gpio directory. Could you please look if my system is different from yours ? I pretty much followed the same instructions as you did.

Ubuntu 18.04

Code:
dev@dell:~/Desktop/i2c-ch341-usb$ sudo make install
cp i2c-ch341-usb.ko /lib/modules/4.15.0-34-generic/kernel/drivers/i2c/busses
depmod
dev@dell:~/Desktop/i2c-ch341-usb$ sudo insmod i2c-ch341-usb.ko
dev@dell:~/Desktop/i2c-ch341-usb$ ls /sys/class/gpio
export  unexport
dev@dell:~/Desktop/i2c-ch341-usb$ lsmod | grep ch341
i2c_ch341_usb          20480  0
ch341                  16384  1
usbserial              45056  3 ch341


Code:
[  618.489080] ch341 3-6:1.0: device disconnected
[  671.825717] usbcore: registered new interface driver i2c-ch341-usb
[  675.759731] usb 3-6: new full-speed USB device number 6 using xhci_hcd
[  675.908551] usb 3-6: New USB device found, idVendor=1a86, idProduct=5523
[  675.908558] usb 3-6: New USB device strings: Mfr=0, Product=0, SerialNumber=0
[  675.909357] ch341 3-6:1.0: ch341-uart converter detected
[  675.909906] usb 3-6: ch341-uart converter now attached to ttyUSB0
  Reply With Quote

Reply


Adding GPIO functionality to a Linux desktop computerHide this!Advertise here!
Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump

Similar Threads
Thread Thread Starter Forum Replies Last Post
Desktop computer speaker idea...cheap makingmoney Multi-Way 7 16th August 2012 04:31 AM
2.1 Computer/Desktop Speaker Design pirate121 Multi-Way 7 30th October 2010 03:15 AM
CMOY : built into desktop computer. jcouture Chip Amps 2 27th October 2010 06:02 PM
Desktop OB computer speakers merajsalek Multi-Way 64 8th April 2009 02:16 AM


New To Site? Need Help?

All times are GMT. The time now is 10:25 PM.


Search Engine Optimisation provided by DragonByte SEO (Pro) - vBulletin Mods & Addons Copyright © 2019 DragonByte Technologies Ltd.
Resources saved on this page: MySQL 15.00%
vBulletin Optimisation provided by vB Optimise (Pro) - vBulletin Mods & Addons Copyright © 2019 DragonByte Technologies Ltd.
Copyright ©1999-2019 diyAudio
Wiki