您尚未登录。

#1 2021-04-28 21:47:32 分享评论

无痕
会员
注册时间: 2021-02-04
已发帖子: 28
积分: 15

linux5.2内核,配置SPI屏幕(ili9341)步骤

内核版本:linux5.2

参考文章:
      https://whycan.com/t_576.html#p1579
      https://blog.csdn.net/qulang000/article/details/114686525

我在配置此屏幕时遇到问题发的帖子
      https://whycan.com/t_6393.html

感谢大佬们的热心指导!

-----------------------------------------------------------------------------------------------------------------------------
1、配置内核驱动
Device Drivers  --->
    [ * ] Staging drivers  --->
        <*>   Support for small TFT LCD display modules  --->
                <*>   FB driver for the ILI9341 LCD Controller
                <*>   Generic FB driver for TFT LCD displays

2、在sun8i-v3s-licheepi-zero.dts添加设备树节点。注意,reset、dc引脚可以自由选择,只要不跟其它驱动冲突即可。

&i2c0 {
112     status = "disable";
113 
114     ns2009: ns2009@48 {
115         compatible = "nsiway,ns2009";
116         reg = <0x48>;
117     };
118 };


183 &spi0 {
184     status = "okay";
185     spi_lcd@0 {
186         #address-cells = <1>;
187         #size-cells = <1>;
188         rotate = <90>;
189         fps = <30>;
190         buswidth = <8>;
191         bgr;
192         dc-gpios = <&pio 1 5 GPIO_ACTIVE_HIGH>;
193         reset-gpios = <&pio 1 7 GPIO_ACTIVE_LOW>;
194         debug = <0x0>;
195         compatible = "ilitek,ili9341";
196         reg = <0>;
197         spi-max-frequency = <48000000>;
198     };
199 };

3、修改drivers/staging/fbtft/fbtft-core.c文件中的fbtft_request_one_gpio函数

注意需要在该文件上引入下面头文件,否则编译报错。
#include <linux/of_gpio.h>

      static int fbtft_request_one_gpio(struct fbtft_par *par,
  76                   const char *name, int index,
  77                   struct gpio_desc **gpiop)
  78 {
  79 /*
  80     struct device *dev = par->info->device;
  81     struct device_node *node = dev->of_node;
  82     int ret = 0;
  83 
  84     if (of_find_property(node, name, NULL)) {
  85         *gpiop = devm_gpiod_get_index(dev, dev->driver->name, index,
  86                           GPIOD_OUT_HIGH);
  87         if (IS_ERR(*gpiop)) {
  88             ret = PTR_ERR(*gpiop);
  89             dev_err(dev,
  90                 "Failed to request %s GPIO:%d\n", name, ret);
  91             return ret;
  92         }
  93         fbtft_par_dbg(DEBUG_REQUEST_GPIOS, par, "%s: '%s' GPIO\n",
  94                   __func__, name);
  95     }
  96 
  97     return ret;
  98 */
 100     struct device *dev = par->info->device;
 101     struct device_node *node = dev->of_node;
 102     int gpio, flags, ret = 0;
 103     enum of_gpio_flags of_flags;
 104     char gpio_names[32];
 105 
 106     //sprintf(gpio_names, "%s-gpios", name);
 107     sprintf(gpio_names, "%s", name);
 108     printk("@ gpio_names = %s\n", gpio_names);
 109     if (of_find_property(node, gpio_names, NULL)) {
 110         gpio = of_get_named_gpio_flags(node, gpio_names, index, &of_flags);
 111         printk ("@ gpio = %d | ENOENT = %d | EPROBE_DEFER = %d  \n", gpio, ENOENT, EPROBE_DEFER);
 112         if (gpio == -ENOENT)
 113             return 0;
 114         if (gpio == -EPROBE_DEFER)
 115             return gpio;
 116         if (gpio < 0) {
 117             dev_err(dev,
 118                 "failed to get '%s' from DT\n", gpio_names);
 119             return gpio;
 120         }
 121 
 122          //active low translates to initially low 
 123         flags = (of_flags & OF_GPIO_ACTIVE_LOW) ? GPIOF_OUT_INIT_LOW :
 124                             GPIOF_OUT_INIT_HIGH;
 125         ret = devm_gpio_request_one(dev, gpio, flags,
 126                         dev->driver->name);
 127         if (ret) {
 128             dev_err(dev,
 129                 "gpio_request_one('%s'=%d) failed with %d\n",
 130                 gpio_names, gpio, ret);
 131             return ret;
 132         }
 133 
 134         *gpiop = gpio_to_desc(gpio);
 135         fbtft_par_dbg(DEBUG_REQUEST_GPIOS, par, "%s: '%s' = GPIO%d\n",
 136                             __func__, gpio_names, gpio);
 137     }
 138     return ret;
 139 }

4、修改drivers/staging/fbtft/fbtft-core.c文件中的fbtft_reset函数

 278 static void fbtft_reset(struct fbtft_par *par)
 279 {
 280     /*
 281     if (!par->gpio.reset)
 282         return;
 283     fbtft_par_dbg(DEBUG_RESET, par, "%s()\n", __func__);
 284     gpiod_set_value_cansleep(par->gpio.reset, 0);
 285     usleep_range(20, 40);
 286     gpiod_set_value_cansleep(par->gpio.reset, 1);
 287     msleep(120);
 288     */
 289 
 290 
 291     if (!par->gpio.reset)
 292         return;
 293     fbtft_par_dbg(DEBUG_RESET, par, "%s()\n", __func__);
 294     gpiod_set_value_cansleep(par->gpio.reset, 1);
 295     usleep_range(20, 40);
 296     gpiod_set_value_cansleep(par->gpio.reset, 0);
 297     msleep(120);
 298     gpiod_set_value_cansleep(par->gpio.reset, 1);
 299     msleep(10);
 300 
 301 }

5、修改修改drivers/staging/fbtft/fbtft-core.c文件中的fbtft_request_gpios_dt函数里面,reset和dc引脚名称,从reset-gpios 和 dc-gpios 改为reset 和dc。

141 static int fbtft_request_gpios_dt(struct fbtft_par *par)
 142 {
 143     int i;
 144     int ret;
 145 
 146     if (!par->info->device->of_node)
 147         return -EINVAL;
 148 
 149 
 150     ret = fbtft_request_one_gpio(par, "reset", 0, &par->gpio.reset);
 151     if (ret)
 152         return ret;
 153 
 154     ret = fbtft_request_one_gpio(par, "dc", 0, &par->gpio.dc);
 155     if (ret)
 156         return ret;
 157 
 158     ret = fbtft_request_one_gpio(par, "rd-gpios", 0, &par->gpio.rd);
 159     if (ret)
 160         return ret;
 161     ret = fbtft_request_one_gpio(par, "wr-gpios", 0, &par->gpio.wr);
 162     if (ret)
 163         return ret;
 164     ret = fbtft_request_one_gpio(par, "cs-gpios", 0, &par->gpio.cs);
 165     if (ret)
 166         return ret;
 167     ret = fbtft_request_one_gpio(par, "latch-gpios", 0, &par->gpio.latch);
 168     if (ret)
 169         return ret;
 170     for (i = 0; i < 16; i++) {
 171         ret = fbtft_request_one_gpio(par, "db-gpios", i,
 172                          &par->gpio.db[i]);
 173         if (ret)
 174             return ret;
 175         ret = fbtft_request_one_gpio(par, "led-gpios", i,
 176                          &par->gpio.led[i]);
 177         if (ret)
 178             return ret;
 179         ret = fbtft_request_one_gpio(par, "aux-gpios", i,
 180                          &par->gpio.aux[i]);
 181         if (ret)
 182             return ret;
 183     }

6、修改drivers/staging/fbtft/fbtft-bus.c 中的fbtft_write_vmem16_bus8函数,直接替换

 
int fbtft_write_vmem16_bus8(struct fbtft_par *par, size_t offset, size_t len)
{
	u16 *vmem16;
	__be16 *txbuf16 = par->txbuf.buf;
	size_t remain;
	size_t to_copy;
	size_t tx_array_size;
	int i;
	int ret = 0;
	size_t startbyte_size = 0;
 
	fbtft_par_dbg(DEBUG_WRITE_VMEM, par, "%s(offset=%zu, len=%zu)\n",
		      __func__, offset, len);
 
	remain = len / 2;
	vmem16 = (u16 *)(par->info->screen_buffer + offset);
 
	if (par->gpio.dc)
	{
		//printk("dc拉高!\n");
		gpiod_set_value(par->gpio.dc, 1);
	}
	/* non buffered write */
	if (!par->txbuf.buf)
		return par->fbtftops.write(par, vmem16, len);
 
	/* buffered write */
	tx_array_size = par->txbuf.len / 2;
 
	if (par->startbyte) {
		txbuf16 = par->txbuf.buf + 1;
		tx_array_size -= 2;
		*(u8 *)(par->txbuf.buf) = par->startbyte | 0x2;
		startbyte_size = 1;
	}
 
	while (remain) {
		to_copy = min(tx_array_size, remain);
		dev_dbg(par->info->device, "to_copy=%zu, remain=%zu\n",
			to_copy, remain - to_copy);
 
		for (i = 0; i < to_copy; i++)
			txbuf16[i] = cpu_to_be16(vmem16[i]);
 
		vmem16 = vmem16 + to_copy;
		ret = par->fbtftops.write(par, par->txbuf.buf,
						startbyte_size + to_copy * 2);
		if (ret < 0)
			return ret;
		remain -= to_copy;
	}
 
	return ret;
}

最后编译运行即可,启动log中会出现下面提示

[    1.165809] fbtft_of_value: buswidth = 8
[    1.169779] fbtft_of_value: debug = 0
[    1.173438] fbtft_of_value: rotate = 90
[    1.177267] fbtft_of_value: fps = 30
[    1.215817] mmc0: host does not support reading read-only switch, assuming write-enable
[    1.225921] mmc0: new high speed SDHC card at address 1234
[    1.233279] mmcblk0: mmc0:1234 SA08G 7.21 GiB
[    1.239976]  mmcblk0: p1 p2
[    1.475892] random: fast init done
[    1.510864] Console: switching to colour frame buffer device 40x30
[    1.517762] graphics fb0: fb_ili9341 frame buffer, 320x240, 150 KiB video memory, 16 KiB buffer memory, fps=33, spi0.0 at 48 MHz

离线

#2 2021-04-28 21:49:14 分享评论

无痕
会员
注册时间: 2021-02-04
已发帖子: 28
积分: 15

Re: linux5.2内核,配置SPI屏幕(ili9341)步骤

接线

SPI屏    zero
3v3    3v3
GND    GND
DC    PWM1
RST    3v3
CS    CS
CLK    CLK
MISO    MISO
MOSI    MOSI
LED   3.3V

离线

#3 2021-04-29 13:10:23 分享评论

阿黄
会员
注册时间: 2018-10-03
已发帖子: 250
积分: 237.5

Re: linux5.2内核,配置SPI屏幕(ili9341)步骤

娃酷网就需要你这样的分享

离线

#4 2021-04-29 16:16:38 分享评论

zzm24
会员
注册时间: 2018-05-07
已发帖子: 60
积分: 41.5

Re: linux5.2内核,配置SPI屏幕(ili9341)步骤

记得spi FIFO只有64字节,楼主可以在刷屏时cat /proc/interrupts看看spi的中断次数不?
看看刷屏中断会不会太频繁了

离线

#5 2021-04-29 17:21:44 分享评论

无痕
会员
注册时间: 2021-02-04
已发帖子: 28
积分: 15

Re: linux5.2内核,配置SPI屏幕(ili9341)步骤

zzm24 说:

记得spi FIFO只有64字节,楼主可以在刷屏时cat /proc/interrupts看看spi的中断次数不?
看看刷屏中断会不会太频繁了

可以呀,但是我现在只是把屏幕配置好。我是打算把摄像头获取到的图像显示在屏幕上的,但是使用的时候遇到了问题。问题发在下面的帖子上。
https://whycan.com/t_3909.html

或者你告诉怎么刷屏

离线

#6 2021-04-30 07:29:36 分享评论

无痕
会员
注册时间: 2021-02-04
已发帖子: 28
积分: 15

Re: linux5.2内核,配置SPI屏幕(ili9341)步骤

zzm24 说:

记得spi FIFO只有64字节,楼主可以在刷屏时cat /proc/interrupts看看spi的中断次数不?
看看刷屏中断会不会太频繁了

你看下

# cat /proc/interrupts
           CPU0
 19:       7542     GIC-0  27 Level     arch_timer
 21:          0     GIC-0  50 Level     timer@1c20c00
 22:          0     GIC-0  82 Level     1c02000.dma-controller
 23:      27439     GIC-0  92 Level     sunxi-mmc
 24:          0     GIC-0 103 Level     musb-hdrc.1.auto
 25:          0     GIC-0 104 Level     ehci_hcd:usb1
 26:          2     GIC-0 105 Level     ohci_hcd:usb2
 27:          0     GIC-0  72 Level     1c20400.rtc
 29:       1021     GIC-0 116 Level     sun6i-csi
 34:        392     GIC-0  32 Level     ttyS0
 35:       1724     GIC-0  39 Level     mv64xxx_i2c
 36:    4082175     GIC-0  97 Level     sun6i-spi
IPI0:          0  CPU wakeup interrupts
IPI1:          0  Timer broadcast interrupts
IPI2:          0  Rescheduling interrupts
IPI3:          0  Function call interrupts
IPI4:          0  CPU stop interrupts
IPI5:          0  IRQ work interrupts
IPI6:          0  completion interrupts
Err:          0

离线

#7 2021-04-30 10:04:54 分享评论

zzm24
会员
注册时间: 2018-05-07
已发帖子: 60
积分: 41.5

Re: linux5.2内核,配置SPI屏幕(ili9341)步骤

FIFO 刷屏这个中断次数确实挺高的
36:    4082175     GIC-0  97 Level     sun6i-spi

一帧320*240*2=153600字节
刷一帧153600/64=2400次
因为我现在F1C100S上在用DMA刷SPI TFT,但是感觉跟其他通道DMA有干扰,想看看主线的FIFO刷的效率

离线

#8 2021-05-02 23:39:32 分享评论

酷酷酷
会员
注册时间: 2021-04-13
已发帖子: 29
积分: 14.5

Re: linux5.2内核,配置SPI屏幕(ili9341)步骤

请问如果移植完是黑屏的怎么办 u-boot使用的默认的配置 没有lcd的

离线

#9 2021-05-03 09:39:26 分享评论

无痕
会员
注册时间: 2021-02-04
已发帖子: 28
积分: 15

Re: linux5.2内核,配置SPI屏幕(ili9341)步骤

酷酷酷 说:

请问如果移植完是黑屏的怎么办 u-boot使用的默认的配置 没有lcd的

cat /dev/urandom > /dev/fb0
cat /dev/zero > /dev/fb0

使用第一条命令可以让屏幕出现雪花

使用第二条命令可以让屏幕变黑

说明屏幕移植成功

离线

#10 2021-05-03 21:33:24 分享评论

酷酷酷
会员
注册时间: 2021-04-13
已发帖子: 29
积分: 14.5

Re: linux5.2内核,配置SPI屏幕(ili9341)步骤

无痕 说:
酷酷酷 说:

请问如果移植完是黑屏的怎么办 u-boot使用的默认的配置 没有lcd的

cat /dev/urandom > /dev/fb0
cat /dev/zero > /dev/fb0

使用第一条命令可以让屏幕出现雪花

使用第二条命令可以让屏幕变黑

说明屏幕移植成功

那有什么库可以显示图片的吗 还有就是控制台的输出是怎么输出在屏幕上的呀
fbv太难移植了 fbset好像又用不了

最近编辑记录 酷酷酷 (2021-05-03 21:34:41)

离线

页脚

工信部备案:粤ICP备20025096号 Powered by FluxBB

感谢为中文互联网持续输出优质内容的各位老铁们。 QQ: 516333132, 微信(wechat): whycan_cn (哇酷网/挖坑网/填坑网) service@whycan.cn