sandric
Posts: 10
Joined: Tue Mar 19, 2019 2:05 pm

[SOLVED] Interfacing goodix overlay on i2c-gpio secondary i2c line?

Thu Oct 17, 2019 8:05 pm

I'm having trouble connecting Goodix touchpanel to rpi0w via secondary i2c-gpio pins. I found that you can create secondary i2c host via whats called "bit bashing". But trying to interface goodix touchscreen via those 2 SDA and SCL pins, I stumble across issue that touchpanel, which working perfectly via primary i2c port, does not recognized if all you do is change two pins from primary i2c to i2c_gpio pins.

Here's my setup:

I wrote my own goodix overlay, copying from some source I found, in /home/pi/goodix2-overlay.dts:

Code: Select all

// Device tree overlay for I2C connected Goodix gt9271 multiple touch controller
// Acme Systems version for 7 inch DPI display
/dts-v1/;
/plugin/;

/ {
        compatible = "brcm,bcm2835";

        fragment@0 {
                target = <&gpio>;
                __overlay__ {
                        goodix_pins: goodix_pins {
                                brcm,pins = <4 17>; // interrupt and reset
                                brcm,function = <0 0>; // in
                                brcm,pull = <2 2>; // pull-up
                        };
                };
        };

        fragment@1 {
                target = <&i2c1>;
                __overlay__ {
                        #address-cells = <1>;
                        #size-cells = <0>;
                        status = "okay";

                        gt9271: gt9271@14 {
                                compatible = "goodix,gt9271";
                                reg = <0x14>;
                                pinctrl-names = "default";
                                pinctrl-0 = <&goodix_pins>;
                                interrupt-parent = <&gpio>;
                                interrupts = <4 2>; // high-to-low edge triggered
                                irq-gpios = <&gpio 4 0>; 
                                reset-gpios = <&gpio 17 0>;
                        };
                };
        };
};

Then I compiled it via:

Code: Select all

sudo dtc -I dts -O dtb -o /boot/overlays/goodix2.dtbo goodix2-overlay.dts

And added it to my /boot/config.txt via line:

Code: Select all

dtoverlay=goodix2

So my full /boot/config.txt:

Code: Select all

# For more options and information see
# http://rpf.io/configtxt
# Some settings may impact device functionality. See link above for details

# uncomment if you get no picture on HDMI for a default "safe" mode
#hdmi_safe=1

# uncomment this if your display has a black border of unused pixels visible
# and your display can output without overscan
#disable_overscan=1

# uncomment the following to adjust overscan. Use positive numbers if console
# goes off screen, and negative if there is too much border
#overscan_left=16
#overscan_right=16
#overscan_top=16
#overscan_bottom=16

# uncomment to force a console size. By default it will be display's size minus
# overscan.
#framebuffer_width=1280
#framebuffer_height=720

# uncomment if hdmi display is not detected and composite is being output
#hdmi_force_hotplug=1

# uncomment to force a specific HDMI mode (this will force VGA)
#hdmi_group=1
#hdmi_mode=1

# uncomment to force a HDMI mode rather than DVI. This can make audio work in
# DMT (computer monitor) modes
#hdmi_drive=2

# uncomment to increase signal to HDMI, if you have interference, blanking, or
# no display
#config_hdmi_boost=4

# uncomment for composite PAL
#sdtv_mode=2

#uncomment to overclock the arm. 700 MHz is the default.
#arm_freq=800

# Uncomment some or all of these to enable the optional hardware interfaces
dtparam=i2c_arm=on
#dtparam=i2s=on
#dtparam=spi=on

# Uncomment this to enable the lirc-rpi module
#dtoverlay=lirc-rpi

# Additional overlays and parameters are documented /boot/overlays/README

# Enable audio (loads snd_bcm2835)
# dtparam=audio=on
dtoverlay=dwc2
dtoverlay=goodix2

Wiring:

Image

After rebooting, in terminal I see one i2c adapter:

Code: Select all

pi@raspberrypi:~ $ sudo i2cdetect -l
i2c-1   i2c             bcm2835 I2C adapter                     I2C adapter

And detected touchscreen on 0x14 address on this adapter:

Code: Select all

pi@raspberrypi:~ $ sudo i2cdetect -y 1
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- UU -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --

As result I see /dev/input/event0 file, that I can perfectly monitor with evtest:

Code: Select all

pi@raspberrypi:~ $ ls -la /dev/input
total 0
drwxr-xr-x  3 root root     120 Oct 17 03:49 .
drwxr-xr-x 14 root root    3320 Oct 17 03:49 ..
drwxr-xr-x  2 root root      60 Oct 17 03:49 by-path
crw-rw----  1 root input 13, 64 Oct 17 03:49 event0
crw-rw----  1 root input 13, 63 Oct 17 03:49 mice
crw-rw----  1 root input 13, 32 Oct 17 03:49 mouse0

So far all work just good. But now I'll add i2c-gpio overlay to interface secondary i2c line on 23 and 24 GPIO ports via that line in /boot/config.txt:

Code: Select all

dtoverlay=i2c-gpio,bus=4,i2c_gpio_sda=23,i2c_gpio_scl=24

And change "target = <&i2c1>" line to "target = <&i2c3>" in my touchscreen overlay:
/home/pi/goodix2-overlay.dts :

Code: Select all

// Device tree overlay for I2C connected Goodix gt9271 multiple touch controller
// Acme Systems version for 7 inch DPI display
/dts-v1/;
/plugin/;

/ {
        compatible = "brcm,bcm2835";

        fragment@0 {
                target = <&gpio>;
                __overlay__ {
                        goodix_pins: goodix_pins {
                                brcm,pins = <4 17>; // interrupt and reset
                                brcm,function = <0 0>; // in
                                brcm,pull = <2 2>; // pull-up
                        };
                };
        };

        fragment@1 {
                target = <&i2c3>;
                __overlay__ {
                        #address-cells = <1>;
                        #size-cells = <0>;
                        status = "okay";

                        gt9271: gt9271@14 {
                                compatible = "goodix,gt9271";
                                reg = <0x14>;
                                pinctrl-names = "default";
                                pinctrl-0 = <&goodix_pins>;
                                interrupt-parent = <&gpio>;
                                interrupts = <4 2>; // high-to-low edge triggered
                                irq-gpios = <&gpio 4 0>; 
                                reset-gpios = <&gpio 17 0>;
                        };
                };
        };
};

Compile it again:

Code: Select all

sudo dtc -I dts -O dtb -o /boot/overlays/goodix2.dtbo goodix2-overlay.dts

And now this is my updated config.txt:

Code: Select all

# For more options and information see
# http://rpf.io/configtxt
# Some settings may impact device functionality. See link above for details

# uncomment if you get no picture on HDMI for a default "safe" mode
#hdmi_safe=1

# uncomment this if your display has a black border of unused pixels visible
# and your display can output without overscan
#disable_overscan=1

# uncomment the following to adjust overscan. Use positive numbers if console
# goes off screen, and negative if there is too much border
#overscan_left=16
#overscan_right=16
#overscan_top=16
#overscan_bottom=16

# uncomment to force a console size. By default it will be display's size minus
# overscan.
#framebuffer_width=1280
#framebuffer_height=720

# uncomment if hdmi display is not detected and composite is being output
#hdmi_force_hotplug=1

# uncomment to force a specific HDMI mode (this will force VGA)
#hdmi_group=1
#hdmi_mode=1

# uncomment to force a HDMI mode rather than DVI. This can make audio work in
# DMT (computer monitor) modes
#hdmi_drive=2

# uncomment to increase signal to HDMI, if you have interference, blanking, or
# no display
#config_hdmi_boost=4

# uncomment for composite PAL
#sdtv_mode=2

#uncomment to overclock the arm. 700 MHz is the default.
#arm_freq=800

# Uncomment some or all of these to enable the optional hardware interfaces
dtparam=i2c_arm=on
#dtparam=i2s=on
#dtparam=spi=on

# Uncomment this to enable the lirc-rpi module
#dtoverlay=lirc-rpi

# Additional overlays and parameters are documented /boot/overlays/README

# Enable audio (loads snd_bcm2835)
# dtparam=audio=on
dtoverlay=dwc2
dtoverlay=i2c-gpio,bus=4,i2c_gpio_sda=23,i2c_gpio_scl=24
dtoverlay=goodix2

Wiring:
Image


After reboot I do see successful mounting of secondary i2c@4 adapter:

Code: Select all

pi@raspberrypi:~ $ sudo i2cdetect -l
i2c-3   i2c             i2c@4                                   I2C adapter
i2c-1   i2c             bcm2835 I2C adapter                     I2C adapter

But when I try to detect touchscreen on i2c-3 channel, I see not "UU", but "14". Which is right goodix address, but not flagged with "UU" as in successful example with primary i2c line:

Code: Select all

pi@raspberrypi:~ $ sudo i2cdetect -y 3
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- 14 -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --

And no /dev/input/event0 file to monitor via evtest:

Code: Select all

pi@raspberrypi:~ $ ls -la /dev/input
total 0
drwxr-xr-x  2 root root      60 Jan  1  1970 .
drwxr-xr-x 14 root root    3320 Oct 17 03:42 ..
crw-rw----  1 root input 13, 63 Oct 17 03:42 mice

So as you can see smth is happening on stage of mounting my goodix2 overlay on i2c-gpio line. i2c@4 adapter is mounted, /dev/i2c-1 and /dev/i2c-3 devices both exists under /dev directory, but for some reason no /dev/input/event0 and no "UU" flag via i2cdetect.
So problem is in goodix2-overlay.dts, right?

I tried change 'compatible = "brcm,bcm2835";' line to 'compatible = "i2c-gpio";', tried to change 'target = <&i2c3>;' line to interface <&i2c4>, <&i2c5>, <&i2c6> - no difference.

I total noob to linux kernel and device trees, but reading through https://www.raspberrypi.org/documentati ... ce-tree.md manual, I didn't found any clue to solution.

Can anyone spot error in my setup? Thx.

P.S. I found out that if connecting touchscreen on primary i2c line and everything works, you plug out and back in SDA or SCL wire - you will also get "14" instead of "UU" flag via i2cdetect and evtest /dev/input/event0 will stop working. So maybe its some king of racing condition on i2c-gpio and goodix2 overlays get mounted?

PhilE
Raspberry Pi Engineer & Forum Moderator
Raspberry Pi Engineer & Forum Moderator
Posts: 2441
Joined: Mon Sep 29, 2014 1:07 pm
Location: Cambridge

Re: Interfacing goodix overlay on i2c-gpio secondary i2c line?

Fri Oct 18, 2019 9:09 am

The firmware can't apply the second version of your overlay because it can't resolve "&i2c3" in the base DTB.

"&i2c3" is a reference to the label "i2c3". In a normal, non-overlay DTB, when the dtc compiler finds a label on a node it gives that node a unique "phandle" value (think of it as a bookmark), then when it finds a reference to that label it replaces it with the respective value. Overlays complicate matters because some symbols/labels in an overlay may remain unresolved until it is applied to a base DTB, but the concept is the same.

The i2c-gpio overlay creates a node in the Device Tree that declares a new I2C bus, one with a driver that bit-bashes the protocol over any arbitrary GPIOs. The I2C subsystem gives this I2C bus a number (and the "bus" overlay parameter allows the user to choose that number), but it doesn't add a new label or symbol to the base DTB. Actually, that's not true - it does add a symbol, but it's called "i2c_gpio" and it points to the wrong location if the "bus" parameter has been used.

The solution for you may be fairly straightforward. Since i2c-gpio is bit-bashed there is nothing to stop your overlay creating a new instance of it. Provided all the devices on that I2C bus are declared within the same overlay (by which I mean provided you aren't trying to share that bus with another overlay) then you can combine an instance of the i2c-gpio overlay with your overlay. My ovmerge utility will do most of the work for you:

Code: Select all

$ ovmerge i2c-gpio-overlay.dts goodix2-overlay.dts > goodix3-overlay.dts
You can find the i2c-gpio overlay here. After the merge you just need to remove any parts you don't need (like the "bus" parameter"), and make sure the labels match. Give it a try, and come back if you have problems.

And while we're talking about non-standard I2C buses, I'd like to recommend including a proper pull-up resistor on the bus - ~4kOhm is the usual value. You may get away with the internal GPIO pull-up with a single device on the bus, but you may also get unreliability under certain conditions.

sandric
Posts: 10
Joined: Tue Mar 19, 2019 2:05 pm

Re: Interfacing goodix overlay on i2c-gpio secondary i2c line?

Mon Oct 21, 2019 5:37 pm

Thanks a lot, I got it working now. The problem appeared when I wanted to use 2 goodix touchscreens connected
together on both i2c lines. For some reason, if I declare two drivers each setting goodix pins on "target = <&i2c1>;" and "target = <&i2c_gpio>;" and write 2 dtoverlay lines in config.txt for it - it gets overwritten by second, I have no idea why. So I tried to write both goodix i2c lines all in 1 file, so here it is, working now:

Code: Select all

/dts-v1/;
/plugin/;

/ {
	compatible = "brcm,bcm2835";
	fragment@0 {
		target-path = "/";
		__overlay__ {
			i2c_gpio: i2c@4 {
				reg = <0xffffffff>;
				compatible = "i2c-gpio";
				gpios = <&gpio 23 0 &gpio 24 0>;
				i2c-gpio,delay-us = <2>;
				#address-cells = <1>;
				#size-cells = <0>;
			};
		};
	};
	fragment@1 {
		target-path = "/aliases";
		__overlay__ {
			i2c_gpio = "/i2c@4";
		};
	};
	fragment@2 {
 		target-path = "/__symbols__";
		__overlay__ {
			i2c_gpio = "/i2c@4";
		};
	};
  fragment@3 {
		target = <&gpio>;
		__overlay__ {
			first_goodix_pins: first_goodix_pins {
				brcm,pins = <20 21>;
				brcm,function = <0 0>;
				brcm,pull = <2 2>;
			};
		};
	};
  fragment@4 {
		target = <&gpio>;
		__overlay__ {
			second_goodix_pins: second_goodix_pins {
				brcm,pins = <4 17>;
				brcm,function = <0 0>;
				brcm,pull = <2 2>;
			};
		};
	};
  fragment@5 {
    target = <&i2c1>;
    __overlay__ {
      #address-cells = <1>;
      #size-cells = <0>;
      status = "okay";

      gt9271@14 {
        compatible = "goodix,gt9271";
        reg = <0x14>;
        pinctrl-names = "default";
        pinctrl-0 = <&first_goodix_pins>;
        interrupt-parent = <&gpio>;
        interrupts = <20 2>;
        irq-gpios = <&gpio 20 0>;
        reset-gpios = <&gpio 21 0>;
      };
    };
  };
	fragment@6 {
		target = <&i2c_gpio>;
		__overlay__ {
			#address-cells = <1>;
			#size-cells = <0>;
			status = "okay";
			gt9271@14 {
				compatible = "goodix,gt9271";
				reg = <0x14>;
				pinctrl-names = "default";
				pinctrl-0 = <&second_goodix_pins>;
				interrupt-parent = <&gpio>;
				interrupts = <4 2>;
				irq-gpios = <&gpio 4 0>;
				reset-gpios = <&gpio 17 0>;
			};
		};
	};
	__overrides__ {
		i2c_gpio_sda = <&i2c_gpio>, "gpios:4";
		i2c_gpio_scl = <&i2c_gpio>, "gpios:16";
		i2c_gpio_delay_us = <&i2c_gpio>, "i2c-gpio,delay-us:0";
		bus = <&i2c_gpio>, "reg:0";
	};
};

Return to “Device Tree”