Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add optional libgpiod support to linuxgpio #1299

Merged
merged 7 commits into from
Mar 21, 2023

Conversation

SebKuzminsky
Copy link
Contributor

@SebKuzminsky SebKuzminsky commented Feb 1, 2023

This PR updates the linuxgpio backend to try both the old sysfs interface and the new (since Linux 4.8, so not that new) libgpiod interface.

  • If libgpiod is not available at build time, it builds only the old sysfs support.
  • If libgpiod is available at build time, the linuxgpio driver will support both sysfs and libgpiod.
  • At runtime, linuxgpio will try the libgpiod interface first, and fall back to sysfs if it doesnt work.

I tested this on a Raspberry Pi 4 (running Debian Bookworm arm64), flashing a little attiny2313. I used the same config file that works on an older system with the sysfs interface.

Fixes #831.

@SebKuzminsky
Copy link
Contributor Author

Oops, I left some debug prints in there, let me clean that up real quick...

@SebKuzminsky
Copy link
Contributor Author

Ok, now it's ready for review.

@mcuee mcuee added the enhancement New feature or request label Feb 1, 2023
@mcuee
Copy link
Collaborator

mcuee commented Feb 1, 2023

This is wonderful. I will carry out some tests soon on my Raspberry Pi 400.

@mcuee mcuee added this to the AVRDUDE 7.2 milestone Feb 2, 2023
@mcuee
Copy link
Collaborator

mcuee commented Feb 2, 2023

@SebKuzminsky

First issue is how to specify the port?

(avrdude.conf linuxgpio contents)
programmer
    id                   = "linuxgpio";
    desc                 = "Use the Linux sysfs interface to bitbang GPIO lines";
    type                 = "linuxgpio";
    prog_modes           = PM_ISP;
    reset                = 25;
    sck                  = 11;
    sdo                  = 10;
    sdi                  = 9;
;

pi@raspberrypi:~/build/avr/avrdude_bin $ gpiodetect
gpiochip0 [pinctrl-bcm2711] (58 lines)
gpiochip1 [raspberrypi-exp-gpio] (8 lines)

pi@raspberrypi:~/build/avr/avrdude_bin $ ./avrdude_pr1299 -c linuxgpio -P gpiochip0 -p m328p -v

avrdude_pr1299: Version 7.1-20230129 (6d95b15)
                Copyright the AVRDUDE authors;
                see https://github.com/avrdudes/avrdude/blob/main/AUTHORS

                System wide configuration file is /home/pi/build/avr/avrdude_bin/avrdude.conf
                User configuration file is /home/pi/.avrduderc
                User configuration file does not exist or is not a regular file, skipping

using libgpiod for linuxgpio
                Using Port                    : gpiochip0
                Using Programmer              : linuxgpio
failed to open GPIO11: No such file or directory
avrdude_pr1299 main() error: unable to open programmer linuxgpio on port gpiochip0

avrdude_pr1299 done.  Thank you.

pi@raspberrypi:~/build/avr/avrdude_bin $ lsb_release -a
No LSB modules are available.
Distributor ID:	Raspbian
Description:	Raspbian GNU/Linux 11 (bullseye)
Release:	11
Codename:	bullseye

git main works fine.

pi@raspberrypi:~/build/avr/avrdude_bin $ ./avrdude -c linuxgpio -P GPIO -p m328p -v

avrdude: Version 7.1-20230131 (dd7b359)
         Copyright the AVRDUDE authors;
         see https://github.com/avrdudes/avrdude/blob/main/AUTHORS

         System wide configuration file is /home/pi/build/avr/avrdude_bin/avrdude.conf
         User configuration file is /home/pi/.avrduderc
         User configuration file does not exist or is not a regular file, skipping

         Using Port                    : GPIO
         Using Programmer              : linuxgpio
         AVR Part                      : ATmega328P
         Chip Erase delay              : 9000 us
         PAGEL                         : PD7
         BS2                           : PC2
         RESET disposition             : possible i/o
         RETRY pulse                   : SCK
         Serial program mode           : yes
         Parallel program mode         : yes
         Timeout                       : 200
         StabDelay                     : 100
         CmdexeDelay                   : 25
         SyncLoops                     : 32
         PollIndex                     : 3
         PollValue                     : 0x53
         Memory Detail                 :

                                           Block Poll               Page                       Polled
           Memory Type Alias    Mode Delay Size  Indx Paged  Size   Size #Pages MinW  MaxW   ReadBack
           ----------- -------- ---- ----- ----- ---- ------ ------ ---- ------ ----- ----- ---------
           eeprom                 65    20     4    0 no       1024    4      0  3600  3600 0x00 0x00
           flash                  65    10   128    0 yes     32768  128    256  4500  4500 0x00 0x00
           lfuse                   0     0     0    0 no          1    1      0  4500  4500 0x00 0x00
           hfuse                   0     0     0    0 no          1    1      0  4500  4500 0x00 0x00
           efuse                   0     0     0    0 no          1    1      0  4500  4500 0x00 0x00
           lock                    0     0     0    0 no          1    1      0  4500  4500 0x00 0x00
           signature               0     0     0    0 no          3    1      0     0     0 0x00 0x00
           calibration             0     0     0    0 no          1    1      0     0     0 0x00 0x00

         Programmer Type : linuxgpio
         Description     : Use the Linux sysfs interface to bitbang GPIO lines
         Pin assignment  : /sys/class/gpio/gpio{n}
           RESET   =  25
           SCK     =  11
           SDO     =  10
           SDI     =  9

avrdude: AVR device initialized and ready to accept instructions
avrdude: device signature = 0x1e950f (probably m328p)

avrdude done.  Thank you.


@sebastiankuzminsky
Copy link

Hmm, thanks for testing, I appreciate the extra eyeballs on this. I'll check it out and get back to you.

@SebKuzminsky
Copy link
Contributor Author

SebKuzminsky commented Feb 2, 2023

This PR currently uses gpiod_line_find() to find the gpio line by its "name", assigned by gpiod:

$  sudo gpioinfo gpiochip0
gpiochip0 - 58 lines:
        line   0:     "ID_SDA"       unused   input  active-high
        line   1:     "ID_SCL"       unused   input  active-high
        line   2:       "SDA1"       unused   input  active-high
        line   3:       "SCL1"       unused   input  active-high
        line   4:  "GPIO_GCLK"       unused   input  active-high
        line   5:      "GPIO5"       unused   input  active-high 
        line   6:      "GPIO6"       unused   input  active-high 
        line   7:  "SPI_CE1_N"       unused   input  active-high 
        line   8:  "SPI_CE0_N"       unused   input  active-high 
        line   9:   "SPI_MISO"       unused   input  active-high 
        line  10:   "SPI_MOSI"       unused   input  active-high 
        line  11:   "SPI_SCLK"       unused   input  active-high 
        line  12:     "GPIO12"       unused   input  active-high 
        line  13:     "GPIO13"       unused   input  active-high 
        line  14:       "TXD1"       unused   input  active-high 
        line  15:       "RXD1"       unused   input  active-high 
        line  16:     "GPIO16"       unused   input  active-high 
        line  17:     "GPIO17"       unused   input  active-high 
        line  18:     "GPIO18"       unused   input  active-high 
        line  19:     "GPIO19"       unused   input  active-high 
        line  20:     "GPIO20"       unused   input  active-high 
        line  21:     "GPIO21"       unused   input  active-high 
        line  22:     "GPIO22"       unused   input  active-high 
        line  23:     "GPIO23"       unused   input  active-high 
        line  24:     "GPIO24"       unused   input  active-high 
        line  25:     "GPIO25"       unused   input  active-high 
        line  26:     "GPIO26"       unused   input  active-high 
        line  27:     "GPIO27"       unused   input  active-high 
        line  28: "RGMII_MDIO"       unused   input  active-high 
        line  29:  "RGMIO_MDC"       unused   input  active-high 
        line  30:       "CTS0"       unused   input  active-high 
        line  31:       "RTS0"       unused   input  active-high 
        line  32:       "TXD0"       unused   input  active-high 
        line  33:       "RXD0"       unused   input  active-high 
        line  34:    "SD1_CLK"       unused   input  active-high 
        line  35:    "SD1_CMD"       unused   input  active-high 
        line  36:  "SD1_DATA0"       unused   input  active-high 
        line  37:  "SD1_DATA1"       unused   input  active-high 
        line  38:  "SD1_DATA2"       unused   input  active-high 
        line  39:  "SD1_DATA3"       unused   input  active-high 
        line  40:  "PWM0_MISO"       unused   input  active-high 
        line  41:  "PWM1_MOSI"       unused   input  active-high
        line  42: "STATUS_LED_G_CLK" "ACT" output active-high [used]
        line  43: "SPIFLASH_CE_N" unused input active-high
        line  44:       "SDA0"       unused   input  active-high
        line  45:       "SCL0"       unused   input  active-high
        line  46: "RGMII_RXCLK" unused input active-high
        line  47: "RGMII_RXCTL" unused input active-high
        line  48: "RGMII_RXD0"       unused   input  active-high
        line  49: "RGMII_RXD1"       unused   input  active-high
        line  50: "RGMII_RXD2"       unused   input  active-high
        line  51: "RGMII_RXD3"       unused   input  active-high
        line  52: "RGMII_TXCLK" unused input active-high
        line  53: "RGMII_TXCTL" unused input active-high
        line  54: "RGMII_TXD0"       unused   input  active-high
        line  55: "RGMII_TXD1"       unused   input  active-high
        line  56: "RGMII_TXD2"       unused   input  active-high
        line  57: "RGMII_TXD3"       unused   input  active-high

The PR constructs this name by appending the pin number to the string "GPIO", like this: https://github.com/SebKuzminsky/avrdude/blob/6d95b150352622edb1046ce2dc2e2d385a0c5bfd/src/linuxgpio.c#L385-L391.

In your example you asked for gpio line 11, which is not named "GPIO11", it's named "SPI_SCLK", so it's not found.

In my testing i limited my gpio usage to the ones named "GPIO-something".

One effect of this technique that I like is that gpiod_line_find() will search all gpiochips, so no port is needed.

But I see now the shortcoming that you pointed out - only pins named "GPIO-something" can be used, and there are many pins with other kinds of names. I'll update the PR to accept a gpiochip as the port and the line number (not name) as the gpio identifier on that gpiochip.

@SebKuzminsky
Copy link
Contributor Author

See if this works better for you, @mcuee.

@mcuee
Copy link
Collaborator

mcuee commented Feb 4, 2023

@SebKuzminsky

Great. Now it works nicely. Tested under Raspberry Pi 400 running 32bit Raspberry Pi OS.

pi@raspberrypi:~/build/avr/avrdude_bin $ lsb_release -a
No LSB modules are available.
Distributor ID:	Raspbian
Description:	Raspbian GNU/Linux 11 (bullseye)
Release:	11
Codename:	bullseye

pi@raspberrypi:~/build/avr/avrdude_bin $ uname -a
Linux raspberrypi 5.15.76-v7l+ #1597 SMP Fri Nov 4 12:14:58 GMT 2022 armv7l GNU/Linux

pi@raspberrypi:~/build/avr/avrdude_bin $ ./avrdude_pr1299v1 -c linuxgpio -P gpiochip0 -p m328p
 -U flash:r:m328p_read.hex:i -v

avrdude_pr1299v1: Version 7.1-20230202 (c0ed9d9)
                  Copyright the AVRDUDE authors;
                  see https://github.com/avrdudes/avrdude/blob/main/AUTHORS

                  System wide configuration file is /home/pi/build/avr/avrdude_bin/avrdude.conf
                  User configuration file is /home/pi/.avrduderc
                  User configuration file does not exist or is not a regular file, skipping

using libgpiod for linuxgpio
                  Using Port                    : gpiochip0
                  Using Programmer              : linuxgpio
                  AVR Part                      : ATmega328P
                  Chip Erase delay              : 9000 us
                  PAGEL                         : PD7
                  BS2                           : PC2
                  RESET disposition             : possible i/o
                  RETRY pulse                   : SCK
                  Serial program mode           : yes
                  Parallel program mode         : yes
                  Timeout                       : 200
                  StabDelay                     : 100
                  CmdexeDelay                   : 25
                  SyncLoops                     : 32
                  PollIndex                     : 3
                  PollValue                     : 0x53
                  Memory Detail                 :

                                                    Block Poll               Page                       Polled
                    Memory Type Alias    Mode Delay Size  Indx Paged  Size   Size #Pages MinW  MaxW   ReadBack
                    ----------- -------- ---- ----- ----- ---- ------ ------ ---- ------ ----- ----- ---------
                    eeprom                 65    20     4    0 no       1024    4      0  3600  3600 0x00 0x00
                    flash                  65    10   128    0 yes     32768  128    256  4500  4500 0x00 0x00
                    lfuse                   0     0     0    0 no          1    1      0  4500  4500 0x00 0x00
                    hfuse                   0     0     0    0 no          1    1      0  4500  4500 0x00 0x00
                    efuse                   0     0     0    0 no          1    1      0  4500  4500 0x00 0x00
                    lock                    0     0     0    0 no          1    1      0  4500  4500 0x00 0x00
                    signature               0     0     0    0 no          3    1      0     0     0 0x00 0x00
                    calibration             0     0     0    0 no          1    1      0     0     0 0x00 0x00

                  Programmer Type : linuxgpio
                  Description     : Use the Linux sysfs interface to bitbang GPIO lines
Pin assignment  : libgpiod
                    RESET   =  25
                    SCK     =  11
                    SDO     =  10
                    SDI     =  9

avrdude_pr1299v1: AVR device initialized and ready to accept instructions
avrdude_pr1299v1: device signature = 0x1e950f (probably m328p)
avrdude_pr1299v1: reading flash memory ...

Reading | ################################################## | 100% 4.86 s 

avrdude_pr1299v1: writing output file m328p_read.hex

avrdude_pr1299v1 done.  Thank you.

@mcuee
Copy link
Collaborator

mcuee commented Feb 4, 2023

@MCUdude

Please take a look at this PR to see if it works for you or not when you have the time. Thanks.

@mcuee mcuee mentioned this pull request Feb 4, 2023
@SebKuzminsky
Copy link
Contributor Author

Based on some of the issues reported around libgpiod, I'm happy to see that if I hit Ctrl-C while avrdude is running, it frees the gpio lines (though it does not restore the outputs to inputs).

@stefanrueger
Copy link
Collaborator

stefanrueger commented Mar 2, 2023

@sebastiankuzminsky Thanks for contributing! I have had a quick glance over the code and it looks competently written.

I don't know much about either of the two interfaces, nor their relative merits. I take it that the gpio sysfs interface is being deprecated, which makes the port to libgpiod desirable. The PR makes libgpiod available when the library exists and works and in this case that supersedes sysfs.

@sebastiankuzminsky What is the rationale to keep sysfs? If that actually has been deprecated on a system, could that then mean that avrdude won't compile/work (haven't looked into whether anything else is used over and above file system calls for gpio through sysfs). Might a user still want to work with the old interface? In which case might it be better to have an independent route to using libgpiod? I don't have an opinion on either, but just wanted to make sure these questions have been asked.

Planning to do a mergefest in the next few days, so would be good if @mcuee and/or @MCUdude could have a final look before including into the list of PRs to merge.

@SebKuzminsky
Copy link
Contributor Author

Hi @stefanrueger, thanks for the comments.

What is the rationale to keep sysfs? If that actually has been deprecated on a system, could that then mean that avrdude won't compile/work (haven't looked into whether anything else is used over and above file system calls for gpio through sysfs). Might a user still want to work with the old interface? In which case might it be better to have an independent route to using libgpiod? I don't have an opinion on either, but just wanted to make sure these questions have been asked.

The argument for leaving sysfs support in is so that avrdude will work on old kernels that don't have the newer gpiod interface.

avrdude does not need anything beyond normal Posix filesystem stuff to use the old sysfs gpio, i.e. no special build dependencies on external libraries. There is only the runtime dependency of an older kernel that supports that interface. So it doesn't "cost" anything (beyond slightly more complicated code in src/linuxgpio.c) to support both the old sysfs gpio and the new gpiod.

I did consider leaving "linuxgpio" unchanged as the old sysfs gpio interface, and adding a new driver (maybe confusingly called "linuxgpiod"?) for the new libgpiod interface, but I made the judgement call that having one driver support both of the two linux-kernel gpio interfaces was cleaner. I am of course willing to be overridden on this: if the avrdude developer community prefers, I will change this PR to leave the old sysfs driver alone and add a new gpiod driver next to it. Just let me know (and if so, please suggest a non-confusing name for the new driver).

@mcuee
Copy link
Collaborator

mcuee commented Mar 3, 2023

I agree with @SebKuzminsky to keep both and use libgpiod when it is available and fall back to sysfs when it is available.

There are probably quite some Linux machines out there using older kernels than 4.8.

Ref: https://git.kernel.org/pub/scm/libs/libgpiod/libgpiod.git/tree/README

Since linux 4.8 the GPIO sysfs interface is deprecated. User space should use
the character device instead. This library encapsulates the ioctl calls and
data structures behind a straightforward API.

@stefanrueger
Copy link
Collaborator

Great shouts. I have no skin in either game. Assuming a system has both: is there a reason why a user might still want to work with the old interface?

@mcuee @MCUdude Other than that, is this PR ready to be merged or do you want it to hang around for a couple more weeks?

@SebKuzminsky
Copy link
Contributor Author

Assuming a system has both: is there a reason why a user might still want to work with the old interface?

I can't think of a reason, but I am not super well versed in the details of either interface.

If the ability to force the linuxgpio driver to use the sysfs interface turns out to be desirable, perhaps we'd use an environment variable, like AVRDUDE_LINUXGPIO=sysfs, and check for it in the linuxgpio driver?

@mcuee
Copy link
Collaborator

mcuee commented Mar 3, 2023

Great shouts. I have no skin in either game. Assuming a system has both: is there a reason why a user might still want to work with the old interface?

I do not see a reason myself.

@mcuee @MCUdude Other than that, is this PR ready to be merged or do you want it to hang around for a couple more weeks?

I am okay with merging this PR. But I'd like to hear from @MCUdude's input to see if this is already good enough to address the concerns he raised in #932.

@MCUdude
Copy link
Collaborator

MCUdude commented Mar 3, 2023

Thanks for the PR! I'll see if I can find some time next week to try this out

@MCUdude
Copy link
Collaborator

MCUdude commented Mar 6, 2023

I have an old 1st gen Raspberry Pi model B that's running the latest Raspbian Bullseye. It's slow as heck, but once it's finished building it works alright.

The first issue was that libgpiod wasn't installed by default, and running sudo apt install gpiod didn't help either. It turned out that I needed to install libgpiod-dev as well.

Programming works like a charm, and IIRC it's also faster than using sysfs. It's also great to see that the GPIOs are freed even if you hit Ctrl+C in the middle of the session.

It would be great if there was a default port number so that we didn't have to specify -P gpiochip0. For some reason, it chooses the default parallel port specified in avrdude.conf, even though this is obviously wrong. Perhaps default_gpio or default_gpiochip could be added to address this?

pi@raspberrypi:~/avrdude-main/build_linux/src $ ./avrdude -clinuxgpio -patmega16 -Uflash:w:atmega16_dump.hex:i
using libgpiod for linuxgpio
failed to open /dev/parport0 line 22: No such file or directory
avrdude error: unable to open programmer linuxgpio on port /dev/parport0

avrdude done.  Thank you.

pi@raspberrypi:~/avrdude-main/build_linux/src $ ./avrdude -clinuxgpio -P gpiochip0 -patmega16 -Uflash:w:atmega16_dump.hex:i
using libgpiod for linuxgpio

avrdude: AVR device initialized and ready to accept instructions
avrdude: device signature = 0x1e9403 (probably m16)
avrdude: Note: flash memory has been specified, an erase cycle will be performed.
         To disable this feature, specify the -D option.
avrdude: erasing chip
avrdude: reading input file atmega16_dump.hex for flash
         with 16384 bytes in 1 section within [0, 0x3fff]
         using 128 pages and 0 pad bytes
avrdude: writing 16384 bytes flash ...

Writing | ######                                             | 11% 0.93 s ^C

pi@raspberrypi:~/avrdude-main/build_linux/src $ ./avrdude -clinuxgpio -P gpiochip0 -patmega16 -Uflash:w:atmega16_dump.hex:i
using libgpiod for linuxgpio

avrdude: AVR device initialized and ready to accept instructions
avrdude: device signature = 0x1e9403 (probably m16)
avrdude: Note: flash memory has been specified, an erase cycle will be performed.
         To disable this feature, specify the -D option.
avrdude: erasing chip
avrdude: reading input file atmega16_dump.hex for flash
         with 16384 bytes in 1 section within [0, 0x3fff]
         using 128 pages and 0 pad bytes
avrdude: writing 16384 bytes flash ...

Writing | ################################################## | 100% 10.45 s 

avrdude: 16384 bytes of flash written
avrdude: verifying flash memory against atmega16_dump.hex

Reading | ################################################## | 100% 9.80 s 

avrdude: 16384 bytes of flash verified

avrdude done.  Thank you.

@SebKuzminsky
Copy link
Contributor Author

Hi @MCUdude, thanks for looking. And thanks for maintaining avrdude, it's super useful :-)

It would be great if there was a default port number so that we didn't have to specify -P gpiochip0. For some reason, it chooses the default parallel port specified in avrdude.conf, even though this is obviously wrong. Perhaps default_gpio or default_gpiochip could be added to address this?

I like that idea.

I think gpiochip devices always show up as /dev/gpiochipN, with the N dependent on what hardware is available and on the order that the different gpiod drivers were loaded.

libgpiod has an API to iterate over the gpiochips available (see e.g. the gpiodetect tool). Maybe in avrdude, if the user does not specify a port we should try to use the first one found by that iterator? That would at least do the right thing on your Raspberry Pi and mine.

@SebKuzminsky
Copy link
Contributor Author

My thinking before was confused - I was imagining that the programmer's open() method would be called with a NULL port argument if none was specified on the command line, but I see now that it gets a default port from main(), in your case and mine too "/dev/parport0".

As I understand it, your suggestion to add a default gpiochip would require a new CONNTYPE for gpio, so that main() knows to pass in default_gpiochip instead of default_something_else. Then the definition of the gpio programmer in avrdude.conf would include something like connection_type = gpio to select that CONNTYPE.

Am I understanding your suggestion correctly?

@MCUdude
Copy link
Collaborator

MCUdude commented Mar 9, 2023

As I understand it, your suggestion to add a default gpiochip would require a new CONNTYPE for gpio, so that main() knows to pass in default_gpiochip instead of default_something_else. Then the definition of the gpio programmer in avrdude.conf would include something like connection_type = gpio to select that CONNTYPE.

Yes, that would be the best option IMO. I'm sure most users that use linuxgpio use the default "port" gpiochip1 anyways, so having this as the default option in avrdude.conf may be a good idea

@SebKuzminsky
Copy link
Contributor Author

Ok, here's a proposal for this new feature.

I'm not sure what the best way to document that the linuxgpio "port" is only used when linuxgpio uses the gpiod backend, and is ignored when linuxgpio uses the sysfs backend. I'm open to suggestions there.

It also occurred to me that there's a user-visible difference in behavior between sysfs and gpiod...

The old linuxgpio sysfs backend uses system-wide GPIO pin identifiers, but the new libgpiod backend uses only gpiochip-wide pin identifiers. On the Raspberry Pi for example, there are two "gpiochip" devices ("gpiochip0" and "gpiochip1"), with some pins on each.

With sysfs you could potentially use pins from multiple gpiochips in your linuxgpio programmer, but because only one port/gpiochip is available in avrdude at a time, your programmer must fit on one port/gpiochip.

On Raspberry Pi, the pins on the main GPIO connector are all on one gpiochip so it works fine, but there might be other platforms that arrange their pins less conveniently.

I can imagine something ugly, like "pin numbers are interpreted as (1000 * gpiochip) + gpio line number". So if you wanted to use line 5 from gpiochip0 you'd call it 5, and line 3 from gpiochip1 would be 1003. Then the port would be ignored, like it is with linuxgpio sysfs.

@SebKuzminsky
Copy link
Contributor Author

Oh, and i see there are conflicts now between this branch and main, i'm happy to rebase this whenever you think it's time, just let me know.

@MCUdude
Copy link
Collaborator

MCUdude commented Mar 9, 2023

Thank you for your work! I just tested your last commit, and here are some thoughts:

  • Is it an idea to use a different pin as the reset pin? Really old raspberry pi with the smaller 26-pin header (like the 1st gen Model B) doesn't have GPIO 12 broken out, so for my test setup, I had to change this to something else (I used GPIO 22). Is there a specific reason why GPIO 12 was chosen?
  • For some reason, the default linuxgpio port specified in avrdude.conf only works for the raspberry_pi_gpio programmer option and not for linuxgpio.
  • The raspberry_pi_gpio option lacks the prog_modes field, and the formatting doesn't quite match the formatting style of other programmers in avrdude.conf has. There is a suggestion below where I've also added prog_modes.
$ ./avrdude -clinuxgpio -patmega16
using libgpiod for linuxgpio
failed to open /dev/parport0 line 22: No such file or directory
avrdude error: unable to open programmer linuxgpio on port /dev/parport0

avrdude done.  Thank you.

$ ./avrdude -clinuxgpio -patmega16 -Pgpiochip0
using libgpiod for linuxgpio

avrdude: AVR device initialized and ready to accept instructions
avrdude: device signature = 0x1e9403 (probably m16)

avrdude done.  Thank you.

$ ./avrdude -craspberry_pi_gpio -patmega16
using libgpiod for linuxgpio

avrdude: AVR device initialized and ready to accept instructions
avrdude: device signature = 0x1e9403 (probably m16)

avrdude done.  Thank you.
#------------------------------------------------------------
# Program from a Raspberry Pi GPIO port using linuxgpio
#------------------------------------------------------------

programmer
    id                     = "raspberry_pi_gpio";
    desc                   = "Bitbang Raspberry Pi GPIO via linuxgpio (sysfs or libgpiod)";
    type                   = "linuxgpio";
    prog_modes             = PM_ISP;
    connection_type        = linuxgpio;
    reset                  = 12;
    sck                    = 24;
    sdo                    = 23;
    sdi                    = 18;
;

@SebKuzminsky
Copy link
Contributor Author

  • Is it an idea to use a different pin as the reset pin? Really old raspberry pi with the smaller 26-pin header (like the 1st gen Model B) doesn't have GPIO 12 broken out, so for my test setup, I had to change this to something else (I used GPIO 22). Is there a specific reason why GPIO 12 was chosen?

Good point! I just picked a random pin on my Raspberry Pi 4B with the 40-pin header. I moved it to GPIO 22 so it works with the older 26-pin header too.

  • For some reason, the default linuxgpio port specified in avrdude.conf only works for the raspberry_pi_gpio programmer option and not for linuxgpio.

The commented-out linuxgpio programmer doesn't specify connection_type = linuxgpio, so it gets the default, which apparently is parallel. I added the missing conntype.

  • The raspberry_pi_gpio option lacks the prog_modes field, and the formatting doesn't quite match the formatting style of other programmers in avrdude.conf has. There is a suggestion below where I've also added prog_modes.

I updated avrdude.conf.in with your version from above, but with reset moved to GPIO 22.

@stefanrueger
Copy link
Collaborator

Where are we with this PR? Good to merge?

i'm happy to rebase

@sebastiankuzminsky Please do!

…sfs"

This commit renames the internal functions and variables of the linuxgpio
pin driver to include "sysfs", to indicate that they're referring to
the older sysfs interface.

The following commits will add libgpiod support to the linuxgpio pin
driver, and autoselect between them.
@SebKuzminsky
Copy link
Contributor Author

Rebased :-)

@stefanrueger
Copy link
Collaborator

Thanks! This looks like an excellent contribution. Earmarked for next mergefest (unless I hear from the other maintainers).

Tiny point though: we tend to leave the programming/white space style from previous contributors unchanged. The many white space changes in src/CMakeLists.txt should not be in this PR (makes it harder to find errors harder to see what's changed later on, etc). Could I ask you to revert to previous white space. Thanks!

And thank you for the contribution in the first place.

@SebKuzminsky
Copy link
Contributor Author

The many white space changes in src/CMakeLists.txt should not be in this PR

Oops, I goofed that up during the rebase, sorry. Re-rebase coming up!

The "linuxgpio" backend will now try both the old sysfs and new (since
Linux 4.8) libgpiod interface to access gpio pins.  If libgpiod works
it will use that, if it does not work it will fall back to the old
sysfs interface.

The libgpiod code is compiled in if libgpiod is available at build time,
and compiled out otherwise.
Before this commit, linuxgpio-gpiod used `gpiod_line_find()` to find
gpio lines by name, and would construct the gpio name by appending the
requested gpio number to the string "GPIO".  This had the advantage
that it didn't have to specify the gpiochip to use, since gpio names are
globally unique in gpiod-land.  But it has the severe drawback that only
gpios whose name begins with "GPIO" could be used.

This commit changes that to use `gpiod_line_get()` instead, which takes
a gpiochip name (the avrdude "port") and an "offset" (the pin number on
that chip).  This lets it use any available gpio line, no matter what
name libgpiod assigned it.
This also adds a default linuxgpio port ("gpiochip0"), and adds a
programmer to the avrdude.conf file using linuxgpio from the Raspberry
Pi GPIO port.
This makes the raspberry_pi_gpio programmer work on older Pis with the
smaller 26-pin GPIO header.

Updates based on code review by Hans (MCUdude).
@SebKuzminsky
Copy link
Contributor Author

Ok, fixed I think. Thanks @stefanrueger for catching that.

@JanLuudi
Copy link

JanLuudi commented Apr 4, 2024

Hey @stefanrueger @SebKuzminsky
I am trying to use avrdude in a similar way like @MCUdude

I am using a Raspberry Pi 4B (40 pin header)
Unfortunately, there seems to be something wrong and I need your help to solve it.

This is the error I am getting

janno@raspberrypi:~ $ lsb_release -a
No LSB modules are available.
Distributor ID:	Raspbian
Description:	Raspbian GNU/Linux 12 (bookworm)
Release:	12
Codename:	bookworm

janno@raspberrypi:~ $ uname -a
Linux raspberrypi 6.6.20+rpt-rpi-v8 #1 SMP PREEMPT Debian 1:6.6.20-1+rpt1 (2024-03-07) aarch64 GNU/Linux
janno@raspberrypi:~ $ sudo avrdude -c spi_mfm -p m328p -P gpiochip0 -v

avrdude: Version 7.3-20240330 (cb611715)
         Copyright the AVRDUDE authors;
         see https://github.com/avrdudes/avrdude/blob/main/AUTHORS

         System wide configuration file is /usr/local/etc/avrdude.conf
         User configuration file is /root/.avrduderc
         User configuration file does not exist or is not a regular file, skipping

         Using port            : gpiochip0
         Using programmer      : spi_mfm
avrdude linuxgpio_sysfs_open() OS error: cannot export GPIO 25, already exported/busy?: Invalid argument
avrdude main() error: unable to open port gpiochip0 for programmer spi_mfm

avrdude done.  Thank you.

It's the same for -P GPIO

Snippet of my avrdude.conf

avrdude_conf_version = "7.3-20240330 (cb611715)";
...
default_linuxgpio  = "gpiochip0";
...

#------------------------------------------------------------
# Program from a Raspberry Pi GPIO port using linuxgpio
#------------------------------------------------------------

programmer # raspberry_pi_gpio
    id                     = "raspberry_pi_gpio";
    desc                   = "Bitbang Raspberry Pi GPIO via linuxgpio (sysfs or libgpiod)";
    type                   = "linuxgpio";
    prog_modes             = PM_ISP;
    connection_type        = linuxgpio;
    reset                  = 22;
    sck                    = 24;
    sdo                    = 23;
    sdi                    = 18;
;

programmer
    id                   = "spi_mfm";
    desc                 = "Use RPi GPIO for mains frequency monitor unit";
    type                 = "linuxgpio";
    prog_modes           = PM_ISP;
    connection_type      = linuxgpio;
    reset                = 25;
    sck                  = 11;
    sdo                 = 10;
    sdi                 = 9;
;

And the content of /sys/class/gpio/

janno@raspberrypi:~ $ ls /sys/class/gpio
export  gpiochip512  gpiochip570  unexport

Do you know, what I am doing wrong?

@stefanrueger
Copy link
Collaborator

avrdude linuxgpio_sysfs_open() OS error: cannot export GPIO 25, already exported/busy?: Invalid argument

Thanks for reporting. Naive question: is GPIO 25 already exported/busy?

Other than that, perhaps best to raise an issue rather than commenting in a closed PR. This to increase visibility of the problem you experience.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Port Linux sysfs GPIO feature to libgpiod
6 participants