Toggling multiple GPIOS using from linux userspace - linux

I am writing application over linux embedded.
I have two leds that I can turn on and off using two different GPIO's pins.
I would like to sync them, by setting both GPIO pins at the same time.
This is doable since the GPIO HW has one register for output value, and each bit
represent one pin.
But I did not manage to find a way to do so without bypassing the kernel driver and writing into that register. This is not a healthy way to do this, and I want to do the same using the user space API.
Is there a way to export a number of pins and "bind" them somehow?

You can write a shell script to sync the GPIOs.. Here's an example of how I toggle a GPIO (say #13) from shell:-
echo 13 > export
root#apq8017:/sys/devices/virtual/gpio/gpio13# ls
active_low direction power subsystem uevent value
root#apq8017:/sys/devices/virtual/gpio/gpio13# cat direction value
out
1
root#apq8017:/sys/devices/virtual/gpio/gpio13# echo out > direction
root#apq8017:/sys/devices/virtual/gpio/gpio13# echo 0 > value
root#apq8017:/sys/devices/virtual/gpio/gpio13# cat direction value
out
0
root#apq8017:/sys/devices/virtual/gpio/gpio13#

Related

Beaglebone black GPIO registers not changing voltage on value change

I'm trying to turn on and off the GPIO headers on the beaglebone, but i'm unable to get the physical pins to switch from high to low and vice versa. Ive written some code within my application to do this but even when I change the values in the command line I have the same issues.
Firstly, all of the pins I want to use have been correctly exported. For this example lets focus on GPIO 117. I'm able to change into /sys/class/gpio/gpio117 and when I run cat value, its in line with what I expected from my program. When I run echo 0 > value it changes to a zero and when I run echo 1 > value its a 1. Everything as expected. When I go to measure the voltage on that pin, it is always high, independent of the value.
Am I missing something here?
GPIO 117 is gpio3_21 on the "MCSAP0_AHCLKX" pin. So it is probably used by some audio device, probably HDMI. You can disable that by adding disable_uboot_overlay_audio=1 to your /boot/uEnv.txt file, see https://elinux.org/Beagleboard:BeagleBoneBlack_Debian#U-Boot_Disable_on-board_devices

GPIO in IO expansion board for Edison from DFROBOT

I have been using Intel Edison Module for my project along with this IO expansion Board from DFRobot.
But I came across a problem when dealing with the GPIOs: the output level seems to be quite unstable compared with the Arduino-Compatible Board.
Here is what I did to use DIO7 as output for both IO borads (called X-board and Arduino-board):
According to this document, for the Arduino-borad, I first set an internal GPIO 255 to high so I can use GPIO48 (mapped to DIO7) as an output. Then I set GPIO 48 to high or low. Everything turns out OK.
echo 255 > /sys/class/gpio/export
echo 48> /sys/class/gpio/export
echo high > /sys/class/gpio/gpio255/direction
echo high or low > /sys/class/gpio/gpio48/direction
On the X-board, the procedure is quite straightforward. I set GPIO 48 to high or low directly.
echo 48> /sys/class/gpio/export
echo high or low > /sys/class/gpio/gpio48/direction
But when I monitor the voltage using an oscilloscope, the pin level on the Arduino-board is quite stable and fluctuates in a small range (10mV) while the one on X-board vibrates in 20MHz between 1-5V (sometimes 0-3V and sometimes stable), which is unacceptable.
I also try using mraa, but also no luck.
Does anybody know where is the problem or what have I missed? Any comment or suggestion will be appreciated.

Register address - change bit value of the second bit (bit index = 1) to 1

i am having the following register address: 0x18040028. Since I am pretty new to that stuff, how am I supposed to access that register address, change that one bit and then write it back (all other entries should stay the same)?
Do I need to write a program, or can I do it from the terminal ?
I am doing that on a linux (openwrt)
thanks
Option 1
On many linux builds you can access the GPIO pins directly using the sysfs. On openwrt in particular it is nearly always exposed.
on the openwrt device's terminal, see if this folder exists:
ls -Al /sys/class/gpio
If it is there, you usually need to export the specific GPIO pin you want to access. I looked at http://www.black-swift.ru/files/AR9331.pdf and can't figure it out. The problem is I don't think that particular pin on that register is exposed that way - at least I can't find it. I would have to be on that system digging around in the GPIO controller to have a chance to figure it out.
The UART pins you want to enable are exposed - GPIO9 (RX) and GPIO10 (TX). So maybe this info will be helpful regardless.
Option 2, below, is pretty much guaranteed to work; I found that after I had written this part.
Depending on your kernel version, you either use that GPIO # directly, or add in an offset.
Try:
cat /sys/class/gpio/gpiochip*/base | head -n1
If it returns a number, thats the offset. Take your GPIO #, add that offset (making up 200 as an example) and use that as your GPIO #.
Using whatever your GPIO number is (either with or without offset), enter the following (using 210 just as an example; 200 offset, GPIO10)
echo "210" > /sys/class/gpio/export
then the GPIO pin will exposed in this directory, again using 210 as example, /sys/class/gpio210/
There will be at least two files created after the export, /sys/class/gpio240/value and /sys/class/gpio240/direction You can interact with them using cat to read them, e.g. cat /sys/class/gpio240/value and modify it using echo: echo 1 > /sys/class/gpio240/value
There is a lot more info on accessing gpio via sysfs in the links I put at the bottom.
This will work easily if you find the right GPIO #, but if not (or even if you do), use:
Option 2
Someone has already done all the work. There are instructions on how to interface with this register to disable / enable the UART. It requires adding a package to your openwrt install called io, and they provide a script that toggles the value of the bit. You can modify that if you want to just echo out, always set it to a certain value, etc. It's written in bash.
You can add either the contents of the script or call the script itself from /etc/rc.local and it will get run at each boot; addressing that concern.
Since you already know you have the AR9331, you can cut out a lot of the script, e.g.:
#!/bin/bash -
# Bitwise operations: & = And, | = Or, ^ = xOr, << = Left Shift
func_addr="0x18040028"
func_value=0x`io -4 $func_addr | cut -f3 -d'
case_bit="1<<1"
# This is where you would make a change if you wanted to
# just set it to 1 every time.
# To always set it to a '1', change from xor ^ to or |; like this
# io -4 $func_addr $(printf "0x%8.8x" $(($func_value | $case_bit)))
# to always be 0 change the operator to and &, and use a mask
# with just bit 1 set to 0
mask32_b1="0xFFFFFFFD"
# io -4 $func_addr $(printf "0x%8.8x" $(($func_value $ $mask32_b1)))
# we using Bitwise xOr operation to switching bit# state (0 or 1)
io -4 $func_addr $(printf "0x%8.8x" $(($func_value ^ $case_bit)))
# read bit# state and depending on the state - print some info
if [ $(($func_value & $case_bit)) = $(($case_bit)) ]; then
echo "Hardware UART is turned OFF"
# You can use this line for automatic configuring GPIOs via sysfs
# or you can load other modules that use these GPIOs
else
echo "Hardware UART is turned ON"
fi
It could be a one liner(fairly ugly one):
io -4 "0x18040028" $(printf "0x%8.8x" $(("0x"$((io -4 "0x18040028" | cut -f3 -d )) ^ "0x2")))
Toggle uart_en on AR9331
I couldn't test any of this, so I could have made a mistake anywhere, but if you follow that guide, and make the modifications to always set to 1 that I put in there (commented out at the moment), then you should be good. Make sure you only leave in one option to modify that register.
Sources / more info:
OpenWrt Wiki
Working with GPIOs
Kernel.org
The quick and dirty way is to try and mmap the memory region out of /dev/mem. See these two questions:
Accessing hardware registers in Linux userspace
Accessing physical address from user space
However, I would not suggest you do this for a production system. What is cleaner would be to write a kernel driver. One option is write a regular kernel module that uses ioremap and ioread/iowrite operations, and exposes the registers via sysfs.
Using IO Memory
Sysfs Documentation
Another option that is particularly slick in my opinion, is to have these registers exposed through the platform_device system in your board support files.
Platform Devices
Basically you need to read the value, and then do:
readvalue |= 1<<1;
Then write the value back to the register.

Bash script to scan for iBeacons and use GPIO on Raspberry Pi

I followed a tutorial to illuminate an LED on a Raspberry Pi so that when an iBeacon detected an LED is turned on using the GPIO pins but I need to alter the script so that the LED goes off again when the iBeacon is no longer detected.
The script at the moment is:
#!/bin/bash
gpio mode 1 out
trap "gpio write 1 0" exit
while read line
do
if [[ `echo $line | grep "2F234454-CF6D-4A0F-ADF2-F4911BA9FFA6 1 1" ` ]]; then
gpio write 1 1
fi
done
Which is being called by:
$ beacon scan -b | ./scriptName
The out put of beacon scan is:
pi#pibeacon ~ $ sudo beacon scan
BLE Beacon Scan ...
iBeacon UUID: 92AB49BE-4127-42F4-B532-90FAF1E26491 MAJOR: 1 MINOR: 1 POWER: -59 RSSI: -62
iBeacon UUID: 92AB49BE-4127-42F4-B532-90FAF1E26491 MAJOR: 1 MINOR: 1 POWER: -59 RSSI: -65
iBeacon UUID: 92AB49BE-4127-42F4-B532-90FAF1E26491 MAJOR: 1 MINOR: 1 POWER: -59 RSSI: -65
Continuously updating all the time the iBeacon is detected and just stops when the iBeacon is undetected.
The aim is to have a script run all the time and use the output of the beacon scan command to determine if the LED should be on or off - if the iBeacon is detected the LED should be on and if the iBeacon is then moved out of range the LED turn off again. The existing strip turns the LED on once and then the only way to reset the situation is to stop the script and start it again.
Thanks
One way you could accomplish it with your existing code is to set a variable to a timestamp inside your if statement. Then, outside your if statement (but inside the while), you can compare the current time to the timestamp. If enough time has passed since the beacon was detected (say 5 seconds), you code can turn off the LED.
The disadvantage of this approach is that if no beacons are detected at all, your code will block on the read line statement. So this is only workable if you know for sure at least one beacon will always be around to keep your program running. This sort of programming is not ideally suited to a simple bash script, because you really need two threads to handle this. But if you want to keep your same basic toolset, this is a decent option.
I worked out a (bad?) solution and thought I'd share it here. It has the effect of when the beacon is detected the light flashes and then when the beacon goes out of range the light stops flashing. I set this code to run on startup of the Pi and has fulfilled the function I needed (a very rough proof of concept prototype!).
I used the very good Radius Networks Development Kit (which is where the original script is from) and would highly recommend that if anyone else is interested in messing about with iBeacons.
#!/bin/bash
gpio mode 1 out
trap "gpio write 1 0" exit
while read line
do
if [[ $line = *"2F234454-CF6D-4A0F-ADF2-F4911BA9FFA6 1 1"* ]]; then
gpio write 1 1
fi
gpio write 1 0
done

Beaglebone gpio input not working

I am using beaglebone to access digital input from specific pin using sysfs interface. And I can change the output states but not the input :(. What I did is, I have two pins pinA and pinB. pinA I made it output and pinB I made input. Connected pinA to pinB. Configured pinA as output pin by sending out to direction attribute in sysfs and pinB as input by passing in. And I changed value of PinA to 1 and it is giving 1 as output (I tested using LED). But when I read the value of PinB it is giving 0 only, even I pass 0 to value of pinA. what may be the reason ?
Thank you :)
As I understood, the steps you followed:
echo 7 > /sys/kernel/debug/omap_mux/gpmc_ad6
echo 38 > /sys/class/gpio/export
echo in > /sys/class/gpio/gpio38/direction
cat /sys/class/gpio/gpio38/value
I also did the same mistake and it took me hours, but the answer was simple: The first line starting with "echo 7" is the problem. Look at the muxing bits:
Bit 5: 1 - Input, 0 - Output
Bit 4: 1 - Pull up, 0 - Pull down
Bit 3: 1 - Pull disabled, 0 - Pull enabled
Bit 2 \
Bit 1 |- Mode
Bit 0 /
You were entering echo 7 which is --> 0 0 0111 and it means: bit 0,1 and 2 is 1, so the mode is set. No problem. However you just forgot to set whether it's an input or output. And it should be like this:
echo 0x27 > /sys/kernel/debug/omap_mux/gpmc_ad6
your bits are now: 1 0 0111 binary which is 0x27 (hex).
When you write "cat /sys/class/gpio/gpio38/value" while giving input, you can see a wonderful 1 :) I’m sure you will be very happy as much as I was :)
Also, one more thing, you are right for Analog input about 1.8V, but GPIO operates with 3.3v.
Several possible causes:
1) Did you set the IO direction of the input pin?
eg. echo "in" > /sys/class/gpio/gpioN/direction
2) (less likely) Is the GPIO pin you're using as an input multiplexed as a GPIO line and in the right direction? Most of the GPIO pins on the OMAP SoCs are multi-function. You're kernel might have set it for an alternate function.
You can check it with:
cat /sys/kernel/debug/omap_mux/board/core
Which dumps the configurations of all IO pins. The output looks like this:
OMAP4_MUX(CSI22_DY1, OMAP_PIN_INPUT | OMAP_MUX_MODE0),
/* gpio_81 */
OMAP4_MUX(CAM_SHUTTER, OMAP_PIN_OUTPUT | OMAP_MUX_MODE3),
OMAP4_MUX(CAM_STROBE, OMAP_PIN_OUTPUT | OMAP_MUX_MODE0),
/* gpio_83 */
In this case, CAM_SHUTTER is set an output, and routed as to the GPIO module (OMAP_MUX_MODE3)
[Caveat: this is from my OMAP4 board - without having the OMAP3 data sheet to hand - there will be a fair amount of similarity]
You can't change this through sysfs - instead you'll need to modify either your kernel (or possibly boot-loader if the kernel uses the configuration it set up).
In the board-file for your system - which I think in your case will be in <linux_source_root>/arch/arm/mach-omap2/board-omap3beagle.c - you'll find a initialiser for the MUX table. You will need the board's schematics, the kernel source tree and the SoC data sheet to get between the primary function name of the pin (in my example above CAM_SHUTTER) and a GPIO number.
3) I was a bit confused by even I pass 0 to value of pinA - I wonder whether you meant that? This does however point to another thing to watch for - there is the programmable pull-up or -down on each IO pin. These are set with the MUX settings. There may conceivably be an external one as well - again you'll need the schematics to be sure.
Yes. The internal pull up and down is configured in the same register as the mux-mode - so it might be that you can configure this in the same way you're setting the mux-mode. Get the AM335x TRM (for OMAP4 the chapter is called Control Module).
In terns of the kernel, look in <linux_source_root>/arch/arm/mach-omap2/mux.h where a bunch of macros are defined
As an example for use I have in my board file:
/* PIC -> OMAP4 interrupt line 2 - GPIO81 */
OMAP4_MUX(CAM_SHUTTER, OMAP_MUX_MODE3 | OMAP_PIN_INPUT_PULLUP),
and
OMAP4_MUX(GPMC_AD11, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLDOWN),
From memory you get a choice of either a pull-up or pull-down but can't select neither.

Resources