linux 添加ili9341屏的驱动
1、修改pinmux
我的板子是MiLK V DUO SPI2默认是做为GPIO,所以先修改为SPI功能
可以修改两个地方,修改一个地方就可以了:
u-boot-2021.10/board/cvitek/cv180x/board.c
pinmux_config(PINMUX_SPI2); //sdk默认把这里注释了,取消掉 PINMUX_CONFIG(SPINOR_CS_X, XGPIOA_24); //添加,这里的默认管脚功能并不是GPIO,修改之 PINMUX_CONFIG(SPINOR_MISO, XGPIOA_23); //添加,这里也一样 cvi_board_init();
build/boards/cv180x/cv1800b_milkv_duo_sd/u-boot/cvi_board_init.c
int cvi_board_init(void) { // sensor i2c1 reset mclk PINMUX_CONFIG(PAD_MIPIRX0P, CAM_MCLK0); // MCLK0 PINMUX_CONFIG(PAD_MIPIRX1P, IIC1_SDA); // I2C 2 PINMUX_CONFIG(PAD_MIPIRX0N, IIC1_SCL); PINMUX_CONFIG(PAD_MIPIRX1N, XGPIOC_8); // all default gpio PINMUX_CONFIG(SPINOR_HOLD_X, XGPIOA_26); PINMUX_CONFIG(SPINOR_SCK, XGPIOA_22); PINMUX_CONFIG(SPINOR_MOSI, XGPIOA_25); PINMUX_CONFIG(SPINOR_WP_X, XGPIOA_27); PINMUX_CONFIG(SPINOR_MISO, XGPIOA_23); PINMUX_CONFIG(SPINOR_CS_X, XGPIOA_24); PINMUX_CONFIG(IIC0_SDA, XGPIOA_29); PINMUX_CONFIG(IIC0_SCL, XGPIOA_28); // sd1 PINMUX_CONFIG(SD1_D3, PWR_GPIO_18); PINMUX_CONFIG(SD1_D2, PWR_GPIO_19); PINMUX_CONFIG(SD1_D1, PWR_GPIO_20); PINMUX_CONFIG(SD1_D0, PWR_GPIO_21); //PINMUX_CONFIG(SD1_CMD, PWR_GPIO_22); //PINMUX_CONFIG(SD1_CLK, PWR_GPIO_23); pinmux_config(PINMUX_SPI2); //打开SPI2 PINMUX_CONFIG(SPINOR_CS_X, XGPIOA_24); //做为GPIO脚CS脚 PINMUX_CONFIG(SPINOR_MISO, XGPIOA_23); //做为GPIO脚REST脚 //default to gpio PINMUX_CONFIG(PAD_MIPIRX1P, XGPIOC_9); PINMUX_CONFIG(PAD_MIPIRX0N, XGPIOC_10); PINMUX_CONFIG(USB_VBUS_DET, XGPIOB_6); PINMUX_CONFIG(PWR_SEQ2, PWR_GPIO_4); return 0; }
2、配置设备树
/dts-v1/; #include "cv180x_base_riscv.dtsi" #include "cv180x_asic_qfn.dtsi" #include "cv180x_asic_sd.dtsi" #include "cv180x_default_memmap.dtsi" &mipi_rx{ snsr-reset = <&portc 8 GPIO_ACTIVE_LOW>, <&portc 8 GPIO_ACTIVE_LOW>, <&portc 8 GPIO_ACTIVE_LOW>; }; &spi2 { status = "okay"; /delete-node/ spidev@0; ili9341:ili9341@0{ compatible = "adafruit,yx240qv29", "ilitek,ili9341"; //驱动 reg = <0>; status = "okay"; spi-max-frequency = <80000000>; spi-cpol; spi-cpha; rotate = <270>; fps = <30>; bgr; buswidth = <8>; dc = <&porta 24 GPIO_ACTIVE_HIGH>; reset = <&porta 23 GPIO_ACTIVE_HIGH>; debug = <0x0>; }; }; / { };
因为我这个板子SPI以前是做GPIO的所有要添加SPI脚上拉
build/boards/default/dts/cv180x/cv180x_base.dtsi
spi2:spi2@041A0000 { compatible = "snps,dw-apb-ssi"; reg = <0x0 0x041A0000 0x0 0x10000>; clocks = <&clk CV180X_CLK_SPI>; #address-cells = <1>; #size-cells = <0>; bias-pull-up; //添加这个地方,作用是上拉 };
3、配置内核
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_ILI9341=y
下面这些不是必须配置的如果你要显示控制台就需要配置。
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
配置上Uboot启动时打印控制台信息到屏上
修改:u-boot-2021.10/include/configs/cv180x-asic.h文件
修改配置:#define CONSOLEDEV "tty0\0" 大约221行左右
4、修改源码
找到ili9341驱动文件:"duo-buildroot-sdk/linux_5.10/drivers/staging/fbtft/fbtft-core.c""
修改fbtft_request_one_gpio函数
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; }
继续:fbtft_reset函数
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); }
下面这个地方我没有修改已经可以正常运行了。"duo-buildroot-sdk/linux_5.10/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; }
然后编译下载到板子上运行。
运行fb-test
运行fbv显示图片