fbtft_device – Noralf Trønnes 2017jan08
fbtft_device is a kernel module for registering FBTFT devices.
Note: fbtft_device is not available starting from Linux 5.4
To understand the need for this module we need to know a little bit about the Linux kernel.
For the kernel to operate some device like a keyboard or a screen, it needs to know how to do it. This is what a device driver provides, it’s a piece of code.
But there is one piece missing, and that is something informing the kernel about the presence of the keyboard or screen. This is what the device provides. A device is a data structure that contains information about the device, like which bus it is connected to (SPI, PCI, USB), IO addresses and other device specific information.
When the kernel has a driver that supports a device, it hands control of the device to the driver
Some ways a Linux device can be created:
- In the platform or board file
When the information changes, the kernel has to be rebuilt.
- A bus driver detects a new hardware device on the bus, and creates a matching Linux device.
- A bus like SPI, doesn’t have enumeration capabilities. The same goes for GPIOs.
- A kernel module
The displays that FBTFT supports uses SPI and/or GPIO. These busses can’t find out what is connected to them, so we must tell the kernel about them. To be able to provide a prebuilt kernel for all displays, we need a kernel module that can provide that information.
fbtft_device does this. It has device information for all the displays it supports, with default values. These values can be changed with module parameters.
There is one required module parameter, and that is name. It specifies which display (device) to register.
sudo modprobe fbtft_device name=adafruit22
fbtft_device prints information to the kernel log
$ dmesg fbtft_device: SPI devices registered: fbtft_device: spidev spi0.0 500kHz 8 bits mode=0x00 fbtft_device: spidev spi0.1 500kHz 8 bits mode=0x00 fbtft_device: 'fb' Platform devices registered: fbtft_device: bcm2708_fb id=-1 pdata? no fbtft_device: Deleting spi0.0 fbtft_device: GPIOS used by 'adafruit22': fbtft_device: 'reset' = GPIO25 fbtft_device: 'led' = GPIO23 fbtft_device: SPI devices registered: fbtft_device: spidev spi0.1 500kHz 8 bits mode=0x00 fbtft_device: fb_hx8340bn spi0.0 32000kHz 8 bits mode=0x00 graphics fb1: fb_hx8340bn frame buffer, 176x220, 75 KiB video memory, 16 KiB buffer memory, fps=20, spi0.0 at 32 MHz
First it lists all SPI devices and platform devices with a name containing ‘fb’ (framebuffer) that was registered before the module was loaded.
Then it deletes the device connected to spi0.0 (spidev) so we can register a new one.
Then it tells which GPIOs that is associated with this display.
Then it lists which SPI devices that are currently registered (spi0.0 means SPI busnum.chipselect).
And lastly the driver is loaded.
The special name list will write the supported devices to the kernel log.
sudo modprobe fbtft_device name=list; dmesg | tail -30 ERROR: could not insert 'fbtft_device': Operation canceled fbtft_device: SPI devices registered: fbtft_device: spidev spi0.1 500kHz 8 bits mode=0x00 fbtft_device: 'fb' Platform devices registered: fbtft_device: bcm2708_fb id=-1 pdata? no fbtft_device: Supported displays: fbtft_device: adafruit18 fbtft_device: adafruit18_green fbtft_device: adafruit22 fbtft_device: flexfb fbtft_device: flexpfb fbtft_device: hy28a fbtft_device: itdb28 fbtft_device: itdb28_spi fbtft_device: mi0283qt-2 fbtft_device: mi0283qt-9a fbtft_device: nokia3310 fbtft_device: pioled fbtft_device: sainsmart18 fbtft_device: sainsmart32 fbtft_device: sainsmart32_fast fbtft_device: sainsmart32_latched fbtft_device: sainsmart32_spi fbtft_device: spidev fbtft_device:
SPI bus number (default=0)
SPI chip select (default=0)
SPI speed in Hz (default varies among displays)
SPI mode (default SPI_MODE_0)
Angle to rotate display counter clockwise: 0, 90, 180, 270
Set BGR bit (supported by some drivers). Use if Red and Blue is swapped. Default is don’t touch.
Most displays need GPIOs for signaling. To simplify configuration, pins with the same functionality has been given names:
- reset – Hardware reset
- dc – Data/Command (sometimes called RS)
- led – Backlight
GPIO only displays
- db00-15 – Databus
- cs – Chip Select
- wr – Write strobe
fbtft_device have default values for these pin names (a few don’t). The values can be changed with the gpios parameter. This is a comma separated array of pin/signal names and GPIO numbers. gpios=pin_name:gpio_number[,pin_name:gpio_number]
When overriding the defaults using gpios, all gpios must be specified.
Example showing the default gpio values of itdb28fb
modprobe fbtft_device name=itdb28 gpios=reset:17,dc:1,wr:0,cs:21,db00:9,db01:11,db02:18,db03:23,db04:24,db05:25,db06:8,db07:7,led:4
Frames per second (default 20)
In effect this states how long the driver will wait after video memory has been changed until display update transfer is started.
See Debug for a way to show how long the actual transfer takes.
String representation of Gamma Curve(s). Driver specific. Not supported by all drivers.
Length of the FBTFT transmit buffer.
This buffer is used by default on Little Endian architectures like on the Raspberry Pi. The 2 bytes in the 16-bit pixel value has to be swapped before transfer.
It is also used when other transformation has to be done.
When FBTFT is compiled on Little Endian, it uses a default buffer of 4096 bytes. txbuflen can be used to change this.
txbuflen has some special values:
- -1 makes the buffer the same size as video memory.
- -2 forces no buffering
Sets the Start byte used by some SPI displays. Usually 0x70 (01110000) or 0x74 (01110100).
Format: 5 bit magic + 1 bit id + 1 bit RS + 1 bit RW. RS and RW is set by FBTFT.
Overrides the default init sequence.
Init sequence Markers: -1: command begin, -2: millisecond delay, -3: end of init sequence
No spaces allowed.
This parameter controls how much information fbtft_device writes to the kernel log
- 0 – silent
- 1 – show gpios used
- 2 – and show devices after registration
- 3 – and show devices before registration (default)
If your display module is not supported by fbtft_device, you can setup your own.
The custom argument is used for this, and the name= argument is passed on as the driver to use.
sudo modprobe fbtft_device custom name=fb_ili9341 buswidth=8 gpios=reset:25,dc:24
Add a custom display device. Use the speed= argument to make it a SPI device, or else it becomes a platform_device
Display width, used with the custom argument
Display height, used with the custom argument
Display bus width, used with the custom argument
Register Sainsmart 1.8 with changes
- SPI: spi0.1 at 16MHz
- GPIOs: reset=18 (when overriding, all must be mentioned)
$ sudo modprobe fbtft_device name=sainsmart18 cs=1 speed=16000000 gpios=reset:18,dc:24 kernel: fbtft_device: Deleting spi0.1 $ dmesg fbtft_device: SPI devices registered: fbtft_device: spidev spi0.0 500kHz 8 bits mode=0x00 fbtft_device: spidev spi0.1 500kHz 8 bits mode=0x00 fbtft_device: 'fb' Platform devices registered: fbtft_device: bcm2708_fb id=-1 pdata? no fbtft_device: Deleting spi0.1 fbtft_device: GPIOS used by 'sainsmart18': fbtft_device: 'reset' = GPIO18 fbtft_device: 'dc' = GPIO24 fbtft_device: SPI devices registered: fbtft_device: spidev spi0.0 500kHz 8 bits mode=0x00 fbtft_device: fb_st7735r spi0.1 16000kHz 8 bits mode=0x00 graphics fb1: fb_st7735r frame buffer, 128x160, 40 KiB video memory, 4 KiB buffer memory, fps=20, spi0.1 at 16 MHz
A note on probe()
When loading a driver, it’s init() function is called and the device(s) it supports is made known to the kernel.
If the device it supports is registered in the kernel, the drivers probe() function is called with the device as an argument.
So, loading a driver when the device is not present, will just sit there. It is loaded, but it won’t do anything before the supported device is present.
A driver can support more than one device.
The fbtft_device module can be built as a loadable kernel module, and built into the kernel proper (kernel.img on the RasPi).
When builtin, the parameters to fbtft_device is provided on the kernel command line (/boot/cmdline.txt on the RasPi).
There is one limitation however: the linux kernel command line is limited to 1024 characters, and remember that the bootloader also adds to the commandline. Use
cat /proc/cmdline | wc --chars to show the length.