how to write and read back GPIO pin states with lgpio
Aug 04, 2024 Last reply: 1 year ago 3 Replies
J
Josef Möllers
Hi,
I used to use the sysfs interface to the GPIO pins (/sys/class/gpio) but I understand that is deprecated nowadays. So I tried to switch to lgpio which looks OK. However, I have problems writing and reading back pin states from different programs.
My setup is as follows: I have a couple of relays (solid state and mechanical ones) that control various external devices. I use one program to switch devices on and off and want to use another program to read back the state of the device.
Doing that with sysfs is easy:
1) export the pin: echo $pin > /sys/class/gpio/export echo $direction > /sys/class/gpio/gpio$pin/direction this needs to be done only once.
2) write the state of the pin, thus switching the device on/off: echo $newstate > /sys/class/gpio/gpio$pin/value this is done every time this is required
3) read back the state of the pin value=$(</sys/class/gpio/gpio$pin/value this is done every time I want to check the state of the device
Now I switch a device on/off with lgpio as follows:
1) open the GPIO chip: h = lgGpiochipOpen(0);
2) claim the pin as an output: lgGpioClaimOutput(h, LG_SET_PULL_NONE, pin, value); which, to my understanding, already changes the pin's state?!?
3) write the new state lgGpioWrite(h, pin, value);
4) close the chip lgGpiochipClose(h);
Reading back the state of the pin requires me to
1) open the GPIO chip: h = lgGpiochipOpen(0);
2) claim the pin as an input: lgGpioClaimInput(h, LG_SET_PULL_NONE, pin);
3) read back the pin's state lgGpioRead(h, pin);
4) close the chip lgGpiochipClose(h);
However ... When I set the pin's state to "1", I still read back "0"!
What am I doing wrong? Thanks in advance for any pointers.
Josef
Didn't find your answer? Ask the community — no account required.
C
Computer Nerd Kev
Personally I switched to using the "gpio" command that's one of the example programs included with the bcm2835 library. If you're just trying to build C programs to replace the /sys/class/gpio devices in a shell script, it's an existing option. It does have some bugs though.
formatting link
See examples/gpio/gpio.c in the source code.
At a GUESS, you're reading the input buffer instead of the output buffer. In output mode the input is disabled and always reads zero or is meaningless.
Unfortunately I've forgotten whether this is the case with the Pi, or at least where to look to confirm I'm not mis-remembering, so check for yourself. But this is a common way for IO hardware to work.
T
The Natural Philosopher
TLDR
Here is my C code to drive 4 relays from a Pi Zero W Adpapted frim someone elses that also works It works:
/* relays.h
2023-04-30 Public Domain */ /* zone 1-4, command ON or OFF */ /* All clever stuff is done in relayio, any call to this * will initialise the hardware if it needs it. */
if (filp != NULL) { while (fgets(buf, sizeof(buf), filp) != NULL) { if (piModel == 0) { if (!strncasecmp("model name", buf, 10)) { if (strstr (buf, "ARMv6") != NULL) { piModel = 1; chars = 4; } else if (strstr (buf, "ARMv7") != NULL) { piModel = 2; chars = 6; } else if (strstr (buf, "ARMv8") != NULL) { piModel = 2; chars = 6; } } }
if (!strncasecmp("revision", buf, 8)) { if (sscanf(buf+strlen(buf)-(chars+1), "%x%c", &rev, &term) == 2) { if (term != '\n') rev = 0; } } } fclose(filp); } return rev; }
int gpioInitialise(void) { int fd; piRev = gpioHardwareRevision(); /* sets piModel and piRev */ fd = open("/dev/gpiomem", O_RDWR | O_SYNC) ; if (fd < 0) { fprintf(stderr, "failed to open /dev/gpiomem\n"); return -1; } gpioReg = (uint32_t *)mmap(NULL, 0xB4, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); close(fd); if (gpioReg == MAP_FAILED) { fprintf(stderr, "Bad, mmap failed\n"); return -1; } return 0; }
void initializeRelays() { if (gpioInitialise() < 0) return; gpioSetMode(RELAY1,PI_OUTPUT); gpioSetMode(RELAY2,PI_OUTPUT); gpioSetMode(RELAY3,PI_OUTPUT); gpioSetMode(RELAY4,PI_OUTPUT); initialized = 1; } void relay(int zone, int command) { int port; if(!initialized) initializeRelays(); switch (zone) { case 1: port=RELAY1; break; case 2: port=RELAY2; break; case 3: port=RELAY3; break; case 4: port=RELAY4; break; default: return; } gpioWrite(port, command); }
J
Josef Möllers
I'll have a look at that, thanks!
Well, the documentation
formatting link
says "This command will work for any claimed GPIO (even if a member of a group). For an output GPIO the value returned will be that last written to the GPIO." So, I was thinking that that would happen.
OK, that sounds logical ... at the hardware level. However, I read the documentation such that either it works eg like the ATMega port pins, where you can read back the state of an output pin, OR the kernel driver would keep a copy of the output state and return that upon a read OR the library function would do that, but shame on me I have not checked the latter myself.
Thanks anyway,
Josef
Join the Discussion
Have something to add? Share your thoughts — no account required.
Didn't find your answer?
Ask the community — no account required
Report Content
You are reporting this content to the moderators. They will look at it
ASAP.