F1C100S添加SPI LCD液晶驱动
在使用F1C100S的時候常常會使用小尺寸的液晶屏,比如市場上比較常見的1.14寸液晶屏,下面我們來為該液晶屏添加驅動。
下面以內核Linux-5.7內核版本,液晶驅動芯片為ST7789V,四線SPI接口為例:(例中液晶引腳接到SPI1上)
注意:SPI總線的SCLK和SDA兩個引腳必須接上拉電阻,10k即可。
這里說明下硬件連接,因為有部分人遇到無法成功問題:
| LCD液晶引腳 | F1C100S板子 |
| SCLK | PA2 |
| SDA | PA1 |
| CS | GND |
| RESET | PE7 |
| DC | PE10 |
1.設備樹中添加SPI節點和ST7789V節點:
spi0:spi@1c05000 {
compatible = "allwinner,suniv-spi", "allwinner,sun8i-h3-spi";
reg = <0x1c05000 0x1000>;
interrupts = <0xa>;
clocks = <&ccu CLK_BUS_SPI0>, <&ccu CLK_BUS_SPI0>;
clock-names = "ahb", "mod";
resets = <&ccu RST_BUS_SPI0>;
status = "disabled";
#address-cells = <1>;
#size-cells = <0>;
pinctrl-names = "default";
pinctrl-0 = <&spi0_pins>;
};
spi1:spi@1c06000 {
compatible = "allwinner,suniv-spi", "allwinner,sun8i-h3-spi";
reg = <0x1c06000 0x1000>;
interrupts = <0xb>;
clocks = <&ccu CLK_BUS_SPI1>, <&ccu CLK_BUS_SPI1>;
clock-names = "ahb", "mod";
resets = <&ccu RST_BUS_SPI1>;
status = "disabled";
#address-cells = <1>;
#size-cells = <0>;
bias-pull-up;
pinctrl-names = "default";
pinctrl-0 = <&spi1_pins>;
};
同時在IO節點中申明引腳定義,如下所示:
pio: pinctrl@1c20800 {
compatible = "allwinner,suniv-f1c100s-pinctrl";
reg = <0x01c20800 0x400>;
interrupts = <38>, <39>, <40>;
clocks = <&ccu CLK_BUS_PIO>, <&osc24M>, <&osc32k>;
clock-names = "apb", "hosc", "losc";
gpio-controller;
interrupt-controller;
#interrupt-cells = <3>;
#gpio-cells = <3>;
uart0_pe_pins: uart0-pe-pins {
pins = "PE0", "PE1";
function = "uart0";
};
lcd_rgb666_pins: lcd-rgb666-pins {
pins = "PD0", "PD1", "PD2", "PD3", "PD4",
"PD5", "PD6", "PD7", "PD8", "PD9",
"PD10", "PD11", "PD12", "PD13", "PD14",
"PD15", "PD16", "PD17", "PD18", "PD19",
"PD20", "PD21";
function = "lcd";
};
mmc0_pins: mmc0-pins {
pins = "PF0", "PF1", "PF2", "PF3", "PF4", "PF5";
function = "mmc0";
};
spi0_pins: spi0-pins{
pins = "PC0", "PC1", "PC2", "PC3";
function = "spi0";
};
spi1_pins: spi1-pins{
pins = "PA2","PA0","PA3","PA1";
function = "spi1";
};
};
在設備樹中添加ST7789V節點:
&spi1 {
st7789v@0 {
status = "okay";
compatible = "sitronix,st7789v";
reg = <0>;
spi-max-frequency = <32000000>; //最大速度32M
rotate = <0>; //屏幕旋轉角度
spi-cpol; //SPI引腳模式
spi-cpha; //SPI引腳模式
rgb; //顏色格式為RGB
fps = <30>; //刷新幀數30
buswidth = <8>; //總線寬度8位
reset-gpios = <&pio 4 7 GPIO_ACTIVE_LOW>; //GPIOE7
dc-gpios = <&pio 4 10 GPIO_ACTIVE_LOW>; //GPIOE10
debug = <0>;
};
};
2.修改drivers/staging/fbtft/fbtft-core.c文件中的gpio申請函數:
這里簡單說下原因:因為在5.2版本之后使用的是另一種方式申請gpio,但是這種方式只是簡單的給出了接口,實際并沒有申請到gpio,因此當不去修改申請方式的時候,即使內核log提示已經申請成功并注冊了驅動,但是實際并沒有,導致液晶屏無法驅動起來。
先添加如下頭文件:
#include <linux/gpio.h> #include <linux/of_gpio.h>
然后修改兩個函數:
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
", 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
",
name, gpio, ret);
return ret;
}
*gpiop = gpio_to_desc(gpio);
fbtft_par_dbg(DEBUG_REQUEST_GPIOS, par, "%s: '%s' = GPIO%d
",
__func__, name, gpio);
}
return ret;
}
static int fbtft_request_gpios(struct fbtft_par *par)
{
int i;
int ret;
ret = fbtft_request_one_gpio(par, "reset-gpios", 0, &par->gpio.reset);
if (ret)
return ret;
ret = fbtft_request_one_gpio(par, "dc-gpios", 0, &par->gpio.dc);
if (ret)
return ret;
ret = fbtft_request_one_gpio(par, "rd-gpios", 0, &par->gpio.rd);
if (ret)
return ret;
ret = fbtft_request_one_gpio(par, "wr-gpios", 0, &par->gpio.wr);
if (ret)
return ret;
ret = fbtft_request_one_gpio(par, "cs-gpios", 0, &par->gpio.cs);
if (ret)
return ret;
ret = fbtft_request_one_gpio(par, "latch-gpios", 0, &par->gpio.latch);
if (ret)
return ret;
for (i = 0; i < 16; i++) {
ret = fbtft_request_one_gpio(par, "db-gpios", i,
&par->gpio.db[i]);
if (ret)
return ret;
ret = fbtft_request_one_gpio(par, "led-gpios", i,
&par->gpio.led[i]);
if (ret)
return ret;
ret = fbtft_request_one_gpio(par, "aux-gpios", i,
&par->gpio.aux[i]);
if (ret)
return ret;
}
return 0;
}
3.由于5.7版本的fbtft復位部分有問題,最后沒有拉高,所以我們需要修改drivers/staging/fbtft/fbtft-core.c中的fbtft_reset函數:
static void fbtft_reset(struct fbtft_par *par)
{
if (!par->gpio.reset)
return;
fbtft_par_dbg(DEBUG_RESET, par, "%s()
", __func__);
gpiod_set_value_cansleep(par->gpio.reset, 1);
msleep(10);
gpiod_set_value_cansleep(par->gpio.reset, 0);
msleep(200);
gpiod_set_value_cansleep(par->gpio.reset, 1);
msleep(10);
}
4.最后由于fbtft提供的ST7789V的初始化代碼部分有問題,導致顏色對不上,因此我們這里使用STM32中的初始化,修改如下:
修改drivers/staging/fbtft/fb_st7789v.c中的init_display函數:
static int init_display(struct fbtft_par *par)
{
par->fbtftops.reset(par);
mdelay(50);
write_reg(par,0x36,0x00);
write_reg(par,0x3A,0x05);
write_reg(par,0xB2,0x0C,0x0C,0x00,0x33,0x33);
write_reg(par,0xB7,0x35);
write_reg(par,0xBB,0x19);
write_reg(par,0xC0,0x2C);
write_reg(par,0xC2,0x01);
write_reg(par,0xC3,0x12);
write_reg(par,0xC4,0x20);
write_reg(par,0xC6,0x0F);
write_reg(par,0xD0,0xA4,0xA1);
write_reg(par,0xE0,0xD0,0x04,0x0D,0x11,0x13,0x2B,0x3F,0x54,0x4C,0x18,0x0D,0x0B,0x1F,0x23);
write_reg(par,0xE1,0xD0,0x04,0x0C,0x11,0x13,0x2C,0x3F,0x44,0x51,0x2F,0x1F,0x1F,0x20,0x23);
write_reg(par,0x21);
write_reg(par,0x11);
mdelay(50);
write_reg(par,0x29);
mdelay(200);
return 0;
}
由于FC1000S的SPI中有一個BUG,因此我們在開啟SPI驅動的時候必須選擇A31(Device Drivers -> SPI support)如圖所示:
現在選擇ST7789V驅動并編譯進內核中,如下:
Device Drivers --->
[*] Staging drivers --->
<*> Support for small TFT LCD display modules --->
<*> FB driver for the ST7789V LCD Controller
最后make -j4編譯鏡像:
總結
以上是生活随笔為你收集整理的F1C100S添加SPI LCD液晶驱动的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 开心宝贝6古灵星历险记乐视视频(开心宝贝
- 下一篇: 64进制和10进制转换