【LuckFox Pico 开发板免费试用】3. 通过fbtft点亮st7735屏幕 - RISC-V MCU技术社区 - 电子技术william hill官网 - 广受欢迎的专业电子william hill官网 - 威廉希尔官方网站
分享 收藏 返回

voidpbq 关注 私信
[文章]

【LuckFox Pico 开发板免费试用】3. 通过fbtft点亮st7735屏幕

前言

本章使用fbtft添加spi lcd st7735/gc9306。
fbtft生成fb0设备,后续通过lvgl可以实现自定义界面绘制。

一、威廉希尔官方网站 图

使用开发板的spi0的scl以及mosi,其余的复用引脚实现,把lcd分配在一起。

二、dtsi

luckfox-pico-main\sysdrv\source\kernel\arch\arm\boot\dts\rv1103g-luckfox-pico.dts

注意先将之前的spi0注销掉。

最前面的配置普通gpio比较简单,仿照hx711实现的即可,注意结合自己的io引脚实现。

spi0定义的spi0m0_pins中默认是打开了miso的,但是由于我这个spi屏幕不需要输入,所以直接复用了。

部分参数的意义加了注释,方便理解。

/**********spi**********/
/{
	/*LCD_CS -- USE MISO*/
    gpio1pc3:gpio1pc3 {
        compatible = "regulator-fixed";
        pinctrl-names = "default";
        pinctrl-0 = <&gpio1_pc3>;
        regulator-name = "gpio1_pc3";
        regulator-always-on;
    };

	/*LCD_BL*/
	gpio0pa4:gpio0pa4 {
		compatible = "regulator-fixed";
		pinctrl-names = "default";
		pinctrl-0 = <&gpio0_pa4>;
		regulator-name = "gpio0_pa4";
		regulator-always-on;
	};

	/*LCD_DC*/
    gpio1pd0:gpio1pd0 {
        compatible = "regulator-fixed";
        pinctrl-names = "default";
        pinctrl-0 = <&gpio1_pd0>;
        regulator-name = "gpio1_pd0";
        regulator-always-on;
    };

	/*LCD_RES*/
    gpio1pd1:gpio1pd1 {
        compatible = "regulator-fixed";
        pinctrl-names = "default";
        pinctrl-0 = <&gpio1_pd1>;
        regulator-name = "gpio1_pd1";
        regulator-always-on;
    };
};

&pinctrl {
	/*LCD_CS -- USE MISO*/
    gpio1-pc3 {
        gpio1_pc3:gpio1-pc3 {
            rockchip,pins = <1 RK_PC3 RK_FUNC_GPIO &pcfg_pull_none>;
        };
    };

	/*LCD_BL*/
	gpio0-pa4 {
		gpio0_pa4:gpio0-pa4 {
			rockchip,pins =	<0 RK_PA4 RK_FUNC_GPIO &pcfg_pull_none>;
		};
	};

	/*LCD_DC*/
    gpio1-pd0 {
        gpio1_pd0:gpio1-pd0 {
            rockchip,pins = <1 RK_PD0 RK_FUNC_GPIO &pcfg_pull_none>;
        };
    };

	/*LCD_RES*/
    gpio1-pd1 {
        gpio1_pd1:gpio1-pd1 {
            rockchip,pins = <1 RK_PD1 RK_FUNC_GPIO &pcfg_pull_none>;
        };
    };

    spi0 {
        /omit-if-no-ref/
        spi0m0_pins: spi0m0-pins {
            rockchip,pins =
                /* spi0_clk_m0 */
                <1 RK_PC1 4 &pcfg_pull_none>,
                /* spie_miso_m0 */
                /* <1 RK_PC3 6 &pcfg_pull_none>, */	// 先不动,还用uart4作为bl
                /* spi_mosi_m0 */
                <1 RK_PC2 6 &pcfg_pull_none>;
        };
    };
};

&spi0 {
	status = "okay";
	pinctrl-names = "default";
	pinctrl-0 = <&spi0m0_pins>;		// 包含clk,mi,mo
	// cs-gpios = <&gpio1 RK_PC0 1>;// 片选,也可以用spi0m0_cs0代替,需要确认pinctrl中是否定义了,1表示高电平有效
	// cs-gpios = <&gpio1 26 1>;	// 26=gpio1C2=3(C)*8+2
	#address-cells = <1>;			// 挂载设备的描述位,比如两个设备就是0,1,设1,若四个则是00-10,设2
	#size-cells = <0>;				// 默认不可改
	/*
	spidev@0 {						// 模拟出spi0设备,0对应的spi下挂载的设备号,和reg一致
		compatible = "rockchip,spidev";
		spi-max-frequency = <1000000000>;
		reg = <0>;
	};
	*/

	lcd: lcd@0{						// 若添加第二个lcd,这里选1
		status = "okay";
		compatible = "sitronix,st7735"; //"sitronix,gc9306"	//后续验证另一个lcd直接改名
		reg = <0>;					// 若添加第二个lcd,对应选1

		spi-max-frequency = <6000000>;	// 24M	由于我的逻辑分析仪最高只能24Mhz,所以设置6Mhz,其实可以设为48M
		spi-cpol;
		spi-cpha;
		rotate = <0>;				// 旋转角度,lcd驱动里会读取并设置对应寄存器
		fps = <30>;
		rgb;
		buswidth = <8>;

		cs = <&gpio1 RK_PC3 GPIO_ACTIVE_LOW>;		//spi0_miso
		led = <&gpio0 RK_PA4 GPIO_ACTIVE_LOW>;		//BL
		dc = <&gpio1 RK_PD0 GPIO_ACTIVE_HIGH>;		//DC
		reset = <&gpio1 RK_PD1 GPIO_ACTIVE_LOW>;	//RES

		debug = <0x7>;
	};
};

三、makefile——添加驱动

# luckfox-pico\sysdrv\source\kernel\drivers\staging\fbtft\Makefile
obj-$(CONFIG_FB_TFT_GC9306)     += fb_gc9306.o
obj-$(CONFIG_FB_TFT_ST7735)     += fb_st7735.o

# luckfox-pico\sysdrv\source\kernel\drivers\staging\Makefile
obj-$(CONFIG_FB_TFT)		+= fbtft/

四、Kconfig——定义驱动

# luckfox-pico\sysdrv\source\kernel\drivers\staging\fbtft\Kconfig
config FB_TFT_GC9306
	tristate "FB driver for the GC9306 LCD Controller"
	depends on FB_TFT
	help
	  Generic Framebuffer support for GC9306

config FB_TFT_ST7735
	tristate "FB driver for the GC9306 LCD Controller"
	depends on FB_TFT
	help
	  Generic Framebuffer support for ST7735

五、deconfig——编译驱动

luckfox-pico\sysdrv\source\kernel\arch\arm\configs\luckfox_rv1106_linux_defconfig

# spi lcd -- st7735s
CONFIG_SPI_MASTER=y
CONFIG_SPI_DESIGNWARE=y
CONFIG_SPI_DW_MMIO=y
CONFIG_FB=y
CONFIG_FB_TFT=y
CONFIG_FB_TFT_ST7735=y
CONFIG_FB_TFT_GC9306=y

六、更改fbtft驱动

由于内核版本变更,可能有写接口不适用。
对比milkv比较好添加驱动,而luckfox的改动又不同。

主要是fbtft-core.c的改动

  1. 添加头文件,用于获取dtsi中引脚的高低有效电平配置
  2. 更改fbtft_request_one_gpio
  3. 更改fbtft_reset,添加cs引脚设置
  4. 改变led-gpio为led

luckfox-pico\sysdrv\source\kernel\drivers\staging\fbtft\fbtft-core.c

#include <linux/gpio.h> //add
#include <linux/of_gpio.h> //add


static int fbtft_request_one_gpio(struct fbtft_par *par,
                  const char *name, int index,
                  struct gpio_desc **gpiop)
{
    struct device *dev = par->info->device;
    struct device_node *node = dev->of_node;
    int gpio, flags, ret = 0;
    enum of_gpio_flags of_flags;
    if (of_find_property(node, name, NULL)) {
        gpio = of_get_named_gpio_flags(node, name, index, &of_flags);
        if (gpio == -ENOENT)
            return 0;
        if (gpio == -EPROBE_DEFER)
            return gpio;
        if (gpio < 0) {
            dev_err(dev,
                "failed to get '%s' from DT\n", name);
            return gpio;
        }
         //active low translates to initially low
        flags = (of_flags & OF_GPIO_ACTIVE_LOW) ? GPIOF_OUT_INIT_LOW :
                            GPIOF_OUT_INIT_HIGH;
        ret = devm_gpio_request_one(dev, gpio, flags,
                        dev->driver->name);
        if (ret) {
            dev_err(dev,
                "gpio_request_one('%s'=%d) failed with %d\n",
                name, gpio, ret);
            return ret;
        }

        *gpiop = gpio_to_desc(gpio);
        fbtft_par_dbg(DEBUG_REQUEST_GPIOS, par, "%s: '%s' = GPIO%d\n",
                            __func__, name, gpio);
    }

    return ret;
}


static void fbtft_reset(struct fbtft_par *par)
{
	if (!par->gpio.reset)
		return;

	fbtft_par_dbg(DEBUG_RESET, par, "%s()\n", __func__);

	gpiod_set_value_cansleep(par->gpio.reset, 1);
	usleep_range(20, 40);
	gpiod_set_value_cansleep(par->gpio.reset, 0);
	msleep(120);
	gpiod_set_value_cansleep(par->gpio.reset, 1);
	msleep(120);

	gpiod_set_value_cansleep(par->gpio.cs, 0);  /* Activate chip */
	msleep(120);
}


// 这里也可以设置led-gpios,但是你fbtft_request_gpios中也要相应改变。
static struct fbtft_platform_data *fbtft_properties_read(struct device *dev)
{
	struct fbtft_platform_data *pdata;

	if (!dev_fwnode(dev)) {
		dev_err(dev, "Missing platform data or properties\n");
		return ERR_PTR(-EINVAL);
	}

	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
	if (!pdata)
		return ERR_PTR(-ENOMEM);

	pdata->display.width = fbtft_property_value(dev, "width");
	pdata->display.height = fbtft_property_value(dev, "height");
	pdata->display.regwidth = fbtft_property_value(dev, "regwidth");
	pdata->display.buswidth = fbtft_property_value(dev, "buswidth");
	pdata->display.backlight = fbtft_property_value(dev, "backlight");
	pdata->display.bpp = fbtft_property_value(dev, "bpp");
	pdata->display.debug = fbtft_property_value(dev, "debug");
	pdata->rotate = fbtft_property_value(dev, "rotate");
	pdata->bgr = device_property_read_bool(dev, "bgr");
	pdata->fps = fbtft_property_value(dev, "fps");
	pdata->txbuflen = fbtft_property_value(dev, "txbuflen");
	pdata->startbyte = fbtft_property_value(dev, "startbyte");
	device_property_read_string(dev, "gamma", (const char **)&pdata->gamma);

	if (device_property_present(dev, "led"))
		pdata->display.backlight = 1;
	if (device_property_present(dev, "init"))
		pdata->display.fbtftops.init_display =
			fbtft_init_display_from_property;

	pdata->display.fbtftops.request_gpios = fbtft_request_gpios;

	return pdata;
}

七、git diff

总结git改动,后面是新增的文件。

diff --git a/sysdrv/source/kernel/arch/arm/boot/dts/rv1103g-luckfox-pico.dts b/sysdrv/source/kernel/arch/arm/boot/dts/rv1103g-luckfox-pico.dts
index 0f1a686fc..fd4f767a5 100644
--- a/sysdrv/source/kernel/arch/arm/boot/dts/rv1103g-luckfox-pico.dts
+++ b/sysdrv/source/kernel/arch/arm/boot/dts/rv1103g-luckfox-pico.dts
[url=home.php?mod=space&uid=1999721]@@[/url] -143,33 +143,18 @@ &i2c3 {
 	clock-frequency = <100000>;
 };
 
-// /**********SPI**********/
-&spi0 {
-	status = "okay";
-	pinctrl-names = "default";
-	pinctrl-0 = <&spi0m0_pins>;
-	cs-gpios = <&gpio1 RK_PC0 1>;
-	// cs-gpios = <&gpio1 26 1>;
-	#address-cells = <1>;
-	#size-cells = <0>;
-	spidev@0 {
-		compatible = "rockchip,spidev";
-		spi-max-frequency = <1000000000>;
-		reg = <0>;
-	};
-};
 
 // /**********UART**********/
-&uart3 {
-	status = "okay";
-	pinctrl-names = "default";
-	pinctrl-0 = <&uart3m1_xfer>;
-};
-&uart4 {
-	status = "okay";
-	pinctrl-names = "default";
-	pinctrl-0 = <&uart4m1_xfer>;
-};
+// &uart3 {
+// 	status = "okay";
+// 	pinctrl-names = "default";
+// 	pinctrl-0 = <&uart3m1_xfer>;
+// };
+// &uart4 {
+// 	status = "okay";
+// 	pinctrl-names = "default";
+// 	pinctrl-0 = <&uart4m1_xfer>;
+// };
 // &uart5 {
 // 	status = "okay";
 // 	pinctrl-names = "default";
@@ -178,18 +163,18 @@ &uart4 {
 
 /**********PWM**********/
 
-&pwm0 {
-	status = "okay";
-	pinctrl-names = "active";
-	pinctrl-0 = <&pwm0m0_pins>;
-	// pinctrl-0 = <&pwm0m1_pins>;
-};
-&pwm1 {
-	status = "okay";
-	pinctrl-names = "active";
-	pinctrl-0 = <&pwm1m0_pins>;
-	// pinctrl-0 = <&pwm1m1_pins>;
-};
+// &pwm0 {
+// 	status = "okay";
+// 	pinctrl-names = "active";
+// 	pinctrl-0 = <&pwm0m0_pins>;
+// 	// pinctrl-0 = <&pwm0m1_pins>;
+// };
+// &pwm1 {
+// 	status = "okay";
+// 	pinctrl-names = "active";
+// 	pinctrl-0 = <&pwm1m0_pins>;
+// 	// pinctrl-0 = <&pwm1m1_pins>;
+// };
 
 // &pwm2 {
 // 	status = "okay";
@@ -234,21 +219,187 @@ &pwm1 {
 // 	pinctrl-0 = <&pwm9m0_pins>;
 // };
 
-&pwm10 {
-	status = "okay";
-	pinctrl-names = "active";
-	pinctrl-0 = <&pwm10m1_pins>;
-	// pinctrl-0 = <&pwm10m2_pins>;
-	// pinctrl-0 = <&pwm10m0_pins>;
+// &pwm10 {
+// 	status = "okay";
+// 	pinctrl-names = "active";
+// 	pinctrl-0 = <&pwm10m1_pins>;
+// 	// pinctrl-0 = <&pwm10m2_pins>;
+// 	// pinctrl-0 = <&pwm10m0_pins>;
+// };
+// &pwm11 {
+// 	status = "okay";
+// 	pinctrl-names = "active";
+// 	pinctrl-0 = <&pwm11m1_pins>;
+// 	// pinctrl-0 = <&pwm11m2_pins>;
+// 	// pinctrl-0 = <&pwm11m0_pins>;
+// };
+
+
+
+/**********iio**********/
+/{
+    /* hx711 clk */
+    gpio1pa2:gpio1pa2 {
+        compatible = "regulator-fixed";
+        pinctrl-names = "default";
+        pinctrl-0 = <&gpio1_pa2>;
+        regulator-name = "gpio1_pa2";
+        regulator-always-on;
+    };
+
+    /* hx711 sda */
+    gpio1pc0:gpio1pc0 {
+        compatible = "regulator-fixed";
+        pinctrl-names = "default";
+        pinctrl-0 = <&gpio1_pc0>;
+        regulator-name = "gpio1_pc0";
+        regulator-always-on;
+    };
 };
-&pwm11 {
-	status = "okay";
-	pinctrl-names = "active";
-	pinctrl-0 = <&pwm11m1_pins>;
-	// pinctrl-0 = <&pwm11m2_pins>;
-	// pinctrl-0 = <&pwm11m0_pins>;
+
+&pinctrl {
+    /* hx711 clk */
+    gpio1-pa2 {
+        gpio1_pa2:gpio1-pa2 {
+            rockchip,pins = <1 RK_PA2 RK_FUNC_GPIO &pcfg_pull_none>;
+        };
+    };
+
+    /* hx711 sda */
+    gpio1-pc0 {
+        gpio1_pc0:gpio1-pc0 {
+            rockchip,pins = <1 RK_PC0 RK_FUNC_GPIO &pcfg_pull_none>;
+        };
+    };
+};
+
+/ {
+    hx711:hx711 {
+        status = "okay";
+        compatible = "avia,hx711";
+        sck-gpios = <&gpio1 RK_PA2 GPIO_ACTIVE_HIGH>;    /* clk */
+        dout-gpios = <&gpio1 RK_PC0 GPIO_ACTIVE_HIGH>;   /* sda */
+        avdd-supply = <&vcc_3v3>;//vcc3v3_sys
+        clock-frequency = <400000>;
+    };
 };
 
+/**********spi**********/
+/{
+	/*LCD_CS -- USE MISO*/
+    gpio1pc3:gpio1pc3 {
+        compatible = "regulator-fixed";
+        pinctrl-names = "default";
+        pinctrl-0 = <&gpio1_pc3>;
+        regulator-name = "gpio1_pc3";
+        regulator-always-on;
+    };
+
+	/*LCD_BL*/
+	gpio0pa4:gpio0pa4 {
+		compatible = "regulator-fixed";
+		pinctrl-names = "default";
+		pinctrl-0 = <&gpio0_pa4>;
+		regulator-name = "gpio0_pa4";
+		regulator-always-on;
+	};
+
+	/*LCD_DC*/
+    gpio1pd0:gpio1pd0 {
+        compatible = "regulator-fixed";
+        pinctrl-names = "default";
+        pinctrl-0 = <&gpio1_pd0>;
+        regulator-name = "gpio1_pd0";
+        regulator-always-on;
+    };
+
+	/*LCD_RES*/
+    gpio1pd1:gpio1pd1 {
+        compatible = "regulator-fixed";
+        pinctrl-names = "default";
+        pinctrl-0 = <&gpio1_pd1>;
+        regulator-name = "gpio1_pd1";
+        regulator-always-on;
+    };
+};
 
+&pinctrl {
+	/*LCD_CS -- USE MISO*/
+    gpio1-pc3 {
+        gpio1_pc3:gpio1-pc3 {
+            rockchip,pins = <1 RK_PC3 RK_FUNC_GPIO &pcfg_pull_none>;
+        };
+    };
+
+	/*LCD_BL*/
+	gpio0-pa4 {
+		gpio0_pa4:gpio0-pa4 {
+			rockchip,pins =	<0 RK_PA4 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+	};
 
+	/*LCD_DC*/
+    gpio1-pd0 {
+        gpio1_pd0:gpio1-pd0 {
+            rockchip,pins = <1 RK_PD0 RK_FUNC_GPIO &pcfg_pull_none>;
+        };
+    };
+
+	/*LCD_RES*/
+    gpio1-pd1 {
+        gpio1_pd1:gpio1-pd1 {
+            rockchip,pins = <1 RK_PD1 RK_FUNC_GPIO &pcfg_pull_none>;
+        };
+    };
+
+    spi0 {
+        /omit-if-no-ref/
+        spi0m0_pins: spi0m0-pins {
+            rockchip,pins =
+                /* spi0_clk_m0 */
+                <1 RK_PC1 4 &pcfg_pull_none>,
+                /* spie_miso_m0 */
+                /* <1 RK_PC3 6 &pcfg_pull_none>, */	// 先不动,还用uart4作为bl
+                /* spi_mosi_m0 */
+                <1 RK_PC2 6 &pcfg_pull_none>;
+        };
+    };
+};
 
+&spi0 {
+	status = "okay";
+	pinctrl-names = "default";
+	pinctrl-0 = <&spi0m0_pins>;		// 包含clk,mi,mo
+	// cs-gpios = <&gpio1 RK_PC0 1>;// 片选,也可以用spi0m0_cs0代替,需要确认pinctrl中是否定义了,1表示高电平有效
+	// cs-gpios = <&gpio1 26 1>;	// 26=gpio1C2=3(C)*8+2
+	#address-cells = <1>;			// 挂载设备的描述位,比如两个设备就是0,1,设1,若四个则是00-10,设2
+	#size-cells = <0>;				// 默认不可改
+	/*
+	spidev@0 {						// 模拟出spi0设备,0对应的spi下挂载的设备号,和reg一致
+		compatible = "rockchip,spidev";
+		spi-max-frequency = <1000000000>;
+		reg = <0>;
+	};
+	*/
+
+	lcd: lcd@0{						// 若添加第二个lcd,这里选1
+		status = "okay";
+		compatible = "sitronix,st7735"; //"sitronix,gc9306"	//后续验证另一个lcd直接改名
+		reg = <0>;					// 若添加第二个lcd,对应选1
+
+		spi-max-frequency = <6000000>;	// 24M	由于我的逻辑分析仪最高只能24Mhz,所以设置6Mhz,其实可以设为48M
+		spi-cpol;
+		spi-cpha;
+		rotate = <0>;				// 旋转角度,lcd驱动里会读取并设置对应寄存器
+		fps = <30>;
+		rgb;
+		buswidth = <8>;
+
+		cs = <&gpio1 RK_PC3 GPIO_ACTIVE_LOW>;		//spi0_miso
+		led = <&gpio0 RK_PA4 GPIO_ACTIVE_LOW>; 		//BL
+		dc = <&gpio1 RK_PD0 GPIO_ACTIVE_HIGH>;		//DC
+		reset = <&gpio1 RK_PD1 GPIO_ACTIVE_LOW>;	//RES
+
+		debug = <0x7>;
+	};
+};
diff --git a/sysdrv/source/kernel/arch/arm/configs/luckfox_rv1106_linux_defconfig b/sysdrv/source/kernel/arch/arm/configs/luckfox_rv1106_linux_defconfig
index 4c54b6965..17fc90225 100755
--- a/sysdrv/source/kernel/arch/arm/configs/luckfox_rv1106_linux_defconfig
+++ b/sysdrv/source/kernel/arch/arm/configs/luckfox_rv1106_linux_defconfig
@@ -320,3 +320,20 @@ CONFIG_DEBUG_FS=y
 # CONFIG_SCHED_DEBUG is not set
 # CONFIG_FTRACE is not set
 # CONFIG_RUNTIME_TESTING_MENU is not set
+
+# sensor -- hx711
+CONFIG_HX711=y
+CONFIG_IIO=y
+
+# spi lcd -- st7735s
+CONFIG_SPI_MASTER=y
+CONFIG_SPI_DESIGNWARE=y
+CONFIG_SPI_DW_MMIO=y
+CONFIG_FB=y
+CONFIG_FB_TFT=y
+CONFIG_FB_TFT_ST7735=y
+CONFIG_FB_TFT_GC9306=y
+# CONFIG_FB_BACKLIGHT=y
+
+# lvgl
+# CONFIG_LVGL=y
diff --git a/sysdrv/source/kernel/drivers/staging/fbtft/Kconfig b/sysdrv/source/kernel/drivers/staging/fbtft/Kconfig
index dad1ddcd7..f77fb81a7 100644
--- a/sysdrv/source/kernel/drivers/staging/fbtft/Kconfig
+++ b/sysdrv/source/kernel/drivers/staging/fbtft/Kconfig
@@ -206,3 +206,15 @@ config FB_TFT_WATTEROTT
 	depends on FB_TFT
 	help
 	  Generic Framebuffer support for WATTEROTT
+
+config FB_TFT_GC9306
+	tristate "FB driver for the GC9306 LCD Controller"
+	depends on FB_TFT
+	help
+	  Generic Framebuffer support for GC9306
+
+config FB_TFT_ST7735
+	tristate "FB driver for the GC9306 LCD Controller"
+	depends on FB_TFT
+	help
+	  Generic Framebuffer support for ST7735
diff --git a/sysdrv/source/kernel/drivers/staging/fbtft/Makefile b/sysdrv/source/kernel/drivers/staging/fbtft/Makefile
index e87193f7d..27bfe4e3a 100644
--- a/sysdrv/source/kernel/drivers/staging/fbtft/Makefile
+++ b/sysdrv/source/kernel/drivers/staging/fbtft/Makefile
@@ -37,3 +37,6 @@ obj-$(CONFIG_FB_TFT_UC1611)      += fb_uc1611.o
 obj-$(CONFIG_FB_TFT_UC1701)      += fb_uc1701.o
 obj-$(CONFIG_FB_TFT_UPD161704)   += fb_upd161704.o
 obj-$(CONFIG_FB_TFT_WATTEROTT)   += fb_watterott.o
+
+obj-$(CONFIG_FB_TFT_GC9306)     += fb_gc9306.o
+obj-$(CONFIG_FB_TFT_ST7735)     += fb_st7735.o
diff --git a/sysdrv/source/kernel/drivers/staging/fbtft/fbtft-core.c b/sysdrv/source/kernel/drivers/staging/fbtft/fbtft-core.c
index d0c8d85f3..a58fbd31f 100644
--- a/sysdrv/source/kernel/drivers/staging/fbtft/fbtft-core.c
+++ b/sysdrv/source/kernel/drivers/staging/fbtft/fbtft-core.c
@@ -30,6 +30,9 @@
 #include "fbtft.h"
 #include "internal.h"
 
+#include <linux/gpio.h> //add
+#include <linux/of_gpio.h> //add
+
 static unsigned long debug;
 module_param(debug, ulong, 0000);
 MODULE_PARM_DESC(debug, "override device debug level");
@@ -71,20 +74,42 @@ void fbtft_dbg_hex(const struct device *dev, int groupsize,
 EXPORT_SYMBOL(fbtft_dbg_hex);
 
 static int fbtft_request_one_gpio(struct fbtft_par *par,
-				  const char *name, int index,
-				  struct gpio_desc **gpiop)
+                  const char *name, int index,
+                  struct gpio_desc **gpiop)
 {
-	struct device *dev = par->info->device;
-
-	*gpiop = devm_gpiod_get_index_optional(dev, name, index,
-					       GPIOD_OUT_LOW);
-	if (IS_ERR(*gpiop))
-		return dev_err_probe(dev, PTR_ERR(*gpiop), "Failed to request %s GPIO\n", name);
-
-	fbtft_par_dbg(DEBUG_REQUEST_GPIOS, par, "%s: '%s' GPIO\n",
-		      __func__, name);
-
-	return 0;
+    struct device *dev = par->info->device;
+    struct device_node *node = dev->of_node;
+    int gpio, flags, ret = 0;
+    enum of_gpio_flags of_flags;
+    if (of_find_property(node, name, NULL)) {
+        gpio = of_get_named_gpio_flags(node, name, index, &of_flags);
+        if (gpio == -ENOENT)
+            return 0;
+        if (gpio == -EPROBE_DEFER)
+            return gpio;
+        if (gpio < 0) {
+            dev_err(dev,
+                "failed to get '%s' from DT\n", name);
+            return gpio;
+        }
+         //active low translates to initially low
+        flags = (of_flags & OF_GPIO_ACTIVE_LOW) ? GPIOF_OUT_INIT_LOW :
+                            GPIOF_OUT_INIT_HIGH;
+        ret = devm_gpio_request_one(dev, gpio, flags,
+                        dev->driver->name);
+        if (ret) {
+            dev_err(dev,
+                "gpio_request_one('%s'=%d) failed with %d\n",
+                name, gpio, ret);
+            return ret;
+        }
+
+        *gpiop = gpio_to_desc(gpio);
+        fbtft_par_dbg(DEBUG_REQUEST_GPIOS, par, "%s: '%s' = GPIO%d\n",
+                            __func__, name, gpio);
+    }
+
+    return ret;
 }
 
 static int fbtft_request_gpios(struct fbtft_par *par)
@@ -223,8 +248,11 @@ static void fbtft_reset(struct fbtft_par *par)
 	usleep_range(20, 40);
 	gpiod_set_value_cansleep(par->gpio.reset, 0);
 	msleep(120);
+	gpiod_set_value_cansleep(par->gpio.reset, 1);
+	msleep(120);
 
-	gpiod_set_value_cansleep(par->gpio.cs, 1);  /* Activate chip */
+	gpiod_set_value_cansleep(par->gpio.cs, 0);  /* Activate chip */
+	msleep(120);
 }
 
 static void fbtft_update_display(struct fbtft_par *par, unsigned int start_line,
@@ -1171,7 +1199,7 @@ static struct fbtft_platform_data *fbtft_properties_read(struct device *dev)
 	pdata->startbyte = fbtft_property_value(dev, "startbyte");
 	device_property_read_string(dev, "gamma", (const char **)&pdata->gamma);
 
-	if (device_property_present(dev, "led-gpios"))
+	if (device_property_present(dev, "led"))
 		pdata->display.backlight = 1;
 	if (device_property_present(dev, "init"))
 		pdata->display.fbtftops.init_display =

八、驱动

luckfox-pico\sysdrv\source\kernel\drivers\staging\fbtft\fb_st7735.c

这是依据st7789v改编的,具体驱动如何改动可以参考我的文章,后续会补全。
【fbtft】如何添加fbtft驱动

8.1 st7735

// SPDX-License-Identifier: GPL-2.0+
/*
 * FB driver for the ST7735 LCD Controller
 *
 * Copyright (C) 2015 Dennis Menschel
 */

#include <linux/bitops.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <video/mipi_display.h>

#include "fbtft.h"

#define DRVNAME "fb_st7735"

#define DEFAULT_GAMMA \
	"70 2C 2E 15 10 09 48 33 53 0B 19 18 20 25\n" \
	"70 2C 2E 15 10 09 48 33 53 0B 19 18 20 25"

#define HSD20_IPS_GAMMA \
	"D0 05 0A 09 08 05 2E 44 45 0F 17 16 2B 33\n" \
	"D0 05 0A 09 08 05 2E 43 45 0F 16 16 2B 33"

#define HSD20_IPS 1

/**
 * enum st7735_command - ST7735 display controller commands
 *
 * @PORCTRL: porch setting
 * @GCTRL: gate control
 * @VCOMS: VCOM setting
 * @VDVVRHEN: VDV and VRH command enable
 * @VRHS: VRH set
 * @VDVS: VDV set
 * @VCMOFSET: VCOM offset set
 * @PWCTRL1: power control 1
 * @PVGAMCTRL: positive voltage gamma control
 * @NVGAMCTRL: negative voltage gamma control
 *
 * The command names are the same as those found in the datasheet to ease
 * looking up their semantics and usage.
 *
 * Note that the ST7735 display controller offers quite a few more commands
 * which have been omitted from this list as they are not used at the moment.
 * Furthermore, commands that are compliant with the MIPI DCS have been left
 * out as well to avoid duplicate entries.
 */
enum st7735_command {
	PORCTRL = 0xB2,
	GCTRL = 0xB7,
	VCOMS = 0xBB,
	VDVVRHEN = 0xC2,
	VRHS = 0xC3,
	VDVS = 0xC4,
	VCMOFSET = 0xC5,
	PWCTRL1 = 0xD0,
	PVGAMCTRL = 0xE0,
	NVGAMCTRL = 0xE1,
};

#define MADCTL_BGR BIT(3) /* bitmask for RGB/BGR order */
#define MADCTL_MV BIT(5) /* bitmask for page/column order */
#define MADCTL_MX BIT(6) /* bitmask for column address order */
#define MADCTL_MY BIT(7) /* bitmask for page address order */

/**
 * init_display() - initialize the display controller
 *
 * @par: FBTFT parameter object
 *
 * Most of the commands in this init function set their parameters to the
 * same default values which are already in place after the display has been
 * powered up. (The main exception to this rule is the pixel format which
 * would default to 18 instead of 16 bit per pixel.)
 * Nonetheless, this sequence can be used as a template for concrete
 * displays which usually need some adjustments.
 *
 * Return: 0 on success, < 0 if error occurred.
 */
static int init_display(struct fbtft_par *par)
{
	par->fbtftops.reset(par);//硬复位

	write_reg(par,0x01);//软复位
	mdelay(150);

	write_reg(par,0x11);//软复位
	mdelay(500);

	//ST7735s Frame Rate
	write_reg(par,0xB1,0x05,0x3c,0x3c); 

	write_reg(par,0xB2,0x05,0x3c,0x3c);  

	write_reg(par,0xB3,0x05,0x3c,0x3c,0x05,0x3c,0x3c); 
 
	write_reg(par,0xB4,0x03); //Column inversion 

	//ST7735s Power Sequence
	write_reg(par,0xC0,0x28,0x08,0x04); 

	write_reg(par,0xC1,0xc0); 

	write_reg(par,0xC2,0x0d,0x00); 
	
	write_reg(par,0xC3,0x8d,0x2a); //VCOM 
	
	write_reg(par,0xc4,0x8d,0xee); //MX, MY, RGB mode  
	write_reg(par,0xc5,0x1a);
	write_reg(par,0x36,0xc0);

	//ST7735s Gamma Sequence
	write_reg(par,0xe0,0x04,0x22,0x07,0x0a,0x2e,0x30,0x25,0x2a,0x28,0x26,0x2e,0x3a,0x00,0x01,0x03,0x13); 

	write_reg(par,0xe1,0x04,0x16,0x06,0x0d,0x2d,0x26,0x23,0x27,0x27,0x25,0x2d,0x3b,0x00,0x01,0x04,0x13);  

	write_reg(par,0x3A,0x05); // 65k mode  

	// write_reg(par,0x20);	// MIPI_DCS_EXIT_INVERT_MODE

	write_reg(par,0x29);	// Display on
	mdelay(100);

	return 0;
}

/**
 * set_var() - apply LCD properties like rotation and BGR mode
 *
 * @par: FBTFT parameter object
 *
 * Return: 0 on success, < 0 if error occurred.
 */
static int set_var(struct fbtft_par *par)
{
	u8 madctl_par = 0;

	if (par->bgr)
		madctl_par |= MADCTL_BGR;
	switch (par->info->var.rotate) {
	case 0:
		madctl_par = 0xc0;
		break;
	case 90:
		madctl_par = 0x70;
		break;
	case 180:
		madctl_par = 0x00;
		break;
	case 270:
		madctl_par = 0xA0;
		break;
	default:
		return -EINVAL;
	}
	write_reg(par, MIPI_DCS_SET_ADDRESS_MODE, madctl_par);	//0x36
	return 0;
}

/**
 * set_gamma() - set gamma curves
 *
 * @par: FBTFT parameter object
 * @curves: gamma curves
 *
 * Before the gamma curves are applied, they are preprocessed with a bitmask
 * to ensure syntactically correct input for the display controller.
 * This implies that the curves input parameter might be changed by this
 * function and that illegal gamma values are auto-corrected and not
 * reported as errors.
 *
 * Return: 0 on success, < 0 if error occurred.
 */
static int set_gamma(struct fbtft_par *par, u32 *curves)
{
	// int i;
	// int j;
	// int c; /* curve index offset */

	// /*
	//  * Bitmasks for gamma curve command parameters.
	//  * The masks are the same for both positive and negative voltage
	//  * gamma curves.
	//  */
	// static const u8 gamma_par_mask[] = {
	// 	0xFF, /* V63[3:0], V0[3:0]*/
	// 	0x3F, /* V1[5:0] */
	// 	0x3F, /* V2[5:0] */
	// 	0x1F, /* V4[4:0] */
	// 	0x1F, /* V6[4:0] */
	// 	0x3F, /* J0[1:0], V13[3:0] */
	// 	0x7F, /* V20[6:0] */
	// 	0x77, /* V36[2:0], V27[2:0] */
	// 	0x7F, /* V43[6:0] */
	// 	0x3F, /* J1[1:0], V50[3:0] */
	// 	0x1F, /* V57[4:0] */
	// 	0x1F, /* V59[4:0] */
	// 	0x3F, /* V61[5:0] */
	// 	0x3F, /* V62[5:0] */
	// };

	// for (i = 0; i < par->gamma.num_curves; i++) {
	// 	c = i * par->gamma.num_values;
	// 	// for (j = 0; j < par->gamma.num_values; j++)
	// 	// 	curves[c + j] &= gamma_par_mask[j];
	// 	write_reg(par, PVGAMCTRL + i,
	// 		  curves[c + 0],  curves[c + 1],  curves[c + 2],
	// 		  curves[c + 3],  curves[c + 4],  curves[c + 5],
	// 		  curves[c + 6],  curves[c + 7],  curves[c + 8],
	// 		  curves[c + 9],  curves[c + 10], curves[c + 11],
	// 		  curves[c + 12], curves[c + 13]);
	// }

	write_reg(par,0xe0,0x04,0x22,0x07,0x0a,0x2e,0x30,0x25,0x2a,0x28,0x26,0x2e,0x3a,0x00,0x01,0x03,0x13); 

	write_reg(par,0xe1,0x04,0x16,0x06,0x0d,0x2d,0x26,0x23,0x27,0x27,0x25,0x2d,0x3b,0x00,0x01,0x04,0x13);  

	return 0;
}

/**
 * blank() - blank the display
 *
 * @par: FBTFT parameter object
 * @on: whether to enable or disable blanking the display
 *
 * Return: 0 on success, < 0 if error occurred.
 */
static int blank(struct fbtft_par *par, bool on)
{
	if (on)
		write_reg(par, MIPI_DCS_SET_DISPLAY_OFF);
	else
		write_reg(par, MIPI_DCS_SET_DISPLAY_ON);
	return 0;
}

static struct fbtft_display display = {
	.regwidth = 8,
	.width = 128,//240,
	.height = 160,//320,
	.gamma_num = 2,
	.gamma_len = 14,
	.gamma = HSD20_IPS_GAMMA,
	.fbtftops = {
		.init_display = init_display,
		.set_var = set_var,
		.set_gamma = set_gamma,
		.blank = blank,
	},
};

FBTFT_REGISTER_DRIVER(DRVNAME, "sitronix,st7735", &display);

MODULE_ALIAS("spi:" DRVNAME);
MODULE_ALIAS("platform:" DRVNAME);
MODULE_ALIAS("spi:st7735");
MODULE_ALIAS("platform:st7735");

MODULE_DESCRIPTION("FB driver for the ST7735 LCD Controller");
MODULE_AUTHOR("Dennis Menschel");
MODULE_LICENSE("GPL");

8.2 gc9306

// SPDX-License-Identifier: GPL-2.0+
/*
 * FB driver for the GC9306 LCD Controller
 *
 * Copyright (C) 2015 Dennis Menschel
 */

#include <linux/bitops.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <video/mipi_display.h>

#include "fbtft.h"

#define DRVNAME "fb_gc9306"

#define GC9306_IPS_GAMMA \
    "02 00 00 1b 1f 0b\n" \
    "01 03 00 28 2b 0e\n" \
    "0b 08 3b 04 03 4c\n" \
    "0e 07 46 04 05 51\n" \
    "08 15 15 1f 22 0F\n" \
    "0b 13 11 1f 21 0F"

/**
 * init_display() - initialize the display controller
 *
 * @par: FBTFT parameter object
 *
 * Most of the commands in this init function set their parameters to the
 * same default values which are already in place after the display has been
 * powered up. (The main exception to this rule is the pixel format which
 * would default to 18 instead of 16 bit per pixel.)
 * Nonetheless, this sequence can be used as a template for concrete
 * displays which usually need some adjustments.
 *
 * Return: 0 on success, < 0 if error occurred.
 */
static int init_display(struct fbtft_par *par)
{
	par->fbtftops.reset(par);//硬复位

	mdelay(50);

    //display control setting
    write_reg(par, 0xfe);
    write_reg(par, 0xef);
    write_reg(par, MIPI_DCS_SET_ADDRESS_MODE, 0x48);//MX, MY, RGB mode 刷新方向 48竖屏
    write_reg(par, MIPI_DCS_SET_PIXEL_FORMAT, MIPI_DCS_PIXEL_FMT_16BIT);//65k mode
    write_reg(par, 0xad,0x33);
    write_reg(par, 0xaf,0x55);
    write_reg(par, 0xae,0x2b);

    //GC9306 Power Sequence
    write_reg(par, 0xa4,0x44,0x44);
    write_reg(par, 0xa5,0x42,0x42);
    write_reg(par, 0xaa,0x88,0x88);
    write_reg(par, 0xae,0x2b);
    write_reg(par, 0xe8,0x11,0x0b);
    write_reg(par, 0xe3,0x01,0x10);
    write_reg(par, 0xff,0x61);
    write_reg(par, 0xac,0x00);
    write_reg(par, 0xaf,0x67);
    write_reg(par, 0xa6,0x2a,0x2a);
    write_reg(par, 0xa7,0x2b,0x2b);
    write_reg(par, 0xa8,0x18,0x18);
    write_reg(par, 0xa9,0x2a,0x2a);

    //display window 240X320 匹配mode
    write_reg(par, 0x2a,0x00,0x00,0x00,0xef);   //MIPI_DCS_SET_COLUMN_ADDRESS - 240
    write_reg(par, 0x2b,0x00,0x00,0x01,0x3f);   //MIPI_DCS_SET_PAGE_ADDRESS - 320
    write_reg(par, 0x2c);                       //MIPI_DCS_WRITE_MEMORY_START

    //GC9306 Gamma Sequence
    write_reg(par, 0xF0,0x02,0x00,0x00,0x1b,0x1f,0x0b);
    write_reg(par, 0xF1,0x01,0x03,0x00,0x28,0x2b,0x0e);
    write_reg(par, 0xF2,0x0b,0x08,0x3b,0x04,0x03,0x4c);
    write_reg(par, 0xF3,0x0e,0x07,0x46,0x04,0x05,0x51);
    write_reg(par, 0xF4,0x08,0x15,0x15,0x1f,0x22,0x0F);
    write_reg(par, 0xF5,0x0b,0x13,0x11,0x1f,0x21,0x0F);

    /* Sleep Out */
    write_reg(par, 0x11);                       //MIPI_DCS_EXIT_SLEEP_MODE
    mdelay(100);

    write_reg(par, 0x2c);                       //MIPI_DCS_WRITE_MEMORY_START

    write_reg(par, 0x20);                       //MIPI_DCS_EXIT_INVERT_MODE

    // luat_lcd_clear(par, BLACK);

    /* display on */
	write_reg(par, 0x29);                       //MIPI_DCS_SET_DISPLAY_ON - 29
	mdelay(100);

    return 0;
}

/**
 * set_var() - apply LCD properties like rotation and BGR mode
 *
 * @par: FBTFT parameter object
 *
 * Return: 0 on success, < 0 if error occurred.
 */
static int set_var(struct fbtft_par *par)
{
	u8 madctl_par = 0;

	if (par->bgr)
		madctl_par =0x48;
	switch (par->info->var.rotate) {
	case 0:
		madctl_par = 0x48;
		break; //48
	case 90:
		madctl_par = 0xE8;
		break;
	case 180:
		madctl_par =0x28;
		break;
	case 270:
		madctl_par =0xF8;
		break;
	default:
		return -EINVAL;
	}
	write_reg(par, MIPI_DCS_SET_ADDRESS_MODE, madctl_par);
	return 0;
}


/**
 * set_gamma() - set gamma curves
 *
 * @par: FBTFT parameter object
 * @curves: gamma curves
 *
 * Before the gamma curves are applied, they are preprocessed with a bitmask
 * to ensure syntactically correct input for the display controller.
 * This implies that the curves input parameter might be changed by this
 * function and that illegal gamma values are auto-corrected and not
 * reported as errors.
 *
 * Return: 0 on success, < 0 if error occurred.
 */
static int set_gamma(struct fbtft_par *par, u32 *curves)
{
    //GC9306 Gamma Sequence
    write_reg(par, 0xF0,0x02,0x00,0x00,0x1b,0x1f,0x0b);
    write_reg(par, 0xF1,0x01,0x03,0x00,0x28,0x2b,0x0e);
    write_reg(par, 0xF2,0x0b,0x08,0x3b,0x04,0x03,0x4c);
    write_reg(par, 0xF3,0x0e,0x07,0x46,0x04,0x05,0x51);
    write_reg(par, 0xF4,0x08,0x15,0x15,0x1f,0x22,0x0F);
    write_reg(par, 0xF5,0x0b,0x13,0x11,0x1f,0x21,0x0F);

	return 0;
}

/**
 * blank() - blank the display
 *
 * @par: FBTFT parameter object
 * @on: whether to enable or disable blanking the display
 *
 * Return: 0 on success, < 0 if error occurred.
 */
static int blank(struct fbtft_par *par, bool on)
{
	if (on)
		write_reg(par, MIPI_DCS_SET_DISPLAY_OFF);
	else
		write_reg(par, MIPI_DCS_SET_DISPLAY_ON);
	return 0;
}

static struct fbtft_display display = {
	.regwidth = 8,
	.width = 240,
	.height = 320,
	.gamma_num = 6,
	.gamma_len = 6,
	.gamma = GC9306_IPS_GAMMA,
	.fbtftops = {
		.init_display = init_display,
		.set_var = set_var,
		.set_gamma = set_gamma,
		.blank = blank,
	},
};

FBTFT_REGISTER_DRIVER(DRVNAME, "sitronix,gc9306", &display);

MODULE_ALIAS("spi:" DRVNAME);
MODULE_ALIAS("platform:" DRVNAME);
MODULE_ALIAS("spi:gc9306");
MODULE_ALIAS("platform:gc9306");

MODULE_DESCRIPTION("FB driver for the GC9306 LCD Controller");
MODULE_AUTHOR("Dennis Menschel & Youkai");
MODULE_LICENSE("GPL");

九、验证驱动

注意:luckfox驱动成功时屏幕为黑色,但是背光是开的,不清楚是不是补色没设导致的,有了解的朋友还请多指教。

执行dmesg查看fb驱动是否正常加载了。

# dmesg | grep fb_
[    0.945494] graphics fb0: fb_gc9306 frame buffer, 240x320, 150 KiB video memory, 4 KiB buffer memory, fps=30, spi0.0 at 6 MHz

// 测试花屏
# cat /dev/urandom > /dev/fb0
// 测试清屏
# cat /dev/zero > /dev/fb0

如果两个测试命令都成功了,则说明你驱动可以正常加载了。

image.png

十、小结

本章只是介绍如何添加lcd spi驱动,后续应用实现要通过lvgl完成。

有兴趣的话可以参考下【lvgl】linux开发板搭建环境,只需要改变makefile中的cc路径即可。

放一个lvgl示例运行的结果图。

在这里插入图片描述

更多回帖

×
发帖