notro / fbtft

Linux Framebuffer drivers for small TFT LCD display modules. Development has moved to https://git.kernel.org/cgit/linux/kernel/git/gregkh/staging.git/tree/drivers/staging/fbtft?h=staging-testing
1.84k stars 495 forks source link

How to get going with an ili9488 #582

Closed woutware closed 2 years ago

woutware commented 2 years ago

Hi,

Newbie here in the Raspberry Pi world, but I am a programmer (C#), so I can possibly contribute if needed.

Anyways, I got an ili9488 display to play with, not realizing there doesn't seem to be support for it (yet?) in the raspberry pi world. From what I understand you need to write a device tree overlay with a bunch of parameters, but it also needs to have an actual driver, i.e. some C code behind it that the overlay is matched with. Am I understanding this correctly? When I look at https://elixir.bootlin.com/linux/latest/source/drivers/staging/fbtft, I see all supported controllers, and the ili9488 isn't there.

So my question is, what steps do I take to add support for the ili9488?

notro commented 2 years ago

Looking at the datasheet ili9488 supports MIPI DBI, DPI and DSI interfaces. Since you're asking here I assume you're pushing pixels over DBI (SPI). DBI compatible controllers use a common MIPI DCS command set meaning you don't have to add support for the specific controller. You just have to add the initialization command sequence to device tree. See https://github.com/notro/fbtft/wiki/FBTFT-RPI-overlays

Somewhere down the road this driver will be backported to downstram rpi-5.15 linux: https://github.com/notro/panel-mipi-dbi/wiki

woutware commented 2 years ago

Omfg, somebody is here! :) Yes I am using the SPI interface (can be 3 or 4 pins).

I'll try to give it a shot. But how do I know what the init sequence is supposed to be? I had a look at the ili9488 data sheet, but it's a zillion pages long and I don't know where to begin with this. I did find some C code googling around doing an init sequence from C, and I can possibly translate that to a .dts file.

Final question, so the driver code is in the fbtft overlay, but if I make my own ili9488.dts file specifying my init code, then I compile it into a ili9488.dtbo, how does that info get passed to the fbtft driver? I don't have an understanding how the C code in fbtft is connected to a .dts file that I make for my screen.

Edit: aaah, I think I get it. Am I right that the following line in the example .dts will link it to the fbtft driver? I still have a very vague understanding of how this all fits together:

compatible = "samsung,s6d02a1";

notro commented 2 years ago

I'll try to give it a shot. But how do I know what the init sequence is supposed to be?

You have to look at the display datasheet, not the controller data sheet. Usually there's some example code available from the seller that shows the necessary setup commands.

Yeah, the compatible links device and driver: https://elixir.bootlin.com/linux/latest/source/drivers/staging/fbtft/fb_s6d02a1.c#L157 (a driver can support multiple compatibles)

woutware commented 2 years ago

Got the display from aliexpress, and info on the display is very basic, but I'll send them a message.

I stole some init codes from here, and there's something happening on the display, and can cat some random stuff do it, so the display is sort of working, but I can't get it to rotate properly (setting TFT_MADCTL value), so I'm not entirely convinced this is even an ili9488 (but the comments on the aliexpress page say so).

I did manage to get output to the screen after editing /etc/X11/xorg.conf, rebooted and got actual text on the display (mirrored), and my hdmi didn't have any output anymore even I tried to make a dual screen configuration (hdmi + spi) .

woutware commented 2 years ago

Ok, 98% sure it's an ili9488, rather than a ili9486 that the package sticker and seller claim. I've tried init sections for both, plus the reset pin 0/1 are opposite for 9488 and 9486 models. With the ili9488 setup I can get an image onto it using the fbi program. But there are 2 problems, I can't take rotation to take effect (in the init), and the display is super slow, it takes half a second or so for the image to appear (probably 0.2 - 0.5 seconds), you see it scanning visibly. I'd expect it to be fairly instead at 20 MHz bus speed that I've configured. Here's my .dts file:

/* Device tree overlay for mytft40 */

/dts-v1/;
/plugin/;

/ {
  compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";

  fragment@0 {
    target = <&spi0>;
    __overlay__ {
      status = "okay";
    };
  };

  fragment@1 {
    target = <&spidev0>;
    __overlay__ {
      status = "disabled";
    };
  };

  fragment@2 {
    target = <&gpio>;
    __overlay__ {
      mytft40_display_pins: mytft40_display_pins {
        brcm,pins = <24 25>;
        brcm,function = <1 1>; // out out.
        //brcm,pull = <0 0>;
      };
    };
  };

  fragment@3 {
    target = <&spi0>;
    __overlay__ {
      /* needed to avoid dtc warning */
      #address-cells = <1>;
      #size-cells = <0>;

      mytft40display: mytft40-display@0{
        // MIPI DBI compatible driver.
        compatible = "ilitek,ili9486";
        reg = <0>;

        pinctrl-names = "default";
        pinctrl-0 = <&mytft40_display_pins>;

        spi-max-frequency = <20000000>;

        //txbuflen = <0x8000>;
        fps = <30>;
        buswidth = <8>;
        regwidth = <8>;
        //regwidth = <16>;

        rotation = <1>; //
        bgr = <0>;
        width = <480>;
        height = <320>;
        reset-gpios = <&gpio 25 1>; // reset is active low hence the 1
        dc-gpios = <&gpio 24 0>;
        debug = <0x4000000>; // print init commands to the kernel log

        // ili9488
        init = <
            0x100003A // Pixel Interface Format
            //0x55  // 16 bit colour for parallel
            0x66  // 18 bit colour for SPI

            0x1000036 // TFT_MADCTL, // Memory Access Control
            0x48          // MV, BGR (landscape)

            0x10000E0 // Positive Gamma Control
            0x00 0x03    0x09 0x08 0x16 0x0A 0x3F 0x78 0x4C 0x09 0x0A 0x08 0x16 0x1A 0x0F

            0x10000E1 // Negative Gamma Control
            0x00 0x16 0x19 0x03 0x0F 0x05 0x32 0x45 0x46 0x04 0x0E 0x0D 0x35 0x37 0x0F

            0x10000C0 // Power Control 1
            0x17 0x15

            0x10000C1 // Power Control 2
            0x41

            0x10000C5 // VCOM Control
            0x00 0x12 0x80

            0x10000B0 // Interface Mode Control
            0x80 // SD0 pin not used.

            0x10000B1 // Frame Rate Control
            0xA0

            0x10000B4 // Display Inversion Control
            0x02

            0x10000B6 // Display Function Control
            0x02 0x02 0x3B

            0x10000B7 // Entry Mode Set
            0xC6

            0x10000F7 // Adjust Control 3
            0xA9 0x51 0x2C 0x82

            0x1000011 // TFT_SLPOUT,  //Exit Sleep
            0x2000096 // delay(150)

            0x1000029 // TFT_DISPON,  //Display on
            0x2000019 // delay(25)
        >;

/*
        // ili9486
        init = <0x10000b0 0x00
                0x1000011
                0x20000ff
                0x100003a 0x55
                0x1000036 0x28
                0x10000c2 0x44
                0x10000c5 0x00 0x00 0x00 0x00
                0x10000e0 0x0f 0x1f 0x1c 0x0c 0x0f 0x08 0x48 0x98 0x37 0x0a 0x13 0x04 0x11 0x0d 0x00
                0x10000e1 0x0f 0x32 0x2e 0x0b 0x0d 0x05 0x47 0x75 0x37 0x06 0x10 0x03 0x24 0x20 0x00
                0x10000e2 0x0f 0x32 0x2e 0x0b 0x0d 0x05 0x47 0x75 0x37 0x06 0x10 0x03 0x24 0x20 0x00
                0x1000036 0x28
                0x1000011
                0x1000029>;          
*/                
      };
    };
  };

  __overrides__ {
    speed = <&mytft40display>,"spi-max-frequency:0";
    //txtbuflen = <&mytft40display>,"txtbuflen:0";
    rotate = <&mytft40display>,"rotation:0";
    fps = <&mytft40display>,"fps:0";
    bgr = <&mytft40display>,"bgr:0";
    debug = <&mytft40display>,"debug:0";
  };
};
notro commented 2 years ago

480x320 is slow over SPI, theoretical maximum @20MHz: 20000000 / (480*320*16) = 8 fps. Try 32 or 48MHz.

The upcoming panel-mipi-dbi driver will help you with this since you can probably do 64MHz with it, see point 4 here: https://github.com/notro/panel-mipi-dbi/wiki/fbtft#fbtft-vs-drm

ili9488/ili9486

It doesn't matter which controller you have, what matters is the init sequence which is display panel specific. You might get lucky if you find a sequence for a matching controller, but I might as well not work.

You are using "ilitek,ili9486" which will result in your 0x36 command being overwritten as stated on the wiki page I linked to. This is were it's overwritten: https://elixir.bootlin.com/linux/v5.16/source/drivers/staging/fbtft/fb_ili9486.c#L57

fbtft is RGB565 only, so command 0x3A needs a 0x55 parameter.

woutware commented 2 years ago

Man it's harder than I expected getting this working. Anyways, setting rotate to 270 seems to do something at least (still not correct width though, just a square area is cleared).

Setting the 16-bit color mode results in the display no longer working at all, display shows like a grey color. Seems to be related to this. I've also seen in other init code that the comment hints on SPI only supporting 18 bits.

I also got init code from someone that was pointed to in the aliexpress comments and that was said to work for the display I bought. Seems almost identical to the one I was using, but more brief.

I think I'm gonna abandon this display, looks like even if I get it working properly, it will be terribly slow too. I wish sellers would provide decent info on what they sold.

/* Device tree overlay for mytft40 */

/dts-v1/;
/plugin/;

/ {
  compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";

  fragment@0 {
    target = <&spi0>;
    __overlay__ {
      status = "okay";
    };
  };

  fragment@1 {
    target = <&spidev0>;
    __overlay__ {
      status = "disabled";
    };
  };

  fragment@2 {
    target = <&gpio>;
    __overlay__ {
      mytft40_display_pins: mytft40_display_pins {
        brcm,pins = <24 25>;
        brcm,function = <1 1>; // out out.
        //brcm,pull = <0 0>;
      };
    };
  };

  fragment@3 {
    target = <&spi0>;
    __overlay__ {
      /* needed to avoid dtc warning */
      #address-cells = <1>;
      #size-cells = <0>;

      mytft40display: mytft40-display@0{
        // MIPI DBI compatible driver.
        compatible = "ilitek,ili9486";
        reg = <0>;

        pinctrl-names = "default";
        pinctrl-0 = <&mytft40_display_pins>;

        spi-max-frequency = <20000000>;

        //txbuflen = <0x8000>;
        fps = <30>;
        buswidth = <8>;
        regwidth = <8>;

        rotation = <270>; //
        rotate = <270>;
        bgr = <1>;
        width = <480>;
        height = <320>;
        reset-gpios = <&gpio 25 1>; // reset is active low hence the 1
        dc-gpios = <&gpio 24 0>;
        debug = <0x4000000>; // print init commands to the kernel log

        // From: https://github.com/ZinggJM/ILI9486_SPI/blob/master/src/ILI9486_SPI.cpp
        init = <
          0x100003A
          0x55  // use 16 bits per pixel color
          //0x66  // use 18 bits per pixel color

          0x1000036
          0x48  // MX, BGR == rotation 0

          // PGAMCTRL(Positive Gamma Control)
          0x10000E0 0x0F 0x1F 0x1C 0x0C 0x0F 0x08 0x48 0x98 0x37 0x0A 0x13 0x04 0x11 0x0D 0x00
          // NGAMCTRL(Negative Gamma Control)
          0x10000E1 0x0F 0x32 0x2E 0x0B 0x0D 0x05 0x47 0x75 0x37 0x06 0x10 0x03 0x24 0x20 0x00
          // Digital Gamma Control 1
          0x10000E2 0x0F 0x32 0x2E 0x0B 0x0D 0x05 0x47 0x75 0x37 0x06 0x10 0x03 0x24 0x20 0x00

          0x1000011  // Sleep OUT
          0x2000096   // wait some time
          0x1000029  // Display ON
        >;
      };
    };
  };

  __overrides__ {
    speed = <&mytft40display>,"spi-max-frequency:0";
    //txtbuflen = <&mytft40display>,"txtbuflen:0";
    rotate = <&mytft40display>,"rotation:0";
    fps = <&mytft40display>,"fps:0";
    bgr = <&mytft40display>,"bgr:0";
    debug = <&mytft40display>,"debug:0";
  };
};
github-actions[bot] commented 2 years ago

This issue is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 7 days.