# GPIO API general (Orange Pi ... H3)



## Isoux (Jan 31, 2022)

Hello folks!

I successfully installed armv7 RELEASE 13.0 GENERIC on my Orange Pi Pc Plus (AllWinner H3 SoC sunxi8).
I set up LAN and DHCP so that I connect to the device via SSH.

As for the use of a 40 pin GPIO connector, I have some experience with STM32 NUCLEO boards, but I do not how GPIO is used via CLI or CMD from the operating system? 
Where can I find instructions for this (or SPI) as well as the required packages and ports and `commands`?


----------



## Phishfry (Jan 31, 2022)

gpioctl(8)
					






					www.freebsd.org
				






			GPIO - FreeBSD Wiki
		


https://www.freebsd.org/cgi/man.cgi?gpio(3) - The C library


----------



## Isoux (Jan 31, 2022)

Phishfry said:


> gpioctl(8)
> 
> 
> 
> ...


Thanks man!


----------



## Phishfry (Jan 31, 2022)

Finding what pin is FreeBSD GPIO Pin to 40 pin header can be challenging.

I write small scripts trying setting output state on groups of pins and I hookup test LED.
This way is horrible because GPIO controls everything from ethernet to display.
Go and flip the state on your SD Card GPIO line. It will crash.

So Linux exports GPIO's to userland and we do not. So be careful.
One godsend is that most Arm boards follow a similar 40 pin layout.
UART console on same pins pretty reliably.

What I have started to do is look at labeling that U-Boot command prompt has for GPIO pins.
On my Rock64 u-boot does not use `GPIO` command but instead `PINCTL`.
So I don't know if this is different per architecture or what. Maybe its a new method they are switching too I dunno.

I suggest you learn how to get into u-boot command prompt and poke around GPIO/PINCTL
When you run `help` from u-boot command prompt it will show you which is used.


----------



## Isoux (Jan 31, 2022)

Thanks, man!
I'll inform you of the results when starting the journey... 
To deal with u-boot at the start time I need to connect TTL  to USB serial device (The HDMI for my device is not yet supported).
Before setting LAN, DHCP and SSH I had used it for the very first time ...

For now I find useful info for my device from  file:
/usr/src/sys/arm/allwinner/h3/h3_padconf.c


```
const static struct allwinner_pins h3_pins[] = {
    {"PA0",  0, 0,  {"gpio_in", "gpio_out", "uart2", "jtag", NULL, NULL, "pa_eint0", NULL}, 6, 0},
    {"PA1",  0, 1,  {"gpio_in", "gpio_out", "uart2", "jtag", NULL, NULL, "pa_eint1", NULL}, 6, 1},
    {"PA2",  0, 2,  {"gpio_in", "gpio_out", "uart2", "jtag", NULL, NULL, "pa_eint2", NULL}, 6, 2},
    {"PA3",  0, 3,  {"gpio_in", "gpio_out", "uart2", "jtag", NULL, NULL, "pa_eint3", NULL}, 6, 3},
    {"PA4",  0, 4,  {"gpio_in", "gpio_out", "uart0", NULL, NULL, NULL, "pa_eint4", NULL}, 6, 4},
    {"PA5",  0, 5,  {"gpio_in", "gpio_out", "uart0", "pwm0", NULL, NULL, "pa_eint5", NULL}, 6, 5},
    {"PA6",  0, 6,  {"gpio_in", "gpio_out", "sim", NULL, NULL, NULL, "pa_eint6", NULL}, 6, 6},
    {"PA7",  0, 7,  {"gpio_in", "gpio_out", "sim", NULL, NULL, NULL, "pa_eint7", NULL}, 6, 7},
    {"PA8",  0, 8,  {"gpio_in", "gpio_out", "sim", NULL, NULL, NULL, "pa_eint8", NULL}, 6, 8},
    {"PA9",  0, 9,  {"gpio_in", "gpio_out", "sim", NULL, NULL, NULL, "pa_eint9", NULL}, 6, 9},
    {"PA10", 0, 10, {"gpio_in", "gpio_out", "sim", NULL, NULL, NULL, "pa_eint10", NULL}, 6, 10},
    {"PA11", 0, 11, {"gpio_in", "gpio_out", "i2c0", "di", NULL, NULL, "pa_eint11", NULL}, 6, 11},
    {"PA12", 0, 12, {"gpio_in", "gpio_out", "i2c0", "di", NULL, NULL, "pa_eint12", NULL}, 6, 12},
    {"PA13", 0, 13, {"gpio_in", "gpio_out", "spi1", "uart3", NULL, NULL, "pa_eint13", NULL}, 6, 13},
    {"PA14", 0, 14, {"gpio_in", "gpio_out", "spi1", "uart3", NULL, NULL, "pa_eint14", NULL}, 6, 14},
    {"PA15", 0, 15, {"gpio_in", "gpio_out", "spi1", "uart3", NULL, NULL, "pa_eint15", NULL}, 6, 15},
    {"PA16", 0, 16, {"gpio_in", "gpio_out", "spi1", "uart3", NULL, NULL, "pa_eint16", NULL}, 6, 16},
    {"PA17", 0, 17, {"gpio_in", "gpio_out", "spdif", NULL, NULL, NULL, "pa_eint17", NULL}, 6, 17},
    {"PA18", 0, 18, {"gpio_in", "gpio_out", "i2s0", "i2c1", NULL, NULL, "pa_eint18", NULL}, 6, 18},
    {"PA19", 0, 19, {"gpio_in", "gpio_out", "i2s0", "i2c1", NULL, NULL, "pa_eint19", NULL}, 6, 19},
    {"PA20", 0, 20, {"gpio_in", "gpio_out", "i2s0", "sim", NULL, NULL, "pa_eint20", NULL}, 6, 20},
    {"PA21", 0, 21, {"gpio_in", "gpio_out", "i2s0", "sim", NULL, NULL, "pa_eint21", NULL}, 6, 21},

    {"PC0",  2, 0,  {"gpio_in", "gpio_out", "nand", "spi0", NULL, NULL, NULL, NULL}},
    {"PC1",  2, 1,  {"gpio_in", "gpio_out", "nand", "spi0", NULL, NULL, NULL, NULL}},
    {"PC2",  2, 2,  {"gpio_in", "gpio_out", "nand", "spi0", NULL, NULL, NULL, NULL}},
    {"PC3",  2, 3,  {"gpio_in", "gpio_out", "nand", "spi0", NULL, NULL, NULL, NULL}},
    {"PC4",  2, 4,  {"gpio_in", "gpio_out", "nand", NULL, NULL, NULL, NULL, NULL}},
    {"PC5",  2, 5,  {"gpio_in", "gpio_out", "nand", "mmc2", NULL, NULL, NULL, NULL}},
    {"PC6",  2, 6,  {"gpio_in", "gpio_out", "nand", "mmc2", NULL, NULL, NULL, NULL}},
    {"PC7",  2, 7,  {"gpio_in", "gpio_out", "nand", NULL, NULL, NULL, NULL, NULL}},
    {"PC8",  2, 8,  {"gpio_in", "gpio_out", "nand", "mmc2", NULL, NULL, NULL, NULL}},
    {"PC9",  2, 9,  {"gpio_in", "gpio_out", "nand", "mmc2", NULL, NULL, NULL, NULL}},
    {"PC10", 2, 10, {"gpio_in", "gpio_out", "nand", "mmc2", NULL, NULL, NULL, NULL}},
    {"PC11", 2, 11, {"gpio_in", "gpio_out", "nand", "mmc2", NULL, NULL, NULL, NULL}},
    {"PC12", 2, 12, {"gpio_in", "gpio_out", "nand", "mmc2", NULL, NULL, NULL, NULL}},
    {"PC13", 2, 13, {"gpio_in", "gpio_out", "nand", "mmc2", NULL, NULL, NULL, NULL}},
    {"PC14", 2, 14, {"gpio_in", "gpio_out", "nand", "mmc2", NULL, NULL, NULL, NULL}},
    {"PC15", 2, 15, {"gpio_in", "gpio_out", "nand", "mmc2", NULL, NULL, NULL, NULL}},
    {"PC16", 2, 16, {"gpio_in", "gpio_out", "nand", "mmc2", NULL, NULL, NULL, NULL}},

    {"PD0",  3, 0,  {"gpio_in", "gpio_out", "emac", NULL, NULL, NULL, NULL, NULL}},
    {"PD1",  3, 1,  {"gpio_in", "gpio_out", "emac", NULL, NULL, NULL, NULL, NULL}},
    {"PD2",  3, 2,  {"gpio_in", "gpio_out", "emac", NULL, NULL, NULL, NULL, NULL}},
    {"PD3",  3, 3,  {"gpio_in", "gpio_out", "emac", NULL, NULL, NULL, NULL, NULL}},
    {"PD4",  3, 4,  {"gpio_in", "gpio_out", "emac", NULL, NULL, NULL, NULL, NULL}},
    {"PD5",  3, 5,  {"gpio_in", "gpio_out", "emac", NULL, NULL, NULL, NULL, NULL}},
    {"PD6",  3, 6,  {"gpio_in", "gpio_out", "emac", NULL, NULL, NULL, NULL, NULL}},
    {"PD7",  3, 7,  {"gpio_in", "gpio_out", "emac", NULL, NULL, NULL, NULL, NULL}},
    {"PD8",  3, 8,  {"gpio_in", "gpio_out", "emac", NULL, NULL, NULL, NULL, NULL}},
    {"PD9",  3, 9,  {"gpio_in", "gpio_out", "emac", NULL, NULL, NULL, NULL, NULL}},
    {"PD10", 3, 10, {"gpio_in", "gpio_out", "emac", NULL, NULL, NULL, NULL, NULL}},
    {"PD11", 3, 11, {"gpio_in", "gpio_out", "emac", NULL, NULL, NULL, NULL, NULL}},
    {"PD12", 3, 12, {"gpio_in", "gpio_out", "emac", NULL, NULL, NULL, NULL, NULL}},
    {"PD13", 3, 13, {"gpio_in", "gpio_out", "emac", NULL, NULL, NULL, NULL, NULL}},
    {"PD14", 3, 14, {"gpio_in", "gpio_out", "emac", NULL, NULL, NULL, NULL, NULL}},
    {"PD15", 3, 15, {"gpio_in", "gpio_out", "emac", NULL, NULL, NULL, NULL, NULL}},
    {"PD16", 3, 16, {"gpio_in", "gpio_out", "emac", NULL, NULL, NULL, NULL, NULL}},
    {"PD17", 3, 17, {"gpio_in", "gpio_out", "emac", NULL, NULL, NULL, NULL, NULL}},

    {"PE0",  4, 0,  {"gpio_in", "gpio_out", "csi", "ts", NULL, NULL, NULL, NULL}},
    {"PE1",  4, 1,  {"gpio_in", "gpio_out", "csi", "ts", NULL, NULL, NULL, NULL}},
    {"PE2",  4, 2,  {"gpio_in", "gpio_out", "csi", "ts", NULL, NULL, NULL, NULL}},
    {"PE3",  4, 3,  {"gpio_in", "gpio_out", "csi", "ts", NULL, NULL, NULL, NULL}},
    {"PE4",  4, 4,  {"gpio_in", "gpio_out", "csi", "ts", NULL, NULL, NULL, NULL}},
    {"PE5",  4, 5,  {"gpio_in", "gpio_out", "csi", "ts", NULL, NULL, NULL, NULL}},
    {"PE6",  4, 6,  {"gpio_in", "gpio_out", "csi", "ts", NULL, NULL, NULL, NULL}},
    {"PE7",  4, 7,  {"gpio_in", "gpio_out", "csi", "ts", NULL, NULL, NULL, NULL}},
    {"PE8",  4, 8,  {"gpio_in", "gpio_out", "csi", "ts", NULL, NULL, NULL, NULL}},
    {"PE9",  4, 9,  {"gpio_in", "gpio_out", "csi", "ts", NULL, NULL, NULL, NULL}},
    {"PE10", 4, 10, {"gpio_in", "gpio_out", "csi", "ts", NULL, NULL, NULL, NULL}},
    {"PE11", 4, 11, {"gpio_in", "gpio_out", "csi", "ts", NULL, NULL, NULL, NULL}},
    {"PE12", 4, 12, {"gpio_in", "gpio_out", "csi", "i2c2", NULL, NULL, NULL, NULL}},
    {"PE13", 4, 13, {"gpio_in", "gpio_out", "csi", "i2c2", NULL, NULL, NULL, NULL}},
    {"PE14", 4, 14, {"gpio_in", "gpio_out", NULL, NULL, NULL, NULL, NULL, NULL}},
    {"PE15", 4, 15, {"gpio_in", "gpio_out", NULL, NULL, NULL, NULL, NULL, NULL}},

    {"PF0",  5, 0,  {"gpio_in", "gpio_out", "mmc0", "jtag", NULL, NULL, NULL, NULL}},
    {"PF1",  5, 1,  {"gpio_in", "gpio_out", "mmc0", "jtag", NULL, NULL, NULL, NULL}},
    {"PF2",  5, 2,  {"gpio_in", "gpio_out", "mmc0", "uart0", NULL, NULL, NULL, NULL}},
    {"PF3",  5, 3,  {"gpio_in", "gpio_out", "mmc0", "jtag", NULL, NULL, NULL, NULL}},
    {"PF4",  5, 4,  {"gpio_in", "gpio_out", "mmc0", "uart0", NULL, NULL, NULL, NULL}},
    {"PF5",  5, 5,  {"gpio_in", "gpio_out", "mmc0", "jtag", NULL, NULL, NULL, NULL}},
    {"PF6",  5, 6,  {"gpio_in", "gpio_out", NULL, NULL, NULL, NULL, NULL, NULL}},

    {"PG0",  6, 0,  {"gpio_in", "gpio_out", "mmc1", NULL, NULL, NULL, "pg_eint0", NULL}, 6, 0, 1},
    {"PG1",  6, 1,  {"gpio_in", "gpio_out", "mmc1", NULL, NULL, NULL, "pg_eint1", NULL}, 6, 1, 1},
    {"PG2",  6, 2,  {"gpio_in", "gpio_out", "mmc1", NULL, NULL, NULL, "pg_eint2", NULL}, 6, 2, 1},
    {"PG3",  6, 3,  {"gpio_in", "gpio_out", "mmc1", NULL, NULL, NULL, "pg_eint3", NULL}, 6, 3, 1},
    {"PG4",  6, 4,  {"gpio_in", "gpio_out", "mmc1", NULL, NULL, NULL, "pg_eint4", NULL}, 6, 4, 1},
    {"PG5",  6, 5,  {"gpio_in", "gpio_out", "mmc1", NULL, NULL, NULL, "pg_eint5", NULL}, 6, 5, 1},
    {"PG6",  6, 6,  {"gpio_in", "gpio_out", "uart1", NULL, NULL, NULL, "pg_eint6", NULL}, 6, 6, 1},
    {"PG7",  6, 7,  {"gpio_in", "gpio_out", "uart1", NULL, NULL, NULL, "pg_eint7", NULL}, 6, 7, 1},
    {"PG8",  6, 8,  {"gpio_in", "gpio_out", "uart1", NULL, NULL, NULL, "pg_eint8", NULL}, 6, 8, 1},
    {"PG9",  6, 9,  {"gpio_in", "gpio_out", "uart1", NULL, NULL, NULL, "pg_eint9", NULL}, 6, 9, 1},
    {"PG10", 6, 10, {"gpio_in", "gpio_out", "i2s1", NULL, NULL, NULL, "pg_eint10", NULL}, 6, 10, 1},
    {"PG11", 6, 11, {"gpio_in", "gpio_out", "i2s1", NULL, NULL, NULL, "pg_eint11", NULL}, 6, 11, 1},
    {"PG12", 6, 12, {"gpio_in", "gpio_out", "i2s1", NULL, NULL, NULL, "pg_eint12", NULL}, 6, 12, 1},
    {"PG13", 6, 13, {"gpio_in", "gpio_out", "i2s1", NULL, NULL, NULL, "pg_eint13", NULL}, 6, 13, 1},
};
```


----------



## Andriy (Feb 1, 2022)

Phishfry said:


> Finding what pin is FreeBSD GPIO Pin to 40 pin header can be challenging.


A diagram like this plus output from `gpioctl -l` and you have everything you need:









Phishfry said:


> So Linux exports GPIO's to userland and we do not.


Not sure what you mean.


----------



## Isoux (Feb 1, 2022)

Thanks, man!

I don't have much time for now so I just tried to turn on and off 2 LEDs via the CMD line:
Status red LED:
`% sudo gpioctl -t PA15`
Power green LED:
`% sudo gpioctl -f /dev/gpioc1 -t PL10`

Man it's works perfectly! 
I'm informing further progress ...


----------



## Andriy (Feb 2, 2022)

BTW, those should be available via gpioled(4) driver.
You should have device entries under /dev/led.


----------



## Isoux (Feb 2, 2022)

Yes I know...

For now, this is the only way I did found to manage from the CMD line:
`:~ # echo 0 > /dev/led/orangepi:green:pwr
:~ # echo 1 > /dev/led/orangepi:green:pwr
:~ # echo 0 > /dev/led/orangepi:red:status
:~ # echo 1 > /dev/led/orangepi:red:status`


----------



## Phishfry (Feb 2, 2022)

Andriy said:


> Not sure what you mean.


On Linux you have to export GPIO pins to sysfs to use them.
They only expose certain GPIO pins.
On FreeFBD gpioctl see's every GPIO line of the system and can alter state and change values crashing the board.

When I started with Arm on the Beaglebone with FreeBSD 10 they had the 4 board LED's available for raw manipulation with `gpioctl`. Now they fall under gpioled.
Nice that they have a device node. but it was fun and learning to manipulate the LEDs with gpioctl and scripts.
Plus no extra parts to buy and they had resistors built in properly.
I took the bonescript LED sample and made it work similarly on FreeBSD. They had a cool light sequence.

 I wonder if we ever see something similar with GPIO.
GPIO device nodes under each parent GPIO controller.
/dev/gpioc2/PA12
That's how Linux does it from my scant knowledge..


----------



## Phishfry (Feb 2, 2022)

What about pin muxing? How do you use alternertive GPIO pin states?

For example on IMX6 PWM1 can be on 3 different pins. One is default and two are alternates states.

Beaglebone had a real nice body of work there. Robert Nelson made it so.
Easy to find the pin muxing without digging thru code by good documentation.

But this was pre-overlays and you just mashed the DT fragment in somewhere.

I see NXP has a Linux software program for programming IMX pin mux state. Real nice graphical format.
I dream of programs like this on FreeBSD.....

How do you mux pins on FreeBSD these days? Write an overlay?

Man this would be a good job for u-boot. Need to read some...


----------



## Isoux (Feb 3, 2022)

Phishfry said:


> What about pin muxing? How do you use alternertive GPIO pin states?
> 
> How do you mux pins on FreeBSD these days? Write an overlay?


I haven't had a chance to try it yet.
I want to try the SPI0 interface for my small display so I will have to use mux 3 as seen in the above picture. But before that, I will test the LED on one of the available pins...


----------



## Phishfry (Feb 3, 2022)

I am currently on Hummingboard testing my GPIO and the command is `pinmux` for u-boot command prompt.

Problem is my u-boot config does not have it. mx6cuboxi_defconfig

# CONFIG_CMD_PINMUX is not set

So I will rebuild and enable it and see what I get.



			pinmux command — Das U-Boot unknown version documentation


----------



## Isoux (Feb 3, 2022)

Phishfry said:


> I am currently on Hummingboard testing my GPIO and the command is `pinmux` for u-boot command prompt.
> So I will rebuild and enable it and see what I get.
> 
> 
> ...


Thanks, man you give me a good inspiration ...
I can’t wait for some free time to dive into the implementation of my endeavor.

Good luck, I wish you success!


----------



## Phishfry (Feb 3, 2022)

There is also some u-boot programming language.



			Pinctrl and Pinmux — Das U-Boot unknown version documentation
		


I don't know how to use this.


----------



## Isoux (Feb 3, 2022)

Phishfry said:


> I don't know how to use this.


I wish I could help you!


----------



## Andriy (Feb 3, 2022)

Phishfry said:


> I wonder if we ever see something similar with GPIO.
> GPIO device nodes under each parent GPIO controller.
> /dev/gpioc2/PA12
> That's how Linux does it from my scant knowledge..


Is that in any way superior to the gpioctl method?


----------



## Phishfry (Feb 3, 2022)

No. I was just musing. There is no wrong way.
Why did they use a device node for gpioled if it is un-superior?
That is the musings of a machinist. Not a programmer.


----------



## Isoux (Feb 10, 2022)

I have a problem with SPI, I can't find the any spi at /dev/spi...
At dmesg no info about SPI
I try:
`:~ # kldstat 
Id Refs Address        Size Name
 1    6 0xc0000000   cbe97c kernel
 2    1 0xc0cc0000    23f84 umodem.ko
 3    2 0xc0ce4000    26fe0 ucom.ko`
After that:
`:~ # kldload spibus
kldload: can't load spibus: module already loaded or in kernel
:~ # kldload spigen
kldload: can't load spigen: module already loaded or in kernel
:~ # kldload gpiospi
kldload: can't load gpiospi: module already loaded or in kernel
:~ # dmesg
KLD gpiospi.ko: depends on gpiospi - not available or version mismatch
module_register: cannot register spibus/spigen from spigen.ko; already loaded from kernel
Module spibus/spigen failed to register: 17
KLD gpiospi.ko: depends on gpiospi - not available or version mismatch`
The result is same:
`:~ # kldstat 
Id Refs Address        Size Name
 1    6 0xc0000000   cbe97c kernel
 2    1 0xc0cc0000    23f84 umodem.ko
 3    2 0xc0ce4000    26fe0 ucom.ko`
I try to add lines at rc.conf:

```
kld_list="spibus.ko"
kld_list="spigen.ko"
kld_list="gpiospi.ko"
```
and line at end of /boot/defaults/loader.conf:

```
sun8i-h3-orangepi-pc-plus.dtb_load="YES"
```
After rebooting, I didn't get any better results.
Any solution?


----------



## covacat (Feb 10, 2022)

they are disabled in the dtb
you need to enable them via an overlay


----------



## Isoux (Feb 10, 2022)

covacat said:


> they are disabled in the dtb
> you need to enable them via an overlay


Thanks but I have no idea how to do it?


----------



## covacat (Feb 10, 2022)

```
/dts-v1/;
/plugin/;

/ {
    compatible = "allwinner,sun8i-h3";

    fragment@0 {
        target = <&spi0>;
        __overlay__ {
            status = "okay";
        };
    };

    fragment@1 {
        target = <&spi1>;
         __overlay__ {
            status = "okay";
        };
    };

};
```
compile it with dtc -O dtb -I dts x.dts >/boot/dtb/overlays/spi-sunxi.dtbo
fdt_overlays="spi-sunxi.dtbo"


----------



## Isoux (Feb 10, 2022)

fdt_overlays="spi-sunxi.dtbo"
Where I must put this line? 
at /etc/rc.conf or /boot/defaults/loader.conf ?


----------



## covacat (Feb 10, 2022)

Isoux said:


> fdt_overlays="spi-sunxi.dtbo"
> Where I must put this line?
> at /etc/rc.conf or /boot/defaults/loader.conf ?


/boot/loader.conf


----------



## Isoux (Feb 10, 2022)

covacat said:


> /boot/loader.conf


Thank you very much!
Now I can see aw_spi0 and aw_spi1 at dmeseg but do not see any aw_spi0 or spi devices at /dev/.... ?


----------



## covacat (Feb 11, 2022)

try this

```
/dts-v1/;
/plugin/;

/ {
    compatible = "allwinner,sun8i-h3";

    fragment@0 {
        target = <&spi0>;
        __overlay__ {
            status = "okay";
    spigen {
     compatible = "freebsd,spigen";
     status = "okay";
     reg = <0>;
     spi-max-frequency = <1000000>;
     };   
        };
    };

    fragment@1 {
        target = <&spi1>;
         __overlay__ {
            status = "okay";
            spigen {
             compatible = "freebsd,spigen";
             status = "okay";
             reg = <0>;
             spi-max-frequency = <1000000>;
             };   
        };
    };
};
```


----------



## Isoux (Feb 11, 2022)

Thank you, man!
You make my day!
Now I have devices /dev/spigen0.0 and /dev/spigen1.0 and they working with SPI()
`:~ # spi -i
Device name:   /dev/spigen0.0
Device mode:   0
Device speed:  1000000
:~ # spi -f /dev/spigen1.0 -i 
Device name:   /dev/spigen1.0
Device mode:   0
Device speed:  1000000`


----------



## Isoux (Feb 11, 2022)

Where can I find documentation on how to write and compile dts files?


----------



## covacat (Feb 11, 2022)

i don't know of any definitive resource
this i adapted from armbian / github
i've got somewhat familiar by playing with u-boot / linux / bsd on various arm hardware


----------



## Andriy (Feb 11, 2022)

That overlay created the devices, but I am not sure if those devices would actually work.

A much simpler overlay that worked for me (on Orange Pi PC Plus): https://cgit.FreeBSD.org/src/commit/?id=b8db946c3b4498d9d2b22d3cd184b2c5033ade73

Ah, I see why you added spigen nodes, without those there obviously won't be /dev/spigen devices.
I opted to configure spigen via hints (in loader.conf):

```
hint.spigen.0.at="spibus0"
hint.spigen.0.clock="60000000"
hint.spigen.0.mode="0"
hint.spigen.0.cs="0"
```


----------



## Phishfry (Feb 11, 2022)

Isoux said:


> Where can I find documentation on how to write and compile dts files?


I think its interesting to decompile your boards dtb. Good practice on using the dtc.
Because the dtb pulls in stuff from many include files it is interesting to study the end product.
Compare that against ofwdump results.

For professional tools NXP has a toolkit for iMX6 that is a GUI representation of the pin header.
You click on a pin and tell it what you want it to do and it writes out to the device tree file.

So caveman compared to modern tools. Many ways to do it. Lots of elaborate bracketry.
Finding where to stab in the fragment in the device tree can be the challenging part.









						Solved - BananaPI M1 problem with ahci channel 0 FreeBSD 12.2
					

Hi All,  Look like I'm last user of BananaPI M1 with Allwinner A20 and embeded SATA. Somewhere between revisions 343862 (last working I have) and 370066 (not working I'm trying to use) is lost ahci channel 0. I'm trying to report as much as possible in bug 251330 with no luck.  It look like some...




					forums.freebsd.org
				











						How to enable the PRU's on the Beaglebone black?
					

I want to use the PRU's with FreeBSD on the BeagleBone black  version:  # uname -a FreeBSD beaglebone 12.0-CURRENT FreeBSD 12.0-CURRENT #0 r319859: Tue Jun 13 00:26:37 UTC 2017     root@releng3.nyi.freebsd.org:/usr/obj/arm.armv6/usr/src/sys/BEAGLEBONE  arm  I installed pructl with pkg.    #...




					forums.freebsd.org


----------



## Isoux (Feb 12, 2022)

Andriy said:


> That overlay created the devices, but I am not sure if those devices would actually work.
> 
> A much simpler overlay that worked for me (on Orange Pi PC Plus): https://cgit.FreeBSD.org/src/commit/?id=b8db946c3b4498d9d2b22d3cd184b2c5033ade73
> 
> ...


Thank you, man!
This way also works for me, just you make a mistake clock=60Mhz  I correct to 6Mhz and:
`:~ # spi -i
Device name:   /dev/spigen0.0
Device mode:   0
Device speed:  6000000`
Also, I make a file sun8i_andriy.dts:

```
/dts-v1/;
/plugin/;

/ {
    compatible = "allwinner,sun8i-h3";
};
&{/soc/spi@1c68000} {
    status = "okay";
};
```
and compiled it:
`dtc -O dtb -I dts sun8i_andriy.dts >/boot/dtb/overlays/sun8i-h3-spi0.dtso`
and added lines to /boot/loader.conf:

```
fdt_overlays="sun8i-h3-spi0.dtso"
hint.spigen.0.at="spibus0"
hint.spigen.0.clock="6000000"
hint.spigen.0.mode="0"
hint.spigen.0.cs="0"
hint.spigen.1.at="spibus1"
hint.spigen.1.clock="6000000"
hint.spigen.1.mode="0"
hint.spigen.1.cs="0"
```
After rebooting:
`:~ # spi -i
Device name:   /dev/spigen0.0
Device mode:   0
Device speed:  6000000
:~ % sudo spi -f /dev/spigen1.0 -i
Device name:   /dev/spigen1.0
Device mode:   0
Device speed:  6000000`


----------



## Andriy (Feb 12, 2022)

The clock can be dynamically changed, so the initial value is not always important.
`spi -s 3000000`


----------



## Isoux (Feb 12, 2022)

Andriy said:


> The clock can be dynamically changed, so the initial value is not always important.
> `spi -s 3000000`


Okay, it's just reporting an error when the clock was  60000000 ...
Sorry, an error was using cmd without SUDO()
`:~ % spi -i
Error - unable to open '/dev/spigen0.0', errno=13`


----------



## Phishfry (Feb 12, 2022)

I would like to steal this work for iMX6 Hummingboard. Can you help me. Here are my spi nodes:


```
HB2-GATE:~ # ofwdump -a|grep spi
        Node 0x1970: spi@2008000
        Node 0x1a84: spi@200c000
        Node 0x1bd0: spi@2010000
        Node 0x1ce4: spi@2014000
          Node 0x56dc: hummingboard2-ecspi2grp
```

Which node should I use for my DT setting?


```
/dts-v1/;
/plugin/;

/ {
    compatible = ""fsl,imx6q";
};
&{/soc/spi@2008000} {
    status = "okay";
};
```

Who can comment on these 'grp' nodes I see here (ecspi2grp) and I see the same for pwm.
A grp node under the parent.


----------



## Phishfry (Feb 12, 2022)

Very nice work. Compiled the above and added hints.

```
imx_spi0: <i.MX ECSPI Master> mem 0x200c000-0x200ffff irq 61 on simplebus2
```


```
HB2-GATE:~ # spi -i
Device name:   /dev/spigen0.0
Device mode:   0
Device speed:  6000000
```


----------



## Isoux (Feb 12, 2022)

Congrats, thanks to Andriy & covacat!

At my dmesg I see spibus1 too ... for that reason, I added hints for spigen1.
If you see at yours spibus1 & 2 & 3, you can add all that hints for them.


----------



## Phishfry (Feb 12, 2022)

I have some temperature chips for a work project.








						MAX31855 Type K Thermocouple Temperature Sensor Module Shield 3.3V 3V USA SHIP  | eBay
					

Find many great new & used options and get the best deals for MAX31855 Type K Thermocouple Temperature Sensor Module Shield 3.3V 3V USA SHIP at the best online prices at eBay! Free shipping for many products!



					www.ebay.com
				



MAX31855 Thermocouple Modules.
They need 3 SPI lines. DO, CS and CLK
How do I use this? Three signal pins needed?


----------



## Isoux (Feb 13, 2022)

Yes 3 pins at least (+ two for power). You need just one SPI channel (spigen0.0). 
DO = SPI0_MOSI
CS = SPI0_CS
CLK = SPI0_CLK
Please give me a time if you need more information.


----------



## Phishfry (Feb 13, 2022)

I think I have found what I need. I need to be using spi1 for ecspi2

From imx6qdl-hummingboard.dtsi

        pinctrl_hummingboard2_ecspi2: hummingboard2-ecspi2grp {
            fsl,pins = <
                MX6QDL_PAD_EIM_OE__ECSPI2_MISO    0x100b1
                MX6QDL_PAD_EIM_CS1__ECSPI2_MOSI    0x100b1
                MX6QDL_PAD_EIM_CS0__ECSPI2_SCLK    0x100b1
                MX6QDL_PAD_EIM_RW__GPIO2_IO26    0x000b1 /* CS */

Snippet from imx6qdl.dtsi
Aliases
        spi0 = &ecspi1;
        spi1 = &ecspi2;
        spi2 = &ecspi3;
        spi3 = &ecspi4;


----------



## Phishfry (Feb 13, 2022)

Phishfry said:


> pinctrl_hummingboard2_ecspi2: hummingboard2-ecspi2grp {
> fsl,pins = <
> MX6QDL_PAD_EIM_OE__ECSPI2_MISO 0x100b1
> MX6QDL_PAD_EIM_CS1__ECSPI2_MOSI 0x100b1
> ...


So I am going to assume here that grp=pin group.
GPIO2_IO26 is an accessible pin.
Maybe this is the control pin for the ecspi2 pin group.

CLK=Clock
MOSI=DO
MISO=DI
GPIO2_IO26=CS


----------



## astyle (Feb 13, 2022)

Phishfry said:


> MISO=?


----------



## Phishfry (Feb 13, 2022)

I was wondering why is ecspi starting at ecspi2.
Looking at mx6dl_pins.h I see that ecspi1 is mapped to CSI0. That is the Pi-Like Camera interface.


> MX6_PAD_DECL(CSI0_DAT5__ECSPI1_MOSI,    0x038C, 0x0078, 2, 0x07E0, 0, 0)


----------



## Phishfry (Feb 13, 2022)

I had to go to the schematic for the pin locations. The ecspi2 pins are located on the mikrobus socket connectors.


----------



## Phishfry (Feb 13, 2022)

astyle said:


>


No soup for you.
NEXT


----------



## Phishfry (Feb 13, 2022)

I can't seem to activate more than one SPI bus. Its not the overlays or loader hints.
It just crashes on bootup with two SPI buses. So I am going to concentrate on one SPI bus. It is all I need.

Any recommendations on the dumbest SPI device for a slave? I want something simple for learning SPI.


----------



## Isoux (Feb 13, 2022)

W25Q Winbond Serial Flash Memory Module SPI W25Q128B BIOS 25Q64BVSIG EEPROM  | eBay
					

Find many great new & used options and get the best deals for W25Q Winbond Serial Flash Memory Module SPI W25Q128B BIOS 25Q64BVSIG EEPROM at the best online prices at eBay! Free shipping for many products!



					www.ebay.com
				



The choice for my taste is something like this.
Moreover, I have one such device, I just haven't tried to connect it to the NUCLEO 64 (STM32) board.


----------



## Phishfry (Feb 14, 2022)

Nice I ended up on the same chipset. Only got a 4 Megabyte module.








						3pcs W25Q32 large capacity FLASH storage module SPI interface BV FV STM32 code  | eBay
					

Find many great new & used options and get the best deals for 3pcs W25Q32 large capacity FLASH storage module SPI interface BV FV STM32 code at the best online prices at eBay! Free shipping for many products!



					www.ebay.com
				



Wonder if u-boot will boot up off it.


----------



## Phishfry (Feb 14, 2022)

I am looking at the ADC boards too.
ADS1118








						ADS1118 16-Bit  4 Channel AD Converter ADC Module Development Board SPI Output  | eBay
					

Find many great new & used options and get the best deals for ADS1118 16-Bit  4 Channel AD Converter ADC Module Development Board SPI Output at the best online prices at eBay! Free shipping for many products!



					www.ebay.com
				




I wish I could find a module with mcp3008.

So whats the story on drivers. Would I need a FreeBSD driver for mcp3008 or is SPI comms enough?


----------



## Isoux (Feb 14, 2022)

1.8 inch 128X160 SPI ST7735S TFT LCD full color display module STM32 for Arduino  | eBay
					

Find many great new & used options and get the best deals for 1.8 inch 128X160 SPI ST7735S TFT LCD full color display module STM32 for Arduino at the best online prices at eBay! Free shipping for many products!



					www.ebay.com
				




I can't say for sure, but I don't think mcp3008 will need any drivers. I am now experimenting with a 128X160 SPI ST7735S TFT LCD ... I was able to initialize the device and print the background color as desired all with one shell script full of SPI() and GPIOCTL() commands ...
I will publish the results soon.


----------



## Phishfry (Feb 14, 2022)

Animated Beastie would be superdeluxe. What is the output(artwork) format needed? Is it seen as a display?


----------



## Phishfry (Feb 15, 2022)

I mean what is the output format for your LCD screen? Not character/text based right?
Is it a display device and could you play an animated beastie logo on it?
How do you use it? Can you play a mp4 to it?

I am asking because I want e-Paper display and I am wondering about workflow for display.
Is it treated like a miniture monitor?





						800×480, 7.5inch E-Ink raw display, SPI interface, without PCB | WF0583CZ09
					

800×480, 7.5inch E-Ink raw display, SPI interface, without PCB | WF0583CZ09




					www.waveshare.com


----------



## Isoux (Feb 15, 2022)

Sorry man, I didn't understand you, at the time your message arrived I had a live consultation on my channel on how to edit a photo for the FreeBSD logo and I changed the photo every few minutes, I thought you were asking me about it.

That's right, not character/text-based.
I can play an animated beastie logo on it, but well need preparation and writing some code for that purpose.
No, I can't play an mp4 on it.
It is a cheap device with 65K colors and no fast data flow.
In general, e-Paper displays have a slow workflow ...

As I promised, I will soon publish basic work about this more as an experiment on how to use the mentioned commands.


----------



## Isoux (Feb 15, 2022)

Okay, I'm doing this as a token of *gratitude* to the people who have helped me reach my desired goal since the beginning of this topic.
This is my Orange Pi with a connected TFT display on a 40 pin connector, SPI0 channel.






In addition to the three lines that are directly connected to the SPI0 channel: pins PC0, PC2 and PC3,
It uses 3 more GPIO pins to control the display: PA12 as Reset, PA13 as DC (data or command protocol) and PA14 as BL (screen on and off).





I needed delays in milliseconds, so I made a simple msleep command without error handling. I call it from the script several times because direct handling of external devices requires delays ...


```
/* msleep.c    FreeBSD */
/* Simple milisleep function */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int
main(int argc, char *argv[])
{
    long res;
    useconds_t u_sec;
    res = strtol(argv[1], NULL, 10);
    u_sec = (useconds_t)res;
    u_sec *= 1000;
    usleep(u_sec);
    exit(0);
}
```
`:~ # cc -o msleep msleep.c`

And finally the script as glue for all commands.


```
#! /bin/tcsh -f
# $FreeBSD$
# Init and Draw background color

#set echo

alias reset        'gpioctl  RESET 0;./msleep 30;gpioctl  RESET 1'
alias DC_ctrl    'gpioctl  DC 0'
alias DC_data  'gpioctl  DC 1'
alias BL_off      'gpioctl  BL 0'
alias BL_on      'gpioctl  BL 1'
alias SPI_tx      'spi -d w -C'
alias SPI_ctrl    'DC_ctrl; SPI_tx'
alias SPI_data  'DC_data; SPI_tx'

# 16 bit colours
set BLACK  = (00 00)
set BLUE   = (00 1F)
set RED    = (F8 00)
set GREEN  = (05 E0)
set YELLOW = (FF 88)
set WHITE  = (FF FF)

# Set colour
set C = ($BLUE)

# For vertical lines loop
set Y = 160
set y = 0

# Init pins
gpioctl -n PA12 RESET
gpioctl -n PA13 DC
gpioctl -n PA14 BL
gpioctl -c RESET OUT
gpioctl -c DC OUT
gpioctl -c BL OUT

# Max SPI speed
# 33.333Mhz is max with good results
spi -s 33333333
reset
BL_off

#echo "init_cmds 1"
SPI_ctrl "01"; ./msleep 150                    # 1. cmd
SPI_ctrl "11"; ./msleep 255                    # 2. cmd
SPI_ctrl "B1"; SPI_data "01 2C 2D"       # 3. cmd
SPI_ctrl "B2"; SPI_data "01 2C 2D"            # 4. cmd
SPI_ctrl "B3"; SPI_data "01 2C 2D 01 2C 2D"    # 5. cmd
SPI_ctrl "B4"; SPI_data "07"                # 6. cmd
SPI_ctrl "C0"; SPI_data "A2 02 84"            # 7. cmd
SPI_ctrl "C1"; SPI_data "C5"                # 8. cmd
SPI_ctrl "C2"; SPI_data "0A 00"                # 9. cmd
SPI_ctrl "C3"; SPI_data "8A 2A"                # 10. cmd
SPI_ctrl "C4"; SPI_data "8A EE"                # 11. cmd
SPI_ctrl "C5"; SPI_data "0E"                # 12. cmd
SPI_ctrl "20"                                # 13. cmd
SPI_ctrl "36"; SPI_data "C0"                # 14. cmd
SPI_ctrl "3A"; SPI_data "05"                # 15. cmd

#echo "init_cmds 2"
SPI_ctrl "2A"; SPI_data "00 00 00 80"        # 1. cmd
SPI_ctrl "2B"; SPI_data "00 00 00 A0"        # 2. cmd

#echo "init_cmds 3"
SPI_ctrl "E0"; SPI_data "02 1c 07 12 37 32 29 2d 29 25 2B 39 00 01 03 10" # 1. cmd
SPI_ctrl "E1"; SPI_data "03 1d 07 06 2E 2C 29 2D 2E 2E 37 3F 00 00 02 10" # 2. cmd
SPI_ctrl "13"; ./msleep 10                           # 3. cmd
SPI_ctrl "29"; ./msleep 100                         # 4. cmd
BL_on

#Set_addr_win:
SPI_ctrl "2A"; SPI_data "00 02 00 81"        # 1. cmd
SPI_ctrl "2B"; SPI_data "00 00 00 A0"        # 2. cmd
SPI_ctrl "2C";

DC_data

# Draw background
while ($y <= $Y)
  @ y = $y + 1
  SPI_tx "$C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C  $C "
end
spi -i
```

And action ...






Thank you and sorry for the *ugly* video!

Source code for the ST7735 display driver:


----------



## covacat (Feb 16, 2022)

what's the cheatcode to watch '90s pr0n ?


----------



## aragats (Feb 16, 2022)

Since we're talking about GPIO API here, I think this is relevant too.
Does anybody know about GPIO interrupts support? The wiki page still shows them as "to do".


----------



## Isoux (Feb 16, 2022)

aragats said:


> Since we're talking about GPIO API here, I think this is relevant too.
> Does anybody know about GPIO interrupts support? The wiki page still shows them as "to do".


I just wanted to announce that I am going a step further on this started topic. After the CLI experiments, I will start writing the right code with gpio (3)() - The C library ... For now, I know nothing about the availability of GPIO interrupts support. If I discover something during the work, I will report it.


----------



## Isoux (Feb 16, 2022)

Something I could spot at first glance:

`:~ % gpioctl -l -v |grep PA11
pin 11:    1    PA11<>, caps:<IN,OUT,PU,PD,INTRLL,INTRLH,INTRER,INTREF,INTREB>
:~ % gpioctl -c PA11 IN INTRLL
Interrupt capability INTRLL cannot be set as configuration flag
:~ % gpioctl -l -v |grep PA11
pin 11:    1    PA11<IN>, caps:<IN,OUT,PU,PD,INTRLL,INTRLH,INTRER,INTREF,INTREB>`

So it accepts that the pin is declared as INPUT but does not accept to be INTERRUPT ...


----------



## obsigna (Feb 16, 2022)

aragats said:


> Since we're talking about GPIO API here, I think this is relevant too.
> Does anybody know about GPIO interrupts support? The wiki page still shows them as "to do".


See a respective thread on the ARM mailing list:


			Porting FreeBSD to ARM processors: User Space GPIO Interrupt programming - GSoC-2018
		


This resulted into the implementation of "userland gpio interrupts“ in December 2020.





						rS368585
					






					reviews.freebsd.org
				




This is working perfectly with FreeBSD 13.0-RELEASE on a BeagleBone Black. I cannot tell anything about the various Fruty Pis, though.


----------



## aragats (Feb 16, 2022)

Isoux said:


> does not accept to be INTERRUPT


gpioctl() doesn't list INTR* caps/flags, obviously it won't accept such configuration.
Interrupts are processed by kernel, it's not clear how to use them in user space.
Within a commercial project I'm involved in I wrote a Linux kernel module, which sends a signal to a userland program when an interrupt occurs. I'm not sure whether such approach is acceptable in general though.


----------



## aragats (Feb 16, 2022)

obsigna said:


> See a respective thread on the ARM mailing list:
> Porting FreeBSD to ARM processors: User Space GPIO Interrupt programming - GSoC-2018


Thanks, obsigna !
However, 2020 stuff is gone from that site, so, the valid link would be this.
There is also another patch PR 251390 which is discussed in the same email thread.


----------



## Isoux (Feb 16, 2022)

Thanks, obsigna & aragats !


----------



## obsigna (Feb 16, 2022)

aragats said:


> gpioctl() doesn't list INTR* caps/flags, obviously it won't accept such configuration.
> Interrupts are processed by kernel, it's not clear how to use them in user space.
> Within a commercial project I'm involved in I wrote a Linux kernel module, which sends a signal to a userland program when an interrupt occurs. I'm not sure whether such approach is acceptable in general though.


Here comes a tiny C program which utilizes the user space interrupts facility for receiving events from a rotary encoder and some buttons which are attached to GPIO pins of the BBB. Interrupt processing is very fast, and the encoder and the buttons need to be debounced. Otherwise pressing a button or turning the encoder gives up to 10 interrupts per action.

Here is a post, on how I debounced the encoder and the buttons.









						GPIO Ground lines
					

I have a GPIO question I have been meaning to ask.  So on your typical Arm GPIO board you have maybe 26 GPIO pins but only 8 Grounds.  How do you handle 26 LED's with only 8 grounds? Is it OK to co-mingle the grounds?  I am making a custom GPIO Lid for the APU1/2/3/4 with a ribbon cable to GPIO...




					forums.freebsd.org
				





```
//  encoder.c
//  Test tool for the Rotary Encoder and Buttons attached to the BBB's the GPIOs
//
//  Compilation: clang encoder.c -lpthread -lgpio -o encoder

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <math.h>
#include <termios.h>
#include <unistd.h>
#include <pthread.h>
#include <fcntl.h>
#include <err.h>
#include <libgpio.h>
#include <dev/iicbus/iic.h>
#include <sys/filio.h>
#include <sys/sysctl.h>
#include <sys/time.h>
#include <sys/types.h>


/*
   07   gpio2[ 2]     gpioctl -f /dev/gpioc2 -c  2 IN
   08   gpio2[ 3]     gpioctl -f /dev/gpioc2 -c  3 IN
   09   gpio2[ 5]     gpioctl -f /dev/gpioc2 -c  5 IN
   10   gpio2[ 4]     gpioctl -f /dev/gpioc2 -c  4 IN
   11   gpio1[13]     gpioctl -f /dev/gpioc1 -c 13 IN
   12   gpio1[12]     gpioctl -f /dev/gpioc1 -c 12 IN
   13   gpio0[23]     gpioctl -f /dev/gpioc0 -c 23 IN
   14   gpio0[26]     gpioctl -f /dev/gpioc0 -c 26 IN
   15   gpio1[15]     gpioctl -f /dev/gpioc1 -c 15 IN
   16   gpio1[14]     gpioctl -f /dev/gpioc1 -c 14 IN
   17   gpio0[27]     gpioctl -f /dev/gpioc0 -c 27 IN
   18   gpio2[ 1]     gpioctl -f /dev/gpioc2 -c  1 IN
   19   gpio0[22]     gpioctl -f /dev/gpioc0 -c 22 IN
*/

static inline double nanostamp(int64_t stamp)
{
   uint64_t ns = (1000000000*(stamp & 0xFFFFFFFFu) >> 32);
   return (int32_t)(stamp >> 32) + ns*1e-9;
}

#define CLK 2
#define DT  3
#define SW  4
#define BR  5

#define B1 12
#define B2 13
#define B3 14
#define B4 15


bool gRunning = true;

void *gpio1Events(void *gpio1_handle)
{
   gpio_handle_t gpio1 = *(gpio_handle_t *)gpio1_handle;
   ssize_t n, rc, rs = sizeof(struct gpio_event_detail);
   double  t;
   struct  gpio_event_detail buffer[64];

   while (gRunning)
   {
      if ((rc = read(gpio1, buffer, sizeof(buffer))) < 0)
         err(EXIT_FAILURE, "Cannot read from GPIO1");

      if (rc%rs != 0)
         err(EXIT_FAILURE, "%s: read() the odd count of %zd bytes from GPIO1\n", getprogname(), rc);

      else
      {
         n = rc/rs - 1;
         t = nanostamp(buffer[n].gp_time);
         printf("    - %12.9f\tGPIO1.%u \t%u\n", t, buffer[n].gp_pin, buffer[n].gp_pinstate);
      }
   }

   return NULL;
}


int main(int argc, char *const argv[])
{
   gpio_handle_t gpio1, gpio2;

   if ((gpio1 = gpio_open(1)) != GPIO_INVALID_HANDLE)
      if ((gpio2 = gpio_open(2)) != GPIO_INVALID_HANDLE)
      {
         gpio_config_t gcfg = {0, {}, 0, GPIO_PIN_INPUT|GPIO_INTR_EDGE_FALLING};
  
         // Button 1
         gcfg.g_pin = B1;
         gpio_pin_set_flags(gpio1, &gcfg);
  
         // Button 2
         gcfg.g_pin = B2;
         gpio_pin_set_flags(gpio1, &gcfg);
  
         // Button 3
         gcfg.g_pin = B3;
         gpio_pin_set_flags(gpio1, &gcfg);
  
         // Button 4
         gcfg.g_pin = B4;
         gpio_pin_set_flags(gpio1, &gcfg);
  
         // Encoder CLK
         gcfg.g_pin = CLK;
         gpio_pin_set_flags(gpio2, &gcfg);
  
         // Encoder SW
         gcfg.g_pin = SW;
         gpio_pin_set_flags(gpio2, &gcfg);
  
         // Reserve Button
         gcfg.g_pin = BR;
         gpio_pin_set_flags(gpio2, &gcfg);
  
         // Encoder DT pin
         gcfg.g_pin = DT;
         gcfg.g_flags = GPIO_PIN_INPUT|GPIO_INTR_NONE;
         gpio_pin_set_flags(gpio2, &gcfg);

         ssize_t   rc;
         pthread_t gpio1_events_thread;
         if ((rc = pthread_create(&gpio1_events_thread, NULL, gpio1Events, &gpio1)))
            err(EXIT_FAILURE, "Cannot create thread for permanently reading GPIO1 interrupts: %d.", rc);

         ssize_t n, rs = sizeof(struct gpio_event_detail);
         double  t;
         int     c = 0;
         struct  gpio_event_detail buffer[64];
  
         do
         {
            if ((rc = read(gpio2, buffer, sizeof(buffer))) < 0)
               err(EXIT_FAILURE, "Cannot read from GPIO2");
  
            if (rc%rs != 0)
               err(EXIT_FAILURE, "%s: read() the odd count of %zd bytes from GPIO2\n", getprogname(), rc);
  
            else
            {
               n = rc/rs - 1;
               t = nanostamp(buffer[n].gp_time);
  
               switch (buffer[n].gp_pin)
               {
                  case CLK:
                     c += (gpio_pin_get(gpio2, DT)) ? +1 : -1;
                     break;
  
                  case DT:
                     break;
  
                  case SW:
                  case BR:
                  default:
                     break;
               }
  
               printf("%5d %12.9f\tGPIO2.%u \t%u\t%zd\n", c, t, buffer[n].gp_pin, buffer[n].gp_pinstate, n);
            }
         } while (buffer[n].gp_pin != SW);
      }
  
      else
      {
         perror("GPIO2 Open");
         gpio_close(gpio1);
         exit(-1);
      }

   else
   {
      perror("GPIO1 Open");
      exit(-1);
   }
}
```


----------



## Isoux (Feb 16, 2022)

obsigna said:


> Here comes a tiny C program ...


Wow man, thanks a lot! You make my day!


----------



## Isoux (Feb 17, 2022)

obsigna said:


> This resulted into the implementation of "userland gpio interrupts“ in December 2020.
> 
> 
> 
> ...


These changes have already been accepted and implemented, I checked it in the code! 
There is also a test program gpioevenst:
`:~ # cd /usr/src/tools/test/gpioevents/
:/usr/src/tools/test/gpioevents # make
:/usr/src/tools/test/gpioevents # make install`

```
:~ % gpioevents
gpioevents: No pin number specified.
usage: gpioevents [-f ctldev] [-m method] [-s] [-n] [-S] [-u][-t timeout] [-d delay-usec] pin intr-config [pin intr-config ...]

  -d  delay before each call to read/poll/select/etc
  -n  Non-blocking IO
  -s  Single-shot (else loop continuously)
  -S  Report summary data (else report each event)
  -u  Show timestamps as UTC (else monotonic time)

Possible options for method:

  r    read (default)
  p    poll
  s    select
  k    kqueue
  a    aio_read (needs sysctl vfs.aio.enable_unsafe=1)
  i    signal-driven I/O

Possible options for intr-config:

  no     no interrupt
  er     edge rising
  ef     edge falling
  eb     edge both
:~ %
```
`:~ % gpioevents -f /dev/gpioc0 -s 11 ef
("waiting")`
For the reason of "ef" (edge falling) configuration and pin (11) state of 1 (high voltage) nothing happens ...
...
... but, after touching pin 11 with 0 voltage result is a quick response of interrupt:
`time 314635.811642768 pin 11 state 0
:~ %`

So it works great!
The next stage is to try to write a kernel module based on:





						251390 – new kernel module for GPIO input interrupt to kevent
					






					bugs.freebsd.org


----------

