一、屏幕概述与引脚分布
随便买的3.5寸LCD电容触摸屏,分辨率为480*320,最大只支持两点触摸,支持spi或并口,朋友帮忙画的板子。
显示ic引脚与触摸ic引脚如下
使用的milkv duo-64M引脚如下
二、一些细节
参考了以下资料。
1.修改设备树
build/boards/cv180x/cv1800b_milkv_duo_sd/dts_riscv/cv1800b_milkv_duo_sd.dts
添加了spi节点下的ili9488,添加了iic节点下fts。内容如下:
&spi2 {
status = "okay";
/delete-node/ spidev@0;
ili9488: ili9488@0{
compatible = "ilitek,ili9488";
reg = <0>;
status = "okay";
spi-max-frequency = <80000000>;
spi-cpol;
spi-cpha;
rotate = <90>; //旋转角度,默认竖屏,顺时针旋转
fps = <60>;
buswidth = <8>;
dc-gpios = <&porta 23 GPIO_ACTIVE_HIGH>; //DC
reset-gpios = <&porta 24 GPIO_ACTIVE_LOW>; //RST
led-gpios = <&portb 3 GPIO_ACTIVE_LOW>; //BL
debug = <0x0>;
};
};
&i2c1 {
status = "okay";
clock-frequency = <400000>;
focaltech@38 {
status = "okay";
compatible = "focaltech,fts";
reg = <0x38>;
// interrupt-parent = <&porta>;
// interrupts = <15 IRQ_TYPE_LEVEL_LOW>;
focaltech,reset-gpios = <&porta 14 GPIO_ACTIVE_LOW>;
focaltech,irq-gpios = <&porta 15 GPIO_ACTIVE_LOW>;
focaltech,max-touch-number = <2>;
focaltech,display-coords = <0 0 320 480>;
};
};
2.配置引脚
build/boards/cv180x/cv1800b_milkv_duo_sd/u-boot/cvi_board_init.c
配置了IIC,SPI和一些GPIO。
// I2C1 --> FT6336u
PINMUX_CONFIG(PAD_MIPIRX1P, IIC1_SDA);
PINMUX_CONFIG(PAD_MIPIRX0N, IIC1_SCL);
PINMUX_CONFIG(SD0_PWR_EN, XGPIOA_14); // RST
PINMUX_CONFIG(SPK_EN, XGPIOA_15); // IRQ
// SPI --> ILI9488
PINMUX_CONFIG(SD1_CLK, SPI2_SCK);
PINMUX_CONFIG(SD1_CMD, SPI2_SDO);
PINMUX_CONFIG(SD1_D0, SPI2_SDI);
PINMUX_CONFIG(SD1_D3, SPI2_CS_X);
PINMUX_CONFIG(SPINOR_MISO, XGPIOA_23); //D/C
PINMUX_CONFIG(SPINOR_CS_X, XGPIOA_24); //RST
PINMUX_CONFIG(ADC1, XGPIOB_3); //BL
3.完善ili9488
改的比较多,就挑一些讲了。
linux_5.10/drivers/staging/fbtft
将fb_ili9488.c添加至上面路径。ili9488与ili9486看起来差别不大,但是很致命。
在fb_ili9486.c中,MIPI_DCS_SET_PIXEL_FORMAT, 像素格式为565。
static const s16 default_init_sequence[] = {
...
/* Interface Pixel Format */
-1, MIPI_DCS_SET_PIXEL_FORMAT, 0x55,
...
ili9488在数据手册里写不进支持rgb565,还支持rgb666。但是实际上,只能使用rgb666,不然有问题。
所以fb_ili9488.c应如下
static const s16 default_init_sequence[] = {
...
/* Interface Pixel Format */
-1, MIPI_DCS_SET_PIXEL_FORMAT, 0x66,
...
其次,像素格式改了,绘制显存的方式也应该改变。
static struct fbtft_display display = {
.regwidth = 8,
.width = WIDTH,
.height = HEIGHT,
.init_sequence = default_init_sequence,
.fbtftops = {
.set_addr_win = set_addr_win,
.set_var = set_var,
.write_vmem = fbtft_write_vmem18to24_bus8,
},
}
相较于ili9486,多了“write_vmem = fbtft_write_vmem18to24_bus8”,定义一个新的函数,将rgb666以3字节发给显存,github里写的,不是我写的,我只是修改了,感谢Snitro。
linux_5.10/drivers/staging/fbtft/fbtft-bus.c
/* 16bpp converted to 18bpp stored in 24-bit over 8-bit databus */
int fbtft_write_vmem18to24_bus8(struct fbtft_par *par, size_t offset, size_t len)
{
u16 *vmem16;
u8 *txbuf = par->txbuf.buf;
size_t remain;
size_t to_copy;
size_t tx_array_size;
int i;
int ret = 0;
/* remaining number of pixels to send */
remain = len / 2;
vmem16 = (u16 *)(par->info->screen_buffer + offset);
if ((int)(par->gpio.dc) != -1)
gpiod_set_value(par->gpio.dc, 1);
/* number of pixels that fits in the transmit buffer */
tx_array_size = par->txbuf.len / 3;
while (remain) {
/* number of pixels to copy in one iteration of the loop */
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++) {
u16 pixel = vmem16[i];
u16 b = pixel & 0x1f;
u16 g = (pixel & (0x3f << 5)) >> 5;
u16 r = (pixel & (0x1f << 11)) >> 11;
txbuf[i * 3 + 2] = (r & 0x1F) << 3;
txbuf[i * 3 + 1] = (g & 0x3F) << 2;
txbuf[i * 3 + 0] = (b & 0x1F) << 3;
}
vmem16 = vmem16 + to_copy;
ret = par->fbtftops.write(par, par->txbuf.buf, to_copy * 3);
if (ret < 0)
return ret;
remain -= to_copy;
}
return ret;
}
EXPORT_SYMBOL(fbtft_write_vmem18to24_bus8);
记得去fbtft.h中声明。
linux_5.10/drivers/staging/fbtft/fbtft.h
int fbtft_write_vmem18to24_bus8(struct fbtft_par *par, size_t offset, size_t len);
最后,添加进Kconfig和Makefile,使其能在内核被选择,才能被编译。
linux_5.10/drivers/staging/fbtft/Kconfig
linux_5.10/drivers/staging/fbtft/Makefile
一些细节请看上面的参考链接。
4.添加触摸驱动
linux_5.10/drivers/input/touchscreen
将focaltech_touch整个文件夹放入上面的路径。
修复了一些bug,功能就保留了最基本的触摸和手势(但是我不知道手势怎么用,单片机给的例程还有近距离唤醒)。
然后,请注意,如“修改设备树”的注释一样,这个屏幕默认竖屏,如果旋转了屏幕,会出现显示坐标系与触摸坐标系不一致的情况。
为了解决问题就有了下面的修改。
#if FTS_MT_PROTOCOL_B_EN
static int fts_input_report_b(struct fts_ts_data *data)
{
......
input_report_abs(data->input_dev, ABS_MT_TOUCH_MAJOR, events[i].area);
#ifdef ROTATE_0
input_report_abs(data->input_dev, ABS_MT_POSITION_X, events[i].x);
input_report_abs(data->input_dev, ABS_MT_POSITION_Y, events[i].y);
#endif
#ifdef ROTATE_90
input_report_abs(data->input_dev, ABS_MT_POSITION_X, events[i].y);
input_report_abs(data->input_dev, ABS_MT_POSITION_Y, 320-events[i].x);
#endif
#ifdef ROTATE_180
input_report_abs(data->input_dev, ABS_MT_POSITION_X, 320-events[i].x);
input_report_abs(data->input_dev, ABS_MT_POSITION_Y, 480-events[i].y);
#endif
#ifdef ROTATE_270
input_report_abs(data->input_dev, ABS_MT_POSITION_X, 480-events[i].y);
input_report_abs(data->input_dev, ABS_MT_POSITION_Y, events[i].x);
#endif
......
请在fts_input_report_b函数之前#define ROTATE_X。
最后,添加进Kconfig和Makefile,使其能在内核被选择,才能被编译。
linux_5.10/drivers/input/touchscreen/Kconfig
linux_5.10/drivers/input/touchscreen/Makefile
我之前想在设备树节点里添加旋转角度,然后读取存入变量,但是这样每次触摸要switch判断,影响还是有的。
其次,这个320和480在设备树节点focaltech,display-coords里能读出来,这么写才规范。但是我懒,3.5寸的基本都是这个分辨率了,而且又不一定是同款触摸芯片。
三、在内核中添加
位于SDK内的根目录。
//配置环境
source device/milkv-duo/boardconfig.sh
source build/milkvsetup.sh
defconfig cv1800b_milkv_duo_sd
如果之前没有配置过内核请按以下方式操作。
menuconfig_kernel
//Exit 退出,保存
cp build/boards/cv180x/cv1800b_milkv_duo_sd/linux/cvitek_cv1800b_milkv_duo_sd_defconfig linux_5.10/.config
menuconfig_kernel
编译时用的内核配置文件在build里,默认内核里配置是空的,生成后退出,然后使用milkv的覆盖掉。
触摸
- 进入Device Drivers
- 进入Input device support
- 勾选<*>Event interface
- 勾选并进入<*>Touchscreens
- 勾选[*]Focaltech Touchscreen
显示
- 进入Device Drivers
- 进入[*]Staging drivers
- 进入<*>Support forsmall TFT LCD display modules
- 勾选<*>FB driver for the ILI9488 Controller
退出保存,编译,烧写。
四、效果与资源
使用了LVGL测试,**lv_demo_benchmark();**结果为37FPS。
实际使用流畅度还可以,cpu占用基本在20%左右。(在解锁了1Ghz加上打了spi-dma的补丁后,之前没有使用dma,cpu占用约80%)
因为这个搞得比较不规范,所以就直接提供文件了。