1. 硬件:
使用正点原子的IMX6ULL Linux开发板
开发板底板原理图版本:V2.1
核心板原理图版本:V1.6
LCD :MSP2402 (IC ILI9341)
2. 查找可用引脚
开发板上引出的引脚是在JP6上,只看JP6会发现没有可用的SPI引脚,但是查看底板原理图中与核心板相连的位置会发现其实JP6上的UART2的TX/RX/CTS/RTS 四个引脚正好可以复用为ECSPI3的 MISO/MOSI/CLK/SS0四个引脚,SPI LCD还需要三个IO口作为Reset/DC/背光的控制引脚,如
下图所示(但是我是偷懒了,将背光引脚直接接的V3.3)
3.添加支持SPI LCD的设备树节点(不废话,直接上干货)
pinctrl_ecspi3: ecspi3grp {
fsl,pins = <
MX6UL_PAD_UART2_RTS_B__ECSPI3_MISO 0x100b1 /* MISO*/
MX6UL_PAD_UART2_CTS_B__ECSPI3_MOSI 0x100b1 /* MOSI*/
MX6UL_PAD_UART2_RX_DATA__ECSPI3_SCLK 0x100b1 /* CLK*/
MX6UL_PAD_UART2_TX_DATA__GPIO1_IO20 0x100b0 /* CS*/
MX6UL_PAD_GPIO1_IO00__GPIO1_IO00 0x17059 /*back light*/
MX6UL_PAD_GPIO1_IO03__GPIO1_IO03 0x17059 /*data&command*/
MX6UL_PAD_GPIO1_IO08__GPIO1_IO08 0x17059 /* Reset IO */
>;
};
&ecspi3 {
fsl,spi-num-chipselects = <1>;
cs-gpios = <&gpio1 20 GPIO_ACTIVE_LOW>; ###特别注意,ATK出厂的设备树这里有问题,原有的cs-gpio 需要改成cs-gpios不然SPI将无法工作
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_ecspi3>;
status = "okay";
spidev: icm20608@0 {
compatible = "alientek,icm20608";
spi-max-frequency = <8000000>;
reg = <0>;
};
spi_lcd_msp2402@0 {
compatible = "spi_lcd_msp2402";
spi-max-frequency = <8000000>;
reg = <0>;
msp2402-bl-gpio = <&gpio1 0 GPIO_ACTIVE_HIGH>;
msp2402-dc-gpio = <&gpio1 3 GPIO_ACTIVE_HIGH>;
msp2402-rst-gpio = <&gpio1 8 GPIO_ACTIVE_HIGH>;
};
4.关键代码:
1.请先分析一下IMX6ULL的SPI设备驱动,网上太多了此处不再赘述
2. LCD初始化命令:
命令序列是从淘宝客服给的单片机代码里摘出来的(没有去看ILI的芯片手册,太长了,五的初衷是学习驱动,而不是研究LCD,因此请不要问我命令都是实现什么功能的,因为我不知道)
struct spi_lcd_cmd{
u8 reg_addr; // command
u8 len; //需要从spi_lcd_datas数组里发出数据字节数
int delay_ms; //此命令发送数据完成后,需延时多久
}cmds[] = {
{0xCF, 3, 0},
{0xED, 4, 0},
{0xE8, 3, 0},
{0xCB, 5, 0},
{0xF7, 1, 0},
{0xEA, 2, 0},
{0xC0, 1, 0},
{0xC1, 1, 0},
{0xC5, 2, 0},
{0xC7, 1, 0},
{0x36, 1, 0},
{0x3A, 1, 0},
{0xB1, 2, 0},
{0xB6, 2, 0},
{0xF2, 1, 0},
{0x26, 1, 0},
{0xE0, 15, 0},
{0xE1, 15, 0},
{0x2B, 9, 0},
{0x11, 0, 120},
{0x29, 0, 0},
};
u8 spi_lcd_datas[] = {
0x00, 0xD9, 0x30, // command: 0xCF
0x64, 0x03, 0x12, 0x81, // command: 0xED
0x85, 0x10, 0x7A, // command: 0xE8
0x39, 0x2C, 0x00, 0x34, 0x02, // command: 0xCB
0x20, // command: 0xF7
0x00, 0x00, // command: 0xEA
0x1B, // command: 0xC0
0x12, // command: 0xC1
0x08, 0x26, // command: 0xC5
0xB7, // command: 0xC7
0x08, // command: 0x36
0x55, // command: 0x3A
0x00, 0x1A, // command: 0xB1
0x0A, 0xA2, // command: 0xB6
0x00, // command: 0xF2
0x01, // command: 0x26
0x0F, 0x1D, 0x1A, 0x0A, 0x0D, 0x07, 0x49, 0x66, 0x3B, 0x07, 0x11, 0x01, 0x09, 0x05, 0x04, //command: 0xE0
0x00, 0x18, 0x1D, 0x02, 0x0F, 0x04, 0x36, 0x13, 0x4C, 0x07, 0x13, 0x0F, 0x2E, 0x2F, 0x05, //command: 0xE1
0x00, 0x00, 0x01, 0x3F, 0x2A, 0x00, 0x00, 0x00, 0xEF, //command: 0x2B
};
3.大名鼎鼎的probe函数:
static int msp2402_probe(struct spi_device *spi)
{
int ret =0;
struct fb_info *fb;
/*初始化spi_device */
printk("File:%s Function:%s Line:%d \n",__FILE__,__FUNCTION__,__LINE__);
if (msp2402_gpio_parse_dt(&msp2402lcd, &spi->dev) < 0) {
printk(KERN_ERR "msp2402lcd gpio parse dt fail!\n");
goto params_parse_fail;
}
/*
Mode 0 CPOL=0, CPHA=0
Mode 1 CPOL=0, CPHA=1
Mode 2 CPOL=1, CPHA=0
Mode 3 CPOL=1, CPHA=1
*/
spi->mode = SPI_MODE_0; /*MODE0,CPOL=0,CPHA=0*/
spi->bits_per_word = 8;
// spi->dev.platform_data = msp2402lcd;
ret = spi_setup(spi);
if (ret < 0)
{
printk("spi_setup failed.\n");
}
/* 初始化msp2402内部寄存器 */
msp2402lcd.spi = spi;
msp2402_reginit(spi);
lcd_fill_rect(spi,0, 0,LCD_W,LCD_H,RED);
LCD_DrawLine(spi,0, 50, 240,50);
//至此,LCD的驱动部分就初始化完成了,屏幕上应该是红色背景,然后显示一条横线
// 下边是为了实现Framwbuffer的必要步骤:
/*填充frambuffer对应项目 */
fb = framebuffer_alloc(0, NULL);
if (!fb) {
printk(KERN_ERR "msp2402 lcd framebuffer alloc fail!\n");
goto dma_alloc_fail;
}
//LCD基本参数设置
fb->var.xres = LCD_W;
fb->var.yres = LCD_H;
fb->var.xres_virtual = LCD_W;
fb->var.yres_virtual = LCD_H;
fb->var.bits_per_pixel = 32;
//LCD RGB格式设置, RGB888
fb->var.red.offset = 16;
fb->var.red.length = 8;
fb->var.green.offset = 8;
fb->var.green.length = 8;
fb->var.blue.offset = 0;
fb->var.blue.length = 8;
//设置固定参数
strcpy(fb->fix.id, "MSP2402,spilcd");
fb->fix.type = FB_TYPE_PACKED_PIXELS;
fb->fix.visual = FB_VISUAL_TRUECOLOR;
//设置显存
fb->fix.line_length = LCD_W * 32 / 8;
fb->fix.smem_len = LCD_W * LCD_H * 32 / 8;
printk("fb->fix.smem_len is %d\n", fb->fix.smem_len);
dma_set_coherent_mask(&spi->dev, DMA_BIT_MASK(32));
fb->screen_base = dma_alloc_coherent(&spi->dev, fb->fix.smem_len, (dma_addr_t*)&fb->fix.smem_start, GFP_KERNEL);
if (!fb->screen_base) {
printk(KERN_ERR "dma_alloc_coherent %d bytes fail!\n", fb->fix.smem_len);
goto dma_alloc_fail;
}
printk("fb->screen_base is 0x%08x\n", (uint32_t)fb->screen_base);
fb->screen_size = LCD_W * LCD_H * 32 / 8;
printk("fb->screen_size is %ld\n", fb->screen_size);
//操作函数集
fb->fbops = &msp2402_fb_ops;
spi_set_drvdata(spi, fb);
ret = register_framebuffer(fb);
if (ret < 0) {
printk(KERN_ERR "register framebuffer fail!\n");
goto register_fail;
}
msp2402lcd.thread = kthread_run(msp2402_refresh_kthread_func, fb, spi->modalias);
printk("probe run successfully ...%s\n", spi->modalias);
return 0;
register_fail:
dma_free_coherent(&spi->dev, fb->fix.smem_len, fb->screen_base, fb->fix.smem_start);
dma_alloc_fail:
framebuffer_release(fb);
params_parse_fail:
gpio_free(msp2402lcd.data_command_io);
gpio_free(msp2402lcd.reset_io);
gpio_free(msp2402lcd.backlight_io);
return -1;
}
4. 清屏代码:
有两种写法建议都尝试以下就会发下差异(我就郁闷了一会)
方法一(这种方法清屏比较慢,需要7s左右,根本无法接受):
void LCD_Clear(struct spi_device *spi,u16 Color)
{
unsigned int i,m;
LCD_SetWindows(spi,0, 0,LCD_W - 1,LCD_H - 1);
gpio_set_value(msp2402lcd.reset_io, 1);
for(i=0;i<LCD_H-1;i++){
for(m=0;m<LCD_W-1;m++){
Lcd_WriteData_16Bit(spi,Color);
}
}
}
方法二:
static void lcd_fill_rect(struct spi_device *spi,uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color)
{
uint32_t size, i;
uint8_t data[] = {0};
uint8_t *mem;
size = (x2 - x1 + 1) * (y2 - y1 + 1) * 2; // RGB888 3个字节
data[1] = color >> 8;
data[0] = color;
mem = (uint8_t *)kzalloc(size, GFP_KERNEL);
if (!mem) {
printk(KERN_ERR "lcd_fill_rect: alloc %d bytes mem fail!\n", size);
}
for (i = 0; i < size/2 ; i++) {
mem[i * 2] = data[1];
mem[i * 2 + 1] = data[0];
}
LCD_SetWindows(spi,0, 0,LCD_W - 1,LCD_H - 1);
gpio_set_value(msp2402lcd.data_command_io, 1);
spi_write(spi,mem, size);
kfree(mem);
}
完整源码地址(如果硬件相同可直接运行):文章来源:https://www.toymoban.com/news/detail-459135.html
(48条消息) IMX6ULL+SPILCDMSP2402(驱动ICILI9341)显示简单的QT界面-C文档类资源-CSDN文库文章来源地址https://www.toymoban.com/news/detail-459135.html
到了这里,关于IMX6ULL + SPI LCD(驱动IC ILI9341)显示简单的QT界面的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!