【milkv】3、添加LCD屏st7735

前言

本文介绍milkv-duo加载st7735的lcd屏幕,以及屏幕显示log。

参考文章:
记录为Linux配置spi屏幕(st7735s)
https://community.milkv.io/t/milk-v-duo-spi-st7789/131

一、电路图

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

1.1 pin设置

打开spi2的引脚
duo-buildroot-sdk\build\boards\cv180x\cv1800b_milkv_duo_sd\u-boot\cvi_board_init.c

	//spi2 -- st7735
	pinmux_config(PINMUX_SPI2);
	PINMUX_CONFIG(SPINOR_MISO, XGPIOA_23);	//DC
	PINMUX_CONFIG(SD0_PWR_EN, XGPIOA_14);	//BL
	PINMUX_CONFIG(SPK_EN, XGPIOA_15);		//RES

注意这里的DC,属于gpioA

这里的pinmux_config(PINMUX_SPI2);可以在源码中找到对应的配置

		case PINMUX_SPI2:
			PINMUX_CONFIG(SD1_CMD, SPI2_SDO);
			PINMUX_CONFIG(SD1_CLK, SPI2_SCK);
			PINMUX_CONFIG(SD1_D0, SPI2_SDI);
			PINMUX_CONFIG(SD1_D3, SPI2_CS_X);
			break;

1.2 dtsi配置

build\boards\cv180x\cv1800b_milkv_duo_sd\dts_riscv\cv1800b_milkv_duo_sd.dts

&spi2 {
	status = "okay";

    /delete-node/ spidev@0;

	st7789v: st7789v@0{
		compatible = "sitronix,st7789v";
		reg = <0>;
		status = "okay";
		spi-max-frequency = <48000000>;
		spi-cpol;
		spi-cpha;
		rotate = <90>;
		fps = <30>;
		rgb;
		buswidth = <8>;

		dc-gpios = <&porta 23 GPIO_ACTIVE_HIGH>;	//DC
		reset-gpios = <&porta 15 GPIO_ACTIVE_HIGH>; //RES
		led-gpios = <&porta 14 GPIO_ACTIVE_HIGH>; //BL

		debug = <0x0>;
	};
};

这里的gpio要结合你的引脚实现。

二、加载驱动

仿照参考文章,使用st7789v代码改动到st7735上。
记录为Linux配置spi屏幕(st7735s)

编译条件
duo-buildroot-sdk\linux_5.10\drivers\staging\fbtft\Makefile

obj-$(CONFIG_FB_TFT_ST7735R)     += fb_st7735r.o
obj-$(CONFIG_FB_TFT_ST7789V)     += fb_st7789v.o

借用st7789v的代码

st7735s和st7735r一致

引用:https://www.cnblogs.com/milton/p/15614304.html#St7735%E4%BB%8B%E7%BB%8D 
ST7735的配置
因为ST7735存在多个型号, 对于ST7735R和ST7735S, 使用默认的初始化方法

duo-buildroot-sdk\build\boards\cv180x\cv1800b_milkv_duo_sd\linux\ cvitek_cv1800b_milkv_duo_sd_defconfig

# spi lcd -- st7735s
CONFIG_SPI=y
CONFIG_SPI_MASTER=y
CONFIG_SPI_DESIGNWARE=y
CONFIG_SPI_DW_MMIO=y
CONFIG_SPI_SPIDEV=y
CONFIG_FB=y
CONFIG_FB_TFT=y
# CONFIG_FB_TFT_ST7735R=y
CONFIG_FB_TFT_ST7789V=y

编译过程提示

  CC      drivers/staging/fbtft/fb_st7789v.o

三、更改驱动

3.1 st7789v驱动

duo-buildroot-sdk\linux_5.10\drivers\staging\fbtft\fb_st7789v.c

参考来源:https://blog.csdn.net/qq_46604211/article/details/116449891

3.1.2 接口更新

由于驱动是st7789v,我的屏幕是st7735,需要更改一些初始化接口。

注意gamma需要注释掉for循环。

// st7735
#define ST7735_FRMCTR1		0xb1
#define ST7735_FRMCTR2		0xb2
#define ST7735_FRMCTR3		0xb3
#define ST7735_INVCTR		0xb4
#define ST7735_PWCTR1		0xc0
#define ST7735_PWCTR2		0xc1
#define ST7735_PWCTR3		0xc2
#define ST7735_PWCTR4		0xc3
#define ST7735_PWCTR5		0xc4
#define ST7735_VMCTR1		0xc5
#define ST7735_GAMCTRP1	0xe0
#define ST7735_GAMCTRN1	0xe1

#define ST7735_MY	BIT(7)
#define ST7735_MX	BIT(6)
#define ST7735_MV	BIT(5)
#define ST7735_RGB	BIT(3)

static int init_display(struct fbtft_par *par)
{
	par->fbtftops.reset(par);//硬复位

	mdelay(50);

    /* turn off sleep mode */
	write_reg(par, MIPI_DCS_EXIT_SLEEP_MODE);
	mdelay(100);

	//下面添加初始化函数write_reg 参数分别为:结构体指针,写命令,写数据....(后都为数据)
	//ST7735s Frame Rate

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

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

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

    //Column inversion
	write_reg(par, ST7735_INVCTR, 0x03); 

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

	write_reg(par, ST7735_PWCTR2, 0xc0); 

	write_reg(par, ST7735_PWCTR3, 0x0d,0x00); 

	write_reg(par, ST7735_PWCTR4, 0x8d,0x2a); //VCOM 

	write_reg(par, ST7735_PWCTR5, 0x8d,0xee); //MX, MY, RGB mode  ??

	write_reg(par, ST7735_VMCTR1, 0x1a);

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

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

    //MX, MY, RGB mode
    write_reg(par, MIPI_DCS_SET_ADDRESS_MODE, 0xc0);

	write_reg(par, MIPI_DCS_SET_PIXEL_FORMAT, MIPI_DCS_PIXEL_FMT_16BIT); //65k mode

	write_reg(par, MIPI_DCS_SET_DISPLAY_ON);//Display on
	mdelay(100);

	return 0;
}


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]);
	}
	return 0;
}

3.1.3 更改宽高

st7735的屏幕宽高为128*160。

duo-buildroot-sdk\linux_5.10\drivers\staging\fbtft\fb_st7789v.c

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,
	},
};

3.2 fbtft-core

duo-buildroot-sdk\linux_5.10\drivers\staging\fbtft\fbtft-core.c

3.2.1增加头文件

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

3.2.2 更改接口

这是由于内核版本更新导致的,一些接口可能需要改动。
dtsi中的属性加上-gpio可以自行选择。
reset重新实现。

//https://blog.csdn.net/qq_46604211/article/details/116449891
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 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;
}

//作者:Leesans https://www.bilibili.com/read/cv9947785/ 出处:bilibili
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);
    msleep(10);
    gpiod_set_value_cansleep(par->gpio.reset, 0);
    msleep(200);
    gpiod_set_value_cansleep(par->gpio.reset, 1);
    msleep(10);
}

四、屏幕显示结果

在这里插入图片描述
驱动正常加载。

通过如下两个命令可以测试屏幕功能。

cat /dev/urandom > /dev/fb0 	//显示花屏
cat /dev/zero > /dev/fb0  		//清空屏幕
echo xxxx > /dev/fb0 				//显示点个数

仔细看右上角,有一条颜色不同的线,很短,你可以echo后面跟很长的x,x越多,线越长。
这是手动赋值给像素点的。

在这里插入图片描述

五、用屏幕显示log

参考来源:
https://community.milkv.io/t/milk-v-duo-spi-st7789/131

5.1 添加编译模块

duo-buildroot-sdk\build\boards\cv180x\cv1800b_milkv_duo_sd\linux\cvitek_cv1800b_milkv_duo_sd_defconfig

# lcd display kernel log
CONFIG_TTY=y
CONFIG_VT=y
CONFIG_CONSOLE_TRANSLATIONS=y
CONFIG_VT_CONSOLE=y
CONFIG_HW_CONSOLE=y
CONFIG_VT_HW_CONSOLE_BINDING=y
CONFIG_FB=y
CONFIG_FB_CMDLINE=y
CONFIG_FB_NOTIFY=y
CONFIG_FONT_SUPPORT=y
CONFIG_FONTS=y
CONFIG_FONT_8x16=y
CONFIG_VGA_CONSOLE=y
CONFIG_DUMMY_CONSOLE=y
CONFIG_DUMMY_CONSOLE_COLUMNS=80
CONFIG_DUMMY_CONSOLE_ROWS=25
CONFIG_FRAMEBUFFER_CONSOLE=y
CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y

5.2 添加tty0用于显示log

duo-buildroot-sdk\u-boot-2021.10\include\configs\cv180x-asic.h

#define SET_BOOTARGS "setenv bootargs ${root} ${mtdparts} " \
		"console=tty0 console=$consoledev,$baudrate $othbootargs;"

5.3 显示

在这里插入图片描述

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
STM32F103C8T6是一款基于ARM Cortex-M3内核的高性能微控制器,ST7735TFT LCD是一种小尺寸彩色液晶显示,而驱动程序则是控制彩显示的软件程序。 要编写STM32F103C8T6与ST7735TFT LCD的驱动程序,首先需要了解ST7735TFT LCD的工作原理和通信协议。通常,彩是通过SPI通信与微控制器进行数据交互的。我们需要通过STM32F103C8T6的SPI接口来发送指令和数据给彩,以控制其显示内容。 在编写驱动程序时,首先需要初始化并配置STM32F103C8T6的SPI接口,设置相应的引脚为SPI功能,同时设置SPI的工作模式、速度等参数。 接下来,通过SPI接口向ST7735TFT LCD发送相应的命令来初始化和配置彩。这些命令可以在ST7735TFT LCD的数据手册中找到,并且需要按照指定的时序和格式进行发送。 一旦彩初始化完成,就可以向彩发送图像数据来实现显示。在驱动程序中,需要提供相应的绘图函数,如画点、画线、画圆等等。这些函数将根据需要生成相应的数据并通过SPI接口发送给彩。 当需要更新或清除屏幕显示内容时,只需要调用相应的函数来更新或清除相应的像素点数据。 最后,我们需要编写适当的延时函数来控制彩的刷新速度,以保证显示效果的流畅性。 总之,编写STM32F103C8T6与ST7735TFT LCD的驱动程序需要深入理解彩的工作原理和通信协议,以及熟悉STM32F103C8T6的SPI接口的配置和使用。通过编写合适的初始化函数、绘图函数和延时函数,我们可以方便地控制ST7735TFT LCD的显示内容。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值