I tried to get a raspberry pi zero a couple of months ago but I couldn't get one because of its demand and availability in India. But my friend Michael Kohn from Missouri sent me a pi-zero camera version. Thanks Mike :)
I have a 160 x 128 TFT (st7735r) and I thought of hooking it up with the pi-zero via SPI. I searched in internet and I found that we can insert some fbtft driver in the latest version of raspbian which can drive the LCD by creating a new frame buffer /dev/fb1.
Then I thought of making a very simple user space equivalent for the same which should directly work based on the existing frame buffer /dev/fb0. Also it should not depend on any additional kernel modules and peripheral driver dependencies except the default bcm spi driver. Also the code should be as simple as possible so that any one can read and understand it, unlike a kernel module which require a bit of kernel experience.
As a start, I wrote two source files gpio.c and spi.c based on ioctl (a device specific system call defined by the driver) by referring online (wiringPi) and BCM2835.pdf. I have already used the same tft display on stm32f4, so I ported the same code to st7735.c and using the ioctl function for spi (in spi.c) I am able to initialise the LCD and able to draw pixels on it. Luckily the ioctl for spi supports DMA transfer. This saves a lot of CPU cycle for frame buffer streaming.
Next step is set the frame buffer to 160x128 with 16-bit depth which can be done using fbset command or modifying the /boot/config.txt.
Then I opened the frame buffer "/dev/fb0" and mmapped (mmap) it to a pointer. After that I streamed the ' 160x128 - 16 bit ' frame buffer to the LCD via SPI in multiple blocks of 4096 bytes. By default the spi dma maximum payload size seems to be 4096, if I use more than that it doesn't works, I dono how to increase that size but it is okay for saving a lot of CPU cycle. To render a frame I need to repeat the transfer for around 10 times in a loop.
But I found an issue, the frame buffer in Pi is little endian and thus the 16 bit 565 colour cannot be displayed properly without swapping the bytes. I searched a lot if it is possible to configure the frame buffer to big-endian but I couldn't find any way method till now, so I manually swapped the bytes in a loop for each frame.
Yes, now the tty1 is displayed on LCD and the CPU usage is only around 3.2%, thanks for the DMA support. !!
I am able to run the full X GUI on it by typing startx. Till now everything is fine.
Then I tried to play video using mplayer but the video is not playing and it is working fine with fbtft driver. At first I couldn't find the reason for this. I thought may be I need to create a new frame buffer '/dev/fb1' for this purpose as in fbtft. But later I found that when I am playing any video, automatically the frame buffer resolution is changing to 640x480 which is totally against my logic.
Then I found an easy workaround for this, I dono if it is a good method, but it works fine for me. Before reading every frame from frame buffer I am reading the resolution as well and if the resolution is changed, accordingly I am adjusting a skipping offset for row and column so that the new frame buffer copy will be always 160x120. I made the display resolution to 160x120 instead of 128 for easily scaling it from 640x480. So now the frame buffer is byte swapped dynamically based on the instantaneous frame buffer by using the skipping offsets.
Yes, now I am able to play video of any resolution on my display using below command!sudo SDL_VIDEODRIVER=directfb SDL_FBDEV=/dev/fb0 mplayer -vo sdl -framedrop test1.m4v
I am adjusting the frame rate by adding usleep delay in the while loop for frame buffer rendering. Also we can reduce the spi clock speed but it is better to keep highest clock speed supported by LCD.
A simple application can be an IP camera viewer using rtsp protocol. For example download "RTSP server" application in android mobile and stream the camera via rtsp and use mplayer to play that live streaming on the LCD using below command:
sudo SDL_VIDEODRIVER=directfb SDL_FBDEV=/dev/fb0 mplayer -vo sdl -framedrop rtsp://192.168.1.3:5540/ch0
(need to modify the rtsp link accordingly)
Using pygame we can implement our own GUI as well.
The repository contains additional files like sample videos, shell scripts for playing videos, rtsp ip camera etc.