給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
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...