Giter VIP home page Giter VIP logo

fbcp-ili9341's Introduction

Feb 2024 Update

The era of fbcp-ili9341 has come to an end. Fbcp-ili9341 was built on top of the Raspberry Pi's VideoCore DispmanX API.

However, this API has been deprecated by the Raspberry Pi Foundation for a while now, and finally obsolete (=unavailable) on Raspberry Pi 5 and onwards.

The later Raspberry Pi distros no longer have DispmanX active by default even for Pi0-Pi4, but instead Raspberry Pi has moved over to the newer KMS driver compositor stack, which has a different abstraction for integrating SPI display drivers. Other people are developing SPI display drivers for the Pi that are compatible with the KMS stack. Head on to this Raspberry Pi forum thread to learn more.

This repository is good to be considered archived/stale, although I am not marking it Archived using the GitHub feature, since that feature apparently would also make the issue tracker read-only. Feel free to continue discussing issues on the tracker.

Introduction

This repository implements a driver for certain SPI-based LCD displays for Raspberry Pi A, B, 2, 3, 4 and Zero.

PiTFT display

The work was motivated by curiosity after seeing this series of videos on the RetroManCave YouTube channel:

In these videos, the SPI (GPIO) bus is referred to being the bottleneck. SPI based displays update over a serial data bus, transmitting one bit per clock cycle on the bus. A 320x240x16bpp display hence requires a SPI bus clock rate of 73.728MHz to achieve a full 60fps refresh frequency. Not many SPI LCD controllers can communicate this fast in practice, but are constrained to e.g. a 16-50MHz SPI bus clock speed, capping the maximum update rate significantly. Can we do anything about this?

The fbcp-ili9341 project started out as a display driver for the Adafruit 2.8" 320x240 TFT w/ Touch screen for Raspberry Pi display that utilizes the ILI9341 controller. On that display, fbcp-ili9341 can achieve a 60fps update rate, depending on the content that is being displayed. Check out these videos for examples of the driver in action:

How It Works

Given that the SPI bus can be so constrained on bandwidth, how come fbcp-ili9341 seems to be able to update at up to 60fps? The way this is achieved is by what could be called adaptive display stream updates. Instead of uploading each pixel at each display refresh cycle, only the actually changed pixels on screen are submitted to the display. This is doable because the ILI9341 controller, as many other popular controllers, have communication interface functions that allow specifying partial screen updates, down to subrectangles or even individual pixel levels. This allows beating the bandwidth limit: for example in Quake, even though it is a fast pacing game, on average only about 46% of all pixels on screen change each rendered frame. Some parts, such as the UI stay practically constant across multiple frames.

Other optimizations are also utilized to squeeze out even more performance:

  • The program directly communicates with the BCM2835 ARM Peripherals controller registers, bypassing the usual Linux software stack.
  • A hybrid of both Polled Mode SPI and DMA based transfers are utilized. Long sequential transfer bursts are performed using DMA, and when DMA would have too much latency, Polled Mode SPI is applied instead.
  • Undocumented BCM2835 features are used to squeeze out maximum bandwidth: SPI CDIV is driven at even numbers (and not just powers of two), and the SPI DLEN register is forced in non-DMA mode to avoid an idle 9th clock cycle for each transferred byte.
  • Good old interlacing is added into the mix: if the amount of pixels that needs updating is detected to be too much that the SPI bus cannot handle it, the driver adaptively resorts to doing an interlaced update, uploading even and odd scanlines at subsequent frames. Once the number of pending pixels to write returns to manageable amounts, progressive updating is resumed. This effectively doubles the maximum display update rate. (If you do not like the visual appearance that interlacing causes, it is easy to disable this by uncommenting the line #define NO_INTERLACING in file config.h)
  • A dedicated SPI communication thread is used in order to keep the SPI bus active at all times.
  • A number of other micro-optimization techniques are used, such as batch updating rectangular spans of pixels, merging disjoint-but-close spans of pixels on the same scanline, and latching Column and Page End Addresses to bottom-right corner of the display to be able to cut CASET and PASET messages in mid-communication.

The result is that the SPI bus can be kept close to 100% saturation, ~94-97% usual, to maximize the utilization rate of the bus, while only transmitting practically the minimum number of bytes needed to describe each new frame.

Tested Devices

The driver has been checked to work (at least some point in the past) on the following systems:

  • Raspberry Pi 3 Model B+ with Raspbian Stretch (GCC 6.3.0)
  • Raspberry Pi 3 Model B Rev 1.2 with Raspbian Jessie (GCC 4.9.2) and Raspbian Stretch (GCC 6.3.0)
  • Raspberry Pi Zero W with Raspbian Jessie (GCC 4.9.2) and Raspbian Stretch (GCC 6.3.0)
  • Raspberry Pi 2 Model B
  • Raspberry Pi B Rev. 2.0 (old board from Q4 2012, board revision ID 000e)

although not all boards are actively tested on, so ymmv especially on older boards. (Bug fixes welcome, use https://elinux.org/RPi_HardwareHistory to identify which board you are running on)

Tested Displays

The following LCD displays have been tested:

Installation

Check the following sections to set up the driver.

Boot configuration

This driver does not utilize the notro/fbtft framebuffer driver, so that needs to be disabled if active. That is, if your /boot/config.txt file has lines that look something like dtoverlay=pitft28r, ..., dtoverlay=waveshare32b, ... or dtoverlay=flexfb, ..., those should be removed.

This program neither utilizes the default SPI driver, so a line such as dtparam=spi=on in /boot/config.txt should also be removed so that it will not cause conflicts.

Likewise, if you have any touch controller related dtoverlays active, such as dtoverlay=ads7846,... or anything that has a penirq= directive, those should be removed as well to avoid conflicts. It would be possible to add touch support to fbcp-ili9341 if someone wants to take a stab at it.

Building and running

Run in the console of your Raspberry Pi:

sudo apt-get install cmake
cd ~
git clone https://github.com/juj/fbcp-ili9341.git
cd fbcp-ili9341
mkdir build
cd build
cmake [options] ..
make -j
sudo ./fbcp-ili9341

Note especially the two dots .. on the CMake line, which denote "up one directory" in this case (instead of referring to "more items go here").

See the next section to see what to input under [options].

If you have been running existing fbcp driver, make sure to remove that e.g. via a sudo pkill fbcp first (while running in SSH prompt or connected to a HDMI display), these two cannot run at the same time. If /etc/rc.local or /etc/init.d contains an entry to start up fbcp at boot, that directive should be deleted.

Configuring build options

There are generally two ways to configure build options, at CMake command line, and in the file config.h.

On the CMake command line, the following options can be configured:

If you have a display Add-On Hat

When using one of the displays that stack on top of the Pi that are already recognized by fbcp-ili9341, you don't need to specify the GPIO pin assignments, but fbcp-ili9341 code already has those. Pass one of the following CMake directives for the hats:

If you wired the display to the Pi yourself

If you connected wires directly on the Pi instead of using a Hat from the above list, you will need to use the configuration directives below. In addition to specifying the display, you will also need to tell fbcp-ili9341 which GPIO pins you wired the connections to. To configure the display controller, pass one of:

  • -DILI9341=ON: If you are running on any other generic ILI9341 display, or on Waveshare32b display that is standalone and not on the FreeplayTech CM3/Zero device, pass this flag.
  • -DILI9340=ON: If you have a ILI9340 display, pass this directive. ILI9340 and ILI9341 chipsets are very similar, but ILI9340 doesn't support all of the features on ILI9341 and they will be disabled or downgraded.
  • -DHX8357D=ON: If you have a HX8357D display, pass this directive.
  • -DSSD1351=ON: If you have a SSD1351 OLED display, use this.
  • -DST7735R=ON: If you have a ST7735R display, use this.
  • -DST7789=ON: If you have a ST7789 display, use this.
  • -DST7789VW=ON: If you have a ST7789VW display, use this.
  • -DST7735S=ON: If you have a ST7735S display, use this.
  • -DILI9486=ON: If you have a ILI9486 display, pass this directive.
  • -DILI9486L=ON: If you have a ILI9486L display, pass this directive. Note that ILI9486 and ILI9486L are quite different, mutually incompatible controller chips, so be careful here identifying which one you have. (or just try both, should not break if you misidentified)
  • -DILI9488=ON: If you have a ILI9488 display, pass this directive.
  • -DMPI3501=ON: If specified, targets a display with MPI3501 display controller.

And additionally, pass the following to customize the GPIO pin assignments you used:

  • -DGPIO_TFT_DATA_CONTROL=number: Specifies/overrides which GPIO pin to use for the Data/Control (DC) line on the 4-wire SPI communication. This pin number is specified in BCM pin numbers. If you have a 3-wire SPI display that does not have a Data/Control line, set this value to -1, i.e. -DGPIO_TFT_DATA_CONTROL=-1 to tell fbcp-ili9341 to target 3-wire ("9-bit") SPI communication.
  • -DGPIO_TFT_RESET_PIN=number: Specifies/overrides which GPIO pin to use for the display Reset line. This pin number is specified in BCM pin numbers. If omitted, it is assumed that the display does not have a Reset pin, and is always on.
  • -DGPIO_TFT_BACKLIGHT=number: Specifies/overrides which GPIO pin to use for the display backlight line. This pin number is specified in BCM pin numbers. If omitted, it is assumed that the display does not have a GPIO-controlled backlight pin, and is always on. If setting this, also see the #define BACKLIGHT_CONTROL option in config.h.

fbcp-ili9341 always uses the hardware SPI0 port, so the MISO, MOSI, CLK and CE0 pins are always the same and cannot be changed. The MISO pin is actually not used (at the moment at least), so you can just skip connecting that one. If your display is a rogue one that ignores the chip enable line, you can omit connecting that as well, or might also be able to get away by connecting that to ground if you are hard pressed to simplify wiring (depending on the display).

Specifying display speed

To get good performance out of the displays, you will drive the displays far out above the rated speed specs (the rated specs yield about ~10fps depending on display). Due to this, you will need to explicitly configure the target speed you want to drive the display at, because due to manufacturing variances each display copy reaches a different maximum speed. There is no "default speed" that fbcp-ili9341 would use. Setting the speed is done via the option

  • -DSPI_BUS_CLOCK_DIVISOR=even_number: Sets the clock divisor number which along with the Pi core_freq= option in /boot/config.txt specifies the overall speed that the display SPI communication bus is driven at. SPI_frequency = core_freq/divisor. SPI_BUS_CLOCK_DIVISOR must be an even number. Default Pi 3B and Zero W core_freq is 400MHz, and generally a value -DSPI_BUS_CLOCK_DIVISOR=6 seems to be the best that a ILI9341 display can do. Try a larger value if the display shows corrupt output, or a smaller value to get higher bandwidth. See ili9341.h and waveshare35b.h for data points on tuning the maximum SPI performance. Safe initial value could be something like -DSPI_BUS_CLOCK_DIVISOR=30.
Specifying the target Pi hardware

There are a couple of options to explicitly say which Pi board you want to target. These should be autodetected for you and generally are not needed, but e.g. if you are cross compiling for another Pi board from another system, or want to be explicit, you can try:

  • -DSINGLE_CORE_BOARD=ON: Pass this option if you are running on a Pi that has only one hardware thread (Pi Model A, Pi Model B, Compute Module 1, Pi Zero/Zero W). If not present, autodetected.
  • -DARMV6Z=ON: Pass this option to specifically optimize for ARMv6Z instruction set (Pi 1A, 1A+, 1B, 1B+, Zero, Zero W). If not present, autodetected.
  • -DARMV7A=ON: Pass this option to specifically optimize for ARMv7-A instruction set (Pi 2B < rev 1.2). If not present, autodetected.
  • -DARMV8A=ON: Pass this option to specifically optimize for ARMv8-A instruction set (Pi 2B >= rev. 1.2, 3B, 3B+, CM3, CM3 lite, 4B, CM4, Pi400). If not present, autodetected.
Specifying other build options

The following build options are general to all displays and Pi boards, they further customize the build:

  • -DBACKLIGHT_CONTROL=ON: If set, enables fbcp-ili9341 to control the display backlight in the given backlight pin. The display will go to sleep after a period of inactivity on the screen. If not, backlight is not touched.
  • -DDISPLAY_CROPPED_INSTEAD_OF_SCALING=ON: If set, and source video frame is larger than the SPI display video resolution, the source video is presented on the SPI display by cropping out parts of it in all directions, instead of scaling to fit.
  • -DDISPLAY_BREAK_ASPECT_RATIO_WHEN_SCALING=ON: When scaling source video to SPI display, scaling is performed by default following aspect ratio, adding letterboxes/pillarboxes as needed. If this is set, the stretching is performed breaking aspect ratio.
  • -DSTATISTICS=number: Specifies the level of overlay statistics to show on screen. 0: disabled, 1: enabled, 2: enabled, and show frame rate interval graph as well. Default value is 1 (enabled).
  • -DUSE_DMA_TRANSFERS=OFF: If specified, disables using DMA transfers (at great expense of lost CPU usage). Pass this directive if DMA is giving some issues, e.g. as a troubleshooting step if something is not looking right.
  • -DDMA_TX_CHANNEL=<num>: Specifies the DMA channel number to use for SPI send commands. Change this if you find a DMA channel conflict.
  • -DDMA_RX_CHANNEL=<num>: Specifies the DMA channel number to use for SPI receive commands. Change this if you find a DMA channel conflict.
  • -DDISPLAY_SWAP_BGR=ON: If this option is passed, red and blue color channels are reversed (RGB<->BGR) swap. Some displays have an opposite color panel subpixel layout that the display controller does not automatically account for, so define this if blue and red are mixed up.
  • -DDISPLAY_INVERT_COLORS=ON: If this option is passed, pixel color value interpretation is reversed (white=0, black=31/63). Default: black=0, white=31/63. Pass this option if the display image looks like a color negative of the actual colors.
  • -DDISPLAY_ROTATE_180_DEGREES=ON: If set, display is rotated 180 degrees. This does not affect HDMI output, only the SPI display output.
  • -DLOW_BATTERY_PIN=<num>: Specifies a GPIO pin that can be polled to get the battery state. By default, when this is set, a low battery icon will be displayed if the pin is pulled low (see config.h for ways in which this can be tweaked).

In addition to the above CMake directives, there are various defines scattered around the codebase, mostly in config.h, that control different runtime options. Edit those directly to further tune the behavior of the program. In particular, after you have finished with the setup, you may want to build with -DSTATISTICS=0 option in CMake configuration line.

Build example

Here is a full example of what to type to build and run, if you have the Adafruit 2.8" 320x240 TFT w/ Touch screen for Raspberry Pi with ILI9341 controller:

cd ~
sudo apt-get install cmake
git clone https://github.com/juj/fbcp-ili9341.git
cd fbcp-ili9341
mkdir build
cd build
cmake -DSPI_BUS_CLOCK_DIVISOR=6 -DADAFRUIT_ILI9341_PITFT=ON ..
make -j
sudo ./fbcp-ili9341

If the above does not work, try specifying -DSPI_BUS_CLOCK_DIVISOR=8 or =10 to make the display run a little slower, or try with -DUSE_DMA_TRANSFERS=OFF to troubleshoot if DMA might be the issue. If you are using another display controller than ILI9341, using a much higher value, like 30 or 40 may be needed. When changing CMake options, you can reissue the CMake directive line without having to reclone or recreate the build directory. However you may need to manually delete file CMakeCache.txt between changing options to avoid CMake remembering old settings.

If you want to do a full rebuild from scratch, you can rm -rf build to delete the build directory and recreate it for a clean rebuild from scratch. There is nothing special about the name or location of this directory, it is just my usual convention. You can also do the build in some other directory relative to the fbcp-ili9341 directory if you please.

Launching the display driver at startup

To set up the driver to launch at startup, edit the file /etc/rc.local in sudo mode, and add a line

sudo /path/to/fbcp-ili9341/build/fbcp-ili9341 &

to the end. Make note of the needed ampersand & at the end of that line.

For example, if you used the command line steps listed above to build, the file /etc/rc.local would receive a line

sudo /home/pi/fbcp-ili9341/build/fbcp-ili9341 &

If the user name of your Raspberry Pi installation is something else than the default pi, change the directory accordingly to point to the user's home directory. (Use pwd to find out the current directory in terminal)

Launching the display driver with systemd

Alternatively, instead of modifying /etc/rc.local, use the provided systemd unit file as below:

sudo install -m 0644 -t /etc fbcp-ili9341.conf 
sudo install -m 0644 -t /etc/systemd/system fbcp-ili9341.service 
sudo systemctl daemon-reload
sudo systemctl enable fbcp && sudo systemctl start fbcp
Configuring HDMI and TFT display sizes

If the size of the default HDMI output /dev/fb0 framebuffer differs from the resolution of the display, the source video size will by default be rescaled to fit to the size of the SPI display. fbcp-ili9341 will manage setting up this rescaling if needed, and it will be done by the GPU, so performance should not be impacted too much. However if the resolutions do not match, small text will probably appear illegible. The resizing will be done in aspect ratio preserving manner, so if the aspect ratios do not match, either horizontal or vertical black borders will appear on the display. If you do not use the HDMI output at all, it is probably best to configure the HDMI output to match the SPI display size so that rescaling will not be needed. This can be done by setting the following lines in /boot/config.txt:

hdmi_group=2
hdmi_mode=87
hdmi_cvt=320 240 60 1 0 0 0
hdmi_force_hotplug=1

If your SPI display has a different resolution than 320x240, change the 320 240 part to e.g. 480 320.

These lines hint native applications about the default display mode, and let them render to the native resolution of the TFT display. This can however prevent the use of the HDMI connector, if the HDMI connected display does not support such a small resolution. As a compromise, if both HDMI and SPI displays want to be used at the same time, some other compatible resolution such as 640x480 can be used. See Raspberry Pi HDMI documentation for the available options to do this.

Tuning Performance

The refresh speed of the display is dictated by the clock speed of the SPI bus that the display is connected to. Due to the way the BCM2835 chip on Raspberry Pi works, there does not exist a simple speed=xxx Mhz option that could be set to define the bus speed. Instead, the SPI bus speed is derived from two separate parameters: the core frequency of the BCM2835 SoC in general (core_freq in /boot/config.txt), and the SPI peripheral CDIV (Clock DIVider) setting. Together, the resulting SPI bus speed is then calculated with the formula SPI_speed=core_freq/CDIV.

To optimize the display to run as fast as possible,

  1. Adjust the CDIV value by passing the directive -DSPI_BUS_CLOCK_DIVISOR=number in CMake command line. Possible values are even numbers 2, 4, 6, 8, .... Note that since CDIV appears in the denominator in the formula for SPI_speed, smaller values result in higher bus speeds, whereas higher values make the display go slower. Initially when you don't know how fast your display can run, try starting with a safe high setting, such as -DSPI_BUS_CLOCK_DIVISOR=30, and work your way to smaller numbers to find the maximum speed the display can cope with. See the table at the end of the README for specific observed maximum bus speeds for different displays.

  2. Ensure turbo speed. This is critical for good frame rates. On the Raspberry Pi 3 Model B, the BCM2835 core runs by default at 400MHz (resulting in 400/CDIV MHz SPI speed) if there is enough power provided to the Pi, and if the CPU temperature does not exceed thermal limits. If the CPU is idle, or voltage is low, the BCM2835 core will instead revert to non-turbo 250MHz state, resulting in 250/CDIV MHz SPI speed. This effect of turbo speed on performance is significant, since 400MHz vs non-turbo 250MHz comes out to +60% of more bandwidth. Getting 60fps in Quake, Sonic or Tyrian often requires this turbo frequency, but e.g. NES and C64 emulated games can often reach 60fps even with the stock 250MHz. If for some reason under-voltage protection is kicking in even when enough power should be fed, you can force-enable turbo when low voltage is present by setting the value avoid_warnings=2 in the file /boot/config.txt.

  3. Perhaps a bit counterintuitively, underclock the core. Setting a smaller core frequency than the default turbo 400MHz can enable using a smaller clock divider to get a higher resulting SPI bus speed. For example, if with default core_freq=400 SPI CDIV=8 works (resulting in SPI bus speed 400MHz/8=50MHz), but CDIV=6 does not (400MHz/6=66.67MHz was too much), you can try lowering core_freq=360 and set CDIV=6 to get an effective SPI bus speed of 360MHz/6=60MHz, a middle ground between the two that might perhaps work. Balancing core_freq= and CDIV options allows one to find the maximum SPI bus speed up to the last few kHz that the display controller can tolerate. One can also try the opposite direction and overclock, but that does then of course have all the issues that come along when overclocking. Underclocking does have the drawback that it makes the Pi run slower overall, so this is certainly a tradeoff.

Tuning CPU Usage

On the other hand, it is desirable to control how much CPU time fbcp-ili9341 is allowed to use. The default build settings are tuned to maximize the display refresh rate at the expense of power consumption on Pi 3B. On Pi Zero, the opposite is done, i.e. by default the driver optimizes for battery saving instead of maximal display update speed. The following options can be controlled to balance between these two:

  • The main option to control CPU usage vs performance aspect is the option #define ALL_TASKS_SHOULD_DMA in config.h. Enabling this option will greatly reduce CPU usage. If this option is disabled, SPI bus utilization is maximized but CPU usage can be up to 80%-120%. When this option is enabled, CPU usage is generally up to around 15%-30%. Maximal CPU usage occurs when watching a video, or playing a fast moving game. If nothing is changing on the screen, CPU consumption of the driver should go down very close to 0-5%. By default #define ALL_TASKS_SHOULD_DMA is enabled for Pi Zero, but disabled for Pi 3B.

  • The CMake option -DUSE_DMA_TRANSFERS=ON should always be enabled for good low CPU usage. If DMA transfers are disabled, the driver will run in Polled SPI mode, which generally utilizes a full dedicated single core of CPU time. If DMA transfers are causing issues, try adjusting the DMA send and receive channels to use for SPI communication with -DDMA_TX_CHANNEL=<num> and -DDMA_RX_CHANNEL=<num> CMake options.

  • The statistics overlay prints out quite detailed information about execution state. Disabling the overlay with -DSTATISTICS=0 option to CMake improves performance and reduces CPU usage. If you want to keep printing statistics, you can try increasing the interval with the #define STATISTICS_REFRESH_INTERVAL <timeInMicroseconds> option in config.h.

  • Enabling #define USE_GPU_VSYNC reduces CPU consumption, but because of raspberrypi/userland#440 can cause stuttering. Disabling #defined USE_GPU_VSYNC produces less stuttering, but because of raspberrypi/userland#440, increases CPU power consumption.

  • The option #define SELF_SYNCHRONIZE_TO_GPU_VSYNC_PRODUCED_NEW_FRAMES can be used in conjunction with #define USE_GPU_VSYNC to try to find a middle ground between raspberrypi/userland#440 issues - moderate to little stuttering while not trying to consume too much CPU. Try experimenting with enabling or disabling this setting.

  • There are a number of #define SAVE_BATTERY_BY_x options in config.h, which all default to being enabled. These should be safe to use always without tradeoffs. If you are experiencing latency or performance related issues, you can try to toggle these to troubleshoot.

  • The option #define DISPLAY_FLIP_ORIENTATION_IN_SOFTWARE does cause a bit of extra CPU usage, so disabling it will lighten up the CPU load a bit.

  • If your SPI display bus is able to run really fast in comparison to the size of the display and the amount of content changing on the screen, you can try enabling #define UPDATE_FRAMES_IN_SINGLE_RECTANGULAR_DIFF option in config.h to reduce CPU usage at the expense of increasing the number of bytes sent over the bus. This has been observed to have a big effect on Pi Zero, so is worth checking out especially there.

  • If the SPI display bus is able to run really really really fast (or you don't care about frame rate, but just about low CPU usage), you can try enabling #define UPDATE_FRAMES_WITHOUT_DIFFING option in config.h to forgo the adaptive delta diffing option altogether. This will revert to naive full frame updates for absolutely minimum overall CPU usage.

  • The option #define RUN_WITH_REALTIME_THREAD_PRIORITY can be enabled to make the driver run at realtime process priority. This can lock up the system however, but still made available for advanced experimentation.

  • In display.h there is an option #define TARGET_FRAME_RATE <number>. Setting this to a smaller value, such as 30, will trade refresh rate to reduce CPU consumption.

About Input Latency

A pleasing aspect of fbcp-ili9341 is that it introduces very little latency overhead: on a 119Hz refreshing ILI9341 display, fbcp-ili9341 gets pixels as response from GPIO input to screen in well less than 16.66 msecs time. I only have a 120fps recording camera, so can't easily measure delays shorter than that, but rough statistical estimate of slow motion video footage suggests this delay could be as low as 2-3 msecs, dominated by the ~8.4msecs panel refresh rate of the ILI9341.

This does not mean that overall input to display latency in games would be so immediate. Briefly testing a NES emulated game in Retropie suggests a total latency of about 60-80 msecs. This latency is caused by the NES game emulator overhead and extra latency added by Linux, DispmanX and GPU rendering, and GPU framebuffer snapshotting. (If you ran fbcp-ili9341 as a static library bypassing DispmanX and the GPU stack, directly linking your GPIO input and application logic into fbcp-ili9341, you would be able to get down to this few msecs of overall latency, like shown in the above GPIO input video)

Interestingly, fbcp-ili9341 is about ~33msecs faster than a cheap 3.5" KeDei HDMI display. I do not know if this is a result of the KeDei HDMI display specifically introducing extra latency, or if all HDMI displays connected to the Pi would have similar latency overhead. An interesting question is also how SPI would compare with DPI connected displays on the Pi.

About Tearing

Unfortunately a limitation of SPI connected displays is that the VSYNC line signal is not available on the display controllers when they are running in SPI mode, so it is not possible to do vsync locked updates even if the SPI bus bandwidth on the display was fast enough. For example, the 4 ILI9341 displays I have can all be run faster than 75MHz so SPI bus bandwidth-wise all of them would be able to update a full frame in less than a vsync interval, but it is not possible to synchronize the updates to vsync since the display controllers do not report it. (If you do know of a display that does actually expose a vsync clock signal even in SPI mode, you can try implementing support to locking on to it)

You can however choose between two distinct types of tearing artifacts: straight line tearing and diagonal tearing. Whichever looks better is a bit subjective, which is why both options exist. I prefer the straight line tearing artifact, it seems to be less intrusive than the diagonal tearing one. To toggle this, edit the option #define DISPLAY_FLIP_ORIENTATION_IN_SOFTWARE in config.h. When this option is enabled, fbcp-ili9341 produces straight line tearing, and consumes a tiny few % more CPU power. By default Pi 3B builds with straight line tearing, and Pi Zero with the faster diagonal tearing. Check out the video Latency and tearing test #2: GPIO input to display latency in fbcp-ili9341 and tearing modes to see in slow motion videos how these two tearing modes look like.

Another option that is known to affect how the tearing artifact looks like is the internal panel refresh rate. For ILI9341 displays this refresh rate can be adjusted in ili9341.h, and this can be set to range between ILI9341_FRAMERATE_61_HZ and ILI9341_FRAMERATE_119_HZ (default). Slower refresh rates produce less tearing, but have higher input-to-display latency, whereas higher refresh rates will result in the opposite. Again visually the resulting effect is a bit subjective.

To get tearing free updates, you should use a DPI display, or a good quality HDMI display. Beware that cheap small 3.5" HDMI displays such as KeDei do also tear - that is, even if they are controlled via HDMI, they don't actually seem to implement VSYNC timed internal operation.

About Smoothness

Having no vsync is not all bad though, since with the lack of vsync, SPI displays have the opportunity to obtain smoother animation on content that is not updating at 60Hz. It is possible that content on the SPI display will stutter even less than what DPI or HDMI displays on the Pi can currently provide (although I have not been able to test this in detail, except for the KeDei case above).

The main option that affects smoothness of display updates is the #define USE_GPU_VSYNC line in config.h. If this is enabled, then the internal Pi GPU HDMI vsync clock is used to drive frames onto the display. The Pi GPU clock runs at a fixed rate that is independent of the content. This rate can be discovered by running tvservice -s on the Pi console, and is usually 59Hz or 60Hz. If your application renders at this rate, animation will look smooth, but if not, there will be stuttering. For example playing a PAL NES game that updates at 50Hz with HDMI clock set at 60Hz will cause bad microstuttering in video output if #define USE_GPU_VSYNC is enabled.

If USE_GPU_VSYNC is disabled, then a busy spinning GPU frame snapshotting thread is used to drive the updates. This will produce smoother animation in content that does not maintain a fixed 60Hz rate. Especially in OpenTyrian, a game that renders at a fixed 36fps and has slowly scrolling scenery, the stuttering caused by USE_GPU_VSYNC is particularly visible. Running on Pi 3B without USE_GPU_VSYNC enabled produces visually smoother looking scrolling on an Adafruit 2.8" ILI9341 PiTFT set to update at 119Hz, compared to enabling USE_GPU_VSYNC on the same setup. Without USE_GPU_VSYNC, the dedicated frame polling loop thread "finds" the 36Hz update rate of the game, and then pushes pixels to the display at this exact rate. This works nicely since SPI displays disregard vsync - the result is that frames are pushed out to the SPI display immediately as they become available, instead of pulling them at a fixed 60Hz rate like HDMI does.

A drawback is that this kind of polling consumes more CPU time than the vsync option. The extra overhead is around +34% of CPU usage compared to the vsync method. It also requires using a background thread, and because of this, it is not feasible to be used on a single core Pi Zero. If this polling was unnecessary, this mode would also work on a Pi Zero, and without the added +34% CPU overhead on Pi 3B. See the Known Issues section below for more details.

PiTFT display

There are two other main options that affect frame delivery timings, #define SELF_SYNCHRONIZE_TO_GPU_VSYNC_PRODUCED_NEW_FRAMES and #define SAVE_BATTERY_BY_PREDICTING_FRAME_ARRIVAL_TIMES. Check out the video fbcp-ili9341 frame delivery smoothness test on Pi 3B and Adafruit ILI9341 at 119Hz for a detailed side by side comparison of these different modes. The conclusions drawn from the four tested scenarios in the video are:

1. vc_dispmanx_vsync_callback() (top left), set #define USE_GPU_VSYNC and unset #define SELF_SYNCHRONIZE_TO_GPU_VSYNC_PRODUCED_NEW_FRAMES:

This mode uses the DispmanX HDMI vsync signal callback to drive frames to the display.

Pros:

  • least CPU overhead if content runs at 60Hz
  • works on Pi Zero

Cons:

  • animation stutters badly on content that is < 60Hz but also on 60Hz content
  • excessive +1 vsync interval input to display latency
  • wastes CPU overhead if content runs at less than 60Hz

2. vc_dispmanx_vsync_callback() + self synchronization (top right), set #define USE_GPU_VSYNC and #define SELF_SYNCHRONIZE_TO_GPU_VSYNC_PRODUCED_NEW_FRAMES:

This mode uses the GPU vsync signal, but also aims to find and synchronize to the edge trigger when content is producing frames. This is the default build mode on Pi Zero.

Pros:

  • works on Pi Zero
  • reduced input to display latency compared to previous mode
  • content that runs at 60hz stutters less

Cons:

  • content that runs < 60 Hz still stutters badly
  • wastes CPU overhead if content runs at less than 60Hz
  • consumes slightly extra CPU compared to previous method

3. gpu polling thread + sleep heuristic (bottom left), unset #define USE_GPU_VSYNC and set #define SAVE_BATTERY_BY_PREDICTING_FRAME_ARRIVAL_TIMES:

This mode runs a dedicated background thread that drives frames from the GPU to the SPI display. This is the default build mode on Pi 3B.

Pros:

  • smooth animation at all content frame rates
  • low input to display latency

Cons:

  • uses excessive CPU time, around +34% more CPU than the vsync signal based approach
  • uses excessive GPU time, the VideoCore GPU will be downscaling and snapshotting redundant frames
  • when content changes frame rate, has difficulties to adjust quickly - takes a bit of time to ramp to the new frame rate
  • requires a continuously running background thread, not feasible on Pi Zero

4. gpu polling thread without sleeping (bottom right), unset #define USE_GPU_VSYNC and unset #define SAVE_BATTERY_BY_PREDICTING_FRAME_ARRIVAL_TIMES:

This mode runs the dedicated GPU thread as fast as possible, without attempting to sleep CPU.

Pros:

  • smoothest animation at all content frame rates
  • lowest input to display latency
  • adapts instantaneously to variable frame rate content

Cons:

  • uses ridiculously much CPU overhead, a full 100% core
  • uses ridiculously much GPU overhead, the VideoCore GPU will be very busy downscaling and snapshotting redundant frames
  • requires a continuously running background thread, not feasible on Pi Zero

Known Issues

Be aware of the following limitations:

No rendered frame delivery via events from VideoCore IV GPU
  • The codebase captures screen framebuffers by snapshotting via the VideoCore vc_dispmanx_snapshot() API, and the obtained pixels are then routed on to the SPI-based display. This kind of polling is performed, since there does not exist an event-based mechanism to get new frames from the GPU as they are produced. The result is inefficient and can easily cause stuttering, since different applications produce frames at different paces. Ideally the code would ask the VideoCore API to receive finished frames in callback notifications immediately after they are rendered, but this kind of functionality does not exist in the current GPU driver stack. In the absence of such event delivery mechanism, the code has to resort to polling snapshots of the display framebuffer using carefully timed heuristics to balance between keeping latency and stuttering low, while not causing excessive power consumption. These heuristics keep continuously guessing the update rate of the animation on screen, and they have been tuned to ensure that CPU usage goes down to 0% when there is no detected activity on screen, but it is certainly not perfect. This GPU limitation is discussed at raspberrypi/userland#440. If you'd like to see fbcp-ili9341 operation reduce latency, stuttering and power consumption, please throw a (kind!) comment or a thumbs up emoji in that bug thread to share that you care about this, and perhaps Raspberry Pi engineers might pick the improvement up on the development roadmap. If this issue is resolved, all of the #define USE_GPU_VSYNC, #define SAVE_BATTERY_BY_PREDICTING_FRAME_ARRIVAL_TIMES and #define SELF_SYNCHRONIZE_TO_GPU_VSYNC_PRODUCED_NEW_FRAMES hacks from the previous section could be deleted from the driver, hopefully leading to a best of all worlds scenario without drawbacks.
Screen resize freezes DispmanX
  • Currently if one resizes the video frame size at runtime, this causes DispmanX API to go sideways. See raspberrypi/userland#461 for more information. Best workaround is to set the desired screen resolution in /boot/config.txt and configure all applications to never change that at runtime.
CPU Turbo is needed for good SPI bus bandwidth
  • The speed of the SPI bus is linked to the BCM2835 core frequency. This frequency is at 250MHz by default (on e.g. Pi Zero, 3B and 3B+), and under CPU load, the core turbos up to 400MHz. This turboing directly scales up the SPI bus speed by 400/250=+60% as well. Therefore when choosing the SPI CDIV value to use, one has to pick one that works for both idle and turbo clock speeds. Conversely, the BCM core reverts to non-turbo speed when there is only light CPU load active, and this slows down the display, so if an application is graphically intensive but light on CPU, the SPI display bus does not get a chance to run at maximum speeds. A way to work around this is to force the BCM core to always stay in its turbo state with force_turbo=1 option in /boot/config.txt, but this has an unfortunate effect of causing the ARM CPU to always run in turbo speed as well, consuming excessive amounts of power. At the time of writing, there does not yet exist a good solution to have both power saving and good performance. This limitation is being discussed in more detail at raspberrypi/firmware#992.
Raspbian + 32-bit only(?)
  • At the moment fbcp-ili9341 is only likely to work on 32-bit OSes, on Raspbian/Ubuntu/Debian family of distributions, where Broadcom and DispmanX libraries are available. 64-bit operating systems do not currently work (see issue #43). It should be possible to port the driver to 64-bit and other OSes, though the amount of work has not been explored.

For more known issues and limitations, check out the bug tracker, especially the entries marked retired, for items that are beyond current scope.

Statistics Overlay

By default fbcp-ili9341 builds with a statistics overlay enabled. See the video fbcp-ili9341 ported to ILI9486 WaveShare 3.5" (B) SpotPear 320x480 SPI display to find details on what each field means. Build with CMake option -DSTATISTICS=0 to disable displaying the statistics. You can also try building with CMake option -DSTATISTICS=2 to show a more detailed frame delivery timings histogram view, see screenshot and video above.

FAQ and Troubleshooting

Why is the project named fbcp-ili9341?

The fbcp part in the name means framebuffer copy; specifically for the ILI9341 controller. fbcp-ili9341 is not actually a framebuffer copying driver, it does not create a secondary framebuffer that it would copy bytes across to from the primary framebuffer. It is also no longer a driver only for the ILI9341 controller. A more appropriate name might be userland-raspi-spi-display-driver or something like that, but the original name stuck.

Does fbcp-ili9341 work on Pi Zero?

Yes, it does, although not quite as well as on Pi 3B. If you'd like it to run better on a Pi Zero, leave a thumbs up at raspberrypi/userland#440 - hard problems are difficult to justify prioritizing unless it is known that many people care about them.

The driver works well, but image is rotated 90 degrees. How do I rotate the display between landscape and portrait?

Edit the file config.h and comment out the line #define DISPLAY_OUTPUT_LANDSCAPE. This will make the display output in portrait mode, effectively rotating it by 90 degrees. Note that this only affects the pixel memory reading mode of the display. It is not possible to change the panel scan order to run between landscape and portrait, the SPI displays typically always scan in portrait mode. The result is that it will change the panel vsync tearing mode from "straight line tearing" over to "diagonal tearing" (see the section About Tearing above).

If you do not want to have diagonal tearing, but would prefer straight line tearing, then additionally enable the option #define DISPLAY_FLIP_ORIENTATION_IN_SOFTWARE in config.h. That will restore straight line tearing, but it will also increase overall CPU consumption.

The driver works well, but image is upside down. How do I rotate the display?

Enable the option #define DISPLAY_ROTATE_180_DEGREES in config.h. This should rotate the SPI display to show up the other way around, while keeping the HDMI connected display orientation unchanged. Another option is to utilize a /boot/config.txt option display_rotate=2, which rotates both the SPI output and the HDMI output.

Note that the setting DISPLAY_ROTATE_180_DEGREES only affects the pixel memory reading mode of the display. It is not possible to flip the panel scan to run inverted by 180 degrees. This means that adjusting these settings will also have effects of changing the visual appearance of the vsync tearing artifact. If you have the ability to mount the display 180 degrees around in your project, it is recommended to do that instead of using the DISPLAY_ROTATE_180_DEGREES option.

How exactly do I edit the build options to e.g. remove the statistics lines or change some other option?

Edit the file config.h in a text editor (a command line one such as pico, vim, nano, or SSH map the drive to your host), and find the appropriate line in the file. Add comment lines // in front of that text to disable the option, or remove the // characters to enable it.

After having edited and saved the file, reissue make -j in the build directory and restart fbcp-ili9341.

Some options are passed to the build from the CMake configuration script. You can run with make VERBOSE=1 to see which configuration items the CMake build is passing. See the above Configuring Build Options section to customize the CMake configure items. For example, to remove the statistics overlay, pass -DSTATISTICS=0 directive to CMake.

bash: cmake: command not found!

Building requires CMake to be installed on the Pi: try sudo apt-get install cmake.

When I change a CMake option on the command line, it does not seem to apply

Try deleting CMakeCache.txt between changing CMake settings.

Does fbcp-ili9341 work with linux command line terminal or X windowing system?

Yes, both work fine. For linux command line terminal, the /dev/tty1 console should be set to output to Linux framebuffer 0 (/dev/fb0). This is the default mode of operation and there do not exist other framebuffers in a default distribution of Raspbian, but if you have manually messed with the con2fbmap command in your installation, you may have inadvertently changed this configuration. Run con2fbmap 1 to see which framebuffer the /dev/tty1 console is outputting to, it should print console 1 is mapped to framebuffer 0. Type con2fbmap 1 0 to reset console 1 back to outputting to framebuffer 0.

Likewise, the X windowing system should be configured to render to framebuffer 0. This is by default the case. The target framebuffer for X windowing service is usually configured via the FRAMEBUFFER environment variable before launching X. If X is not working by default, you can try overriding the framebuffer by launching X with FRAMEBUFFER=/dev/fb0 startx instead of just running startx.

Does fbcp-ili9341 work on Raspberry Pi 1 or Pi 2?

I don't know, I don't currently have any to test. Perhaps the code does need some model specific configuration, or perhaps it might work out of the box. I only have Pi 3B, Pi 3B+, Pi Zero W and a Pi 3 Compute Module based systems to experiment on. Pi 2 B has been reported to work by users (#17).

Does fbcp-ili9341 work on display XYZ?

If the display controller is one of the currently tested ones (see the list above), and it is wired up to run using 4-line SPI, then it should work. Pay attention to configure the Data/Control GPIO pin number correctly, and also specify the Reset GPIO pin number if the device has one.

If the display controller is not one of the tested ones, it may still work if it is similar to one of the existing ones. For example, ILI9340 and ILI9341 are practically the same controller. You can just try with a specific one to see how it goes.

If fbcp-ili9341 does not support your display controller, you will have to write support for it. fbcp-ili9341 does not have a "generic SPI TFT driver routine" that might work across multiple devices, but needs specific code for each. If you have the spec sheet available, you can ask for advice, but please do not request to add support to a display controller "blind", that is not possible.

Does fbcp-ili9341 work with 3-wire SPI displays?

Perhaps. This is a more recent experimental feature that may not be as stable, and there are some limitations, but 3-wire ("9-bit") SPI display support is now available. If you have a 3-wire SPI display, i.e. one that does not have a Data/Control (DC) GPIO pin to connect, configure it via CMake with directive -DGPIO_TFT_DATA_CONTROL=-1 to tell fbcp-ili9341 that it should be driving the display with 3-wire protocol.

Current limitations of 3-wire communication are:

  • The performance option ALL_TASKS_SHOULD_DMA is currently not supported, there is an issue with DMA chaining that prevents this from being enabled. As result, CPU usage on 3-wire displays will be slightly higher than on 4-wire displays.
  • The performance option OFFLOAD_PIXEL_COPY_TO_DMA_CPP is currently not supported. As a result, 3-wire displays may not work that well on single core Pis like Pi Zero.
  • This has only been tested on my Adafruit SSD1351 128x96 RGB OLED display, which can be soldered to operate in 3-wire SPI mode, so testing has not been particularly extensive.
  • Displays that have a 16-bit wide command word, such as ILI9486, do not currently work in 3-wire ("17-bit") mode. (But ILI9486L has 8-bit command word, so that does work)

Does fbcp-ili9341 work with I2C, DPI, MIPI DSI or USB connected displays?

No. Those are completely different technologies altogether. It should be possible to port the driver algorithm to work on I2C however, if someone is interested.

Does fbcp-ili9341 work with touch displays?

At the moment one cannot utilize the XPT2046/ADS7846 touch controllers while running fbcp-ili9341, so touch is mutually incompatible with this driver. In order for fbcp-ili9341 to function, you will need to remove all dtoverlays in /boot/config.txt related to touch.

Is it possible to break my display with this driver if I misconfigure something?

I have done close to everything possible to my displays - cut power in middle of operation, sent random data and command bytes, set their operating voltage commands and clock timings to arbitrary high and low values, tested unspecified and reserved command fields, and driven the displays dozens of MHz faster than they managed to keep up with, and I have not yet done permanent damage to any of my displays or Pis.

Easiest way to do permanent damage is to fail at wiring, e.g. drive 5 volts if your display requires 3.3v, or short a connection, or something similar.

The one thing that fbcp-ili9341 stays clear off is that it does not program the non-volatile memory areas of any of the displays. Therefore a hard power off on a display should clear all performed initialization and reset the display to its initial state at next power on.

That being said, if it breaks, you'll get to purchase a new shiny one to replace it.

Can I have both the HDMI and SPI connected at the same time?

Yes, fbcp-ili9341 shows the output of the HDMI display on the SPI screen, and both can be attached at the same time. A HDMI display does not have to be connected however, although fbcp-ili9341 operation will still be affected by whatever HDMI display mode is configured. Check out tvservice -s on the command line to check what the current DispmanX HDMI output mode is.

Do I have to show the same image on HDMI output and the SPI display, or can they be different?

At the moment fbcp-ili9341 has been developed to only display the contents of the main DispmanX GPU framebuffer over to the SPI display. That is, the SPI display will show the same picture as the HDMI output does. There is no technical restriction that requires this though, so if you know C/C++ well, it should be a manageable project to turn fbcp-ili9341 to operate as an offscreen display library to show a completely separate (non-GPU-accelerated) image than what the main HDMI display outputs. For example you could have two different outputs, e.g. a HUD overlay, a dashboard for network statistics, weather, temps, etc. showing on the SPI while having the main Raspberry Pi desktop on the HDMI.

In this kind of mode, you would probably strip the DispmanX bits out of fbcp-ili9341, and recast it as a static library that you would link to in your drawing application, and instead of snapshotting frames, you can then programmatically write to a framebuffer in memory from your C/C++ code.

I am running fbcp-ili9341 on a display that was listed above, but the display stays white after startup?

Unfortunately there are a number of things to go wrong that all result in a white screen. This is probably the hardest part to diagnose. Some ideas:

  • double check the wiring,
  • double check that the display controller is really what you expected. Trying to drive with the display with wrong initialization code usually results in the display not reacting, and the screen stays white,
  • shut down and physically power off the Pi and the display in between multiple tests. Driving a display with a wrong initialization routine may put it in a bad state that needs a physical power off for it to reset,
  • if there is a reset pin on the display, make sure to pass it in CMake line. Or alternatively, try driving fbcp-ili9341 without specifying the reset pin,
  • make sure the display is configured to run 4-wire SPI mode, and not in parallel mode or 3-wire SPI mode. You may need to solder or desolder some connections or set a jumper to configure the specific driving mode. Support for 3-wire SPI displays does exist, but it is more limited and a bit experimental.

The display stays blank at boot without lighting up

This suggests that the power line or the backlight line might not be properly connected. Or if the backlight connects to a GPIO pin on the Pi (and not a voltage pin), then it may be that the pin is not in correct state for the backlight to turn on. Most of the LCD TFT displays I have immediately light up their backlight when they receive power. The Tontec one has a backlight GPIO pin that boots up high but must be pulled low to activate the backlight. OLED displays on the other hand seem to stay all black even after they do get power, while waiting for their initialization to be performed, so for OLEDs it may be normal for nothing to show up on the screen immediately after boot.

If the backlight connects to a GPIO pin, you may need to define -DGPIO_TFT_BACKLIGHT=<pin> in CMake command line or config.h, and edit config.h to enable #define BACKLIGHT_CONTROL.

The display clears from white to black after starting fbcp-ili9341, but picture does not show up?

fbcp-ili9341 runs a clear screen command at low speed as first thing after init, so if that goes through, it is a good sign. Try increasing -DSPI_BUS_CLOCK_DIVISOR= CMake option to a higher number to see if the display driving rate was too fast. Or try disabling DMA with -DUSE_DMA_TRANSFERS=OFF to see if this might be a DMA conflict.

Image does show up on display, but it freezes shortly afterwards

This suggests same as above, increase SPI bus divisor or troubleshoot disabling DMA. If DMA is detected to be the culprit, try changing up the DMA channels. Double check that /boot/config.txt does not have any dtoverlays regarding other SPI display drivers or touch screen controllers, and that it does NOT have a dtparam=spi=on line in it - fbcp-ili9341 does not use the Linux kernel SPI driver.

Make sure other fbcp programs are not running, or that another copy of fbcp-ili9341 is not running on the background.

Image does show up on display, but when I start up program XYZ, the image freezes

This is likely caused by the program resizing the video resolution at runtime, which breaks DispmanX. See raspberrypi/userland#461 for more details.

The display works for some seconds or minutes, but then turns all white or black, or freezes

Check that the Pi is powered off of a power supply that can keep up with the voltage, and the low voltage icon is not showing up. (remove any avoid_warnings=1/2 directive from /boot/config.txt if that was used to get rid of warnings overlay, to check that voltage is good) It has been observed that if there is not enough power supplied, the display can be the first to starve, while the Pi might keep on running fine. Try removing turbo settings or lowering the clock speed if you have overclocked to verify that the display crash is not power usage related.

Also try lowering SPI bus speed to a safe lower value, e.g. half of the maximum speed that the display was able to manage.

The driver is updating pixels on the display, but it looks all garbled

Double check the Data/Command (D/C) GPIO pin physically, and in CMake command line. Whenever fbcp-ili9341 refers to pin numbers, they are always specified in BCM pin numbers. Try setting a higher -DSPI_BUS_CLOCK_DIVISOR= value to CMake. Make sure no other fbcp programs or SPI drivers or dtoverlays are enabled.

Colors look wrong on the display

BGR vs RGB and inverted colors

If the color channels are mixed (red is blue, blue is red, green is green) like shown on the left image, pass the CMake option -DDISPLAY_SWAP_BGR=ON to the build.

If the color intensities look wrong (white is black, black is white, color looks like a negative image) like seen in the middle image, pass the CMake option -DDISPLAY_INVERT_COLORS=ON to the build.

If the colors looks off in some other fashion, it is possible that the display is just being driven at a too high SPI bus speed, in which case try making the display run slower by choosing a higher -DSPI_BUS_CLOCK_DIVISOR= option to CMake. Especially on ILI9486 displays it has been observed that the colors on the display can become distorted if the display is run too fast beyond its maximum capability.

Failed to allocate GPU memory!

fbcp-ili9341 needs a few megabytes of GPU memory to function if DMA transfers are enabled. The gpu_mem boot config option dictates how much of the Pi's memory area is allocated to the GPU. By default this is 64MB, which has been observed to not leave enough memory for fbcp-ili9341 if HDMI is run at 1080p. If this error happens, try increasing GPU memory to e.g. 128MB by adding a line gpu_mem=128 in /boot/config.txt.

It does not build, or crashes, or something is obviously out of date

As the number of supported displays, Raspberry Pi device models, Raspbian/Retropie/Lakka OS versions, accompanied C++ compiler versions and fbcp-ili9341 build options have grown in number, there is a combinatorial explosion of all possible build modes that one can put the codebase through, so it is not easy to keep every possible combo tested all the time. Something may have regressed or gotten outdated. Stay calm, and report a bug.

You can also try looking through the commit history to find changes related to your configuration combo, to see if there's a mention of a known good commit in time that should work for your case. If you get an odd compiler error on cmake or make lines, those will usually be very easy to fix, as they are most of the time a result of some configurational oversight.

Which SPI display should I buy to make sure it works best with fbcp-ili9341?

First, make sure the display is a 4-wire SPI and not a 3-wire one. A display is 4-wire SPI if it has a Data/Control (DC) GPIO line that needs connecting. Sometimes the D/C pin is labeled RS (Register Select). Support for 3-wire SPI displays does exist, but it is experimental and not nearly as well tested as 4-wire displays.

Second is the consideration about display speed. Below is a performance chart of the different displays I have tested. Note that these are sample sizes of one, I don't know how much sample variance there exists. Also I don't know if it is likely that there exists big differences between displays with same controller from different manufacturers. At least the different ILI9341 displays that I have are all quite consistent on performance, whether they are from Adafruit or WaveShare or from BuyDisplay.com.

Vendor Size Resolution Controller Rated SPI Bus Speed Obtained Bus Speed Frame Rate
Adafruit PiTFT 2.8" 240x320 ILI9341 10MHz 294MHz/4=73.50MHz 59.81 fps
Adafruit PiTFT 2.2" 240x320 ILI9340 15.15MHz 338MHz/4=84.50MHz 68.76 fps
Adafruit PiTFT 3.5" 320x480 HX8357D 15.15MHz 314MHz/6=52.33MHz 21.29 fps
Adafruit OLED 1.27" 128x96 SSD1351 20MHz 360MHz/20=18.00MHz 91.55 fps
Waveshare RPi LCD (B) IPS 3.5" 320x480 ILI9486 15.15MHz 255MHz/8=31.88MHz 12.97 fps
maithoga TFT LCD 3.5" 320x480 ILI9486L 15.15MHz 400MHz/8=50.00MHz 13.56 fps*
BuyDisplay.com SPI TFT copy #1 3.2" 240x320 ILI9341 10MHz 310MHz/4=77.50MHz 63.07 fps
BuyDisplay.com SPI TFT copy #2 3.2" 240x320 ILI9341 10MHz 300MHz/4=75.00MHz 61.03 fps
Arduino A000096 LCD 1.77" 128x160 ST7735R 15.15MHz 355MHz/6=59.16MHz 180.56 fps
Tontec MZ61581-PI-EXT 2016.1.28 3.5" 320x480 MZ61581 128MHz 280MHz/2=140.00MHz 56.97 fps
Adafruit 240x240 Wide Angle TFT 1.54" 240x240 ST7789 ? 340MHz/4=85.00MHz 92.23 fps
WaveShare 240x240 Display HAT 1.3" 240x240 ST7789VW 62.5MHz 338MHz/4=84.50MHz 91.69 fps
WaveShare 128x128 Display HAT 1.44" 128x128 ST7735S 15.15MHz (untested) (untested)
KeDei v6.3 3.5" 320x480 MPI3501 ? 400MHz/12=33.333MHz 4.8fps **

In this list, Rated SPI Bus Speed is the maximum clock speed that the display controller is rated to run at. The Obtained Bus Speed column lists the fastest SPI bus speed that was achieved in practice, and the core_freq BCM Core speed and SPI Clock Divider CDIV setting that was used to achieve that rate. Note how most display controllers can generally be driven much faster than what they are officially rated at in their spec sheets.

The Frame Rate column shows the worst case frame rate when full screen updates are being performed. This occurs for example when watching fullscreen video (that is not a flat colored cartoon). Because fbcp-ili9341 only sends over the pixels that have changed, displays such as HX8357D and ILI9486 can still be used to play many games at 60fps. Retro games work especially well.

All the ILI9341 displays work nice and super fast at ~70-80MHz. My WaveShare 3.5" 320x480 ILI9486 display runs really slow compared to its pixel resolution, ~32MHz only. See fbcp-ili9341 ported to ILI9486 WaveShare 3.5" (B) SpotPear 320x480 SPI display for a video of this display in action. Adafruit's 320x480 3.5" HX8357D PiTFTs is ~64% faster in comparison.

The ILI9486L controller based maithoga display runs a bit faster than ILI9486 WaveShare, 50MHz versus 31.88MHz, i.e. +56.8% bandwidth increase. However fps-wise maithoga reaches only 13.56 vs WaveShare 12.97 fps, because the bandwidth advantage is fully lost in pixel format differences: ILI9486L requires transmitting 24 bits per each pixel (R6G6B6 mode), whereas ILI9486 supports 16 bits per pixel R5G6B5 mode. This is reflected in the above chart refresh rate for the maithoga display (marked with a star).

If manufacturing variances turn out not to be high between copies, and you'd like to have a bigger 320x480 display instead of a 240x320 one, then it is recommended to avoid ILI9486, they indeed are slow.

The KeDei v6.3 display with MPI3501 controller takes the crown of being horrible, in all aspects imaginable. It is able to run at 33.33 MHz, but due to technical design limitations of the display (see #40), effective bus speed is halved, and only about 72% utilization of the remaining bus rate is achieved. DMA cannot be used, so CPU usage will be off the charts. Even though fbcp-ili9341 supports this display, level of support is expected to be poor, because the hardware design is a closed secret without open documentation publicly available from the manufacturer. Stay clear of KeDei or MPI3501 displays.

The Tontec MZ61581 controller based 320x480 3.5" display on the other hand can be driven insanely fast at up to 140MHz! These seem to be quite hard to come by though and they are expensive. Tontec seems to have gone out of business and for example the domain itontec.com from which the supplied instructions sheet asks to download original drivers from is no longer registered. I was able to find one from eBay for testing.

Search around, or ask the manufacturer of the display what the maximum SPI bus speed is for the device. This is the most important aspect to getting good frame rates, but unfortunately most web links never state the SPI speed rating, or they state it ridiculously low like in the spec sheets. Try and buy to see, or ask in some community forums from people who already have a particular display to find out what SPI bus speed it can achieve.

One might think that since Pi Zero is slower than a Pi 3, the SPI bus speed might not matter as much when running on a Pi Zero, but the effect is rather the opposite. To get good framerates on a Pi Zero, it should be paired with a display with as high SPI bus speed capability as possible. This is because the higher the SPI bus speed is, the more autonomously a DMA controller can drive it without CPU intervention. For the same reason, the interlacing technique does not (currently at least) perform well on a Pi Zero, so it is disabled there by default. ILI9341s run well on Pi Zero, ILI9486 on the other hand is quite difficult to combine with a Pi Zero.

Ultimately, it should be noted that parallel displays (DPI) are the proper method for getting fast framerates easily. SPI displays should only be preferred if display form factor is important and a desired product might only exist as SPI and not as DPI, or the number of GPIO pins that are available on the Pi is scarce that sacrificing dozens of pins to RGB data is not feasible.

What other options/alternatives do I have to fbcp-ili9341?

Hardware-wise, there are six different ways to connect displays to the Pi. Here are the pros and cons of each:

  1. Composite video
    • +simple one-wire connectivity
    • +the Pi GPU drives the signal on its own without CPU assistance, no driver needed
    • +has vsync, no tearing artifacts
    • +available for a cheap price
    • -low quality analog signal that is blurry and has color artifacts
  2. I²C (Inter-Integrated Circuit)
    • +fewest amount of digital signals (two): SDA (data) and SCL (clock)
    • +available for a cheap price
    • -slowest bandwidth, generally only the smallest displays with low resolution utilize this
    • -need software CPU cycles to push pixels to display
    • -no video vsync, causes tearing artifacts
  3. SPI (Serial Peripheral Interface)
    • the method used/supported by this driver
    • +only few digital signal lines needed: SCLK (clock), MOSI (data), D/C (data/command) (MISO line is not read by fbcp-ili9341), CS (Chip Select) (sometimes optional)
    • +much faster than I²C
    • +very low video display latency
    • +available for a cheap price
    • -no single pin or protocol standard, be careful about hardware compatibility
    • -need software CPU cycles to push pixels to display
    • -no video vsync, causes tearing artifacts
    • -low resolution, generally 480x320 or smaller
  4. DPI (Display Parallel Interface)
    • +high quality digital signal driven directly by the Pi GPU without CPU assistance
    • +fixed 60hz updates without missed frames
    • +has vsync, no tearing artifacts
    • -no single pin or protocol standard, be careful about hardware compatibility
    • -consumes most of the pins on the Pi GPIO header (20-28 digital signal pins)
    • -no ability to disable vsync, likely more video latency than SPI
  5. MIPI-DSI (Display Serial Interface)
    • +high quality digital signal driven directly by the Pi GPU without CPU assistance
    • +fixed 60hz updates without missed frames
    • +has vsync, no tearing artifacts
    • +does not require GPIO pins, leaving them free for other use
    • +available in high resolution
    • -uses proprietary DSI connectivity on the Pi, not an open ecosystem
    • -only one official display exists
  6. HDMI
    • +high quality digital signal driven directly by the Pi GPU without CPU assistance
    • +fixed 60hz updates without missed frames
    • +has vsync, no tearing artifacts
    • +does not require GPIO pins, leaving them free for other use
    • +very standard, little configuration needed in /boot/config.txt
    • +available in high resolution
    • -bulky connector for most portable designs

Displays are generally manufactured to utilize one specific interfacing method, with the exception that some displays have a both I²C and SPI modes that can be configured via soldering.

Fbcp-ili9341 driver is about interfacing with SPI displays. If your display utilizes some other connection mechanism, fbcp-ili9341 will not apply.

Software-wise, there are two possible alternatives to fbcp-ili9341:

  1. notro/fbtft + tasanakorn/rpi-fbcp
  2. Use an ad hoc drawing library that provides both drawing primitives plus the display interface, e.g. adafruit/Adafruit_Python_ILI9341.

Resources

The following links proved helpful when writing this:

I Want To Contribute / Future Work / TODOs

If you would like to help push Raspberry Pi SPI display support further, there are always more things to do in the project. Here is a list of ideas and TODOs for recognized work items to contribute, roughly rated in order of increasing difficulty.

  • Vote up issue raspberrypi/userland/#440 if you would like to see Raspberry Pi Foundation improve CPU performance and reduce latency of the Pi when used with SPI displays.
  • Vote up issue raspberrypi/userland/#461 if you would like to see fbcp-ili9341 not die (due to DispmanX dying) when HDMI display resolution changes.
  • Vote up issue raspberrypi/firmware/#992 if you would like to see Raspberry Pi SPI bus to have high throughput even when the Pi CPU is not under heavy CPU load (better SPI throughput with lower power consumption), a performance feature only SDHOST on the Pi currently enjoys.
  • Benchmark fbcp-ili9341 performance in your use case with CPU tool top/htop, or with a power meter off the wall and report the results.
  • Do you have a display with an unlisted or unknown display controller? Post close up photos of it to an issue in the tracker, and report if you were able to make it work with fbcp-ili9341?
  • Did you have to do something unexpected or undocumented to get fbcp-ili9341 to work in your environment or use case? Write up a tutorial or record a video to let people know about the gotchas.
  • If you have access to a high frequency scope/logic analyzer (~128MHz), audit the utilization of the SPI MOSI bus to find any remaining idle times on the bus, and analyze their sources.
  • Port fbcp-ili9341 to work as a static code library that one can link to another application for CPU-based drawing directly to display, bypassing inefficiencies and latency of the general purpose Linux DispmanX/graphics stack.
  • Improve existing display initialization routines with options to control e.g. gamma curves, color saturation, driving voltages, refresh rates or other potentially useful features that the display controller protocols expose.
  • Add support to fbcp-ili9341 to a new display controller. (e.g. #26)
  • Implement support for reading the MISO line for display identification numbers/strings for potentially interesting statistics (could some of the displays be autodetected this way?)
  • Add support for other color modes, like RGB666 or RGB888. Currently fbcp-ili9341 only knows about RGB565 display mode.
  • Implement a kernel module that enables userland programs to allocate DMA channels, which fbcp-ili9341 could use to amicably reserve its own DMA channels without danger of conflicting.
  • Implement support for touch control while fbcp-ili9341 is active. (#33)
  • Implement support for SPI-based SD card readers that are sometimes attached to displays.
  • Port fbcp-ili9341 to work with I2C displays.
  • Port more key algorithms to ARM assembly to optimize performance of fbcp-ili9341 in hotspots, or optimize execution in some other ways?
  • Add support to building fbcp-ili9341 on another operating system than Raspbian. (see #43)
  • Add support for building on 64-bit operating systems. (see #43)
  • Port fbcp-ili9341 over to a new single-board computer hardware. (e.g. #30)
  • Improve support for 3-wire displays, e.g. for 1) "17-bit" 3-wire communication, 2) fix up SPI_3WIRE_PROTOCOL + ALL_TASKS_SHOULD_DMA to work together, or 3) fix up SPI_3WIRE_PROTOCOL + OFFLOAD_PIXEL_COPY_TO_DMA_CPP to work together.
  • Optimize away unnecessary zero padding that 3-wire communication currently incurs, by keeping a queue of leftover untransmitted partial bits of a byte, and piggybacking them onto the next transfer that comes in.
  • Port the high performance DMA-based SPI communication technique from fbcp-ili9341 over to another project that uses the SPI bus for something else, for close to 100% saturation of the SPI bus in the project.
  • Improve the implementation of chaining DMA transfers to not only chain transfers within a single SPI task, but also across multiple SPI tasks.
  • Optimize ALL_TASKS_SHOULD_DMA mode to be always superior in performance and CPU usage so that the non-ALL_TASKS_SHOULD_DMA path can be dropped from the codebase. (probably requires the above chaining to function efficiently)
  • If you are knowledgeable with BCM2835 DMA, investigate whether the hacky dance where two DMA channels need to be used to reset and resume DMA SPI transfers when chaining, can be avoided?
  • If you have contacts with Broadcom, ask them to promote use of the SoC hardware with DMA chaining + mixed SPI & non-SPI tasks as a first class tested use case. Current DMA SPI hardware behavior of BCM2835 is, to say the least, surprising.

License

This driver is licensed under the MIT License. See LICENSE.txt. In nonlegal terms, it's yours for both free and commercial projects, DIY packages, kickstarters, Etsys and Ebays, and you don't owe back a dime. Feel free to apply and derive as you wish.

If you found fbcp-ili9341 useful, it makes me happy to hear back about the projects it found a home in. If you did a build or a project where fbcp-ili9341 worked out, it'd be great to see a video or some photos or read about your experiences.

I hope you build something you enjoy!

Contacting

Best way to discuss the driver is to open a GitHub issue. You may also be able to find me over at sudomod.com Discord channel.

fbcp-ili9341's People

Contributors

daviel avatar dglaude avatar fritz3n avatar gayuha avatar howardqiao avatar joonamo avatar juj avatar manawyrm avatar mkende avatar nightkurz avatar quezadaminter avatar ricmatsui avatar samveen avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

fbcp-ili9341's Issues

Screen stays white

Hello! i came across this page and i am wondering why my display is not working (ILI9341)
i have connected the D/C pin to 22 and rest to 3.3v
after running sudo ./fbcp-ili9341 my screen stays white ;-; but with FBTFT it works any help would be great :D

Thanks,
M.Mubin

BGR to RGB - display color inversion

Hi juj,
First, thank you for your hard work, I'm enjoying it very much.
Working with Pi Zero went flawlessly with waveshare 35b.
I have a 4" (a) (https://www.waveshare.com/wiki/4inch_RPi_LCD_(A))
The fbcp can run the 4"(a) very well, just one problem...colors are inverted (not distorted).
Is there any way i can change something in code to swap bgr to rgb ?
Thanks in advance.
el.

"vc_dispmanx_snapshot() failed with return code -1!" when kodi launches

When fbcp-ili9341 (also happens on fbcp-rpi) is running and kodi gets launched fbcp-ili9341 exits with "vc_dispmanx_snapshot() failed with return code -1!" on pi zero.
But when running fbcp-ili9341 after kodi was started everything works like it should.

Maybe retrying couple of times to make an dispmanx snapshot with some delay could fix this issue?

Statistics overlay

I'm trying to disable overlay but it still shows up, I tried removing the whole // #define STATISTICS line from display.h but overlay still pops up

Doesn't launch correctly without keyboard plugged in.

Summary: If there is no keyboard attached to the device on boot, the screen fails to load.
Plugging in a keyboard and rebooting restores screen functionality.

Expected behavior: Screen should load even if no keyboard is found.
Use Case: I am using this in a handheld game system that does not have a keyboard attached, it simply uses an arduino controller as a gamepad for HID input.

Issue occurs on Raspberry Pi 3, running Raspbian Scratch and Retropie 4.4

Built with the following configs:

cmake -DILI9341=ON -DGPIO_TFT_DATA_CONTROL=24 -DGPIO_TFT_BACKLIGHT=18 -DBACKLIGHT_CONTROL=ON -DGPIO_TFT_RESET_PIN=25 -DDISPLAY_ROTATE_180_DEGREES=ON -DSPI_BUS_CLOCK_DIVISOR=6 -DSTATISTICS=0 ..

Screen Tearing (Horizontal)

After building an compiling, the screen runs awesome (generic ILI9341, pins 24,25)
Running RetroPie, on navigating through the menu i get slight horizontal tearing/artifcating

Playing games like Super Mario Word, tearing is too severe and disrupts gameplay

Hardware:
Raspberry Pi Zero W

Suggestions?

Driver Applies Overscan When Not Needed

I'm working with FreePlay, we got pixel perfect to work, just thought you should know that you set the NES overscan settings to the default, so I'd comment them out on the repo version. We already made the change on our local copy.

fbcp-ili9341 does not initialize on boot

Hello there,

I installed and compiled the driver for my Raspberry Pi Zero W running Retropie over Raspbian Stretch, and it seems that it won't start the driver after a reboot. The log says that it can't find the directory specified in rc.local (which I definitely copied and pasted there). Any advice?

Thanks!

Any chance of porting to H3 boards?

Hi there - any chance this might be able to be ported to the sunxi H2/3/5 boards? I.e OrangePi etc.

I have a few of the waveshare screens and the sunxi is pretty well supported (well the Mali OpenGL mainlining effort is still underway) but the armsoc X and DRI stuff is available.

Zero/Zero W inconsistent

As the driver currently is, we couldn't get the Zero (or the W, could be one or the other) to work with DMA transfers, but the other worked just fine. This severely hampers our battery life and CPU usage and were wondering if you'd ever make a work around for the one that doesn't work or if we have to research and get it working ourselves.

At this point we think it's probably less an issue of hardware and more about some kind of driver that uses specific DMA channels (more than likely the WiFi/BT).

keyboard event

this driver is a great piece of work, thanks!!!
however, my keyboard was on another event (/dev/input) resulting in an error and i am planning to use no keyboard at all. is it possible to exclude the keyboard events e.g. as a compiler option?

Backlight control on 9486L appears to do nothing.

I build with -DGPIO_TFT_BACKLIGHT=23 -DBACKLIGHT_CONTROL=ON and let the Pi sit for a while. After an hour (with the BL pin connected to GPIO 23, of course) nothing seems to have happened.

When connecting the BL pin on my screen to 3.3v, the screen gets slightly brighter. When connecting it to GND the screen goes black. Is this different behavior from other screens?

integrating ili9342

Have you had a chance to do an ili9342 integration? looking to do 8-bit (DB0:7)

ili9486

Hi
I have a 3.5LCD ili9486(Waveshare 3.5inch RPi LCD (B)) and I tried to make your program work on it.
I changed the initialization to this:

void InitILI9341()
{
    BEGIN_SPI_COMMUNICATION();
  {
        SPI_TRANSFER(0xb0/*Interface Mode Control*/, 0x0);
        SPI_TRANSFER(0x11/*Sleep Out*/);
        usleep(120 * 1000);
        SPI_TRANSFER(0x3A, 0x55/*use 16 bits per pixel color*/);
        SPI_TRANSFER(0x36, 0x48/*MX, BGR == rotation 0*/);
        SPI_TRANSFER(0xC2, 0x44/*Power Control 3*/);
        SPI_TRANSFER(0xC5, 0x00, 0x00, 0x00, 0x00/*VCOM Control 1*/);
        SPI_TRANSFER(0xE0/*Positive Gamma Correction*/, 0x0F, 0x1F, 0x1C, 0x0C, 0x0F, 0x08, 0x48, 0x98, 0x37, 0x0A, 0x13, 0x04, 0x11, 0x0D, 0x00);
        SPI_TRANSFER(0xE1/*Negative Gamma Correction*/, 0x0F, 0x32, 0x2E, 0x0B, 0x0D, 0x05, 0x47, 0x75,0x37, 0x06, 0x10, 0x03, 0x24, 0x20, 0x00);
        SPI_TRANSFER(0xE2/* Digital Gamma Control 1 */, 0x0F, 0x32, 0x2E, 0x0B, 0x0D, 0x05, 0x47, 0x75, 0x37, 0x06, 0x10, 0x03, 0x24, 0x20, 0x00);
        SPI_TRANSFER(0x11/*Sleep Out*/);
        usleep(120 * 1000);
        SPI_TRANSFER(/*Display ON*/0x29);

    // Some wonky effects to try out:
//    SPI_TRANSFER(0x20/*Display Inversion OFF*/);
//    SPI_TRANSFER(0x21/*Display Inversion ON*/);
//    SPI_TRANSFER(0x38/*Idle Mode OFF*/);
//    SPI_TRANSFER(0x39/*Idle Mode ON*/); // Idle mode gives a super-saturated high contrast reduced colors mode

    // Since we are doing delta updates to only changed pixels, clear display initially to black for known starting state
    for(int y = 0; y < DISPLAY_HEIGHT; ++y)
    {
      SPI_TRANSFER(DISPLAY_SET_CURSOR_X, 0, 0, DISPLAY_WIDTH >> 8, DISPLAY_WIDTH & 0xFF);
      SPI_TRANSFER(DISPLAY_SET_CURSOR_Y, y >> 8, y & 0xFF, DISPLAY_HEIGHT >> 8, DISPLAY_HEIGHT & 0xFF);
      SPITask *clearLine = AllocTask(SCANLINE_SIZE);
      clearLine->cmd = DISPLAY_WRITE_PIXELS;
      memset(clearLine->data, 0, clearLine->size);
      CommitTask(clearLine);
      RunSPITask(clearLine);
      DoneTask(clearLine);
    }
    SPI_TRANSFER(DISPLAY_SET_CURSOR_X, 0, 0, DISPLAY_WIDTH >> 8, DISPLAY_WIDTH & 0xFF);
    SPI_TRANSFER(DISPLAY_SET_CURSOR_Y, 0, 0, DISPLAY_HEIGHT >> 8, DISPLAY_HEIGHT & 0xFF);
  }

  END_SPI_COMMUNICATION();
}

And the screen turned all white.
I'm a novice at these things . Could you help me ?

Raspberry Pi Model B working

Hi @juj!

This issue is to let you know that I got a working build on the Pi 1, model B.

I've got a cheap ili9341 screen like the one bamsegod used over at sudomod. Only I got the 2.4" version. I also had an old Model B Pi rev 000f lying around. So I thought it would be nice to put them to good use by combining them and build a tiny retropie machine.

img_20180924_114306

I used commit 83f1326 and started toying around with overclocking and divider settings. Currently I'm using the TURBO preset and using a CDIV value of 10. Using 8 does work, but I noticed some flickering when running ioquake3 which is almost completely absent when using 10 as a CDIV value.

Currently I'm testing Sonic because it has a nice attract mode which I can leave running for long periods of time just to test how stable the config is. Obviously I don't get a constant 60fps but there's no noticeable lag so that's awesome on such a humble machine. Even ioquake3 ran incredibly smooth as well.

So if there's anything I can do to test I'd be glad to help. It's the least I can do after the great work you provided.

GPU Memory leak?

After running for ~30 minutes on RPi 3B with 96MB GPU memory allocated i've started getting message "Failed to allocate GPU memory! Try increasing gpu_mem allocation in /boot/config.txt. See https://www.raspberrypi.org/documentation/configuration/config-txt/memory.md".
I don't actually think it's a memory leak, but maybe some issue in memory mapping calculation?

Video setup in config.txt:
gpu_mem=96 hdmi_force_hotplug=1 hdmi_group=2 hdmi_mode=87 hdmi_cvt 480 320 60 6 0 0 0

Built parameters:
-DSPI_BUS_CLOCK_DIVISOR=12 -DWAVESHARE35B_ILI9486=ON -DARMV6Z=ON

No overclocking/downclocking.

TinyPi

Howdy @juj

I thought i would give your code a bit of the old college try on my TinyPi Pro board. It is using a ST7789 screen which looks much like the one on the 1.3" waveshare board (actual screen is here https://www.aliexpress.com/item/1-3-inch-white-light-full-view-SPI-OLED-LCD-SSD1306-drive-IC-128-64-not/1609778123.html) mounted on a custom board, and i have been using the notro flexfb driver with great success, using the following modprobe lines
modprobe fbtft_device name=flexfb speed=32000000 gpios=reset:25,dc:24 modprobe flexfb width=240 height=240 init=-1,0x11,-2,120,-1,0x36,0x00,-1,0x3A,0x05,-1,0xB2,0x0C,0x0C,0x00,0x33,0x33,-1,0xB7,0x35,-1,0xBB,0x1A,-1,0xC0,0x2C,-1,0xC2,0x01,-1,0xC3,0x0B,-1,0xC4,0x20,-1,0xC6,0x0F,-1,0xD0,0xA4,0xA1,-1,0x21,-1,0xE0,0x00,0x19,0x1E,0x0A,0x09,0x15,0x3D,0x44,0x51,0x12,0x03,0x00,0x3F,0x3F,-1,0xE1,0x00,0x18,0x1E,0x0A,0x09,0x25,0x3F,0x43,0x52,0x33,0x03,0x00,0x3F,0x3F,-1,0x29,-3

I have spent the best part of a day trying to get your code to work, and im sure i must be doing something silly, but im struggling to put my finger on it. At first i though it was down to the fact that i had some old fbtft settings lying about somewhere, so i have got a fresh copy of retropie today, and installed nothing but your code to make sure there are no conflicts, and im still struggling.

I would like to think i know what im doing in this area, but alas no screen yet!!

My cmake code is as follows
cmake -DST7789VW=ON -DGPIO_TFT_DATA_CONTROL=24 -DGPIO_TFT_RESET_PIN=25 -DSPI_BUS_CLOCK_DIVISOR=10 -DUSE_DMA_TRANSFERS=OFF ..

have tried various combinations of divisor and dma and such to no avail. even adding pi zero specific options to see if that helps!!

Any chance you could cast an eye over my config, see if you can spot anything obvious?

Many thanks

Pete

Driver don't work with official Waveshare 3.5inch LCD (B)

Hello!

(sorry for my bad english)

First, thanks for this awesome driver!

I'm trying it with an official Waveshare 3.5 inch LCD IPS (B) display (not a clone), which is supported out of the box. But, I only got black screen with sometimes flash in white.

I used this cmake:

pi@raspberrypi:~/fbcp-ili9341/build $ cmake -DSPI_BUS_CLOCK_DIVISOR=8 -DWAVESHARE35B_ILI9486=ON -DSTATISTICS=1 ..

The output:

-- Doing a Release build
-- Board revision: a020d3
-- Detected this Pi to be one of: Pi 2B rev. 1.2, 3B, 3B+, CM3 or CM3 lite, with 4 hardware cores and ARMv8-A instruction set CPU.
-- Enabling optimization flags that target ARMv8-A instruction set (Pi 2B >= rev. 1.2, 3B, 3B+, CM3 or CM3 lite)
-- Using 4-wire SPI mode of communication, with GPIO pin 10 for Data/Control line
-- Using GPIO pin 25 for Reset line
-- Scaling source image to view. If the HDMI resolution does not match the SPI display resolution, this will produce blurriness. Match the HDMI display resolution with the SPI resolution in /boot/config.txt to get crisp pixel perfect rendering, or alternatively pass -DDISPLAY_CROPPED_INSTEAD_OF_SCALING=ON to crop instead of scale if you want to view the center of the screen pixel perfect when HDMI and SPI resolutions do not match.
-- Preserving aspect ratio when scaling source image to the SPI display, introducing letterboxing/pillarboxing if HDMI and SPI aspect ratios are different (Pass -DDISPLAY_BREAK_ASPECT_RATIO_WHEN_SCALING=ON to stretch HDMI to cover full screen if you do not care about aspect ratio)
-- SPI_BUS_CLOCK_DIVISOR set to 8. Try setting this to a higher value (must be an even number) if this causes problems. Display update speed = core_freq/divisor. (on Pi3B, by default core_freq=400)
-- USE_DMA_TRANSFERS enabled, this improves performance. Try running CMake with -DUSE_DMA_TRANSFERS=OFF it this causes problems, or try adjusting the DMA channels to use with -DDMA_TX_CHANNEL=<num> -DDMA_RX_CHANNEL=<num>.
-- Targeting Adafruit PiTFT with ILI9340/ILI9341
-- Configuring done
-- Generating done
-- Build files have been written to: /home/pi/fbcp-ili9341/build

The first problem I see is -- Targeting Adafruit PiTFT with ILI9340/ILI9341. But I continue.

pi@raspberrypi:~/fbcp-ili9341/build $ make -j
[  5%] Building CXX object CMakeFiles/fbcp-ili9341.dir/fbcp-ili9341.cpp.o
[ 11%] Building CXX object CMakeFiles/fbcp-ili9341.dir/diff.cpp.o
[ 16%] Building CXX object CMakeFiles/fbcp-ili9341.dir/display.cpp.o
[ 22%] Building CXX object CMakeFiles/fbcp-ili9341.dir/dma.cpp.o
[ 27%] Building CXX object CMakeFiles/fbcp-ili9341.dir/mem_alloc.cpp.o
[ 33%] Building CXX object CMakeFiles/fbcp-ili9341.dir/ili9341.cpp.o
[ 38%] Building CXX object CMakeFiles/fbcp-ili9341.dir/gpu.cpp.o
[ 44%] Building CXX object CMakeFiles/fbcp-ili9341.dir/hx8357d.cpp.o
[ 50%] Building CXX object CMakeFiles/fbcp-ili9341.dir/text.cpp.o
[ 55%] Building CXX object CMakeFiles/fbcp-ili9341.dir/ili9486.cpp.o
[ 61%] Building CXX object CMakeFiles/fbcp-ili9341.dir/spi.cpp.o
[ 66%] Building CXX object CMakeFiles/fbcp-ili9341.dir/st7735r.cpp.o
[ 72%] Building CXX object CMakeFiles/fbcp-ili9341.dir/mz61581.cpp.o
[ 77%] Building CXX object CMakeFiles/fbcp-ili9341.dir/statistics.cpp.o
[ 83%] Building CXX object CMakeFiles/fbcp-ili9341.dir/mailbox.cpp.o
[ 88%] Building CXX object CMakeFiles/fbcp-ili9341.dir/keyboard.cpp.o
[ 94%] Building CXX object CMakeFiles/fbcp-ili9341.dir/ssd1351.cpp.o
[100%] Linking CXX executable fbcp-ili9341
[100%] Built target fbcp-ili9341

Then run driver:

pi@raspberrypi:~/fbcp-ili9341/build $ sudo ./fbcp-ili9341
bcm_host_get_peripheral_address: 0x3f000000, bcm_host_get_peripheral_size: 16777216, bcm_host_get_sdram_address: 0xc0000000
BCM core speed: current: 250000000hz, max turbo: 400000000hz. SPI CDIV: 8, SPI max frequency: 50000000hz
Allocated DMA channel 7
Allocated DMA channel 1
Enabling DMA channels Tx:7 and Rx:1
DMA hardware register file is at ptr: 0x75b66000, using DMA TX channel: 7 and DMA RX channel: 1
DMA hardware TX channel register file is at ptr: 0x75b66700, DMA RX channel register file is at ptr: 0x75b66100
Resetting DMA channels for use
DMA all set up
Initializing display
Resetting display at reset GPIO pin 25
Creating SPI task thread
InitSPI done
DISPLAY_FLIP_ORIENTATION_IN_SOFTWARE: Swapping width/height to update display in portrait mode to minimize tearing.
Relevant source display area size with overscan cropped away: 480x320.
Source GPU display is 480x320. Output SPI display is 240x320 with a drawable area of 240x320. Applying scaling factor horiz=0.50x & vert=0.50x, xOffset: 0, yOffset: 80, scaledWidth: 240, scaledHeight: 160
Creating dispmanX resource of size 240x160 (aspect ratio=1.500000).
GPU grab rectangle is offset x=0,y=0, size w=240xh=160, aspect ratio=1.500000
All initialized, now running main loop...

Here, I see the problem Output SPI display is 240x320 with a drawable area of 240x320. Display resolution is 480x320, not 240x320. I have forced 480x320 HDMI resolution in /boot/config.txt.

The display turns black, and if I move the mouse the screen sometimes flash in white.

I'm using a Raspberry Pi 3 B+ with latest Raspbian. No legacy fbcp driver is loaded and SPI is disabled in /boot/config.txt.

Maybe I'm missing something ?

Thanks!!!

Error compiling project in Raspberry Pi 3 with Alpine Linux aarch64

I've installed Alpine Linux 3.8.1 aarch64 in Raspberry PI 3. I cloned the project with git, and want to build it natively with gcc 6.4.0 so I configured with command:

cmake -DWAVESHARE35B_ILI9486=ON -DSPI_BUS_CLOCK_DIVISOR=10 -DARMV8A=ON ..

but when I do make, these errors appear:

rpi3-64:~/projects/fbcp-ili9341/build$ make
[  5%] Building CXX object CMakeFiles/fbcp-ili9341.dir/diff.cpp.o
c++: error: unrecognized argument in option '-mtls-dialect=gnu2'
c++: note: valid arguments to '-mtls-dialect=' are: desc trad
c++: error: unrecognized command line option '-marm'; did you mean '-fasm'?
c++: error: unrecognized command line option '-mhard-float'; did you mean '--warn-format'?
c++: error: unrecognized command line option '-mfloat-abi=hard'
make[2]: *** [CMakeFiles/fbcp-ili9341.dir/build.make:63: CMakeFiles/fbcp-ili9341.dir/diff.cpp.o] Error 1
make[1]: *** [CMakeFiles/Makefile2:68: CMakeFiles/fbcp-ili9341.dir/all] Error 2
make: *** [Makefile:84: all] Error 2

frame sync using HDMI signal?

Would be possible to sync the frames using the clock of the hdmi connector and feed in back to the raspberry pi? this behaviour could give a performance boost avoiding to pull the framebuffer.

ili9486L SPI screen will not initialize

Hello,

I recently bought this screen from Aliexpress: https://www.aliexpress.com/item/3-5-inch-8P-SPI-TFT-LCD-Color-Screen-Module-ILI9486-Drive-IC-320-480-RGB/32828284227.html

I wired it up to my Pi Zero W as follows (Raspberry Pi Pins, not GPIO): GND >20 VCC>17 CLK>23 MOS>21 RES>22 DC>18 BLK>12 MIS>21

I cmake-ed fbcp-ili9341 with the following options: -DPI-ZERO=ON -DWAVESHARE35B_ILI9486=ON -DUSE_DMA_TRANSFERS=OFF -DSPI_BUS_CLOCK_DIVISOR=14 -DGPIO_TFT_RESET_PIN=25 -DGPIO_TFT_DATA_CONTROL=24

Using make-j after cmake-ing it with DILI9486=ON gave me a myriad of errors so I used the waveshare display flag instead.

When running sudo ./fbcp-ili9431, it seems to go through some initialization setup, and then stops giving further info, but the entire time the Pi has been plugged in, the screen has done nothing but shown a flat white display. It does not flicker when running ./fbcp-ili9431. I have made sure that the spi dtoverlay is commented out on my config.txt, and my core_freq is 400.

Waveshare 35b 1/3 screen not displaying, rest has garbage text, rotated 90 degrees, and mirrored.

Hello again.

I just got in a Waveshare35b, did a fresh install of Raspbian Lite on my SD card, then downloaded FBCP-ili9341.

I built with these options:
cmake - DPI_ZERO=ON -DWAVESHARE35B_ILI9486=ON -DSPI_BUS_CLOCK_DIVISOR=16 -DGPIO_TFT_DATA_CONTROL=24 -DGPIO_TFT_RESET_PIN=25 -DDISPLAY_INVERT_COLORS=ON -DDISPLAY_CROPPED_INSTEAD_OF_SCALING=ON

When running the built script, I get some text, but it's mirrored, and backwards, and lots of the blank space is garbage, but once I enter some text and hit enter a bunch of times to bring it into frame, it seems to appear properly.

There appears to be no difference between cropped, not cropped, or different screen resolutions when not cropped. It still has the garbage in the blank spaces, and the rotation/mirrored. I am currently running the Pi in 640x480 so I can use the HDMI monitor as well as the SPI screen.

Here is an image before I pressed anything, and after I cleared out the screen and added some text approximately in the middle of the HDMI monitor

https://i.imgur.com/SPCOMI2.jpg
https://i.imgur.com/9ivNhzz.jpg

And a youtube video of me starting the script after power cycling the Pi and screen.
https://www.youtube.com/watch?v=NypLTy83oBM

Thanks.

White screen only with custom resolution

System: Raspberry Pi 3
Screen: 3.2 Inch 320x240 TFT (ILI9341)
Build Parameter: -DILI9341=ON -DGPIO_TFT_DATA_CONTROL=24 -DGPIO_TFT_RESET_PIN=25 -DGPIO_TFT_BACKLIGHT=18 -DSPI_BUS_CLOCK_DIVISOR=6 -DDISPLAY_ROTATE_180_DEGREES=ON -DSTATISTICS=0

If I don't use a custom resolution everything works. I can see the screen and scaling is applied, but if I set the HDMI resolution to the one of the screen it will just show a white screen. No error thrown. Is there something I could be doing wrong?

/boot/config.txt

hdmi_group=2
hdmi_mode=87
hdmi_drive=2
hdmi_cvt=320 240 60 1 0 0 0
hdmi_force_hotplug=1

console output

bcm_host_get_peripheral_address: 0x3f000000, bcm_host_get_peripheral_size: 16777216, bcm_host_get_sdram_address: 0xc0000000
BCM core speed: current: 250000000hz, max turbo: 400000000hz. SPI CDIV: 6, SPI max frequency: 66666667hz
Allocated DMA channel 7
Allocated DMA channel 1
Enabling DMA channels Tx:7 and Rx:1
DMA hardware register file is at ptr: 0x75ae6000, using DMA TX channel: 7 and DMA RX channel: 1
DMA hardware TX channel register file is at ptr: 0x75ae6700, DMA RX channel register file is at ptr: 0x75ae6100
Resetting DMA channels for use
DMA all set up
Initializing display
Resetting display at reset GPIO pin 25
Creating SPI task thread
InitSPI done
DISPLAY_FLIP_ORIENTATION_IN_SOFTWARE: Swapping width/height to update display in portrait mode to minimize tearing.
Relevant source display area size with overscan cropped away: 240x320.
Source GPU display is 240x320. Output SPI display is 240x320 with a drawable area of 240x320. Applying scaling factor horiz=1.00x & vert=1.00x, xOffset: 0, yOffset: 0,                                      scaledWidth: 240, scaledHeight: 320
Creating dispmanX resource of size 240x320 (aspect ratio=0.750000).
GPU grab rectangle is offset x=0,y=0, size w=240xh=320, aspect ratio=0.750000
All initialized, now running main loop...

Thoughts on Hyperpixel Screens?

Juj-
Was curious if you have experimented with either of the Hyperpixel displays, especially the new 4.0” version. I wonder if your driver could incorporate that display and the resolution that it puts out?

Support for Pi2

Super nice work!
I just tried your code on a Raspberry Pi 2 and it worked out of the box (Waveshare 3.5B).
However, the lowest/best CDIV value I could achieve was 12, everything lower ended in a non-usable picture ;) But with this value I already got a smooth result.
Btw for me N64 games on Retropie only work with disabled DMA, just to let you know (at least the ones I tried).

Freeplay Use Full Viewable Area

img_20180607_154335

I feel like I might not be understanding this correctly, but I'd like to use the full "viewable" area of the Freeplay Zero (302x202).

I'd also like to set the HDMI resolution to 1024x768, because it works for most HDMI TVs/Monitors. This way the HDMI output can be hot pluggable while the LCD remains fully usable.

Today we tried 1024x768 and 320x240 HDMI resolution on the Freeplay Zero. As shown in the attached photo, the LCD gets sized to (I think) 269x202 which doesn't use the full viewable 302x202.

I understand that 269/202 = 1.3 just like 1024/768 (or 320/240), but I would prefer to stretch this output to 302x202 and allow the emulator to do the scaling. That way the HDMI output and the LCD output will match and use the entire viewable area.

Can we attain this? If so, what settings should I use to set it up?

How do I remove (CPU, GPU, SPI etc)refreshing

Thanks,its very helpful for me. Im using a 2.2" ili9341 screen and got it working with a pi 3B plus. Just 1 issues i need help with. On the top part of the screen there is some stats permanently being displayed and constantly refreshing (CPU, GPU, SPI etc). How do I remove this? thank you

waveshare 1.44in lcd hat & ST7735r driver , display works but various issues

Hi, I bought one of these cheap displays ages ago to muck around with my pi zero, but they don't seem that widely supported so I am always having trouble getting it set up.

I found this driver by chance so decided to try it, because I saw it supports the ST7735r controller. This thing is actually an ST7735S, but I figured what the hell, and sure enough it worked. At first it was a bit garbled and the wrong resolution, but it was visible enough to make me keep going.

I tweaked the code to give it the correct resolution of 128x128 , and it seems to run stable enough with the spi clock divisor set at 12. It runs well enough, but the orientation is wrong (seems this can be the fault of the board layout, its mounted sideways to save space by the look of it), and also the left/right screen axis is flipped so everything reads backwards.

I managed to flip the horizontal axis. I have no idea how this is meant to be done properly, but I found a line that read 'madctl |= MADCTL_ROW_ADDRESS_ORDER_SWAP;', and commenting that out got me back to proper left and right orientation. Sorry if that seems like a kludge, but I am not really a programmer, my method is usually along the lines of 'hit it until it works', I'd appreciate some insight on how to properly do this.

I also don't know the best way to fix the rotation, it basically needs to be rotated 90 degrees, I know raspbian can do this, but I am typing this on my pi zero on a desktop monitor so I don't want to have to turn my head 90 degrees quite yet. I was also hoping there is a way to do this in the driver itself, because it would be nice to retain the ability to easily use the HDMI port, eg, to plug into a TV at someones house.

I'm really impressed by the performance, with fbtft+fbcp I only got terrible refresh rates and ended up sticking the thing in a drawer in disappointment, but with this I can play Doom with super smooth frame rates, and seemingly anti aliasing thrown in as a side effect of the screen scaling :) . It really is a nifty little gadget, a tiny joystick, 3 buttons and a screen on a board that perfectly matches the pi zero, so it's nice to finally get it working well, thanks for your hard work!

Adafruit 3.5 TFT

Hello juj,

I'm having issues with the pitft_35r_hx8357d.

I am utilizing the following cmake flags and the screen is flipped horizontally.

cmake -DSPI_BUS_CLOCK_DIVISOR=6 -DADAFRUIT_HX8357D_PITFT=ON -DDISPLAY_SWAP_BGR=ON -DSTATISTICS=0 ..

Thanks.

DMA channel conflict on Freeplay Zero?

First, fantastic work! Seeing this in action is amazing, so kudos to you!

Second, the guys over at Freeplay Tech have been helping me out, but they referred me here for more help. I'm running a Freeplay Zero, and I have been using their binaries for this driver. They have a NoDMA option that works, but the CPU usage is too extreme to get any real performance from emulators. The other option they have is fbcpZero, which is supposed to work, and the guys at Freeplay say it works, but I seem to be getting DMA channel conflicts as soon as EmulationStation loads.

Here's the output after switching to the fbcpZero driver:

bcm_host_get_peripheral_address: 0x20000000, bcm_host_get_peripheral_size: 33554432, bcm_host_get_sdram_address: 0x40000000
BCM core speed: current: 500000000hz, max turbo: 500000000hz. SPI CDIV: 6, SPI max frequency: 83333333hz
Allocated DMA channel 5
Allocated DMA channel 1
Enabling DMA channels Tx:5 and Rx:1
DMA hardware register file is at ptr: 0xb4b9d000, using DMA TX channel: 5 and DMA RX channel: 1
DMA hardware TX channel register file is at ptr: 0xb4b9d500, DMA RX channel register file is at ptr: 0xb4b9d100
DMA RX channel 1 was assigned another peripheral map 17!
DMA channel 0 has peripheral map 0 (is lite channel: 0, currently active: 0, current control block: (nil))
DMA channel 1 has peripheral map 17 (is lite channel: 0, currently active: 1, current control block: (nil))
DMA channel 2 has peripheral map 0 (is lite channel: 0, currently active: 0, current control block: (nil))
DMA channel 3 has peripheral map 5 (is lite channel: 0, currently active: 1, current control block: 0xdf554620)
DMA channel 4 has peripheral map 13 (is lite channel: 0, currently active: 0, current control block: (nil))
DMA channel 5 has peripheral map 6 (is lite channel: 0, currently active: 0, current control block: (nil))
DMA channel 6 has peripheral map 13 (is lite channel: 0, currently active: 1, current control block: (nil))
DMA channel 7 has peripheral map 0 (is lite channel: 1, currently active: 0, current control block: (nil))
DMA channel 8 has peripheral map 7 (is lite channel: 1, currently active: 0, current control block: (nil))
DMA channel 9 has peripheral map 0 (is lite channel: 1, currently active: 0, current control block: (nil))
DMA channel 10 has peripheral map 0 (is lite channel: 1, currently active: 0, current control block: (nil))
DMA channel 11 has peripheral map 0 (is lite channel: 1, currently active: 0, current control block: (nil))
DMA channel 12 has peripheral map 0 (is lite channel: 1, currently active: 0, current control block: (nil))
DMA channel 13 has peripheral map 0 (is lite channel: 1, currently active: 0, current control block: (nil))
DMA channel 14 has peripheral map 0 (is lite channel: 1, currently active: 0, current control block: (nil))
DMA RX channel was assigned another peripheral map!

After that, the display just stops updating. I've made sure that I have no overclocking set in my /boot/config.txt. My next option was to do a new build and switch the TX and RX channels, but I'm not exactly sure how to go about this on the Freeplay Zero... any advice you have would be greatly appreciated!

I am trying 128x128 SSD1351 display SPI 7 contacts

The system is:
Machine model: Raspberry Pi Zero Rev 1.3
Linux version 4.14.83+ (dom@dom-XPS-13-9370) - some Raspbian.

Display started to work in a 128x98 SSD1351 configuration. I even changed the resolution to 128x128 in ssd1351.h file. BUT it still "GPU grab rectangle is offset x=0,y=0, size w=128xh=96, aspect ratio=1.333333" So the screen shows me very distorted pictures. Where i can tune it up? I can't find.
The display itself is Ok. I tested it with Luma Python libs. They are very slow.
Thanx in advance!

P.S.
"source display area size with overscan cropped away: 640x480"
P.P.S.
cmake string is "-DGPIO_TFT_DATA_CONTROL=24 -DSPI_BUS_CLOCK_DIVISOR=18 -DSSD1351=ON -DSINGLE_CORE_BOARD=ON -DGPIO_TFT_RESET_PIN=25 -DSTATISTICS=0 -DUSE_DMA_TRANSFERS=ON .."

Run on Power Up

Is there a way to add the driver to cmdline.txt to run on power up instead of having white screen for 15 seconds?

not really an issue, more a feature request

I2S Audio Controllers over GPIO?

I'm trying to build a device that uses I2S audio, however the software side of this requires that we use a dtoverlay to accomplish the driver loadout for the DAC. Do you have any suggestions for how to get around this as whenever I try to run this on a Retropie, it loads up to the main Retropie menu, but crashes when trying to load up the emulator and the sound fires up.

Scroll down to "Add Device Tree overlay"
https://learn.adafruit.com/adafruit-i2s-stereo-decoder-uda1334a/raspberry-pi-usage

dtoverlay=hifiberry-dac
dtoverlay=i2s-mmap

Any thoughts on how we could incorporate this?

KeDei 3.5" spi driver?

Hi there, have tried multiple cmake options but no luck. To save further wasted time can anyone confirm if it is possible to get the kedei 3.5" spi screen working with fbcp-ili9341?
cheers

Setup freezes

I bought a 3.5 TFT LCD from Aliexpress (https://www.aliexpress.com/item/3-5-inch-26P-SPI-TFT-LCD-Display-Screen-with-Touch-Panel-320-480-for-RPi1/32746328272.html ),it has an ILI9486 chip and it says that the SKU is MPI3501.Before finding your driver I have tried other methods to get it working but the refresh rate was very slow so I decided on your setup.
I have been trying to get it working with differny cmake options(waveshare,ili9486,specifing the pins),but it every time the setup gets stuck here:
image.
The pinout for the display is:
interface
DC:18,Reset:22
I would be very thankul if you could help me at least with some tips.

having problems building for pi2b

adafruit 2.8" 320x240 tft
pi 2b
raspbian stretch fresh instal+updates

everything worked fine until i get hung up on the make -j line.
getting these compile errors:

pi@raspberrypi:~/fbcp-ili9341/build $ sudo make -j [ 11%] Building CXX object CMakeFiles/fbcp-ili9341.dir/ili9341.cpp.o [ 11%] Building CXX object CMakeFiles/fbcp-ili9341.dir/dma.cpp.o [ 16%] Building CXX object CMakeFiles/fbcp-ili9341.dir/display.cpp.o [ 22%] Building CXX object CMakeFiles/fbcp-ili9341.dir/diff.cpp.o [ 27%] Building CXX object CMakeFiles/fbcp-ili9341.dir/statistics.cpp.o [ 33%] Building CXX object CMakeFiles/fbcp-ili9341.dir/spi.cpp.o In file included from /home/pi/fbcp-ili9341/display.cpp:3:0: /home/pi/fbcp-ili9341/spi.h: In member function ‘uint8_t* SPITask::PayloadStart()’: /home/pi/fbcp-ili9341/spi.h:121:58: error: ‘size9BitTaskWithPadding’ was not declared in this scope inline uint8_t *PayloadStart() { return data + (size - size9BitTaskWithPadding); } ^~~~~~~~~~~~~~~~~~~~~~~ /home/pi/fbcp-ili9341/spi.h: In member function ‘uint32_t SPITask::PayloadSize() const’: /home/pi/fbcp-ili9341/spi.h:123:48: error: ‘size9BitTaskWithPadding’ was not declared in this scope inline uint32_t PayloadSize() const { return size9BitTaskWithPadding - SPI_9BIT_TASK_PADDING_BYTES; } ^~~~~~~~~~~~~~~~~~~~~~~ CMakeFiles/fbcp-ili9341.dir/build.make:86: recipe for target 'CMakeFiles/fbcp-ili9341.dir/display.cpp.o' failed make[2]: *** [CMakeFiles/fbcp-ili9341.dir/display.cpp.o] Error 1 make[2]: *** Waiting for unfinished jobs.... In file included from /home/pi/fbcp-ili9341/diff.cpp:6:0: /home/pi/fbcp-ili9341/spi.h: In member function ‘uint8_t* SPITask::PayloadStart()’: /home/pi/fbcp-ili9341/spi.h:121:58: error: ‘size9BitTaskWithPadding’ was not declared in this scope inline uint8_t *PayloadStart() { return data + (size - size9BitTaskWithPadding); } ^~~~~~~~~~~~~~~~~~~~~~~ /home/pi/fbcp-ili9341/spi.h: In member function ‘uint32_t SPITask::PayloadSize() const’: /home/pi/fbcp-ili9341/spi.h:123:48: error: ‘size9BitTaskWithPadding’ was not declared in this scope inline uint32_t PayloadSize() const { return size9BitTaskWithPadding - SPI_9BIT_TASK_PADDING_BYTES; } ^~~~~~~~~~~~~~~~~~~~~~~ In file included from /home/pi/fbcp-ili9341/ili9341.cpp:5:0: /home/pi/fbcp-ili9341/spi.h: In member function ‘uint8_t* SPITask::PayloadStart()’: /home/pi/fbcp-ili9341/spi.h:121:58: error: ‘size9BitTaskWithPadding’ was not declared in this scope inline uint8_t *PayloadStart() { return data + (size - size9BitTaskWithPadding); } ^~~~~~~~~~~~~~~~~~~~~~~ CMakeFiles/fbcp-ili9341.dir/build.make:62: recipe for target 'CMakeFiles/fbcp-ili9341.dir/diff.cpp.o' failed make[2]: *** [CMakeFiles/fbcp-ili9341.dir/diff.cpp.o] Error 1 /home/pi/fbcp-ili9341/spi.h: In member function ‘uint32_t SPITask::PayloadSize() const’: /home/pi/fbcp-ili9341/spi.h:123:48: error: ‘size9BitTaskWithPadding’ was not declared in this scope inline uint32_t PayloadSize() const { return size9BitTaskWithPadding - SPI_9BIT_TASK_PADDING_BYTES; } ^~~~~~~~~~~~~~~~~~~~~~~ In file included from /home/pi/fbcp-ili9341/statistics.cpp:15:0: /home/pi/fbcp-ili9341/spi.h: In member function ‘uint8_t* SPITask::PayloadStart()’: /home/pi/fbcp-ili9341/spi.h:121:58: error: ‘size9BitTaskWithPadding’ was not declared in this scope inline uint8_t *PayloadStart() { return data + (size - size9BitTaskWithPadding); } ^~~~~~~~~~~~~~~~~~~~~~~ /home/pi/fbcp-ili9341/spi.h: In member function ‘uint32_t SPITask::PayloadSize() const’: /home/pi/fbcp-ili9341/spi.h:123:48: error: ‘size9BitTaskWithPadding’ was not declared in this scope inline uint32_t PayloadSize() const { return size9BitTaskWithPadding - SPI_9BIT_TASK_PADDING_BYTES; } ^~~~~~~~~~~~~~~~~~~~~~~ CMakeFiles/fbcp-ili9341.dir/build.make:422: recipe for target 'CMakeFiles/fbcp-ili9341.dir/statistics.cpp.o' failed make[2]: *** [CMakeFiles/fbcp-ili9341.dir/statistics.cpp.o] Error 1 CMakeFiles/fbcp-ili9341.dir/build.make:206: recipe for target 'CMakeFiles/fbcp-ili9341.dir/ili9341.cpp.o' failed make[2]: *** [CMakeFiles/fbcp-ili9341.dir/ili9341.cpp.o] Error 1 In file included from /home/pi/fbcp-ili9341/dma.cpp:17:0: /home/pi/fbcp-ili9341/spi.h: In member function ‘uint8_t* SPITask::PayloadStart()’: /home/pi/fbcp-ili9341/spi.h:121:58: error: ‘size9BitTaskWithPadding’ was not declared in this scope inline uint8_t *PayloadStart() { return data + (size - size9BitTaskWithPadding); } ^~~~~~~~~~~~~~~~~~~~~~~ /home/pi/fbcp-ili9341/spi.h: In member function ‘uint32_t SPITask::PayloadSize() const’: /home/pi/fbcp-ili9341/spi.h:123:48: error: ‘size9BitTaskWithPadding’ was not declared in this scope inline uint32_t PayloadSize() const { return size9BitTaskWithPadding - SPI_9BIT_TASK_PADDING_BYTES; } ^~~~~~~~~~~~~~~~~~~~~~~ In file included from /home/pi/fbcp-ili9341/spi.cpp:16:0: /home/pi/fbcp-ili9341/spi.h: In member function ‘uint8_t* SPITask::PayloadStart()’: /home/pi/fbcp-ili9341/spi.h:121:58: error: ‘size9BitTaskWithPadding’ was not declared in this scope inline uint8_t *PayloadStart() { return data + (size - size9BitTaskWithPadding); } ^~~~~~~~~~~~~~~~~~~~~~~ /home/pi/fbcp-ili9341/spi.h: In member function ‘uint32_t SPITask::PayloadSize() const’: /home/pi/fbcp-ili9341/spi.h:123:48: error: ‘size9BitTaskWithPadding’ was not declared in this scope inline uint32_t PayloadSize() const { return size9BitTaskWithPadding - SPI_9BIT_TASK_PADDING_BYTES; } ^~~~~~~~~~~~~~~~~~~~~~~ CMakeFiles/fbcp-ili9341.dir/build.make:350: recipe for target 'CMakeFiles/fbcp-ili9341.dir/spi.cpp.o' failed make[2]: *** [CMakeFiles/fbcp-ili9341.dir/spi.cpp.o] Error 1 CMakeFiles/fbcp-ili9341.dir/build.make:110: recipe for target 'CMakeFiles/fbcp-ili9341.dir/dma.cpp.o' failed make[2]: *** [CMakeFiles/fbcp-ili9341.dir/dma.cpp.o] Error 1 CMakeFiles/Makefile2:67: recipe for target 'CMakeFiles/fbcp-ili9341.dir/all' failed make[1]: *** [CMakeFiles/fbcp-ili9341.dir/all] Error 2 Makefile:83: recipe for target 'all' failed make: *** [all] Error 2

Is this comatible with Driver: ILI9486 Dots: 320x480 SKU: MPI3501?

I tried with dwaverhare35b_ili9486 and div 8, and got half screen in black and the other random horizontal lines that update, with more random...

I know this driver requires 4-wire spi, sadly i don't even know the pin out of this display it came with no manual.
It is probably a 3 wire, but who knows may some one knows something about this display.

General questions and suggestions

Hi,
Love this project, really innovative way to deal with the hardware limitations. Great work.
I have some suggestions:

  • Maybe post the maximum refresh rate achieved with each display, or does it top at 120hz for all? Anyway, it's pretty cool that it achieves 120hz and deserves a line in the readme. Could be used for stereoscopic rendering perhaps. You can drive a pair of IR 3D glasses and sync it with the display. (I have some code for driving Sony protocol shutters and works great, it's not too hard).
  • Another thing in the readme that would be convenient is a paragraph about the algorithm you made to optimize transfers.
    I read through the code and don't understand it quite yet. I'd expect a frame difference (prev frame - current frame) and blob detection. The blobs would then get uploaded.
  • A suggestion I have is to allow for lossy uploading with a setting. If a value changes by the least significant bit, it might not be a big deal to skip. The setting could have multiple levels for lossy uploading. In principle it be like (prev frame - new frame) >> factor << factor, or / factor * factor .

And some questions:

  • I am considering porting this to ESP32. It has a 40mhz ISP bus. I was thinking it would be a fun and cheap wired/wireless display driver. Any thoughts on that? The Wifi speed would be a limiting factor for driving it.

Cheers!

How to use with buildroot and raspberry pi 3?

Hi, I am stuck. While I got the driver working perfectly when building inside raspbian on the rpi3, it does not work well after I built it via buildroot.
I added one library (vchostif) to make it compile (found this hint somewhere on the internet), maybe it is the problem. It is supposed to substitute the directory normally included from /opt/vc.

When I launch the executable and subsequent GUI programs, the screen flashes shortly and goes back to blank. I am shure that I configured the pins right as the same config works in raspbian.

I am addressing anybody who might have build this with buildroot before, any help is appreciated. It might be some buildroot configuration problem. The packages I installed are mainly rpi-firmware and rpi-userland.

Here are the files that I added in package/fbcp:

Added these lines in CMakeLists.txt:

target_link_libraries(fbcp-ili9341 pthread bcm_host atomic vchostif)
install(TARGETS fbcp-ili9341 RUNTIME DESTINATION bin )

Config.In:

config BR2_PACKAGE_FBCP
        bool "fbcp SPI Driver for ILI9341 LCD display"
        help
          FBCP

fbcp.mk:

FBCP_VERSION = master
FBCP_SITE = https://github.com/juj/fbcp-ili9341.git
FBCP_SITE_METHOD = git
FBCP_CONF_OPTS = -DILI9341=ON -DGPIO_TFT_BACKLIGHT=18 -DGPIO_TFT_DATA_CONTROL=24 -DGPIO_TFT_RESET_PIN=25 -DSPI_BUS_CLOCK_DIVISOR=32 -DDEFAULT_TO_ARMV8A=ON

$(eval $(cmake-package)))

And added entry in global package/Config.in file:

source "package/fbcp/Config.in"

I do get this warning since I am cross-compiling, not sure how much of a problem it is:

-- Board revision:
CMake Warning at CMakeLists.txt:40 (message):
The board revision of this hardware is not known. Please add detection to
this board in CMakeLists.txt. (proceeding to compile against a generic
multicore CPU)

Adding Touch Support

Hi Juj;

Firstly I'd like to thank you for making this driver; I can confirm that the driver works with the Elecrow 3.5" display by using the Waveshare settings (the board seems to be just a Waveshare clone). I was wondering if you were intending to add touchscreen support in the near future, or if that is something which is on the backburner. (The Elecrow utilises the XPT2046 driver.) Thanks!

[Discussion] Reduce tearing in ILI9341V by ESP32 controller

Thanks for sharing your project and the demo video in Youtube. I'm intrigued with your impressive work.

I want to reduce tearing effect in NES emulator under an odroid-go portable gadget that uses ILI9341V LCD running in ESP32 controller. Here is my proposal:
OtherCrashOverride/go-play#5

The current owner didn't have a proper double buffering implemented. So I will first bring back double buffering. Then I want to experiment interlacing and progressive update as you suggested.

Knowing the fact that SPI doesn't allow VSYNC, I want to know two things from you since you are more experienced on this topic. I swear I already RTFM on ILI9341V specs. But I can't find the command in the specs:

  1. Command to switch tearing style from diagonal tearing vs line tearing.
  2. Command to do a progressive update.

BTW, your code is well written. It is just me being lazy or dumb to find it out from your source code. Thanks!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.