内核版本: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
离线
接线
SPI屏 zero
3v3 3v3
GND GND
DC PWM1
RST 3v3
CS CS
CLK CLK
MISO MISO
MOSI MOSI
LED 3.3V
离线
记得spi FIFO只有64字节,楼主可以在刷屏时cat /proc/interrupts看看spi的中断次数不?
看看刷屏中断会不会太频繁了
可以呀,但是我现在只是把屏幕配置好。我是打算把摄像头获取到的图像显示在屏幕上的,但是使用的时候遇到了问题。问题发在下面的帖子上。
https://whycan.com/t_3909.html
或者你告诉怎么刷屏
离线
记得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
离线
请问如果移植完是黑屏的怎么办 u-boot使用的默认的配置 没有lcd的
cat /dev/urandom > /dev/fb0
cat /dev/zero > /dev/fb0
使用第一条命令可以让屏幕出现雪花
使用第二条命令可以让屏幕变黑
说明屏幕移植成功
离线