給linux移植fbtft驅動st7735s小屏幕(f1c100s)

来源:https://www.cnblogs.com/maomaotou-thu/archive/2023/09/01/17671371.html
-Advertisement-
Play Games

**內核版本5.4** 在使用spi匯流排接上了一個小網卡,實現了我們開發板對網路的訪問之後,我還想接一個小的[spi屏幕 1.44寸款](https://item.taobao.com/item.htm?spm=a1z09.2.0.0.731e2e8dAkrB01&id=571409957622&_ ...


內核版本5.4
在使用spi匯流排接上了一個小網卡,實現了我們開發板對網路的訪問之後,我還想接一個小的spi屏幕 1.44寸款,來畫一隻小企鵝,順便顯示一些系統的調試信息。但是由於我這個開發板向外暴露出來的spi介面就兩個,而且有一個已經因為串口的設置而不能使用。所以我們只能讓這個小屏幕和enc28j60共用一個spi外設。

內核配置

直接make menuconfig,進入Device Drivers,打開SPI,打開ST7735R的驅動。保存,再make -j16.

接線與修改設備樹

我打算讓enc28j60使用spi自己的cs作為片選線,然後另外找一個GPIO作為spi屏幕的片選。
那這樣的話又得改設備樹。我們這個spi屏幕的驅動器晶元是"st7735s"。但是linux有st7735r,這倆
是相容的,可以直接用。

/ {
	model = "Lichee Pi Nano";
	compatible = "licheepi,licheepi-nano", "allwinner,suniv-f1c100s";

	aliases {
		serial1 = &uart1;
	};

	chosen {
		stdout-path = "serial1:115200n8";
		/delete-node/ framebuffer@0;
	};
	
	reg_vcc3v3: vcc3v3 {
			compatible = "regulator-fixed";
			regulator-name = "vcc3v3";
			regulator-min-microvolt = <3300000>;
			regulator-max-microvolt = <3300000>;
	};

	backlight: backlight {
		compatible = "gpio-backlight";
		gpios = <&pio 4 4 GPIO_ACTIVE_HIGH>;
		default-on;
	};
};

&spi1{
	status = "okay";
	pinctrl-names = "default";
	pinctrl-0 = <&spi1_pins>;
	cs-gpios = <0>,<&pio 4 5 GPIO_ACTIVE_LOW>;
	enc28j60: ethernet@0 {
		compatible = "microchip,enc28j60";
		pinctrl-names = "default";
		pinctrl-0 = <&enc28j60_pins>;
		reg = <0x0>;
		interrupt-parent = <&pio>;
		interrupts = <4 11 IRQ_TYPE_EDGE_FALLING>;
		spi-max-frequency = <12000000>;
	};
	display@1{
		compatible = "okaya,rh128128t", "sitronix,st7735r";
		reg = <0x1>;
		status = "okay";
		spi-max-frequency = <48000000>;
		spi-cpol;
		spi-cpha;
		bgr;
		rotate = <90>;
		fps = <30>;
		buswidth = <8>;
		dc-gpios = <&pio 4 2 GPIO_ACTIVE_HIGH>;
		reset-gpios = <&pio 4 3 GPIO_ACTIVE_LOW>;
		backlight = <&backlight>;
	};
};

我們在spi節點下增加了一個display設備,進入linux主線的設備的DTC綁定信息都是在內核源碼中可以找得到的。例如我們要找"sitronix,st7735r"的設備樹綁定信息,我們直接打開內核根目錄,一搜,就可以在Documentation/devicetree/bindings/display/sitronix,st7735r.yaml找到我們要的信息。

這個yaml給的是最新的drm驅動匹配方式,不過我們目前還是使用比較簡單,資料比較多的framebuffer TFT驅動比較好。下一次可以嘗試用這個drm驅動。

我們這個spi屏幕由於和enc28j60共用一個spi,所以我們需要指定其片選。我們可以在spi節點下直接設置cs-gpios = <0>,<&pio 4 5 GPIO_ACTIVE_LOW>。這是什麼意思呢?第一個<0>代表了對於第一個spi設備,我們使用spi預設的片選引腳。第二個<&pio 4 5 GPIO_ACTIVE_LOW>,代表的是我們指定第二個spi設備的片選引腳為PE5,並且低電平有效。GPIO_ACTIVE_LOW的意思是低電平有效,這樣做可以在內核中配置不同設備的正負邏輯。

引腳正負邏輯與代碼分析

fbtft設備在申請GPIO時,其實用的是gpio子系統的api。這些api用來用去最後是調用了

struct gpio_desc *of_find_gpio(struct device_node *np, const char *con_id,
			       unsigned int idx, unsigned long *flags)

它調用了

desc = of_get_named_gpiod_flags(np, prop_name, idx, &of_flags);
*flags = of_convert_gpio_flags(of_flags);

來獲取設備樹下gpio屬性的flag。在設置gpio的輸出值時,即調用gpiod_set_value時,會調用

static void gpiod_set_value_nocheck(struct gpio_desc *desc, int value)
{
	if (test_bit(FLAG_ACTIVE_LOW, &desc->flags))
		value = !value;
	if (test_bit(FLAG_OPEN_DRAIN, &desc->flags))
		gpio_set_open_drain_value_commit(desc, value);
	else if (test_bit(FLAG_OPEN_SOURCE, &desc->flags))
		gpio_set_open_source_value_commit(desc, value);
	else
		gpiod_set_raw_value_commit(desc, value);
}

所以我們在設備樹中配置引腳的正負邏輯,會在這裡被處理。如果是正邏輯,直接輸出,如果是負邏輯,則需要取反。

配置引腳正負邏輯

為了知道我們到底應該在哪些引腳配置我們的正負邏輯,我們應該直接看源代碼,因為壓根就沒有文檔說這些。

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.cs, 1);  /* Activate chip */
}

RESET引腳在低電平的時候將會導致屏幕複位,Chip-Select在低電平時將會使能設備。所以這兩個引腳都是負邏輯。我們應當在他們設備樹的GPIO後邊加一個GPIO_ACTIVE_LOW

上電測試

我上電後,屏幕一直白屏,調試了很久,代碼改來改去,TF卡不知道插拔了多少次,也找不到原因。

最後插上邏輯分析儀,邏輯分析儀真的是電子工程師的眼睛,以前屏幕從來就沒調通過,這次插了邏輯分析儀,能夠分析邏輯後,調試就變得很容易了。一直看波形,發現RESET引腳一直被拉低。才發現原來linux的gpio子系統有這麼一套正負邏輯的區別。

配置好之後,屏幕時好時壞。有多時好時壞呢,一插上邏輯分析儀,屏幕就成功初始化。一拔掉邏輯分析儀,這個屏幕又白屏了。最後一聯想,就想到邏輯分析儀不是自帶上拉嗎?是不是因為我的RESET,CS,MOSI,CLK這些引腳都沒有上拉?找了兩個上拉電阻,一試,屏幕跑起來了!小企鵝出現了!

背光碟機動的修改

其實我一開始把PE4的一個引腳設置為背光引腳(這樣做似乎不太對,應該用mosfet或者三極體來驅動這個tft,因為電流大了會把f1c100s的引腳給燒了)。但是這個屏幕不知道為什麼,就是不亮,亮都不亮一下。於是我就把這根線拔了,直接把TFT的LED引腳連了3V3。但是我覺得這樣不夠優雅,一定要讓linux自己能夠設置這個背光。

backlight: backlight {
    compatible = "gpio-backlight";
    gpios = <&pio 4 4 GPIO_ACTIVE_HIGH>;
    default-on;
};

這個backlight會註冊一個class,位置在/sys/class/backlight/backlight,這個目錄下有一個文件叫brightness,即亮度,可以通過echo 1 > brightness,打開我們的背光。

這裡我們把gpio配置為正邏輯,這樣1就對應著打開背光,符合人類的操作邏輯。

但是為什麼,這個背光不工作呢?設置成1或者0,在調試後,發現

static int gpio_backlight_update_status(struct backlight_device *bl)
{
	struct gpio_backlight *gbl = bl_get_data(bl);
	int brightness = bl->props.brightness;

	if (bl->props.power != FB_BLANK_UNBLANK ||
	    bl->props.fb_blank != FB_BLANK_UNBLANK ||
	    bl->props.state & (BL_CORE_SUSPENDED | BL_CORE_FBBLANK))
		brightness = 0;

	gpiod_set_value_cansleep(gbl->gpiod, brightness);

	return 0;
}

是它判斷這些power fb_blakn state的時候,直接把brightness設置成0了。我們直接去掉這幾行代碼。但是它調用gpiod_set_value_cansleep(gbl->gpiod, brightness);,我們的gpio也沒有輸出。

最後看了幾遍代碼,發現原來是它沒有配置好gpio為輸出。

static int gpio_backlight_probe_dt(struct platform_device *pdev,
				   struct gpio_backlight *gbl)
{
	struct device *dev = &pdev->dev;
	int ret;

	gbl->def_value = device_property_read_bool(dev, "default-on");

	gbl->gpiod = devm_gpiod_get(dev, NULL, GPIOD_ASIS);
	if (IS_ERR(gbl->gpiod)) {
		ret = PTR_ERR(gbl->gpiod);

		if (ret != -EPROBE_DEFER) {
			dev_err(dev,
				"Error: The gpios parameter is missing or invalid.\n");
		}
		return ret;
	}

	return 0;
}

問題就在gbl->gpiod = devm_gpiod_get(dev, NULL, GPIOD_ASIS);的這個GPIOD_ASIS

/**
 * enum gpiod_flags - Optional flags that can be passed to one of gpiod_* to
 *                    configure direction and output value. These values
 *                    cannot be OR'd.
 *
 * @GPIOD_ASIS:			Don't change anything
 * @GPIOD_IN:			Set lines to input mode
 * @GPIOD_OUT_LOW:		Set lines to output and drive them low
 * @GPIOD_OUT_HIGH:		Set lines to output and drive them high
 * @GPIOD_OUT_LOW_OPEN_DRAIN:	Set lines to open-drain output and drive them low
 * @GPIOD_OUT_HIGH_OPEN_DRAIN:	Set lines to open-drain output and drive them high
 */
enum gpiod_flags {
	GPIOD_ASIS	= 0,
	GPIOD_IN	= GPIOD_FLAGS_BIT_DIR_SET,
	GPIOD_OUT_LOW	= GPIOD_FLAGS_BIT_DIR_SET | GPIOD_FLAGS_BIT_DIR_OUT,
	GPIOD_OUT_HIGH	= GPIOD_FLAGS_BIT_DIR_SET | GPIOD_FLAGS_BIT_DIR_OUT |
			  GPIOD_FLAGS_BIT_DIR_VAL,
	GPIOD_OUT_LOW_OPEN_DRAIN = GPIOD_OUT_LOW | GPIOD_FLAGS_BIT_OPEN_DRAIN,
	GPIOD_OUT_HIGH_OPEN_DRAIN = GPIOD_OUT_HIGH | GPIOD_FLAGS_BIT_OPEN_DRAIN,
};

我們改成GPIOD_OUT_LOW,即成功解決問題。當然,最新的驅動已經修複了這些問題。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • ## 前言 **`Visual Studio`** 開發工具的熟練使用,能夠潛在的提升我們工作效率,而且一些開發技巧的使用,會讓我們的工作顯得那麼方便快捷。那麼你知道VS中有哪些你不知道的使用小技巧呢?接下來,我們就來探索VS中的**“任務列表”**的使用。 任務列表是使用 `TODO` 、 `HA ...
  • # .Net 6/Net Core Vue Element Uniapp前後端分離低代碼快速開發框架 這是一個能提高開發效率的開發框架,全自動生成PC與移動端(uniapp)代碼;支持移動ios/android/h5/微信小程式。 # 一、框架能做什麼 1、前後端分離項目 2、純後端項目 3、移動端 ...
  • ## 前言 在軟體系統中,當創建一個類的實例的過程很昂貴或很複雜,並且我們需要創建多個這樣類的實例時,如果我們用new操作符去創建這樣的類實例,這就會增加創建類的複雜度和創建過程與客戶代碼複雜的耦合度。如果採用工廠模式來創建這樣的實例對象的話,隨著產品類的不斷增加,導致子類的數量不斷增多,也導致了相 ...
  • # 高併發解決方法-LVS、LVS-NAT、LVS-DR ## 前言: 集群功能分類: 1.LB Load Balancing,負載均衡(增加處理能力),有一定高可用能力,但不是高可用集群,是以提高服務的**併發處理**能力為根本著重點。**LVS** 2.HA High Availability ...
  • 哈嘍大家好,我是鹹魚 在《[一臺伺服器上部署 Redis 偽集群》](https://mp.weixin.qq.com/s?__biz=MzkzNzI1MzE2Mw==&mid=2247486439&idx=1&sn=0b10317397ef3259dd98d493915dd706&chksm=c2 ...
  • 1.操作系統的多進程圖像 操作系統main函數中最後 if(!fork()) {init();} ,也就是main函數最後創建了第1個進程,init執行了shell(Windows)桌面。 操作系統管理和組織進程都使用PCB(Process Control Block),不同的程式的PCB放在不同的 ...
  • **背景:** 項目現場有一個伺服器需要作國家二級等保整改,有一個高風險選項是需要安裝防惡意代碼軟體,所以就考慮安裝clamAV來實現。現場使用cnetos7伺服器,且無外網,只能離線安裝。 如果有外網直接執行以下命令就行了。 ``` # ubuntu sudo apt install clamav ...
  • iostat 是一個常用的工具,可以提供關於磁碟活動的詳細統計信息。通過運行命令 iostat -x 1 可以實時監測磁碟的使用情況,其中 %util 列就表示磁碟的繁忙度,數值越高表示磁碟越繁忙。 ...
一周排行
    -Advertisement-
    Play Games
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...