Compare commits

..

21 Commits

Author SHA1 Message Date
goodtft
d420696013
Update config-nomal.txt 2019-07-05 17:46:26 +08:00
lcdwiki
57f087731c modify PI4 bug 2019-07-04 14:25:04 +01:00
lcdwiki
9d41f30559 delete some config file 2019-07-04 03:33:08 +01:00
lcdwiki
f3898b3c76 delete Raspbian judgement 2019-07-03 10:44:48 +01:00
lcdwiki
eccd8281dc add noobs driver 2019-07-03 09:43:26 +01:00
lcdwiki
8c82009e3c modify LCD-hdmi 2019-07-02 11:43:42 +01:00
lcdwiki
fd7fb6a1fa update to the latest system config 2019-07-02 09:59:17 +01:00
lcdwiki
7bc06046b1 update raspbain resistance touch bug 2019-06-25 07:57:02 +01:00
lcdwiki
d06266304d update system restore bug 2019-06-15 06:38:23 +00:00
lcdwiki
5117271023 update MHS32,35,40 2019-06-10 10:20:03 +00:00
lcdwiki
ffe910b4d5 update LCD7B,LCD7C,MPI5001 2019-06-06 08:01:38 +01:00
lcdwiki
fcfa9d45bd modify system backup 2019-06-05 12:19:52 +01:00
lcdwiki
bae0a0da81 add LCD24-3A+,LCD24,LCD28,LCD32,LCD35 2019-06-05 10:40:29 +01:00
lcdwiki
1dd11e6259 add LCD5 2019-06-05 03:48:26 +01:00
lcdwiki
16e6e618be update MPI3508 2019-06-05 02:51:13 +01:00
lcdwiki
cb4f8803dc add MPI3508 2019-06-04 12:02:16 +01:00
lcdwiki
9d5f990fb0 update LCD7B,LCD7C 2019-06-04 11:22:25 +01:00
lcdwiki
9b7e782f82 add LCD7B,LCD7C 2019-06-04 11:04:00 +01:00
lcdwiki
7029fa6ac3 update mhs 2019-06-04 08:12:41 +01:00
lcdwiki
49431c5b4d delete rpi-fbcp 2019-05-30 07:30:18 +01:00
lcdwiki
62be42eb69 update LCD show 2019-05-30 07:15:10 +01:00
170 changed files with 377 additions and 12203 deletions

View File

@ -1,38 +0,0 @@
#!/bin/bash
sudo ./system_backup.sh
#sudo cp -rf ./boot/config-nomal.txt ./boot/config.txt.bak
source ./system_config.sh
sudo echo "dtoverlay=qddpi18" >> ./boot/config.txt.bak
sudo echo "enable_dpi_lcd=1" >> ./boot/config.txt.bak
sudo echo "display_default_lcd=1" >> ./boot/config.txt.bak
sudo echo "dpi_group=2" >> ./boot/config.txt.bak
sudo echo "dpi_mode=87" >> ./boot/config.txt.bak
sudo echo "dpi_output_format=0x6f016" >> ./boot/config.txt.bak
sudo echo "dpi_timings=800 0 210 1 46 480 0 22 1 23 0 0 0 60 0 33000000 6" >> ./boot/config.txt.bak
sudo echo "disable_overscan=1" >> ./boot/config.txt.bak
sudo echo "dtoverlay=i2c5,pins_10_11" >> ./boot/config.txt.bak
sudo echo "dtoverlay=goodix_dpi,interrupt=26,reset=18" >> ./boot/config.txt.bak
#sudo echo "gpio=19=op,dh" >> ./boot/config.txt.bak
sudo cp -rf ./boot/config.txt.bak /boot/config.txt
sudo cp ./usr/qddpi18.dtb /boot/overlays/qddpi18.dtbo
sudo cp ./usr/goodix_dpi.dtb /boot/overlays/goodix_dpi.dtbo
sudo touch ./.have_installed
#echo "hdmi:capacity:7C-1024x600:0:1024:600" > ./.have_installed
sudo sync
sudo sync
sleep 1
if [ $# -eq 1 ]; then
sudo ./rotate.sh $1
elif [ $# -gt 1 ]; then
echo "Too many parameters"
fi
echo "reboot now"
sudo reboot

View File

@ -1,35 +0,0 @@
#!/bin/bash
sudo ./system_backup.sh
#sudo cp -rf ./boot/config-nomal.txt ./boot/config.txt.bak
source ./system_config.sh
sudo echo "dtoverlay=qddpi18" >> ./boot/config.txt.bak
sudo echo "enable_dpi_lcd=1" >> ./boot/config.txt.bak
sudo echo "display_default_lcd=1" >> ./boot/config.txt.bak
sudo echo "dpi_group=2" >> ./boot/config.txt.bak
sudo echo "dpi_mode=87" >> ./boot/config.txt.bak
sudo echo "dpi_output_format=0x6f016" >> ./boot/config.txt.bak
sudo echo "dpi_timings=1024 0 160 20 140 600 0 12 3 20 0 0 0 60 0 45000000 3" >> ./boot/config.txt.bak
sudo echo "disable_overscan=1" >> ./boot/config.txt.bak
sudo echo "dtoverlay=i2c5,pins_10_11" >> ./boot/config.txt.bak
sudo echo "dtoverlay=goodix_dpi,interrupt=26,reset=18" >> ./boot/config.txt.bak
#sudo echo "gpio=19=op,dh" >> ./boot/config.txt.bak
sudo cp -rf ./boot/config.txt.bak /boot/config.txt
sudo cp ./usr/qddpi18.dtb /boot/overlays/qddpi18.dtbo
sudo cp ./usr/goodix_dpi.dtb /boot/overlays/goodix_dpi.dtbo
sudo touch ./.have_installed
#echo "hdmi:capacity:7C-1024x600:0:1024:600" > ./.have_installed
sudo sync
sudo sync
sleep 1
if [ $# -eq 1 ]; then
sudo ./rotate.sh $1
elif [ $# -gt 1 ]; then
echo "Too many parameters"
fi
echo "reboot now"
sudo reboot

View File

@ -1,18 +1,12 @@
#!/bin/bash #!/bin/bash
#dev=`grep -rn "Option" /usr/share/X11/xorg.conf.d/99-fbturbo.conf | grep "fbdev" |awk -F\" '{printf $4}'` dev=`grep -rn "Option" /usr/share/X11/xorg.conf.d/99-fbturbo.conf | grep "fbdev" |awk -F\" '{printf $4}'`
#if test "$dev" = "/dev/fb0";then if test "$dev" = "/dev/fb0";then
#echo "The system is already output for HDMI and does not need to be set up any more" echo "The system is already output for HDMI and does not need to be set up any more"
#exit exit
#fi fi
sudo ./system_backup.sh sudo ./system_backup.sh
source ./system_config.sh
#sudo cp -rf ./boot/config-nomal.txt ./boot/config.txt.bak
sudo echo "hdmi_force_hotplug=1" >> ./boot/config.txt.bak
sudo cp -rf ./boot/config.txt.bak /boot/config.txt
sudo sync
sudo sync
#sudo cp -rf ./usr/modules-HDMI /etc/modules #sudo cp -rf ./usr/modules-HDMI /etc/modules
#sudo cp -rf ./usr/99-fbturbo.conf-HDMI /usr/share/X11/xorg.conf.d/99-fbturbo.conf #sudo cp -rf ./usr/99-fbturbo.conf-HDMI /usr/share/X11/xorg.conf.d/99-fbturbo.conf
#sudo cp ./boot/config-nomal.txt /boot/config.txt #sudo cp ./boot/config-nomal.txt /boot/config.txt

View File

@ -1,52 +0,0 @@
#!/bin/bash
sudo ./system_backup.sh
#root_dev=`grep -oPr "root=[^\s]*" /boot/cmdline.txt | awk -F= '{printf $NF}'`
#if test "$root_dev" = "/dev/mmcblk0p7";then
#sudo cp -rf ./boot/config-noobs-nomal.txt ./boot/config.txt.bak
#else
#sudo cp -rf ./boot/config-nomal.txt ./boot/config.txt.bak
#sudo echo "hdmi_force_hotplug=1" >> ./boot/config.txt.bak
#fi
source ./system_config.sh
sudo echo "hdmi_force_hotplug=1" >> ./boot/config.txt.bak
sudo echo "hdmi_force_edid_audio=1" >> ./boot/config.txt.bak
sudo echo "dtparam=i2c_arm=on" >> ./boot/config.txt.bak
sudo echo "dtparam=spi=on" >> ./boot/config.txt.bak
sudo echo "enable_uart=1" >> ./boot/config.txt.bak
sudo echo "display_rotate=0" >> ./boot/config.txt.bak
sudo echo "max_usb_current=1" >> ./boot/config.txt.bak
sudo echo "config_hdmi_boost=7" >> ./boot/config.txt.bak
sudo echo "hdmi_group=2" >> ./boot/config.txt.bak
sudo echo "hdmi_mode=87" >> ./boot/config.txt.bak
sudo echo "hdmi_drive=2" >> ./boot/config.txt.bak
sudo echo "hdmi_timings=1024 1 200 18 200 600 1 50 3 50 0 0 0 60 0 51200000 3" >> ./boot/config.txt.bak
sudo cp -rf ./boot/config.txt.bak /boot/config.txt
#sudo cp -rf ./boot/config-7C-1024x600.txt /boot/config.txt
#if test "$root_dev" = "/dev/mmcblk0p7";then
#sudo cp ./usr/cmdline.txt-noobs /boot/cmdline.txt
#else
#sudo cp ./usr/cmdline.txt /boot/
#fi
sudo cp ./usr/inittab /etc/
sudo cp -rf ./usr/99-fbturbo.conf-HDMI /usr/share/X11/xorg.conf.d/99-fbturbo.conf
if [ ! -d /etc/X11/xorg.conf.d ]; then
sudo mkdir /etc/X11/xorg.conf.d
fi
sudo cp ./usr/40-libinput.conf-0 /etc/X11/xorg.conf.d/40-libinput.conf
sudo touch ./.have_installed
echo "hdmi:capacity:101H-1024x600:0:1024:600" > ./.have_installed
sudo sync
sudo sync
sleep 1
if [ $# -eq 1 ]; then
sudo ./rotate.sh $1
elif [ $# -gt 1 ]; then
echo "Too many parameters"
fi
echo "reboot now"
sudo reboot

View File

@ -1,50 +0,0 @@
#!/bin/bash
sudo ./system_backup.sh
#root_dev=`grep -oPr "root=[^\s]*" /boot/cmdline.txt | awk -F= '{printf $NF}'`
#if test "$root_dev" = "/dev/mmcblk0p7";then
#sudo cp -rf ./boot/config-noobs-nomal.txt ./boot/config.txt.bak
#else
#sudo cp -rf ./boot/config-nomal.txt ./boot/config.txt.bak
#sudo echo "hdmi_force_hotplug=1" >> ./boot/config.txt.bak
#fi
source ./system_config.sh
sudo sed -i -e 's/#dtoverlay=vc4-fkms-v3d/dtoverlay=vc4-fkms-v3d/' ./boot/config.txt.bak
sudo sed -i -e 's/#dtoverlay=vc4-kms-v3d/dtoverlay=vc4-fkms-v3d/' ./boot/config.txt.bak
sudo echo "max_usb_current=1" >> ./boot/config.txt.bak
sudo echo "hdmi_force_hotplug=1" >> ./boot/config.txt.bak
sudo echo "config_hdmi_boost=7" >> ./boot/config.txt.bak
sudo echo "hdmi_group=2" >> ./boot/config.txt.bak
sudo echo "hdmi_mode=1" >> ./boot/config.txt.bak
sudo echo "hdmi_mode=87" >> ./boot/config.txt.bak
sudo echo "hdmi_drive=2" >> ./boot/config.txt.bak
sudo echo "hdmi_cvt 1280 800 60 6 0 0 0" >> ./boot/config.txt.bak
sudo cp -rf ./boot/config.txt.bak /boot/config.txt
#sudo cp -rf ./boot/config-7C-1024x600.txt /boot/config.txt
#if test "$root_dev" = "/dev/mmcblk0p7";then
#sudo cp ./usr/cmdline.txt-noobs /boot/cmdline.txt
#else
#sudo cp ./usr/cmdline.txt /boot/
#fi
sudo cp ./usr/inittab /etc/
sudo cp -rf ./usr/99-fbturbo.conf-HDMI /usr/share/X11/xorg.conf.d/99-fbturbo.conf
if [ ! -d /etc/X11/xorg.conf.d ]; then
sudo mkdir /etc/X11/xorg.conf.d
fi
sudo cp ./usr/40-libinput.conf-0 /etc/X11/xorg.conf.d/40-libinput.conf
sudo touch ./.have_installed
echo "hdmi:capacity:101H-1280x800:0:1280:800" > ./.have_installed
sudo sync
sudo sync
sleep 1
if [ $# -eq 1 ]; then
sudo ./rotate.sh $1
elif [ $# -gt 1 ]; then
echo "Too many parameters"
fi
echo "reboot now"
sudo reboot

View File

@ -1,52 +0,0 @@
#!/bin/bash
sudo ./system_backup.sh
#root_dev=`grep -oPr "root=[^\s]*" /boot/cmdline.txt | awk -F= '{printf $NF}'`
#if test "$root_dev" = "/dev/mmcblk0p7";then
#sudo cp -rf ./boot/config-noobs-nomal.txt ./boot/config.txt.bak
#else
#sudo cp -rf ./boot/config-nomal.txt ./boot/config.txt.bak
#sudo echo "hdmi_force_hotplug=1" >> ./boot/config.txt.bak
#fi
source ./system_config.sh
sudo echo "hdmi_force_hotplug=1" >> ./boot/config.txt.bak
sudo echo "hdmi_force_edid_audio=1" >> ./boot/config.txt.bak
#sudo echo "dtparam=i2c_arm=on" >> ./boot/config.txt.bak
#sudo echo "dtparam=spi=on" >> ./boot/config.txt.bak
#sudo echo "enable_uart=1" >> ./boot/config.txt.bak
sudo echo "display_rotate=3" >> ./boot/config.txt.bak
sudo echo "max_usb_current=1" >> ./boot/config.txt.bak
sudo echo "config_hdmi_boost=7" >> ./boot/config.txt.bak
sudo echo "hdmi_group=2" >> ./boot/config.txt.bak
sudo echo "hdmi_mode=87" >> ./boot/config.txt.bak
sudo echo "hdmi_drive=2" >> ./boot/config.txt.bak
sudo echo "hdmi_timings=800 1 50 10 50 1280 1 10 3 9 0 0 0 60 0 70000000 3" >> ./boot/config.txt.bak
sudo cp -rf ./boot/config.txt.bak /boot/config.txt
#sudo cp -rf ./boot/config-7C-1024x600.txt /boot/config.txt
#if test "$root_dev" = "/dev/mmcblk0p7";then
#sudo cp ./usr/cmdline.txt-noobs /boot/cmdline.txt
#else
#sudo cp ./usr/cmdline.txt /boot/
#fi
sudo cp ./usr/inittab /etc/
sudo cp -rf ./usr/99-fbturbo.conf-HDMI /usr/share/X11/xorg.conf.d/99-fbturbo.conf
if [ ! -d /etc/X11/xorg.conf.d ]; then
sudo mkdir /etc/X11/xorg.conf.d
fi
sudo cp ./usr/40-libinput.conf-270 /etc/X11/xorg.conf.d/40-libinput.conf
sudo touch ./.have_installed
echo "hdmi:capacity:101TMP-1280x800:270:1280:800" > ./.have_installed
sudo sync
sudo sync
sleep 1
if [ $# -eq 1 ]; then
sudo ./rotate.sh $1
elif [ $# -gt 1 ]; then
echo "Too many parameters"
fi
echo "reboot now"
sudo reboot

View File

@ -1,51 +0,0 @@
#!/bin/bash
sudo ./system_backup.sh
#root_dev=`grep -oPr "root=[^\s]*" /boot/cmdline.txt | awk -F= '{printf $NF}'`
#if test "$root_dev" = "/dev/mmcblk0p7";then
#sudo cp -rf ./boot/config-noobs-nomal.txt ./boot/config.txt.bak
#else
#sudo cp -rf ./boot/config-nomal.txt ./boot/config.txt.bak
#sudo echo "hdmi_force_hotplug=1" >> ./boot/config.txt.bak
#fi
source ./system_config.sh
sudo echo "hdmi_force_hotplug=1" >> ./boot/config.txt.bak
sudo echo "dtparam=i2c_arm=on" >> ./boot/config.txt.bak
sudo echo "dtparam=spi=on" >> ./boot/config.txt.bak
sudo echo "enable_uart=1" >> ./boot/config.txt.bak
sudo echo "display_rotate=0" >> ./boot/config.txt.bak
sudo echo "max_usb_current=1" >> ./boot/config.txt.bak
sudo echo "config_hdmi_boost=7" >> ./boot/config.txt.bak
sudo echo "hdmi_group=2" >> ./boot/config.txt.bak
sudo echo "hdmi_mode=87" >> ./boot/config.txt.bak
sudo echo "hdmi_drive=1" >> ./boot/config.txt.bak
sudo echo "hdmi_cvt 1280 800 60 6 0 0 0" >> ./boot/config.txt.bak
sudo cp -rf ./boot/config.txt.bak /boot/config.txt
#sudo cp -rf ./boot/config-7C-1024x600.txt /boot/config.txt
#if test "$root_dev" = "/dev/mmcblk0p7";then
#sudo cp ./usr/cmdline.txt-noobs /boot/cmdline.txt
#else
#sudo cp ./usr/cmdline.txt /boot/
#fi
sudo cp ./usr/inittab /etc/
sudo cp -rf ./usr/99-fbturbo.conf-HDMI /usr/share/X11/xorg.conf.d/99-fbturbo.conf
if [ ! -d /etc/X11/xorg.conf.d ]; then
sudo mkdir /etc/X11/xorg.conf.d
fi
sudo cp ./usr/40-libinput.conf-0 /etc/X11/xorg.conf.d/40-libinput.conf
sudo touch ./.have_installed
echo "hdmi:capacity:101Y-1280x800:0:1280:800" > ./.have_installed
sudo sync
sudo sync
sleep 1
if [ $# -eq 1 ]; then
sudo ./rotate.sh $1
elif [ $# -gt 1 ]; then
echo "Too many parameters"
fi
echo "reboot now"
sudo reboot

View File

@ -1,150 +0,0 @@
#!/bin/bash
sudo ./system_backup.sh
if [ -f /etc/X11/xorg.conf.d/40-libinput.conf ]; then
sudo rm -rf /etc/X11/xorg.conf.d/40-libinput.conf
fi
#if [ ! -d /etc/X11/xorg.conf.d ]; then
#sudo mkdir -p /etc/X11/xorg.conf.d
#fi
#sudo cp ./usr/mhs35-overlay.dtb /boot/overlays/
#sudo cp ./usr/mhs35-overlay.dtb /boot/overlays/mhs35.dtbo
#root_dev=`grep -oPr "root=[^\s]*" /boot/cmdline.txt | awk -F= '{printf $NF}'`
#if test "$root_dev" = "/dev/mmcblk0p7";then
#sudo cp -rf ./boot/config-noobs-nomal.txt ./boot/config.txt.bak
#else
#sudo cp -rf ./boot/config-nomal.txt ./boot/config.txt.bak
#sudo echo "hdmi_force_hotplug=1" >> ./boot/config.txt.bak
#fi
source ./system_config.sh
sudo echo "hdmi_force_hotplug=1" >> ./boot/config.txt.bak
sudo echo "hdmi_cvt 300 300 60 1 0 0 0" >> ./boot/config.txt.bak
sudo echo "hdmi_group=2" >> ./boot/config.txt.bak
sudo echo "hdmi_mode=1" >> ./boot/config.txt.bak
sudo echo "hdmi_mode=87" >> ./boot/config.txt.bak
sudo echo "display_rotate=0" >> ./boot/config.txt.bak
sudo echo "gpio=6,19,5,26,13,21,20,16=pu" >> ./boot/config.txt.bak
sudo cp -rf ./boot/config.txt.bak /boot/config.txt
#sudo cp -rf ./usr/99-calibration.conf-mhs35-90 /etc/X11/xorg.conf.d/99-calibration.conf
#sudo cp -rf ./usr/99-fbturbo.conf /usr/share/X11/xorg.conf.d/99-fbturbo.conf
#if test "$root_dev" = "/dev/mmcblk0p7";then
#sudo cp ./usr/cmdline.txt-noobs /boot/cmdline.txt
#else
#sudo cp ./usr/cmdline.txt /boot/
#fi
#sudo cp ./usr/inittab /etc/
#sudo cp ./boot/config-mhs35.txt /boot/config.txt
sudo touch ./.have_installed
echo "gpio:resistance:LCD154:90:300:300" > ./.have_installed
#FBCP install
if [ -d ./fbcp-ili9341 ]; then
sudo rm -rf ./fbcp-ili9341
fi
wget --spider -q -o /dev/null --tries=1 -T 10 https://github.com
if [ $? -eq 0 ]; then
#sudo cp -rf ./usr/99-fbturbo-fbcp.conf /usr/share/X11/xorg.conf.d/99-fbturbo.conf
sudo apt-get install cmake 2> error_output.txt
result=`cat ./error_output.txt`
echo -e "\033[31m$result\033[0m"
grep -q "^E:" ./error_output.txt && exit
#sudo rm -rf rpi-fbcp
sudo git clone https://github.com/juj/fbcp-ili9341.git
sudo mkdir ./fbcp-ili9341/build
cd ./fbcp-ili9341/build/
sudo cmake -DSPI_BUS_CLOCK_DIVISOR=10 -DWAVESHARE_ST7789VW_HAT=ON -DBACKLIGHT_CONTROL=OFF -DSTATISTICS=0 -DUSE_DMA_TRANSFERS=OFF ..
sudo make -j
sudo install fbcp-ili9341 /usr/local/bin/fbcp
cd - > /dev/null
sudo cp -rf ./etc/rc.local /etc/rc.local
else
type fbcp > /dev/null 2>&1
if [ $? -eq 1 ]; then
sudo cp -rf ./usr/fbcp-ili9341 ./
sudo mkdir ./fbcp-ili9341/build
cd ./fbcp-ili9341/build/
sudo cmake -DSPI_BUS_CLOCK_DIVISOR=10 -DWAVESHARE_ST7789VW_HAT=ON -DBACKLIGHT_CONTROL=OFF -DSTATISTICS=0 -DUSE_DMA_TRANSFERS=OFF ..
sudo make -j
sudo install fbcp-ili9341 /usr/local/bin/fbcp
cd - > /dev/null
sudo cp -rf ./etc/rc.local /etc/rc.local
fi
fi
#KEY install
wget --spider -q -o /dev/null --tries=1 -T 10 http://mirrors.zju.edu.cn
if [ $? -eq 0 ]; then
sudo apt-get install python-xlib 2> error_output.txt
else
dpkg -l | grep python-xlib
if [ $? -eq 1 ]; then
sudo dpkg -i -B ./python-xlib_0.23-2_all.deb 2> error_output.txt
fi
fi
result=`cat ./error_output.txt`
echo -e "\033[31m$result\033[0m"
grep -q "^E:" ./error_output.txt && exit
grep -q "error:" ./error_output.txt && exit
wget --spider -q -o /dev/null --tries=1 -T 10 https://pypi.org
if [ $? -eq 0 ]; then
sudo pip install PyMouse 2> error_output.txt
result=`cat ./error_output.txt`
echo -e "\033[31m$result\033[0m"
grep -q "^E:" ./error_output.txt && exit
grep -q "error:" ./error_output.txt && exit
else
pip list | grep PyMouse
if [ $? -eq 1 ]; then
sudo tar xvzf ./PyMouse-1.0.tar.gz
sudo python PyMouse-1.0/setup.py install
fi
fi
if [ ! -d ~/.config/autostart ]; then
sudo mkdir -p ~/.config/autostart
fi
if [ ! -f ~/.config/autostart/local.desktop ]; then
sudo cp -rf ./usr/local.desktop ~/.config/autostart
fi
#evdev install
#nodeplatform=`uname -n`
#kernel=`uname -r`
#version=`uname -v`
#if test "$nodeplatform" = "raspberrypi";then
#echo "this is raspberrypi kernel"
#version=${version##* }
#version=${version#*#}
#echo $version
#if test $version -lt 2017;then
#echo "reboot"
#else
#echo "need to update touch configuration"
#sudo dpkg -i -B ./xserver-xorg-input-evdev_1%3a2.10.6-1+b1_armhf.deb 2> error_output.txt
#sudo apt-get install xserver-xorg-input-evdev 2> error_output.txt
#result=`cat ./error_output.txt`
#echo -e "\033[31m$result\033[0m"
#grep -q "error:" ./error_output.txt && exit
#sudo cp -rf /usr/share/X11/xorg.conf.d/10-evdev.conf /usr/share/X11/xorg.conf.d/45-evdev.conf
#echo "reboot"
#fi
#else
#echo "this is not raspberrypi kernel, no need to update touch configure, reboot"
#fi
sudo sync
sudo sync
sleep 1
if [ $# -eq 1 ]; then
sudo ./rotate.sh $1
elif [ $# -gt 1 ]; then
echo "Too many parameters"
fi
echo "reboot now"
sudo reboot

View File

@ -10,86 +10,35 @@ sudo mkdir -p /etc/X11/xorg.conf.d
fi fi
sudo cp ./usr/tft9341-overlay.dtb /boot/overlays/ sudo cp ./usr/tft9341-overlay.dtb /boot/overlays/
sudo cp ./usr/tft9341-overlay.dtb /boot/overlays/tft9341.dtbo sudo cp ./usr/tft9341-overlay.dtb /boot/overlays/tft9341.dtbo
#root_dev=`grep -oPr "root=[^\s]*" /boot/cmdline.txt | awk -F= '{printf $NF}'` root_dev=`grep -oPr "root=[^\s]*" /boot/cmdline.txt | awk -F= '{printf $NF}'`
#if test "$root_dev" = "/dev/mmcblk0p7";then if test "$root_dev" = "/dev/mmcblk0p7";then
#sudo cp -rf ./boot/config-noobs-nomal.txt ./boot/config.txt.bak sudo cp -rf ./boot/config-noobs-nomal.txt ./boot/config.txt.bak
#else else
#sudo cp -rf ./boot/config-nomal.txt ./boot/config.txt.bak sudo cp -rf ./boot/config-nomal.txt ./boot/config.txt.bak
#sudo echo "hdmi_force_hotplug=1" >> ./boot/config.txt.bak
#fi
source ./system_config.sh
sudo echo "hdmi_force_hotplug=1" >> ./boot/config.txt.bak sudo echo "hdmi_force_hotplug=1" >> ./boot/config.txt.bak
fi
sudo echo "dtparam=i2c_arm=on" >> ./boot/config.txt.bak sudo echo "dtparam=i2c_arm=on" >> ./boot/config.txt.bak
sudo echo "dtparam=spi=on" >> ./boot/config.txt.bak sudo echo "dtparam=spi=on" >> ./boot/config.txt.bak
sudo echo "enable_uart=1" >> ./boot/config.txt.bak sudo echo "enable_uart=1" >> ./boot/config.txt.bak
sudo echo "dtoverlay=tft9341:rotate=90" >> ./boot/config.txt.bak sudo echo "dtoverlay=tft9341:rotate=90" >> ./boot/config.txt.bak
sudo echo "hdmi_group=2" >> ./boot/config.txt.bak
sudo echo "hdmi_mode=1" >> ./boot/config.txt.bak
sudo echo "hdmi_mode=87" >> ./boot/config.txt.bak
sudo echo "hdmi_cvt 480 360 60 6 0 0 0" >> ./boot/config.txt.bak
sudo echo "hdmi_drive=2" >> ./boot/config.txt.bak
sudo cp -rf ./boot/config.txt.bak /boot/config.txt sudo cp -rf ./boot/config.txt.bak /boot/config.txt
sudo cp -rf ./usr/99-calibration.conf-32-90 /etc/X11/xorg.conf.d/99-calibration.conf sudo cp -rf ./usr/99-calibration.conf-32-90 /etc/X11/xorg.conf.d/99-calibration.conf
sudo cp -rf ./usr/99-fbturbo.conf /usr/share/X11/xorg.conf.d/99-fbturbo.conf sudo cp -rf ./usr/99-fbturbo.conf /usr/share/X11/xorg.conf.d/99-fbturbo.conf
#if test "$root_dev" = "/dev/mmcblk0p7";then if test "$root_dev" = "/dev/mmcblk0p7";then
#sudo cp ./usr/cmdline.txt-noobs /boot/cmdline.txt sudo cp ./usr/cmdline.txt-noobs /boot/cmdline.txt
#else else
#sudo cp ./usr/cmdline.txt /boot/ sudo cp ./usr/cmdline.txt /boot/
#fi fi
sudo cp ./usr/inittab /etc/ sudo cp ./usr/inittab /etc/
#sudo cp ./boot/config-32.txt /boot/config.txt #sudo cp ./boot/config-32.txt /boot/config.txt
sudo touch ./.have_installed sudo touch ./.have_installed
echo "gpio:resistance:32:90:480:360" > ./.have_installed echo "gpio:resistance:32:90:320:240" > ./.have_installed
sudo apt-get update
#FBCP install
wget --spider -q -o /dev/null --tries=1 -T 10 https://cmake.org/
if [ $? -eq 0 ]; then
#sudo apt-get update
sudo apt-get install cmake -y 2> error_output.txt
result=`cat ./error_output.txt`
echo -e "\033[31m$result\033[0m"
grep -q "^E:" ./error_output.txt
type cmake > /dev/null 2>&1
if [ $? -eq 0 ]; then
sudo rm -rf rpi-fbcp
wget --spider -q -o /dev/null --tries=1 -T 10 https://github.com
if [ $? -eq 0 ]; then
sudo git clone https://github.com/tasanakorn/rpi-fbcp
if [ $? -ne 0 ]; then
echo "download fbcp failed, copy native fbcp!!!"
sudo cp -r ./usr/rpi-fbcp .
fi
else
echo "bad network, copy native fbcp!!!"
sudo cp -r ./usr/rpi-fbcp .
fi
sudo mkdir ./rpi-fbcp/build
cd ./rpi-fbcp/build/
sudo cmake ..
sudo make
sudo install fbcp /usr/local/bin/fbcp
cd - > /dev/null
type fbcp > /dev/null 2>&1
if [ $? -eq 0 ]; then
sudo cp -rf ./usr/99-fbturbo-fbcp.conf /usr/share/X11/xorg.conf.d/99-fbturbo.conf
sudo cp -rf ./etc/rc.local /etc/rc.local
fi
else
echo "install cmake error!!!!"
fi
else
echo "bad network, can't install cmake!!!"
fi
#evdev install #evdev install
#nodeplatform=`uname -n` #nodeplatform=`uname -n`
#kernel=`uname -r` #kernel=`uname -r`
version=`uname -v` version=`uname -v`
#if test "$nodeplatform" = "raspberrypi";then #if test "$nodeplatform" = "raspberrypi";then
#echo "this is raspberrypi kernel" #echo "this is raspberrypi kernel"
input_result=0
version=${version##* } version=${version##* }
#version=${version#*#} #version=${version#*#}
echo $version echo $version
@ -97,23 +46,8 @@ if test $version -lt 2017;then
echo "reboot" echo "reboot"
else else
echo "need to update touch configuration" echo "need to update touch configuration"
wget --spider -q -o /dev/null --tries=1 -T 10 http://mirrors.zju.edu.cn/raspbian/raspbian sudo dpkg -i -B ./xserver-xorg-input-evdev_2.10.5-1_armhf.deb 2> error_output.txt
if [ $? -ne 0 ]; then #sudo apt-get install xserver-xorg-input-evdev 2> error_output.txt
input_result=1
else
sudo apt-get install xserver-xorg-input-evdev 2> error_output.txt
dpkg -l | grep xserver-xorg-input-evdev > /dev/null 2>&1
if [ $? -ne 0 ]; then
input_result=1
fi
fi
if [ $input_result -eq 1 ]; then
if [ $hardware_arch -eq 32 ]; then
sudo dpkg -i -B ./xserver-xorg-input-evdev_1%3a2.10.6-1+b1_armhf.deb 2> error_output.txt
elif [ $hardware_arch -eq 64 ]; then
sudo dpkg -i -B ./xserver-xorg-input-evdev_1%3a2.10.6-2_arm64.deb 2> error_output.txt
fi
fi
result=`cat ./error_output.txt` result=`cat ./error_output.txt`
echo -e "\033[31m$result\033[0m" echo -e "\033[31m$result\033[0m"
grep -q "error:" ./error_output.txt && exit grep -q "error:" ./error_output.txt && exit

View File

@ -10,86 +10,35 @@ sudo mkdir -p /etc/X11/xorg.conf.d
fi fi
sudo cp ./usr/tft9341-overlay.dtb /boot/overlays/ sudo cp ./usr/tft9341-overlay.dtb /boot/overlays/
sudo cp ./usr/tft9341-overlay.dtb /boot/overlays/tft9341.dtbo sudo cp ./usr/tft9341-overlay.dtb /boot/overlays/tft9341.dtbo
#root_dev=`grep -oPr "root=[^\s]*" /boot/cmdline.txt | awk -F= '{printf $NF}'` root_dev=`grep -oPr "root=[^\s]*" /boot/cmdline.txt | awk -F= '{printf $NF}'`
#if test "$root_dev" = "/dev/mmcblk0p7";then if test "$root_dev" = "/dev/mmcblk0p7";then
#sudo cp -rf ./boot/config-noobs-nomal.txt ./boot/config.txt.bak sudo cp -rf ./boot/config-noobs-nomal.txt ./boot/config.txt.bak
#else else
#sudo cp -rf ./boot/config-nomal.txt ./boot/config.txt.bak sudo cp -rf ./boot/config-nomal.txt ./boot/config.txt.bak
#sudo echo "hdmi_force_hotplug=1" >> ./boot/config.txt.bak
#fi
source ./system_config.sh
sudo echo "hdmi_force_hotplug=1" >> ./boot/config.txt.bak sudo echo "hdmi_force_hotplug=1" >> ./boot/config.txt.bak
fi
sudo echo "dtparam=i2c_arm=on" >> ./boot/config.txt.bak sudo echo "dtparam=i2c_arm=on" >> ./boot/config.txt.bak
sudo echo "dtparam=spi=on" >> ./boot/config.txt.bak sudo echo "dtparam=spi=on" >> ./boot/config.txt.bak
sudo echo "enable_uart=1" >> ./boot/config.txt.bak sudo echo "enable_uart=1" >> ./boot/config.txt.bak
sudo echo "dtoverlay=tft9341:rotate=270" >> ./boot/config.txt.bak sudo echo "dtoverlay=tft9341:rotate=270" >> ./boot/config.txt.bak
sudo echo "hdmi_group=2" >> ./boot/config.txt.bak
sudo echo "hdmi_mode=1" >> ./boot/config.txt.bak
sudo echo "hdmi_mode=87" >> ./boot/config.txt.bak
sudo echo "hdmi_cvt 480 360 60 6 0 0 0" >> ./boot/config.txt.bak
sudo echo "hdmi_drive=2" >> ./boot/config.txt.bak
sudo cp -rf ./boot/config.txt.bak /boot/config.txt sudo cp -rf ./boot/config.txt.bak /boot/config.txt
sudo cp -rf ./usr/99-calibration.conf-32-270 /etc/X11/xorg.conf.d/99-calibration.conf sudo cp -rf ./usr/99-calibration.conf-32-270 /etc/X11/xorg.conf.d/99-calibration.conf
sudo cp -rf ./usr/99-fbturbo.conf /usr/share/X11/xorg.conf.d/99-fbturbo.conf sudo cp -rf ./usr/99-fbturbo.conf /usr/share/X11/xorg.conf.d/99-fbturbo.conf
#if test "$root_dev" = "/dev/mmcblk0p7";then if test "$root_dev" = "/dev/mmcblk0p7";then
#sudo cp ./usr/cmdline.txt-noobs /boot/cmdline.txt sudo cp ./usr/cmdline.txt-noobs /boot/cmdline.txt
#else else
#sudo cp ./usr/cmdline.txt /boot/ sudo cp ./usr/cmdline.txt /boot/
#fi fi
sudo cp ./usr/inittab /etc/ sudo cp ./usr/inittab /etc/
#sudo cp ./boot/config-32.txt /boot/config.txt #sudo cp ./boot/config-32.txt /boot/config.txt
sudo touch ./.have_installed sudo touch ./.have_installed
echo "gpio:resistance:32:270:480:360" > ./.have_installed echo "gpio:resistance:32:270:320:240" > ./.have_installed
sudo apt-get update
#FBCP install
wget --spider -q -o /dev/null --tries=1 -T 10 https://cmake.org/
if [ $? -eq 0 ]; then
#sudo apt-get update
sudo apt-get install cmake -y 2> error_output.txt
result=`cat ./error_output.txt`
echo -e "\033[31m$result\033[0m"
grep -q "^E:" ./error_output.txt
type cmake > /dev/null 2>&1
if [ $? -eq 0 ]; then
sudo rm -rf rpi-fbcp
wget --spider -q -o /dev/null --tries=1 -T 10 https://github.com
if [ $? -eq 0 ]; then
sudo git clone https://github.com/tasanakorn/rpi-fbcp
if [ $? -ne 0 ]; then
echo "download fbcp failed, copy native fbcp!!!"
sudo cp -r ./usr/rpi-fbcp .
fi
else
echo "bad network, copy native fbcp!!!"
sudo cp -r ./usr/rpi-fbcp .
fi
sudo mkdir ./rpi-fbcp/build
cd ./rpi-fbcp/build/
sudo cmake ..
sudo make
sudo install fbcp /usr/local/bin/fbcp
cd - > /dev/null
type fbcp > /dev/null 2>&1
if [ $? -eq 0 ]; then
sudo cp -rf ./usr/99-fbturbo-fbcp.conf /usr/share/X11/xorg.conf.d/99-fbturbo.conf
sudo cp -rf ./etc/rc.local /etc/rc.local
fi
else
echo "install cmake error!!!!"
fi
else
echo "bad network, can't install cmake!!!"
fi
#evdev install #evdev install
#nodeplatform=`uname -n` #nodeplatform=`uname -n`
#kernel=`uname -r` #kernel=`uname -r`
version=`uname -v` version=`uname -v`
#if test "$nodeplatform" = "raspberrypi";then #if test "$nodeplatform" = "raspberrypi";then
#echo "this is raspberrypi kernel" #echo "this is raspberrypi kernel"
input_result=0
version=${version##* } version=${version##* }
#version=${version#*#} #version=${version#*#}
echo $version echo $version
@ -97,23 +46,8 @@ if test $version -lt 2017;then
echo "reboot" echo "reboot"
else else
echo "need to update touch configuration" echo "need to update touch configuration"
wget --spider -q -o /dev/null --tries=1 -T 10 http://mirrors.zju.edu.cn/raspbian/raspbian sudo dpkg -i -B ./xserver-xorg-input-evdev_2.10.5-1_armhf.deb 2> error_output.txt
if [ $? -ne 0 ]; then #sudo apt-get install xserver-xorg-input-evdev 2> error_output.txt
input_result=1
else
sudo apt-get install xserver-xorg-input-evdev 2> error_output.txt
dpkg -l | grep xserver-xorg-input-evdev > /dev/null 2>&1
if [ $? -ne 0 ]; then
input_result=1
fi
fi
if [ $input_result -eq 1 ]; then
if [ $hardware_arch -eq 32 ]; then
sudo dpkg -i -B ./xserver-xorg-input-evdev_1%3a2.10.6-1+b1_armhf.deb 2> error_output.txt
elif [ $hardware_arch -eq 64 ]; then
sudo dpkg -i -B ./xserver-xorg-input-evdev_1%3a2.10.6-2_arm64.deb 2> error_output.txt
fi
fi
result=`cat ./error_output.txt` result=`cat ./error_output.txt`
echo -e "\033[31m$result\033[0m" echo -e "\033[31m$result\033[0m"
grep -q "error:" ./error_output.txt && exit grep -q "error:" ./error_output.txt && exit

View File

@ -10,86 +10,35 @@ sudo mkdir -p /etc/X11/xorg.conf.d
fi fi
sudo cp ./usr/tft9341-overlay.dtb /boot/overlays/ sudo cp ./usr/tft9341-overlay.dtb /boot/overlays/
sudo cp ./usr/tft9341-overlay.dtb /boot/overlays/tft9341.dtbo sudo cp ./usr/tft9341-overlay.dtb /boot/overlays/tft9341.dtbo
#root_dev=`grep -oPr "root=[^\s]*" /boot/cmdline.txt | awk -F= '{printf $NF}'` root_dev=`grep -oPr "root=[^\s]*" /boot/cmdline.txt | awk -F= '{printf $NF}'`
#if test "$root_dev" = "/dev/mmcblk0p7";then if test "$root_dev" = "/dev/mmcblk0p7";then
#sudo cp -rf ./boot/config-noobs-nomal.txt ./boot/config.txt.bak sudo cp -rf ./boot/config-noobs-nomal.txt ./boot/config.txt.bak
#else else
#sudo cp -rf ./boot/config-nomal.txt ./boot/config.txt.bak sudo cp -rf ./boot/config-nomal.txt ./boot/config.txt.bak
#sudo echo "hdmi_force_hotplug=1" >> ./boot/config.txt.bak
#fi
source ./system_config.sh
sudo echo "hdmi_force_hotplug=1" >> ./boot/config.txt.bak sudo echo "hdmi_force_hotplug=1" >> ./boot/config.txt.bak
fi
sudo echo "dtparam=i2c_arm=on" >> ./boot/config.txt.bak sudo echo "dtparam=i2c_arm=on" >> ./boot/config.txt.bak
sudo echo "dtparam=spi=on" >> ./boot/config.txt.bak sudo echo "dtparam=spi=on" >> ./boot/config.txt.bak
sudo echo "enable_uart=1" >> ./boot/config.txt.bak sudo echo "enable_uart=1" >> ./boot/config.txt.bak
sudo echo "dtoverlay=tft9341:rotate=270" >> ./boot/config.txt.bak sudo echo "dtoverlay=tft9341:rotate=270" >> ./boot/config.txt.bak
sudo echo "hdmi_group=2" >> ./boot/config.txt.bak
sudo echo "hdmi_mode=1" >> ./boot/config.txt.bak
sudo echo "hdmi_mode=87" >> ./boot/config.txt.bak
sudo echo "hdmi_cvt 480 360 60 6 0 0 0" >> ./boot/config.txt.bak
sudo echo "hdmi_drive=2" >> ./boot/config.txt.bak
sudo cp -rf ./boot/config.txt.bak /boot/config.txt sudo cp -rf ./boot/config.txt.bak /boot/config.txt
sudo cp -rf ./usr/99-calibration.conf-32-270 /etc/X11/xorg.conf.d/99-calibration.conf sudo cp -rf ./usr/99-calibration.conf-32-270 /etc/X11/xorg.conf.d/99-calibration.conf
sudo cp -rf ./usr/99-fbturbo.conf /usr/share/X11/xorg.conf.d/99-fbturbo.conf sudo cp -rf ./usr/99-fbturbo.conf /usr/share/X11/xorg.conf.d/99-fbturbo.conf
#if test "$root_dev" = "/dev/mmcblk0p7";then if test "$root_dev" = "/dev/mmcblk0p7";then
#sudo cp ./usr/cmdline.txt-noobs /boot/cmdline.txt sudo cp ./usr/cmdline.txt-noobs /boot/cmdline.txt
#else else
#sudo cp ./usr/cmdline.txt /boot/ sudo cp ./usr/cmdline.txt /boot/
#fi fi
sudo cp ./usr/inittab /etc/ sudo cp ./usr/inittab /etc/
#sudo cp ./boot/config-32.txt /boot/config.txt #sudo cp ./boot/config-32.txt /boot/config.txt
sudo touch ./.have_installed sudo touch ./.have_installed
echo "gpio:resistance:32:270:480:360" > ./.have_installed echo "gpio:resistance:32:270:320:240" > ./.have_installed
sudo apt-get update
#FBCP install
wget --spider -q -o /dev/null --tries=1 -T 10 https://cmake.org/
if [ $? -eq 0 ]; then
#sudo apt-get update
sudo apt-get install cmake -y 2> error_output.txt
result=`cat ./error_output.txt`
echo -e "\033[31m$result\033[0m"
grep -q "^E:" ./error_output.txt
type cmake > /dev/null 2>&1
if [ $? -eq 0 ]; then
sudo rm -rf rpi-fbcp
wget --spider -q -o /dev/null --tries=1 -T 10 https://github.com
if [ $? -eq 0 ]; then
sudo git clone https://github.com/tasanakorn/rpi-fbcp
if [ $? -ne 0 ]; then
echo "download fbcp failed, copy native fbcp!!!"
sudo cp -r ./usr/rpi-fbcp .
fi
else
echo "bad network, copy native fbcp!!!"
sudo cp -r ./usr/rpi-fbcp .
fi
sudo mkdir ./rpi-fbcp/build
cd ./rpi-fbcp/build/
sudo cmake ..
sudo make
sudo install fbcp /usr/local/bin/fbcp
cd - > /dev/null
type fbcp > /dev/null 2>&1
if [ $? -eq 0 ]; then
sudo cp -rf ./usr/99-fbturbo-fbcp.conf /usr/share/X11/xorg.conf.d/99-fbturbo.conf
sudo cp -rf ./etc/rc.local /etc/rc.local
fi
else
echo "install cmake error!!!!"
fi
else
echo "bad network, can't install cmake!!!"
fi
#evdev install #evdev install
#nodeplatform=`uname -n` #nodeplatform=`uname -n`
#kernel=`uname -r` #kernel=`uname -r`
version=`uname -v` version=`uname -v`
#if test "$nodeplatform" = "raspberrypi";then #if test "$nodeplatform" = "raspberrypi";then
#echo "this is raspberrypi kernel" #echo "this is raspberrypi kernel"
input_result=0
version=${version##* } version=${version##* }
#version=${version#*#} #version=${version#*#}
echo $version echo $version
@ -97,23 +46,8 @@ if test $version -lt 2017;then
echo "reboot" echo "reboot"
else else
echo "need to update touch configuration" echo "need to update touch configuration"
wget --spider -q -o /dev/null --tries=1 -T 10 http://mirrors.zju.edu.cn/raspbian/raspbian sudo dpkg -i -B ./xserver-xorg-input-evdev_2.10.5-1_armhf.deb 2> error_output.txt
if [ $? -ne 0 ]; then #sudo apt-get install xserver-xorg-input-evdev 2> error_output.txt
input_result=1
else
sudo apt-get install xserver-xorg-input-evdev 2> error_output.txt
dpkg -l | grep xserver-xorg-input-evdev > /dev/null 2>&1
if [ $? -ne 0 ]; then
input_result=1
fi
fi
if [ $input_result -eq 1 ]; then
if [ $hardware_arch -eq 32 ]; then
sudo dpkg -i -B ./xserver-xorg-input-evdev_1%3a2.10.6-1+b1_armhf.deb 2> error_output.txt
elif [ $hardware_arch -eq 64 ]; then
sudo dpkg -i -B ./xserver-xorg-input-evdev_1%3a2.10.6-2_arm64.deb 2> error_output.txt
fi
fi
result=`cat ./error_output.txt` result=`cat ./error_output.txt`
echo -e "\033[31m$result\033[0m" echo -e "\033[31m$result\033[0m"
grep -q "error:" ./error_output.txt && exit grep -q "error:" ./error_output.txt && exit

View File

@ -10,86 +10,35 @@ sudo mkdir -p /etc/X11/xorg.conf.d
fi fi
sudo cp ./usr/tft9341-overlay.dtb /boot/overlays/ sudo cp ./usr/tft9341-overlay.dtb /boot/overlays/
sudo cp ./usr/tft9341-overlay.dtb /boot/overlays/tft9341.dtbo sudo cp ./usr/tft9341-overlay.dtb /boot/overlays/tft9341.dtbo
#root_dev=`grep -oPr "root=[^\s]*" /boot/cmdline.txt | awk -F= '{printf $NF}'` root_dev=`grep -oPr "root=[^\s]*" /boot/cmdline.txt | awk -F= '{printf $NF}'`
#if test "$root_dev" = "/dev/mmcblk0p7";then if test "$root_dev" = "/dev/mmcblk0p7";then
#sudo cp -rf ./boot/config-noobs-nomal.txt ./boot/config.txt.bak sudo cp -rf ./boot/config-noobs-nomal.txt ./boot/config.txt.bak
#else else
#sudo cp -rf ./boot/config-nomal.txt ./boot/config.txt.bak sudo cp -rf ./boot/config-nomal.txt ./boot/config.txt.bak
#sudo echo "hdmi_force_hotplug=1" >> ./boot/config.txt.bak
#fi
source ./system_config.sh
sudo echo "hdmi_force_hotplug=1" >> ./boot/config.txt.bak sudo echo "hdmi_force_hotplug=1" >> ./boot/config.txt.bak
fi
sudo echo "dtparam=i2c_arm=on" >> ./boot/config.txt.bak sudo echo "dtparam=i2c_arm=on" >> ./boot/config.txt.bak
sudo echo "dtparam=spi=on" >> ./boot/config.txt.bak sudo echo "dtparam=spi=on" >> ./boot/config.txt.bak
sudo echo "enable_uart=1" >> ./boot/config.txt.bak sudo echo "enable_uart=1" >> ./boot/config.txt.bak
sudo echo "dtoverlay=tft9341:rotate=270" >> ./boot/config.txt.bak sudo echo "dtoverlay=tft9341:rotate=270" >> ./boot/config.txt.bak
sudo echo "hdmi_group=2" >> ./boot/config.txt.bak
sudo echo "hdmi_mode=1" >> ./boot/config.txt.bak
sudo echo "hdmi_mode=87" >> ./boot/config.txt.bak
sudo echo "hdmi_cvt 480 360 60 6 0 0 0" >> ./boot/config.txt.bak
sudo echo "hdmi_drive=2" >> ./boot/config.txt.bak
sudo cp -rf ./boot/config.txt.bak /boot/config.txt sudo cp -rf ./boot/config.txt.bak /boot/config.txt
sudo cp -rf ./usr/99-calibration.conf-32-270 /etc/X11/xorg.conf.d/99-calibration.conf sudo cp -rf ./usr/99-calibration.conf-32-270 /etc/X11/xorg.conf.d/99-calibration.conf
sudo cp -rf ./usr/99-fbturbo.conf /usr/share/X11/xorg.conf.d/99-fbturbo.conf sudo cp -rf ./usr/99-fbturbo.conf /usr/share/X11/xorg.conf.d/99-fbturbo.conf
#if test "$root_dev" = "/dev/mmcblk0p7";then if test "$root_dev" = "/dev/mmcblk0p7";then
#sudo cp ./usr/cmdline.txt-noobs /boot/cmdline.txt sudo cp ./usr/cmdline.txt-noobs /boot/cmdline.txt
#else else
#sudo cp ./usr/cmdline.txt /boot/ sudo cp ./usr/cmdline.txt /boot/
#fi fi
sudo cp ./usr/inittab /etc/ sudo cp ./usr/inittab /etc/
#sudo cp ./boot/config-32.txt /boot/config.txt #sudo cp ./boot/config-32.txt /boot/config.txt
sudo touch ./.have_installed sudo touch ./.have_installed
echo "gpio:resistance:32:270:480:360" > ./.have_installed echo "gpio:resistance:32:270:320:240" > ./.have_installed
sudo apt-get update
#FBCP install
wget --spider -q -o /dev/null --tries=1 -T 10 https://cmake.org/
if [ $? -eq 0 ]; then
#sudo apt-get update
sudo apt-get install cmake -y 2> error_output.txt
result=`cat ./error_output.txt`
echo -e "\033[31m$result\033[0m"
grep -q "^E:" ./error_output.txt
type cmake > /dev/null 2>&1
if [ $? -eq 0 ]; then
sudo rm -rf rpi-fbcp
wget --spider -q -o /dev/null --tries=1 -T 10 https://github.com
if [ $? -eq 0 ]; then
sudo git clone https://github.com/tasanakorn/rpi-fbcp
if [ $? -ne 0 ]; then
echo "download fbcp failed, copy native fbcp!!!"
sudo cp -r ./usr/rpi-fbcp .
fi
else
echo "bad network, copy native fbcp!!!"
sudo cp -r ./usr/rpi-fbcp .
fi
sudo mkdir ./rpi-fbcp/build
cd ./rpi-fbcp/build/
sudo cmake ..
sudo make
sudo install fbcp /usr/local/bin/fbcp
cd - > /dev/null
type fbcp > /dev/null 2>&1
if [ $? -eq 0 ]; then
sudo cp -rf ./usr/99-fbturbo-fbcp.conf /usr/share/X11/xorg.conf.d/99-fbturbo.conf
sudo cp -rf ./etc/rc.local /etc/rc.local
fi
else
echo "install cmake error!!!!"
fi
else
echo "bad network, can't install cmake!!!"
fi
#evdev install #evdev install
#nodeplatform=`uname -n` #nodeplatform=`uname -n`
#kernel=`uname -r` #kernel=`uname -r`
version=`uname -v` version=`uname -v`
#if test "$nodeplatform" = "raspberrypi";then #if test "$nodeplatform" = "raspberrypi";then
#echo "this is raspberrypi kernel" #echo "this is raspberrypi kernel"
input_result=0
version=${version##* } version=${version##* }
#version=${version#*#} #version=${version#*#}
echo $version echo $version
@ -97,23 +46,8 @@ if test $version -lt 2017;then
echo "reboot" echo "reboot"
else else
echo "need to update touch configuration" echo "need to update touch configuration"
wget --spider -q -o /dev/null --tries=1 -T 10 http://mirrors.zju.edu.cn/raspbian/raspbian sudo dpkg -i -B ./xserver-xorg-input-evdev_2.10.5-1_armhf.deb 2> error_output.txt
if [ $? -ne 0 ]; then #sudo apt-get install xserver-xorg-input-evdev 2> error_output.txt
input_result=1
else
sudo apt-get install xserver-xorg-input-evdev 2> error_output.txt
dpkg -l | grep xserver-xorg-input-evdev > /dev/null 2>&1
if [ $? -ne 0 ]; then
input_result=1
fi
fi
if [ $input_result -eq 1 ]; then
if [ $hardware_arch -eq 32 ]; then
sudo dpkg -i -B ./xserver-xorg-input-evdev_1%3a2.10.6-1+b1_armhf.deb 2> error_output.txt
elif [ $hardware_arch -eq 64 ]; then
sudo dpkg -i -B ./xserver-xorg-input-evdev_1%3a2.10.6-2_arm64.deb 2> error_output.txt
fi
fi
result=`cat ./error_output.txt` result=`cat ./error_output.txt`
echo -e "\033[31m$result\033[0m" echo -e "\033[31m$result\033[0m"
grep -q "error:" ./error_output.txt && exit grep -q "error:" ./error_output.txt && exit

View File

@ -10,87 +10,38 @@ sudo mkdir -p /etc/X11/xorg.conf.d
fi fi
sudo cp ./usr/tft35a-overlay.dtb /boot/overlays/ sudo cp ./usr/tft35a-overlay.dtb /boot/overlays/
sudo cp ./usr/tft35a-overlay.dtb /boot/overlays/tft35a.dtbo sudo cp ./usr/tft35a-overlay.dtb /boot/overlays/tft35a.dtbo
#root_dev=`grep -oPr "root=[^\s]*" /boot/cmdline.txt | awk -F= '{printf $NF}'` hw_version=`tr -d '\0' < /proc/device-tree/model`
#if test "$root_dev" = "/dev/mmcblk0p7";then root_dev=`grep -oPr "root=[^\s]*" /boot/cmdline.txt | awk -F= '{printf $NF}'`
#sudo cp -rf ./boot/config-noobs-nomal.txt ./boot/config.txt.bak if test "$root_dev" = "/dev/mmcblk0p7";then
#else sudo cp -rf ./boot/config-noobs-nomal.txt ./boot/config.txt.bak
#sudo cp -rf ./boot/config-nomal.txt ./boot/config.txt.bak else
#sudo echo "hdmi_force_hotplug=1" >> ./boot/config.txt.bak sudo cp -rf ./boot/config-nomal.txt ./boot/config.txt.bak
#fi
source ./system_config.sh
sudo echo "hdmi_force_hotplug=1" >> ./boot/config.txt.bak sudo echo "hdmi_force_hotplug=1" >> ./boot/config.txt.bak
fi
[[ $hw_version =~ "Raspberry Pi 4 Model" ]] || (sed -i 's/^dtoverlay=/#&/g' ./boot/config.txt.bak;sed -i 's/^max_framebuffers=/#&/g' ./boot/config.txt.bak)
sudo echo "dtparam=i2c_arm=on" >> ./boot/config.txt.bak sudo echo "dtparam=i2c_arm=on" >> ./boot/config.txt.bak
sudo echo "dtparam=spi=on" >> ./boot/config.txt.bak sudo echo "dtparam=spi=on" >> ./boot/config.txt.bak
sudo echo "enable_uart=1" >> ./boot/config.txt.bak sudo echo "enable_uart=1" >> ./boot/config.txt.bak
sudo echo "dtoverlay=tft35a:rotate=90" >> ./boot/config.txt.bak sudo echo "dtoverlay=tft35a:rotate=90" >> ./boot/config.txt.bak
sudo echo "hdmi_group=2" >> ./boot/config.txt.bak
sudo echo "hdmi_mode=1" >> ./boot/config.txt.bak
sudo echo "hdmi_mode=87" >> ./boot/config.txt.bak
sudo echo "hdmi_cvt 480 320 60 6 0 0 0" >> ./boot/config.txt.bak
sudo echo "hdmi_drive=2" >> ./boot/config.txt.bak
sudo cp -rf ./boot/config.txt.bak /boot/config.txt sudo cp -rf ./boot/config.txt.bak /boot/config.txt
sudo cp -rf ./usr/99-calibration.conf-35-90 /etc/X11/xorg.conf.d/99-calibration.conf sudo cp -rf ./usr/99-calibration.conf-35-90 /etc/X11/xorg.conf.d/99-calibration.conf
sudo cp -rf ./usr/99-fbturbo.conf /usr/share/X11/xorg.conf.d/99-fbturbo.conf sudo cp -rf ./usr/99-fbturbo.conf /usr/share/X11/xorg.conf.d/99-fbturbo.conf
#if test "$root_dev" = "/dev/mmcblk0p7";then if test "$root_dev" = "/dev/mmcblk0p7";then
#sudo cp ./usr/cmdline.txt-noobs /boot/cmdline.txt sudo cp ./usr/cmdline.txt-noobs /boot/cmdline.txt
#else else
#sudo cp ./usr/cmdline.txt /boot/ sudo cp ./usr/cmdline.txt /boot/
#fi fi
sudo cp ./usr/inittab /etc/ sudo cp ./usr/inittab /etc/
#sudo cp ./boot/config-35.txt /boot/config.txt #sudo cp ./boot/config-35.txt /boot/config.txt
sudo touch ./.have_installed sudo touch ./.have_installed
echo "gpio:resistance:35:90:480:320" > ./.have_installed echo "gpio:resistance:35:90:480:320" > ./.have_installed
sudo apt-get update
#FBCP install
wget --spider -q -o /dev/null --tries=1 -T 10 https://cmake.org/
if [ $? -eq 0 ]; then
#sudo apt-get update
sudo apt-get install cmake -y 2> error_output.txt
result=`cat ./error_output.txt`
echo -e "\033[31m$result\033[0m"
grep -q "^E:" ./error_output.txt
type cmake > /dev/null 2>&1
if [ $? -eq 0 ]; then
sudo rm -rf rpi-fbcp
wget --spider -q -o /dev/null --tries=1 -T 10 https://github.com
if [ $? -eq 0 ]; then
sudo git clone https://github.com/tasanakorn/rpi-fbcp
if [ $? -ne 0 ]; then
echo "download fbcp failed, copy native fbcp!!!"
sudo cp -r ./usr/rpi-fbcp .
fi
else
echo "bad network, copy native fbcp!!!"
sudo cp -r ./usr/rpi-fbcp .
fi
sudo mkdir ./rpi-fbcp/build
cd ./rpi-fbcp/build/
sudo cmake ..
sudo make
sudo install fbcp /usr/local/bin/fbcp
cd - > /dev/null
type fbcp > /dev/null 2>&1
if [ $? -eq 0 ]; then
sudo cp -rf ./usr/99-fbturbo-fbcp.conf /usr/share/X11/xorg.conf.d/99-fbturbo.conf
sudo cp -rf ./etc/rc.local /etc/rc.local
fi
else
echo "install cmake error!!!!"
fi
else
echo "bad network, can't install cmake!!!"
fi
#evdev install #evdev install
#nodeplatform=`uname -n` #nodeplatform=`uname -n`
#kernel=`uname -r` #kernel=`uname -r`
version=`uname -v` version=`uname -v`
#if test "$nodeplatform" = "raspberrypi";then #if test "$nodeplatform" = "raspberrypi";then
#echo "this is raspberrypi kernel" #echo "this is raspberrypi kernel"
input_result=0
version=${version##* } version=${version##* }
#version=${version#*#} #version=${version#*#}
echo $version echo $version
@ -98,23 +49,8 @@ if test $version -lt 2017;then
echo "reboot" echo "reboot"
else else
echo "need to update touch configuration" echo "need to update touch configuration"
wget --spider -q -o /dev/null --tries=1 -T 10 http://mirrors.zju.edu.cn/raspbian/raspbian sudo dpkg -i -B ./xserver-xorg-input-evdev_2.10.5-1_armhf.deb 2> error_output.txt
if [ $? -ne 0 ]; then #sudo apt-get install xserver-xorg-input-evdev 2> error_output.txt
input_result=1
else
sudo apt-get install xserver-xorg-input-evdev 2> error_output.txt
dpkg -l | grep xserver-xorg-input-evdev > /dev/null 2>&1
if [ $? -ne 0 ]; then
input_result=1
fi
fi
if [ $input_result -eq 1 ]; then
if [ $hardware_arch -eq 32 ]; then
sudo dpkg -i -B ./xserver-xorg-input-evdev_1%3a2.10.6-1+b1_armhf.deb 2> error_output.txt
elif [ $hardware_arch -eq 64 ]; then
sudo dpkg -i -B ./xserver-xorg-input-evdev_1%3a2.10.6-2_arm64.deb 2> error_output.txt
fi
fi
result=`cat ./error_output.txt` result=`cat ./error_output.txt`
echo -e "\033[31m$result\033[0m" echo -e "\033[31m$result\033[0m"
grep -q "error:" ./error_output.txt && exit grep -q "error:" ./error_output.txt && exit

View File

@ -2,19 +2,15 @@
sudo ./system_backup.sh sudo ./system_backup.sh
#root_dev=`grep -oPr "root=[^\s]*" /boot/cmdline.txt | awk -F= '{printf $NF}'` hw_version=`tr -d '\0' < /proc/device-tree/model`
#if test "$root_dev" = "/dev/mmcblk0p7";then root_dev=`grep -oPr "root=[^\s]*" /boot/cmdline.txt | awk -F= '{printf $NF}'`
#sudo cp -rf ./boot/config-noobs-nomal.txt ./boot/config.txt.bak if test "$root_dev" = "/dev/mmcblk0p7";then
#else sudo cp -rf ./boot/config-noobs-nomal.txt ./boot/config.txt.bak
#sudo cp -rf ./boot/config-nomal.txt ./boot/config.txt.bak else
#sudo echo "hdmi_force_hotplug=1" >> ./boot/config.txt.bak sudo cp -rf ./boot/config-nomal.txt ./boot/config.txt.bak
#fi
source ./system_config.sh
row=`grep -nr "#dtoverlay=vc4-fkms-v3d" ./boot/config.txt.bak | awk -F ':' '{if(NR==1)printf $1}'`
sudo sed -i -e ''"$row"'s/#dtoverlay=vc4-fkms-v3d/dtoverlay=vc4-fkms-v3d/' ./boot/config.txt.bak
sudo sed -i -e 's/#max_framebuffers=2/max_framebuffers=2/' ./boot/config.txt.bak
sudo echo "hdmi_force_hotplug=1" >> ./boot/config.txt.bak sudo echo "hdmi_force_hotplug=1" >> ./boot/config.txt.bak
fi
[[ $hw_version =~ "Raspberry Pi 4 Model" ]] || (sed -i 's/^dtoverlay=/#&/g' ./boot/config.txt.bak;sed -i 's/^max_framebuffers=/#&/g' ./boot/config.txt.bak)
sudo echo "dtparam=i2c_arm=on" >> ./boot/config.txt.bak sudo echo "dtparam=i2c_arm=on" >> ./boot/config.txt.bak
sudo echo "dtparam=spi=on" >> ./boot/config.txt.bak sudo echo "dtparam=spi=on" >> ./boot/config.txt.bak
sudo echo "enable_uart=1" >> ./boot/config.txt.bak sudo echo "enable_uart=1" >> ./boot/config.txt.bak
@ -27,15 +23,14 @@ sudo echo "hdmi_mode=87" >> ./boot/config.txt.bak
sudo echo "hdmi_drive=1" >> ./boot/config.txt.bak sudo echo "hdmi_drive=1" >> ./boot/config.txt.bak
sudo echo "hdmi_cvt 800 480 60 6 0 0 0" >> ./boot/config.txt.bak sudo echo "hdmi_cvt 800 480 60 6 0 0 0" >> ./boot/config.txt.bak
sudo echo "dtoverlay=ads7846,cs=1,penirq=25,penirq_pull=2,speed=50000,keep_vref_on=0,swapxy=0,pmax=255,xohms=150,xmin=200,xmax=3900,ymin=200,ymax=3900" >> ./boot/config.txt.bak sudo echo "dtoverlay=ads7846,cs=1,penirq=25,penirq_pull=2,speed=50000,keep_vref_on=0,swapxy=0,pmax=255,xohms=150,xmin=200,xmax=3900,ymin=200,ymax=3900" >> ./boot/config.txt.bak
sudo cp -rf ./boot/config.txt.bak /boot/config.txt sudo cp -rf ./boot/config.txt.bak /boot/config.txt
#sudo cp -rf ./boot/config-5.txt /boot/config.txt #sudo cp -rf ./boot/config-5.txt /boot/config.txt
#if test "$root_dev" = "/dev/mmcblk0p7";then if test "$root_dev" = "/dev/mmcblk0p7";then
#sudo cp ./usr/cmdline.txt-noobs /boot/cmdline.txt sudo cp ./usr/cmdline.txt-noobs /boot/cmdline.txt
#else else
#sudo cp ./usr/cmdline.txt /boot/ sudo cp ./usr/cmdline.txt /boot/
#fi fi
sudo cp ./usr/inittab /etc/ sudo cp ./usr/inittab /etc/
sudo cp -rf ./usr/99-fbturbo.conf-HDMI /usr/share/X11/xorg.conf.d/99-fbturbo.conf sudo cp -rf ./usr/99-fbturbo.conf-HDMI /usr/share/X11/xorg.conf.d/99-fbturbo.conf
if [ ! -d /etc/X11/xorg.conf.d ]; then if [ ! -d /etc/X11/xorg.conf.d ]; then
@ -49,7 +44,6 @@ echo "hdmi:resistance:5:0:800:480" > ./.have_installed
version=`uname -v` version=`uname -v`
#if test "$nodeplatform" = "raspberrypi";then #if test "$nodeplatform" = "raspberrypi";then
#echo "this is raspberrypi kernel" #echo "this is raspberrypi kernel"
input_result=0
version=${version##* } version=${version##* }
#version=${version#*#} #version=${version#*#}
echo $version echo $version
@ -57,24 +51,8 @@ if test $version -lt 2017;then
echo "reboot" echo "reboot"
else else
echo "need to update touch configuration" echo "need to update touch configuration"
wget --spider -q -o /dev/null --tries=1 -T 10 http://mirrors.zju.edu.cn/raspbian/raspbian sudo dpkg -i -B ./xserver-xorg-input-evdev_2.10.5-1_armhf.deb 2> error_output.txt
if [ $? -ne 0 ]; then #sudo apt-get install xserver-xorg-input-evdev 2> error_output.txt
input_result=1
else
sudo apt-get update
sudo apt-get install xserver-xorg-input-evdev 2> error_output.txt
dpkg -l | grep xserver-xorg-input-evdev > /dev/null 2>&1
if [ $? -ne 0 ]; then
input_result=1
fi
fi
if [ $input_result -eq 1 ]; then
if [ $hardware_arch -eq 32 ]; then
sudo dpkg -i -B ./xserver-xorg-input-evdev_1%3a2.10.6-1+b1_armhf.deb 2> error_output.txt
elif [ $hardware_arch -eq 64 ]; then
sudo dpkg -i -B ./xserver-xorg-input-evdev_1%3a2.10.6-2_arm64.deb 2> error_output.txt
fi
fi
result=`cat ./error_output.txt` result=`cat ./error_output.txt`
echo -e "\033[31m$result\033[0m" echo -e "\033[31m$result\033[0m"
grep -q "error:" ./error_output.txt && exit grep -q "error:" ./error_output.txt && exit

View File

@ -1,53 +0,0 @@
#!/bin/bash
sudo ./system_backup.sh
#root_dev=`grep -oPr "root=[^\s]*" /boot/cmdline.txt | awk -F= '{printf $NF}'`
#if test "$root_dev" = "/dev/mmcblk0p7";then
#sudo cp -rf ./boot/config-noobs-nomal.txt ./boot/config.txt.bak
#else
#sudo cp -rf ./boot/config-nomal.txt ./boot/config.txt.bak
#sudo echo "hdmi_force_hotplug=1" >> ./boot/config.txt.bak
#fi
source ./system_config.sh
sudo echo "hdmi_force_hotplug=1" >> ./boot/config.txt.bak
sudo echo "hdmi_force_edid_audio=1" >> ./boot/config.txt.bak
sudo echo "dtparam=i2c_arm=on" >> ./boot/config.txt.bak
sudo echo "dtparam=spi=on" >> ./boot/config.txt.bak
sudo echo "enable_uart=1" >> ./boot/config.txt.bak
sudo echo "display_rotate=0" >> ./boot/config.txt.bak
sudo echo "max_framebuffer_height=1920" >> ./boot/config.txt.bak
sudo echo "max_usb_current=1" >> ./boot/config.txt.bak
sudo echo "config_hdmi_boost=7" >> ./boot/config.txt.bak
sudo echo "hdmi_group=2" >> ./boot/config.txt.bak
sudo echo "hdmi_mode=87" >> ./boot/config.txt.bak
sudo echo "hdmi_drive=1" >> ./boot/config.txt.bak
sudo echo "hdmi_cvt 1920 1080 60 6 0 0 0" >> ./boot/config.txt.bak
sudo cp -rf ./boot/config.txt.bak /boot/config.txt
#if test "$root_dev" = "/dev/mmcblk0p7";then
#sudo cp ./usr/cmdline.txt-noobs /boot/cmdline.txt
#else
#sudo cp ./usr/cmdline.txt /boot/
#fi
sudo cp ./usr/inittab /etc/
sudo cp -rf ./usr/99-fbturbo.conf-HDMI /usr/share/X11/xorg.conf.d/99-fbturbo.conf
if [ ! -d /etc/X11/xorg.conf.d ]; then
sudo mkdir /etc/X11/xorg.conf.d
fi
sudo cp ./usr/40-libinput.conf-90 /etc/X11/xorg.conf.d/40-libinput.conf
sudo touch ./.have_installed
echo "hdmi:capacity:55-1920x1080:90:1920:1080" > ./.have_installed
sudo sync
sudo sync
sleep 1
if [ $# -eq 1 ]; then
sudo ./rotate.sh $1
elif [ $# -gt 1 ]; then
echo "Too many parameters"
fi
echo "reboot now"
sudo reboot

View File

@ -2,16 +2,13 @@
sudo ./system_backup.sh sudo ./system_backup.sh
#root_dev=`grep -oPr "root=[^\s]*" /boot/cmdline.txt | awk -F= '{printf $NF}'` root_dev=`grep -oPr "root=[^\s]*" /boot/cmdline.txt | awk -F= '{printf $NF}'`
#if test "$root_dev" = "/dev/mmcblk0p7";then if test "$root_dev" = "/dev/mmcblk0p7";then
#sudo cp -rf ./boot/config-noobs-nomal.txt ./boot/config.txt.bak sudo cp -rf ./boot/config-noobs-nomal.txt ./boot/config.txt.bak
#else else
#sudo cp -rf ./boot/config-nomal.txt ./boot/config.txt.bak sudo cp -rf ./boot/config-nomal.txt ./boot/config.txt.bak
#sudo echo "hdmi_force_hotplug=1" >> ./boot/config.txt.bak
#fi
source ./system_config.sh
sudo echo "hdmi_force_hotplug=1" >> ./boot/config.txt.bak sudo echo "hdmi_force_hotplug=1" >> ./boot/config.txt.bak
fi
sudo echo "dtparam=i2c_arm=on" >> ./boot/config.txt.bak sudo echo "dtparam=i2c_arm=on" >> ./boot/config.txt.bak
sudo echo "dtparam=spi=on" >> ./boot/config.txt.bak sudo echo "dtparam=spi=on" >> ./boot/config.txt.bak
sudo echo "enable_uart=1" >> ./boot/config.txt.bak sudo echo "enable_uart=1" >> ./boot/config.txt.bak
@ -19,16 +16,17 @@ sudo echo "display_rotate=0" >> ./boot/config.txt.bak
sudo echo "max_usb_current=1" >> ./boot/config.txt.bak sudo echo "max_usb_current=1" >> ./boot/config.txt.bak
sudo echo "config_hdmi_boost=7" >> ./boot/config.txt.bak sudo echo "config_hdmi_boost=7" >> ./boot/config.txt.bak
sudo echo "hdmi_group=2" >> ./boot/config.txt.bak sudo echo "hdmi_group=2" >> ./boot/config.txt.bak
sudo echo "hdmi_mode=1" >> ./boot/config.txt.bak
sudo echo "hdmi_mode=87" >> ./boot/config.txt.bak sudo echo "hdmi_mode=87" >> ./boot/config.txt.bak
sudo echo "hdmi_drive=1" >> ./boot/config.txt.bak sudo echo "hdmi_drive=1" >> ./boot/config.txt.bak
sudo echo "hdmi_cvt 800 480 60 6 0 0 0" >> ./boot/config.txt.bak sudo echo "hdmi_cvt 800 480 60 6 0 0 0" >> ./boot/config.txt.bak
sudo cp -rf ./boot/config.txt.bak /boot/config.txt sudo cp -rf ./boot/config.txt.bak /boot/config.txt
#sudo cp -rf ./boot/config-7B-800x480.txt /boot/config.txt #sudo cp -rf ./boot/config-7B-800x480.txt /boot/config.txt
#if test "$root_dev" = "/dev/mmcblk0p7";then if test "$root_dev" = "/dev/mmcblk0p7";then
#sudo cp ./usr/cmdline.txt-noobs /boot/cmdline.txt sudo cp ./usr/cmdline.txt-noobs /boot/cmdline.txt
#else else
#sudo cp ./usr/cmdline.txt /boot/ sudo cp ./usr/cmdline.txt /boot/
#fi fi
sudo cp ./usr/inittab /etc/ sudo cp ./usr/inittab /etc/
sudo cp -rf ./usr/99-fbturbo.conf-HDMI /usr/share/X11/xorg.conf.d/99-fbturbo.conf sudo cp -rf ./usr/99-fbturbo.conf-HDMI /usr/share/X11/xorg.conf.d/99-fbturbo.conf

View File

@ -2,16 +2,13 @@
sudo ./system_backup.sh sudo ./system_backup.sh
#root_dev=`grep -oPr "root=[^\s]*" /boot/cmdline.txt | awk -F= '{printf $NF}'` root_dev=`grep -oPr "root=[^\s]*" /boot/cmdline.txt | awk -F= '{printf $NF}'`
#if test "$root_dev" = "/dev/mmcblk0p7";then if test "$root_dev" = "/dev/mmcblk0p7";then
#sudo cp -rf ./boot/config-noobs-nomal.txt ./boot/config.txt.bak sudo cp -rf ./boot/config-noobs-nomal.txt ./boot/config.txt.bak
#else else
#sudo cp -rf ./boot/config-nomal.txt ./boot/config.txt.bak sudo cp -rf ./boot/config-nomal.txt ./boot/config.txt.bak
#sudo echo "hdmi_force_hotplug=1" >> ./boot/config.txt.bak
#fi
source ./system_config.sh
sudo echo "hdmi_force_hotplug=1" >> ./boot/config.txt.bak sudo echo "hdmi_force_hotplug=1" >> ./boot/config.txt.bak
fi
sudo echo "dtparam=i2c_arm=on" >> ./boot/config.txt.bak sudo echo "dtparam=i2c_arm=on" >> ./boot/config.txt.bak
sudo echo "dtparam=spi=on" >> ./boot/config.txt.bak sudo echo "dtparam=spi=on" >> ./boot/config.txt.bak
sudo echo "enable_uart=1" >> ./boot/config.txt.bak sudo echo "enable_uart=1" >> ./boot/config.txt.bak
@ -19,16 +16,17 @@ sudo echo "display_rotate=0" >> ./boot/config.txt.bak
sudo echo "max_usb_current=1" >> ./boot/config.txt.bak sudo echo "max_usb_current=1" >> ./boot/config.txt.bak
sudo echo "config_hdmi_boost=7" >> ./boot/config.txt.bak sudo echo "config_hdmi_boost=7" >> ./boot/config.txt.bak
sudo echo "hdmi_group=2" >> ./boot/config.txt.bak sudo echo "hdmi_group=2" >> ./boot/config.txt.bak
sudo echo "hdmi_mode=1" >> ./boot/config.txt.bak
sudo echo "hdmi_mode=87" >> ./boot/config.txt.bak sudo echo "hdmi_mode=87" >> ./boot/config.txt.bak
sudo echo "hdmi_drive=1" >> ./boot/config.txt.bak sudo echo "hdmi_drive=1" >> ./boot/config.txt.bak
sudo echo "hdmi_cvt 1024 600 60 6 0 0 0" >> ./boot/config.txt.bak sudo echo "hdmi_cvt 1024 600 60 6 0 0 0" >> ./boot/config.txt.bak
sudo cp -rf ./boot/config.txt.bak /boot/config.txt sudo cp -rf ./boot/config.txt.bak /boot/config.txt
#sudo cp -rf ./boot/config-7C-1024x600.txt /boot/config.txt #sudo cp -rf ./boot/config-7C-1024x600.txt /boot/config.txt
#if test "$root_dev" = "/dev/mmcblk0p7";then if test "$root_dev" = "/dev/mmcblk0p7";then
#sudo cp ./usr/cmdline.txt-noobs /boot/cmdline.txt sudo cp ./usr/cmdline.txt-noobs /boot/cmdline.txt
#else else
#sudo cp ./usr/cmdline.txt /boot/ sudo cp ./usr/cmdline.txt /boot/
#fi fi
sudo cp ./usr/inittab /etc/ sudo cp ./usr/inittab /etc/
sudo cp -rf ./usr/99-fbturbo.conf-HDMI /usr/share/X11/xorg.conf.d/99-fbturbo.conf sudo cp -rf ./usr/99-fbturbo.conf-HDMI /usr/share/X11/xorg.conf.d/99-fbturbo.conf

View File

@ -1,52 +0,0 @@
#!/bin/bash
sudo ./system_backup.sh
#root_dev=`grep -oPr "root=[^\s]*" /boot/cmdline.txt | awk -F= '{printf $NF}'`
#if test "$root_dev" = "/dev/mmcblk0p7";then
#sudo cp -rf ./boot/config-noobs-nomal.txt ./boot/config.txt.bak
#else
#sudo cp -rf ./boot/config-nomal.txt ./boot/config.txt.bak
#sudo echo "hdmi_force_hotplug=1" >> ./boot/config.txt.bak
#fi
source ./system_config.sh
sudo echo "hdmi_force_hotplug=1" >> ./boot/config.txt.bak
sudo echo "hdmi_force_edid_audio=1" >> ./boot/config.txt.bak
sudo echo "dtparam=i2c_arm=on" >> ./boot/config.txt.bak
sudo echo "dtparam=spi=on" >> ./boot/config.txt.bak
sudo echo "enable_uart=1" >> ./boot/config.txt.bak
sudo echo "display_rotate=0" >> ./boot/config.txt.bak
sudo echo "max_usb_current=1" >> ./boot/config.txt.bak
sudo echo "config_hdmi_boost=7" >> ./boot/config.txt.bak
sudo echo "hdmi_group=2" >> ./boot/config.txt.bak
sudo echo "hdmi_mode=87" >> ./boot/config.txt.bak
sudo echo "hdmi_drive=2" >> ./boot/config.txt.bak
sudo echo "hdmi_cvt 1024 600 60 6 0 0 0" >> ./boot/config.txt.bak
sudo cp -rf ./boot/config.txt.bak /boot/config.txt
#sudo cp -rf ./boot/config-7C-1024x600.txt /boot/config.txt
#if test "$root_dev" = "/dev/mmcblk0p7";then
#sudo cp ./usr/cmdline.txt-noobs /boot/cmdline.txt
#else
#sudo cp ./usr/cmdline.txt /boot/
#fi
sudo cp ./usr/inittab /etc/
sudo cp -rf ./usr/99-fbturbo.conf-HDMI /usr/share/X11/xorg.conf.d/99-fbturbo.conf
if [ ! -d /etc/X11/xorg.conf.d ]; then
sudo mkdir /etc/X11/xorg.conf.d
fi
sudo cp ./usr/40-libinput.conf-0 /etc/X11/xorg.conf.d/40-libinput.conf
sudo touch ./.have_installed
echo "hdmi:capacity:7H-1024x600:0:1024:600" > ./.have_installed
sudo sync
sudo sync
sleep 1
if [ $# -eq 1 ]; then
sudo ./rotate.sh $1
elif [ $# -gt 1 ]; then
echo "Too many parameters"
fi
echo "reboot now"
sudo reboot

View File

@ -1,52 +0,0 @@
#!/bin/bash
sudo ./system_backup.sh
#root_dev=`grep -oPr "root=[^\s]*" /boot/cmdline.txt | awk -F= '{printf $NF}'`
#if test "$root_dev" = "/dev/mmcblk0p7";then
#sudo cp -rf ./boot/config-noobs-nomal.txt ./boot/config.txt.bak
#else
#sudo cp -rf ./boot/config-nomal.txt ./boot/config.txt.bak
#sudo echo "hdmi_force_hotplug=1" >> ./boot/config.txt.bak
#fi
source ./system_config.sh
sudo echo "hdmi_force_hotplug=1" >> ./boot/config.txt.bak
sudo echo "hdmi_force_edid_audio=1" >> ./boot/config.txt.bak
sudo echo "dtparam=i2c_arm=on" >> ./boot/config.txt.bak
sudo echo "dtparam=spi=on" >> ./boot/config.txt.bak
sudo echo "enable_uart=1" >> ./boot/config.txt.bak
sudo echo "display_rotate=0" >> ./boot/config.txt.bak
sudo echo "max_usb_current=1" >> ./boot/config.txt.bak
sudo echo "config_hdmi_boost=7" >> ./boot/config.txt.bak
sudo echo "hdmi_group=2" >> ./boot/config.txt.bak
sudo echo "hdmi_mode=87" >> ./boot/config.txt.bak
sudo echo "hdmi_drive=2" >> ./boot/config.txt.bak
sudo echo "hdmi_cvt 1024 600 60 6 0 0 0" >> ./boot/config.txt.bak
sudo cp -rf ./boot/config.txt.bak /boot/config.txt
#sudo cp -rf ./boot/config-7C-1024x600.txt /boot/config.txt
#if test "$root_dev" = "/dev/mmcblk0p7";then
#sudo cp ./usr/cmdline.txt-noobs /boot/cmdline.txt
#else
#sudo cp ./usr/cmdline.txt /boot/
#fi
sudo cp ./usr/inittab /etc/
sudo cp -rf ./usr/99-fbturbo.conf-HDMI /usr/share/X11/xorg.conf.d/99-fbturbo.conf
if [ ! -d /etc/X11/xorg.conf.d ]; then
sudo mkdir /etc/X11/xorg.conf.d
fi
sudo cp ./usr/40-libinput.conf-0 /etc/X11/xorg.conf.d/40-libinput.conf
sudo touch ./.have_installed
echo "hdmi:capacity:7S-1024x600:0:1024:600" > ./.have_installed
sudo sync
sudo sync
sleep 1
if [ $# -eq 1 ]; then
sudo ./rotate.sh $1
elif [ $# -gt 1 ]; then
echo "Too many parameters"
fi
echo "reboot now"
sudo reboot

View File

@ -10,16 +10,13 @@ sudo mkdir -p /etc/X11/xorg.conf.d
fi fi
sudo cp ./usr/mhs32-overlay.dtb /boot/overlays/ sudo cp ./usr/mhs32-overlay.dtb /boot/overlays/
sudo cp ./usr/mhs32-overlay.dtb /boot/overlays/mhs32.dtbo sudo cp ./usr/mhs32-overlay.dtb /boot/overlays/mhs32.dtbo
#root_dev=`grep -oPr "root=[^\s]*" /boot/cmdline.txt | awk -F= '{printf $NF}'` root_dev=`grep -oPr "root=[^\s]*" /boot/cmdline.txt | awk -F= '{printf $NF}'`
#if test "$root_dev" = "/dev/mmcblk0p7";then if test "$root_dev" = "/dev/mmcblk0p7";then
#sudo cp -rf ./boot/config-noobs-nomal.txt ./boot/config.txt.bak sudo cp -rf ./boot/config-noobs-nomal.txt ./boot/config.txt.bak
#else else
#sudo cp -rf ./boot/config-nomal.txt ./boot/config.txt.bak sudo cp -rf ./boot/config-nomal.txt ./boot/config.txt.bak
#sudo echo "hdmi_force_hotplug=1" >> ./boot/config.txt.bak
#fi
source ./system_config.sh
sudo echo "hdmi_force_hotplug=1" >> ./boot/config.txt.bak sudo echo "hdmi_force_hotplug=1" >> ./boot/config.txt.bak
fi
sudo echo "dtparam=i2c_arm=on" >> ./boot/config.txt.bak sudo echo "dtparam=i2c_arm=on" >> ./boot/config.txt.bak
sudo echo "dtparam=spi=on" >> ./boot/config.txt.bak sudo echo "dtparam=spi=on" >> ./boot/config.txt.bak
sudo echo "enable_uart=1" >> ./boot/config.txt.bak sudo echo "enable_uart=1" >> ./boot/config.txt.bak
@ -27,70 +24,45 @@ sudo echo "dtoverlay=mhs32:rotate=270" >> ./boot/config.txt.bak
sudo echo "hdmi_group=2" >> ./boot/config.txt.bak sudo echo "hdmi_group=2" >> ./boot/config.txt.bak
sudo echo "hdmi_mode=1" >> ./boot/config.txt.bak sudo echo "hdmi_mode=1" >> ./boot/config.txt.bak
sudo echo "hdmi_mode=87" >> ./boot/config.txt.bak sudo echo "hdmi_mode=87" >> ./boot/config.txt.bak
sudo echo "hdmi_cvt 480 360 60 6 0 0 0" >> ./boot/config.txt.bak sudo echo "hdmi_cvt 480 320 60 6 0 0 0" >> ./boot/config.txt.bak
sudo echo "hdmi_drive=2" >> ./boot/config.txt.bak sudo echo "hdmi_drive=2" >> ./boot/config.txt.bak
sudo cp -rf ./boot/config.txt.bak /boot/config.txt sudo cp -rf ./boot/config.txt.bak /boot/config.txt
sudo cp -rf ./usr/99-calibration.conf-mhs32-270 /etc/X11/xorg.conf.d/99-calibration.conf sudo cp -rf ./usr/99-calibration.conf-mhs32-270 /etc/X11/xorg.conf.d/99-calibration.conf
sudo cp -rf ./usr/99-fbturbo.conf /usr/share/X11/xorg.conf.d/99-fbturbo.conf sudo cp -rf ./usr/99-fbturbo.conf /usr/share/X11/xorg.conf.d/99-fbturbo.conf
#if test "$root_dev" = "/dev/mmcblk0p7";then if test "$root_dev" = "/dev/mmcblk0p7";then
#sudo cp ./usr/cmdline.txt-noobs /boot/cmdline.txt sudo cp ./usr/cmdline.txt-noobs /boot/cmdline.txt
#else else
#sudo cp ./usr/cmdline.txt /boot/ sudo cp ./usr/cmdline.txt /boot/
#fi fi
sudo cp ./usr/inittab /etc/ sudo cp ./usr/inittab /etc/
#sudo cp ./boot/config-mhs32.txt /boot/config.txt #sudo cp ./boot/config-mhs32.txt /boot/config.txt
sudo touch ./.have_installed sudo touch ./.have_installed
echo "gpio:resistance:mhs32:270:480:360" > ./.have_installed echo "gpio:resistance:mhs32:270:480:320" > ./.have_installed
sudo apt-get update
#FBCP install #FBCP install
wget --spider -q -o /dev/null --tries=1 -T 10 https://cmake.org/
if [ $? -eq 0 ]; then
#sudo apt-get update
sudo apt-get install cmake -y 2> error_output.txt
result=`cat ./error_output.txt`
echo -e "\033[31m$result\033[0m"
grep -q "^E:" ./error_output.txt
type cmake > /dev/null 2>&1
if [ $? -eq 0 ]; then
sudo rm -rf rpi-fbcp
wget --spider -q -o /dev/null --tries=1 -T 10 https://github.com wget --spider -q -o /dev/null --tries=1 -T 10 https://github.com
if [ $? -eq 0 ]; then if [ $? -eq 0 ]; then
sudo cp -rf ./usr/99-fbturbo-fbcp.conf /usr/share/X11/xorg.conf.d/99-fbturbo.conf
sudo cp -rf ./etc/rc.local /etc/rc.local
sudo apt-get install git cmake -y 2> error_output.txt
result=`cat ./error_output.txt`
echo -e "\033[31m$result\033[0m"
grep -q "^E:" ./error_output.txt && exit
sudo rm -rf rpi-fbcp
sudo git clone https://github.com/tasanakorn/rpi-fbcp sudo git clone https://github.com/tasanakorn/rpi-fbcp
if [ $? -ne 0 ]; then
echo "download fbcp failed, copy native fbcp!!!"
sudo cp -r ./usr/rpi-fbcp .
fi
else
echo "bad network, copy native fbcp!!!"
sudo cp -r ./usr/rpi-fbcp .
fi
sudo mkdir ./rpi-fbcp/build sudo mkdir ./rpi-fbcp/build
cd ./rpi-fbcp/build/ cd ./rpi-fbcp/build/
sudo cmake .. sudo cmake ..
sudo make sudo make
sudo install fbcp /usr/local/bin/fbcp sudo install fbcp /usr/local/bin/fbcp
cd - > /dev/null cd - > /dev/null
type fbcp > /dev/null 2>&1
if [ $? -eq 0 ]; then
sudo cp -rf ./usr/99-fbturbo-fbcp.conf /usr/share/X11/xorg.conf.d/99-fbturbo.conf
sudo cp -rf ./etc/rc.local /etc/rc.local
fi fi
else
echo "install cmake error!!!!"
fi
else
echo "bad network, can't install cmake!!!"
fi
#evdev install #evdev install
#nodeplatform=`uname -n` #nodeplatform=`uname -n`
#kernel=`uname -r` #kernel=`uname -r`
version=`uname -v` version=`uname -v`
#if test "$nodeplatform" = "raspberrypi";then #if test "$nodeplatform" = "raspberrypi";then
#echo "this is raspberrypi kernel" #echo "this is raspberrypi kernel"
input_result=0
version=${version##* } version=${version##* }
#version=${version#*#} #version=${version#*#}
echo $version echo $version
@ -98,23 +70,8 @@ if test $version -lt 2017;then
echo "reboot" echo "reboot"
else else
echo "need to update touch configuration" echo "need to update touch configuration"
wget --spider -q -o /dev/null --tries=1 -T 10 http://mirrors.zju.edu.cn/raspbian/raspbian sudo dpkg -i -B ./xserver-xorg-input-evdev_2.10.5-1_armhf.deb 2> error_output.txt
if [ $? -ne 0 ]; then #sudo apt-get install xserver-xorg-input-evdev 2> error_output.txt
input_result=1
else
sudo apt-get install xserver-xorg-input-evdev 2> error_output.txt
dpkg -l | grep xserver-xorg-input-evdev > /dev/null 2>&1
if [ $? -ne 0 ]; then
input_result=1
fi
fi
if [ $input_result -eq 1 ]; then
if [ $hardware_arch -eq 32 ]; then
sudo dpkg -i -B ./xserver-xorg-input-evdev_1%3a2.10.6-1+b1_armhf.deb 2> error_output.txt
elif [ $hardware_arch -eq 64 ]; then
sudo dpkg -i -B ./xserver-xorg-input-evdev_1%3a2.10.6-2_arm64.deb 2> error_output.txt
fi
fi
result=`cat ./error_output.txt` result=`cat ./error_output.txt`
echo -e "\033[31m$result\033[0m" echo -e "\033[31m$result\033[0m"
grep -q "error:" ./error_output.txt && exit grep -q "error:" ./error_output.txt && exit

View File

@ -11,16 +11,15 @@ fi
sudo cp ./usr/mhs35-overlay.dtb /boot/overlays/ sudo cp ./usr/mhs35-overlay.dtb /boot/overlays/
sudo cp ./usr/mhs35-overlay.dtb /boot/overlays/mhs35.dtbo sudo cp ./usr/mhs35-overlay.dtb /boot/overlays/mhs35.dtbo
#root_dev=`grep -oPr "root=[^\s]*" /boot/cmdline.txt | awk -F= '{printf $NF}'` hw_version=`tr -d '\0' < /proc/device-tree/model`
#if test "$root_dev" = "/dev/mmcblk0p7";then root_dev=`grep -oPr "root=[^\s]*" /boot/cmdline.txt | awk -F= '{printf $NF}'`
#sudo cp -rf ./boot/config-noobs-nomal.txt ./boot/config.txt.bak if test "$root_dev" = "/dev/mmcblk0p7";then
#else sudo cp -rf ./boot/config-noobs-nomal.txt ./boot/config.txt.bak
#sudo cp -rf ./boot/config-nomal.txt ./boot/config.txt.bak else
#sudo echo "hdmi_force_hotplug=1" >> ./boot/config.txt.bak sudo cp -rf ./boot/config-nomal.txt ./boot/config.txt.bak
#fi
source ./system_config.sh
sudo echo "hdmi_force_hotplug=1" >> ./boot/config.txt.bak sudo echo "hdmi_force_hotplug=1" >> ./boot/config.txt.bak
fi
[[ $hw_version =~ "Raspberry Pi 4 Model" ]] || (sed -i 's/^dtoverlay=/#&/g' ./boot/config.txt.bak;sed -i 's/^max_framebuffers=/#&/g' ./boot/config.txt.bak)
sudo echo "dtparam=i2c_arm=on" >> ./boot/config.txt.bak sudo echo "dtparam=i2c_arm=on" >> ./boot/config.txt.bak
sudo echo "dtparam=spi=on" >> ./boot/config.txt.bak sudo echo "dtparam=spi=on" >> ./boot/config.txt.bak
sudo echo "enable_uart=1" >> ./boot/config.txt.bak sudo echo "enable_uart=1" >> ./boot/config.txt.bak
@ -34,63 +33,40 @@ sudo cp -rf ./boot/config.txt.bak /boot/config.txt
sudo cp -rf ./usr/99-calibration.conf-mhs35-90 /etc/X11/xorg.conf.d/99-calibration.conf sudo cp -rf ./usr/99-calibration.conf-mhs35-90 /etc/X11/xorg.conf.d/99-calibration.conf
sudo cp -rf ./usr/99-fbturbo.conf /usr/share/X11/xorg.conf.d/99-fbturbo.conf sudo cp -rf ./usr/99-fbturbo.conf /usr/share/X11/xorg.conf.d/99-fbturbo.conf
#if test "$root_dev" = "/dev/mmcblk0p7";then if test "$root_dev" = "/dev/mmcblk0p7";then
#sudo cp ./usr/cmdline.txt-noobs /boot/cmdline.txt sudo cp ./usr/cmdline.txt-noobs /boot/cmdline.txt
#else else
#sudo cp ./usr/cmdline.txt /boot/ sudo cp ./usr/cmdline.txt /boot/
#fi fi
sudo cp ./usr/inittab /etc/ sudo cp ./usr/inittab /etc/
#sudo cp ./boot/config-mhs35.txt /boot/config.txt #sudo cp ./boot/config-mhs35.txt /boot/config.txt
sudo touch ./.have_installed sudo touch ./.have_installed
echo "gpio:resistance:mhs35:90:480:320" > ./.have_installed echo "gpio:resistance:mhs35:90:480:320" > ./.have_installed
sudo apt-get update
#FBCP install #FBCP install
wget --spider -q -o /dev/null --tries=1 -T 10 https://cmake.org/
if [ $? -eq 0 ]; then
sudo apt-get install cmake -y 2> error_output.txt
result=`cat ./error_output.txt`
echo -e "\033[31m$result\033[0m"
grep -q "^E:" ./error_output.txt
type cmake > /dev/null 2>&1
if [ $? -eq 0 ]; then
sudo rm -rf rpi-fbcp
wget --spider -q -o /dev/null --tries=1 -T 10 https://github.com wget --spider -q -o /dev/null --tries=1 -T 10 https://github.com
if [ $? -eq 0 ]; then if [ $? -eq 0 ]; then
sudo cp -rf ./usr/99-fbturbo-fbcp.conf /usr/share/X11/xorg.conf.d/99-fbturbo.conf
sudo cp -rf ./etc/rc.local /etc/rc.local
sudo apt-get install git cmake -y 2> error_output.txt
result=`cat ./error_output.txt`
echo -e "\033[31m$result\033[0m"
grep -q "^E:" ./error_output.txt && exit
sudo rm -rf rpi-fbcp
sudo git clone https://github.com/tasanakorn/rpi-fbcp sudo git clone https://github.com/tasanakorn/rpi-fbcp
if [ $? -ne 0 ]; then
echo "download fbcp failed, copy native fbcp!!!"
sudo cp -r ./usr/rpi-fbcp .
fi
else
echo "bad network, copy native fbcp!!!"
sudo cp -r ./usr/rpi-fbcp .
fi
sudo mkdir ./rpi-fbcp/build sudo mkdir ./rpi-fbcp/build
cd ./rpi-fbcp/build/ cd ./rpi-fbcp/build/
sudo cmake .. sudo cmake ..
sudo make sudo make
sudo install fbcp /usr/local/bin/fbcp sudo install fbcp /usr/local/bin/fbcp
cd - > /dev/null cd - > /dev/null
type fbcp > /dev/null 2>&1
if [ $? -eq 0 ]; then
sudo cp -rf ./usr/99-fbturbo-fbcp.conf /usr/share/X11/xorg.conf.d/99-fbturbo.conf
sudo cp -rf ./etc/rc.local /etc/rc.local
fi fi
else
echo "install cmake error!!!!"
fi
else
echo "bad network, can't install cmake!!!"
fi
#evdev install #evdev install
#nodeplatform=`uname -n` #nodeplatform=`uname -n`
#kernel=`uname -r` #kernel=`uname -r`
version=`uname -v` version=`uname -v`
#if test "$nodeplatform" = "raspberrypi";then #if test "$nodeplatform" = "raspberrypi";then
#echo "this is raspberrypi kernel" #echo "this is raspberrypi kernel"
input_result=0
version=${version##* } version=${version##* }
#version=${version#*#} #version=${version#*#}
echo $version echo $version
@ -98,31 +74,17 @@ if test $version -lt 2017;then
echo "reboot" echo "reboot"
else else
echo "need to update touch configuration" echo "need to update touch configuration"
wget --spider -q -o /dev/null --tries=1 -T 10 http://mirrors.zju.edu.cn/raspbian/raspbian sudo dpkg -i -B ./xserver-xorg-input-evdev_2.10.5-1_armhf.deb 2> error_output.txt
if [ $? -ne 0 ]; then #sudo apt-get install xserver-xorg-input-evdev 2> error_output.txt
input_result=1
else
sudo apt-get install xserver-xorg-input-evdev 2> error_output.txt
dpkg -l | grep xserver-xorg-input-evdev > /dev/null 2>&1
if [ $? -ne 0 ]; then
input_result=1
fi
fi
if [ $input_result -eq 1 ]; then
if [ $hardware_arch -eq 32 ]; then
sudo dpkg -i -B ./xserver-xorg-input-evdev_1%3a2.10.6-1+b1_armhf.deb 2> error_output.txt
elif [ $hardware_arch -eq 64 ]; then
sudo dpkg -i -B ./xserver-xorg-input-evdev_1%3a2.10.6-2_arm64.deb 2> error_output.txt
fi
fi
result=`cat ./error_output.txt` result=`cat ./error_output.txt`
echo -e "\033[31m$result\033[0m" echo -e "\033[31m$result\033[0m"
grep -q "error:" ./error_output.txt && exit grep -q "error:" ./error_output.txt && exit
sudo cp -rf /usr/share/X11/xorg.conf.d/10-evdev.conf /usr/share/X11/xorg.conf.d/45-evdev.conf sudo cp -rf /usr/share/X11/xorg.conf.d/10-evdev.conf /usr/share/X11/xorg.conf.d/45-evdev.conf
#echo "reboot" #echo "reboot"
fi
#else #else
#echo "this is not raspberrypi kernel, no need to update touch configure, reboot" #echo "this is not raspberrypi kernel, no need to update touch configure, reboot"
fi #fi
sudo sync sudo sync
sudo sync sudo sync

View File

@ -1,144 +0,0 @@
#!/bin/bash
sudo ./system_backup.sh
if [ -f /etc/X11/xorg.conf.d/40-libinput.conf ]; then
sudo rm -rf /etc/X11/xorg.conf.d/40-libinput.conf
fi
if [ ! -d /etc/X11/xorg.conf.d ]; then
sudo mkdir -p /etc/X11/xorg.conf.d
fi
sudo cp ./usr/mhs35b-overlay.dtb /boot/overlays/
sudo cp ./usr/mhs35b-overlay.dtb /boot/overlays/mhs35b.dtbo
#root_dev=`grep -oPr "root=[^\s]*" /boot/cmdline.txt | awk -F= '{printf $NF}'`
#if test "$root_dev" = "/dev/mmcblk0p7";then
#sudo cp -rf ./boot/config-noobs-nomal.txt ./boot/config.txt.bak
#else
#sudo cp -rf ./boot/config-nomal.txt ./boot/config.txt.bak
#sudo echo "hdmi_force_hotplug=1" >> ./boot/config.txt.bak
#fi
source ./system_config.sh
sudo echo "hdmi_force_hotplug=1" >> ./boot/config.txt.bak
sudo echo "dtparam=i2c_arm=on" >> ./boot/config.txt.bak
sudo echo "dtparam=spi=on" >> ./boot/config.txt.bak
sudo echo "enable_uart=1" >> ./boot/config.txt.bak
sudo echo "dtoverlay=mhs35b:rotate=90" >> ./boot/config.txt.bak
sudo echo "dtoverlay=goodix" >> ./boot/config.txt.bak
sudo echo "hdmi_group=2" >> ./boot/config.txt.bak
sudo echo "hdmi_mode=1" >> ./boot/config.txt.bak
sudo echo "hdmi_mode=87" >> ./boot/config.txt.bak
sudo echo "hdmi_cvt 480 320 60 6 0 0 0" >> ./boot/config.txt.bak
sudo echo "hdmi_drive=2" >> ./boot/config.txt.bak
sudo cp -rf ./boot/config.txt.bak /boot/config.txt
if [ -f /boot/overlays/goodix.dtbo ]; then
sudo mv /boot/overlays/goodix.dtbo /boot/overlays/goodix.dtbo.bak
sudo cp ./usr/goodix.dtbo /boot/overlays/
fi
sudo cp -rf ./usr/99-calibration.conf-mhs35b-90 /etc/X11/xorg.conf.d/99-calibration.conf
sudo cp -rf ./usr/99-fbturbo.conf /usr/share/X11/xorg.conf.d/99-fbturbo.conf
#if test "$root_dev" = "/dev/mmcblk0p7";then
#sudo cp ./usr/cmdline.txt-noobs /boot/cmdline.txt
#else
#sudo cp ./usr/cmdline.txt /boot/
#fi
sudo cp ./usr/inittab /etc/
sudo touch ./.have_installed
echo "gpio:resistance:mhs35b:90:480:320" > ./.have_installed
sudo apt-get update
#FBCP install
wget --spider -q -o /dev/null --tries=1 -T 10 https://cmake.org/
if [ $? -eq 0 ]; then
#sudo apt-get update
sudo apt-get install cmake -y 2> error_output.txt
result=`cat ./error_output.txt`
echo -e "\033[31m$result\033[0m"
grep -q "^E:" ./error_output.txt
type cmake > /dev/null 2>&1
if [ $? -eq 0 ]; then
sudo rm -rf rpi-fbcp
wget --spider -q -o /dev/null --tries=1 -T 10 https://github.com
if [ $? -eq 0 ]; then
sudo git clone https://github.com/tasanakorn/rpi-fbcp
if [ $? -ne 0 ]; then
echo "download fbcp failed, copy native fbcp!!!"
sudo cp -r ./usr/rpi-fbcp .
fi
else
echo "bad network, copy native fbcp!!!"
sudo cp -r ./usr/rpi-fbcp .
fi
sudo mkdir ./rpi-fbcp/build
cd ./rpi-fbcp/build/
sudo cmake ..
sudo make
sudo install fbcp /usr/local/bin/fbcp
cd - > /dev/null
type fbcp > /dev/null 2>&1
if [ $? -eq 0 ]; then
sudo cp -rf ./usr/99-fbturbo-fbcp.conf /usr/share/X11/xorg.conf.d/99-fbturbo.conf
sudo cp -rf ./etc/rc.local /etc/rc.local
fi
else
echo "install cmake error!!!!"
fi
else
echo "bad network, can't install cmake!!!"
fi
#evdev install
#nodeplatform=`uname -n`
#kernel=`uname -r`
version=`uname -v`
#if test "$nodeplatform" = "raspberrypi";then
#echo "this is raspberrypi kernel"
input_result=0
version=${version##* }
#version=${version#*#}
echo $version
if test $version -lt 2017;then
echo "reboot"
else
echo "need to update touch configuration"
wget --spider -q -o /dev/null --tries=1 -T 10 http://mirrors.zju.edu.cn/raspbian/raspbian
if [ $? -ne 0 ]; then
input_result=1
else
sudo apt-get install xserver-xorg-input-evdev 2> error_output.txt
dpkg -l | grep xserver-xorg-input-evdev > /dev/null 2>&1
if [ $? -ne 0 ]; then
input_result=1
fi
fi
if [ $input_result -eq 1 ]; then
if [ $hardware_arch -eq 32 ]; then
sudo dpkg -i -B ./xserver-xorg-input-evdev_1%3a2.10.6-1+b1_armhf.deb 2> error_output.txt
elif [ $hardware_arch -eq 64 ]; then
sudo dpkg -i -B ./xserver-xorg-input-evdev_1%3a2.10.6-2_arm64.deb 2> error_output.txt
fi
fi
result=`cat ./error_output.txt`
echo -e "\033[31m$result\033[0m"
grep -q "error:" ./error_output.txt && exit
sudo cp -rf /usr/share/X11/xorg.conf.d/10-evdev.conf /usr/share/X11/xorg.conf.d/45-evdev.conf
#echo "reboot"
fi
#else
#echo "this is not raspberrypi kernel, no need to update touch configure, reboot"
#fi
sudo sync
sudo sync
sleep 1
if [ $# -eq 1 ]; then
sudo ./rotate.sh $1
elif [ $# -gt 1 ]; then
echo "Too many parameters"
fi
echo "reboot now"
sudo reboot

View File

@ -1,137 +0,0 @@
#!/bin/bash
sudo ./system_backup.sh
if [ -f /etc/X11/xorg.conf.d/40-libinput.conf ]; then
sudo rm -rf /etc/X11/xorg.conf.d/40-libinput.conf
fi
if [ ! -d /etc/X11/xorg.conf.d ]; then
sudo mkdir -p /etc/X11/xorg.conf.d
fi
sudo cp ./usr/mhs35ips-overlay.dtb /boot/overlays/
sudo cp ./usr/mhs35ips-overlay.dtb /boot/overlays/mhs35ips.dtbo
#root_dev=`grep -oPr "root=[^\s]*" /boot/cmdline.txt | awk -F= '{printf $NF}'`
#if test "$root_dev" = "/dev/mmcblk0p7";then
#sudo cp -rf ./boot/config-noobs-nomal.txt ./boot/config.txt.bak
#else
#sudo cp -rf ./boot/config-nomal.txt ./boot/config.txt.bak
#sudo echo "hdmi_force_hotplug=1" >> ./boot/config.txt.bak
#fi
source ./system_config.sh
sudo echo "hdmi_force_hotplug=1" >> ./boot/config.txt.bak
sudo echo "dtparam=i2c_arm=on" >> ./boot/config.txt.bak
sudo echo "dtparam=spi=on" >> ./boot/config.txt.bak
sudo echo "enable_uart=1" >> ./boot/config.txt.bak
sudo echo "dtoverlay=mhs35ips:rotate=90" >> ./boot/config.txt.bak
sudo echo "hdmi_group=2" >> ./boot/config.txt.bak
sudo echo "hdmi_mode=1" >> ./boot/config.txt.bak
sudo echo "hdmi_mode=87" >> ./boot/config.txt.bak
sudo echo "hdmi_cvt 480 320 60 6 0 0 0" >> ./boot/config.txt.bak
sudo echo "hdmi_drive=2" >> ./boot/config.txt.bak
sudo cp -rf ./boot/config.txt.bak /boot/config.txt
sudo cp -rf ./usr/99-calibration.conf-mhs35ips-90 /etc/X11/xorg.conf.d/99-calibration.conf
sudo cp -rf ./usr/99-fbturbo.conf /usr/share/X11/xorg.conf.d/99-fbturbo.conf
#if test "$root_dev" = "/dev/mmcblk0p7";then
#sudo cp ./usr/cmdline.txt-noobs /boot/cmdline.txt
#else
#sudo cp ./usr/cmdline.txt /boot/
#fi
sudo cp ./usr/inittab /etc/
#sudo cp ./boot/config-mhs35.txt /boot/config.txt
sudo touch ./.have_installed
echo "gpio:resistance:mhs35ips:90:480:320" > ./.have_installed
sudo apt-get update
#FBCP install
wget --spider -q -o /dev/null --tries=1 -T 10 https://cmake.org/
if [ $? -eq 0 ]; then
sudo apt-get install cmake -y 2> error_output.txt
result=`cat ./error_output.txt`
echo -e "\033[31m$result\033[0m"
grep -q "^E:" ./error_output.txt
type cmake > /dev/null 2>&1
if [ $? -eq 0 ]; then
sudo rm -rf rpi-fbcp
wget --spider -q -o /dev/null --tries=1 -T 10 https://github.com
if [ $? -eq 0 ]; then
sudo git clone https://github.com/tasanakorn/rpi-fbcp
if [ $? -ne 0 ]; then
echo "download fbcp failed, copy native fbcp!!!"
sudo cp -r ./usr/rpi-fbcp .
fi
else
echo "bad network, copy native fbcp!!!"
sudo cp -r ./usr/rpi-fbcp .
fi
sudo mkdir ./rpi-fbcp/build
cd ./rpi-fbcp/build/
sudo cmake ..
sudo make
sudo install fbcp /usr/local/bin/fbcp
cd - > /dev/null
type fbcp > /dev/null 2>&1
if [ $? -eq 0 ]; then
sudo cp -rf ./usr/99-fbturbo-fbcp.conf /usr/share/X11/xorg.conf.d/99-fbturbo.conf
sudo cp -rf ./etc/rc.local /etc/rc.local
fi
else
echo "install cmake error!!!!"
fi
else
echo "bad network, can't install cmake!!!"
fi
#evdev install
#nodeplatform=`uname -n`
#kernel=`uname -r`
version=`uname -v`
#if test "$nodeplatform" = "raspberrypi";then
#echo "this is raspberrypi kernel"
input_result=0
version=${version##* }
#version=${version#*#}
echo $version
if test $version -lt 2017;then
echo "reboot"
else
echo "need to update touch configuration"
wget --spider -q -o /dev/null --tries=1 -T 10 http://mirrors.zju.edu.cn/raspbian/raspbian
if [ $? -ne 0 ]; then
input_result=1
else
sudo apt-get install xserver-xorg-input-evdev 2> error_output.txt
dpkg -l | grep xserver-xorg-input-evdev > /dev/null 2>&1
if [ $? -ne 0 ]; then
input_result=1
fi
fi
if [ $input_result -eq 1 ]; then
if [ $hardware_arch -eq 32 ]; then
sudo dpkg -i -B ./xserver-xorg-input-evdev_1%3a2.10.6-1+b1_armhf.deb 2> error_output.txt
elif [ $hardware_arch -eq 64 ]; then
sudo dpkg -i -B ./xserver-xorg-input-evdev_1%3a2.10.6-2_arm64.deb 2> error_output.txt
fi
fi
result=`cat ./error_output.txt`
echo -e "\033[31m$result\033[0m"
grep -q "error:" ./error_output.txt && exit
sudo cp -rf /usr/share/X11/xorg.conf.d/10-evdev.conf /usr/share/X11/xorg.conf.d/45-evdev.conf
#echo "reboot"
#else
#echo "this is not raspberrypi kernel, no need to update touch configure, reboot"
fi
sudo sync
sudo sync
sleep 1
if [ $# -eq 1 ]; then
sudo ./rotate.sh $1
elif [ $# -gt 1 ]; then
echo "Too many parameters"
fi
echo "reboot now"
sudo reboot

View File

@ -10,16 +10,13 @@ sudo mkdir -p /etc/X11/xorg.conf.d
fi fi
sudo cp ./usr/mhs395-overlay.dtb /boot/overlays/ sudo cp ./usr/mhs395-overlay.dtb /boot/overlays/
sudo cp ./usr/mhs395-overlay.dtb /boot/overlays/mhs395.dtbo sudo cp ./usr/mhs395-overlay.dtb /boot/overlays/mhs395.dtbo
#root_dev=`grep -oPr "root=[^\s]*" /boot/cmdline.txt | awk -F= '{printf $NF}'` root_dev=`grep -oPr "root=[^\s]*" /boot/cmdline.txt | awk -F= '{printf $NF}'`
#if test "$root_dev" = "/dev/mmcblk0p7";then if test "$root_dev" = "/dev/mmcblk0p7";then
#sudo cp -rf ./boot/config-noobs-nomal.txt ./boot/config.txt.bak sudo cp -rf ./boot/config-noobs-nomal.txt ./boot/config.txt.bak
#else else
#sudo cp -rf ./boot/config-nomal.txt ./boot/config.txt.bak sudo cp -rf ./boot/config-nomal.txt ./boot/config.txt.bak
#sudo echo "hdmi_force_hotplug=1" >> ./boot/config.txt.bak
#fi
source ./system_config.sh
sudo echo "hdmi_force_hotplug=1" >> ./boot/config.txt.bak sudo echo "hdmi_force_hotplug=1" >> ./boot/config.txt.bak
fi
sudo echo "dtparam=i2c_arm=on" >> ./boot/config.txt.bak sudo echo "dtparam=i2c_arm=on" >> ./boot/config.txt.bak
sudo echo "dtparam=spi=on" >> ./boot/config.txt.bak sudo echo "dtparam=spi=on" >> ./boot/config.txt.bak
sudo echo "enable_uart=1" >> ./boot/config.txt.bak sudo echo "enable_uart=1" >> ./boot/config.txt.bak
@ -32,64 +29,40 @@ sudo echo "hdmi_drive=2" >> ./boot/config.txt.bak
sudo cp -rf ./boot/config.txt.bak /boot/config.txt sudo cp -rf ./boot/config.txt.bak /boot/config.txt
sudo cp -rf ./usr/99-calibration.conf-mhs395-90 /etc/X11/xorg.conf.d/99-calibration.conf sudo cp -rf ./usr/99-calibration.conf-mhs395-90 /etc/X11/xorg.conf.d/99-calibration.conf
sudo cp -rf ./usr/99-fbturbo.conf /usr/share/X11/xorg.conf.d/99-fbturbo.conf sudo cp -rf ./usr/99-fbturbo.conf /usr/share/X11/xorg.conf.d/99-fbturbo.conf
#if test "$root_dev" = "/dev/mmcblk0p7";then if test "$root_dev" = "/dev/mmcblk0p7";then
#sudo cp ./usr/cmdline.txt-noobs /boot/cmdline.txt sudo cp ./usr/cmdline.txt-noobs /boot/cmdline.txt
#else else
#sudo cp ./usr/cmdline.txt /boot/ sudo cp ./usr/cmdline.txt /boot/
#fi fi
sudo cp ./usr/inittab /etc/ sudo cp ./usr/inittab /etc/
#sudo cp ./boot/config-mhs395.txt /boot/config.txt #sudo cp ./boot/config-mhs395.txt /boot/config.txt
sudo touch ./.have_installed sudo touch ./.have_installed
echo "gpio:resistance:mhs395:90:480:320" > ./.have_installed echo "gpio:resistance:mhs395:90:480:320" > ./.have_installed
sudo apt-get update
#FBCP install #FBCP install
wget --spider -q -o /dev/null --tries=1 -T 10 https://cmake.org/
if [ $? -eq 0 ]; then
#sudo apt-get update
sudo apt-get install cmake -y 2> error_output.txt
result=`cat ./error_output.txt`
echo -e "\033[31m$result\033[0m"
grep -q "^E:" ./error_output.txt
type cmake > /dev/null 2>&1
if [ $? -eq 0 ]; then
sudo rm -rf rpi-fbcp
wget --spider -q -o /dev/null --tries=1 -T 10 https://github.com wget --spider -q -o /dev/null --tries=1 -T 10 https://github.com
if [ $? -eq 0 ]; then if [ $? -eq 0 ]; then
sudo cp -rf ./usr/99-fbturbo-fbcp.conf /usr/share/X11/xorg.conf.d/99-fbturbo.conf
sudo cp -rf ./etc/rc.local /etc/rc.local
sudo apt-get install git cmake -y 2> error_output.txt
result=`cat ./error_output.txt`
echo -e "\033[31m$result\033[0m"
grep -q "^E:" ./error_output.txt && exit
sudo rm -rf rpi-fbcp
sudo git clone https://github.com/tasanakorn/rpi-fbcp sudo git clone https://github.com/tasanakorn/rpi-fbcp
if [ $? -ne 0 ]; then
echo "download fbcp failed, copy native fbcp!!!"
sudo cp -r ./usr/rpi-fbcp .
fi
else
echo "bad network, copy native fbcp!!!"
sudo cp -r ./usr/rpi-fbcp .
fi
sudo mkdir ./rpi-fbcp/build sudo mkdir ./rpi-fbcp/build
cd ./rpi-fbcp/build/ cd ./rpi-fbcp/build/
sudo cmake .. sudo cmake ..
sudo make sudo make
sudo install fbcp /usr/local/bin/fbcp sudo install fbcp /usr/local/bin/fbcp
cd - > /dev/null cd - > /dev/null
type fbcp > /dev/null 2>&1
if [ $? -eq 0 ]; then
sudo cp -rf ./usr/99-fbturbo-fbcp.conf /usr/share/X11/xorg.conf.d/99-fbturbo.conf
sudo cp -rf ./etc/rc.local /etc/rc.local
fi fi
else
echo "install cmake error!!!!"
fi
else
echo "bad network, can't install cmake!!!"
fi
#evdev install #evdev install
#nodeplatform=`uname -n` #nodeplatform=`uname -n`
#kernel=`uname -r` #kernel=`uname -r`
version=`uname -v` version=`uname -v`
#if test "$nodeplatform" = "raspberrypi";then #if test "$nodeplatform" = "raspberrypi";then
#echo "this is raspberrypi kernel" #echo "this is raspberrypi kernel"
input_result=0
version=${version##* } version=${version##* }
#version=${version#*#} #version=${version#*#}
echo $version echo $version
@ -97,23 +70,8 @@ if test $version -lt 2017;then
echo "reboot" echo "reboot"
else else
echo "need to update touch configuration" echo "need to update touch configuration"
wget --spider -q -o /dev/null --tries=1 -T 10 http://mirrors.zju.edu.cn/raspbian/raspbian sudo dpkg -i -B ./xserver-xorg-input-evdev_2.10.5-1_armhf.deb 2> error_output.txt
if [ $? -ne 0 ]; then #sudo apt-get install xserver-xorg-input-evdev 2> error_output.txt
input_result=1
else
sudo apt-get install xserver-xorg-input-evdev 2> error_output.txt
dpkg -l | grep xserver-xorg-input-evdev > /dev/null 2>&1
if [ $? -ne 0 ]; then
input_result=1
fi
fi
if [ $input_result -eq 1 ]; then
if [ $hardware_arch -eq 32 ]; then
sudo dpkg -i -B ./xserver-xorg-input-evdev_1%3a2.10.6-1+b1_armhf.deb 2> error_output.txt
elif [ $hardware_arch -eq 64 ]; then
sudo dpkg -i -B ./xserver-xorg-input-evdev_1%3a2.10.6-2_arm64.deb 2> error_output.txt
fi
fi
result=`cat ./error_output.txt` result=`cat ./error_output.txt`
echo -e "\033[31m$result\033[0m" echo -e "\033[31m$result\033[0m"
grep -q "error:" ./error_output.txt && exit grep -q "error:" ./error_output.txt && exit

View File

@ -1,143 +0,0 @@
#!/bin/bash
sudo ./system_backup.sh
if [ -f /etc/X11/xorg.conf.d/40-libinput.conf ]; then
sudo rm -rf /etc/X11/xorg.conf.d/40-libinput.conf
fi
if [ ! -d /etc/X11/xorg.conf.d ]; then
sudo mkdir -p /etc/X11/xorg.conf.d
fi
#root_dev=`grep -oPr "root=[^\s]*" /boot/cmdline.txt | awk -F= '{printf $NF}'`
#if test "$root_dev" = "/dev/mmcblk0p7";then
#sudo cp -rf ./boot/config-noobs-nomal.txt ./boot/config.txt.bak
#else
#sudo cp -rf ./boot/config-nomal.txt ./boot/config.txt.bak
#sudo echo "hdmi_force_hotplug=1" >> ./boot/config.txt.bak
#fi
source ./system_config.sh
sudo echo "hdmi_force_hotplug=1" >> ./boot/config.txt.bak
sudo echo "dtparam=i2c_arm=on" >> ./boot/config.txt.bak
sudo echo "dtparam=spi=on" >> ./boot/config.txt.bak
sudo echo "enable_uart=1" >> ./boot/config.txt.bak
sudo echo "display_rotate=0" >> ./boot/config.txt.bak
sudo echo "hdmi_group=2" >> ./boot/config.txt.bak
sudo echo "hdmi_mode=1" >> ./boot/config.txt.bak
sudo echo "hdmi_mode=87" >> ./boot/config.txt.bak
sudo echo "hdmi_cvt 800 480 60 6 0 0 0" >> ./boot/config.txt.bak
sudo echo "hdmi_drive=2" >> ./boot/config.txt.bak
sudo echo "dtoverlay=ads7846,cs=1,penirq=17,penirq_pull=2,speed=1000000,keep_vref_on=1,swapxy=1,pmax=255,xohms=60,xmin=200,xmax=3900,ymin=200,ymax=3900" >> ./boot/config.txt.bak
sudo cp -rf ./boot/config.txt.bak /boot/config.txt
sudo cp -rf ./usr/99-calibration.conf-mhs397-0 /etc/X11/xorg.conf.d/99-calibration.conf
#sudo cp -rf ./usr/99-fbturbo.conf /usr/share/X11/xorg.conf.d/99-fbturbo.conf
sudo cp -rf ./usr/99-fbturbo-fbcp.conf /usr/share/X11/xorg.conf.d/99-fbturbo.conf
sudo cp -rf ./etc/rc.local /etc/rc.local
#if test "$root_dev" = "/dev/mmcblk0p7";then
#sudo cp ./usr/cmdline.txt-noobs /boot/cmdline.txt
#else
#sudo cp ./usr/cmdline.txt /boot/
#fi
#sudo cp ./usr/inittab /etc/
#sudo cp ./boot/config-mhs397.txt /boot/config.txt
sudo cp -rf ./etc/modules /etc/modules
sudo chmod 644 /etc/modules
sudo cp -rf ./etc/modprobe.d/fbtft.conf /etc/modprobe.d/
sudo touch ./.have_installed
echo "hdmi:resistance:mhs397:0:800:480" > ./.have_installed
sudo apt-get update
#FBCP install
wget --spider -q -o /dev/null --tries=1 -T 10 https://cmake.org/
if [ $? -eq 0 ]; then
#sudo apt-get update
sudo apt-get install cmake -y 2> error_output.txt
result=`cat ./error_output.txt`
echo -e "\033[31m$result\033[0m"
grep -q "^E:" ./error_output.txt
type cmake > /dev/null 2>&1
if [ $? -eq 0 ]; then
sudo rm -rf rpi-fbcp
wget --spider -q -o /dev/null --tries=1 -T 10 https://github.com
if [ $? -eq 0 ]; then
sudo git clone https://github.com/tasanakorn/rpi-fbcp
if [ $? -ne 0 ]; then
echo "download fbcp failed, copy native fbcp!!!"
sudo cp -r ./usr/rpi-fbcp .
fi
else
echo "bad network, copy native fbcp!!!"
sudo cp -r ./usr/rpi-fbcp .
fi
sudo mkdir ./rpi-fbcp/build
cd ./rpi-fbcp/build/
sudo cmake ..
sudo make
sudo install fbcp /usr/local/bin/fbcp
cd - > /dev/null
type fbcp > /dev/null 2>&1
if [ $? -eq 0 ]; then
sudo cp -rf ./usr/99-fbturbo-fbcp.conf /usr/share/X11/xorg.conf.d/99-fbturbo.conf
sudo cp -rf ./etc/rc.local /etc/rc.local
fi
else
echo "install cmake error!!!!"
fi
else
echo "bad network, can't install cmake!!!"
fi
#evdev install
#nodeplatform=`uname -n`
#kernel=`uname -r`
version=`uname -v`
#if test "$nodeplatform" = "raspberrypi";then
#echo "this is raspberrypi kernel"
input_result=0
version=${version##* }
#version=${version#*#}
echo $version
if test $version -lt 2017;then
echo "reboot"
else
echo "need to update touch configuration"
wget --spider -q -o /dev/null --tries=1 -T 10 http://mirrors.zju.edu.cn/raspbian/raspbian
if [ $? -ne 0 ]; then
input_result=1
else
sudo apt-get install xserver-xorg-input-evdev 2> error_output.txt
dpkg -l | grep xserver-xorg-input-evdev > /dev/null 2>&1
if [ $? -ne 0 ]; then
input_result=1
fi
fi
if [ $input_result -eq 1 ]; then
if [ $hardware_arch -eq 32 ]; then
sudo dpkg -i -B ./xserver-xorg-input-evdev_1%3a2.10.6-1+b1_armhf.deb 2> error_output.txt
elif [ $hardware_arch -eq 64 ]; then
sudo dpkg -i -B ./xserver-xorg-input-evdev_1%3a2.10.6-2_arm64.deb 2> error_output.txt
fi
fi
result=`cat ./error_output.txt`
echo -e "\033[31m$result\033[0m"
grep -q "error:" ./error_output.txt && exit
sudo cp -rf /usr/share/X11/xorg.conf.d/10-evdev.conf /usr/share/X11/xorg.conf.d/45-evdev.conf
#echo "reboot"
fi
#else
#echo "this is not raspberrypi kernel, no need to update touch configure, reboot"
#fi
sudo sync
sudo sync
sleep 1
if [ $# -eq 1 ]; then
sudo ./rotate.sh $1
elif [ $# -gt 1 ]; then
echo "Too many parameters"
fi
echo "reboot now"
sudo reboot

View File

@ -1,139 +1,45 @@
#!/bin/bash #!/bin/bash
sudo ./system_backup.sh
if [ -f /etc/X11/xorg.conf.d/40-libinput.conf ]; then
sudo rm -rf /etc/X11/xorg.conf.d/40-libinput.conf sudo rm -rf /etc/X11/xorg.conf.d/40-libinput.conf
fi
if [ ! -d /etc/X11/xorg.conf.d ]; then
sudo mkdir -p /etc/X11/xorg.conf.d sudo mkdir -p /etc/X11/xorg.conf.d
fi
sudo cp ./usr/mis35-overlay.dtb /boot/overlays/ sudo cp ./usr/mis35-overlay.dtb /boot/overlays/
sudo cp ./usr/mis35-overlay.dtb /boot/overlays/mis35.dtbo sudo cp ./usr/mis35-overlay.dtb /boot/overlays/mis35.dtbo
sudo cp -rf ./usr/99-calibration.conf-mhs35 /etc/X11/xorg.conf.d/99-calibration.conf
#root_dev=`grep -oPr "root=[^\s]*" /boot/cmdline.txt | awk -F= '{printf $NF}'` sudo cp -rf ./usr/99-fbturbo-fbcp.conf /usr/share/X11/xorg.conf.d/99-fbturbo.conf
#if test "$root_dev" = "/dev/mmcblk0p7";then if [ -b /dev/mmcblk0p7 ]; then
#sudo cp -rf ./boot/config-noobs-nomal.txt ./boot/config.txt.bak sudo cp ./usr/cmdline.txt-noobs /boot/cmdline.txt
#else
#sudo cp -rf ./boot/config-nomal.txt ./boot/config.txt.bak
#sudo echo "hdmi_force_hotplug=1" >> ./boot/config.txt.bak
#fi
source ./system_config.sh
sudo echo "hdmi_force_hotplug=1" >> ./boot/config.txt.bak
sudo echo "dtparam=i2c_arm=on" >> ./boot/config.txt.bak
sudo echo "dtparam=spi=on" >> ./boot/config.txt.bak
sudo echo "enable_uart=1" >> ./boot/config.txt.bak
sudo echo "dtoverlay=mis35:rotate=90" >> ./boot/config.txt.bak
sudo echo "hdmi_group=2" >> ./boot/config.txt.bak
sudo echo "hdmi_mode=1" >> ./boot/config.txt.bak
sudo echo "hdmi_mode=87" >> ./boot/config.txt.bak
sudo echo "hdmi_cvt 480 320 60 6 0 0 0" >> ./boot/config.txt.bak
sudo echo "hdmi_drive=2" >> ./boot/config.txt.bak
sudo cp -rf ./boot/config.txt.bak /boot/config.txt
sudo cp -rf ./usr/99-calibration.conf-mis35-90 /etc/X11/xorg.conf.d/99-calibration.conf
sudo cp -rf ./usr/99-fbturbo.conf /usr/share/X11/xorg.conf.d/99-fbturbo.conf
#if test "$root_dev" = "/dev/mmcblk0p7";then
#sudo cp ./usr/cmdline.txt-noobs /boot/cmdline.txt
#else
#sudo cp ./usr/cmdline.txt /boot/
#fi
sudo cp ./usr/inittab /etc/
#sudo cp ./boot/config-mhs35.txt /boot/config.txt
sudo touch ./.have_installed
echo "gpio:resistance:mis35:90:480:320" > ./.have_installed
sudo apt-get update
#FBCP install
wget --spider -q -o /dev/null --tries=1 -T 10 https://cmake.org/
if [ $? -eq 0 ]; then
#sudo apt-get update
sudo apt-get install cmake -y 2> error_output.txt
result=`cat ./error_output.txt`
echo -e "\033[31m$result\033[0m"
grep -q "^E:" ./error_output.txt
type cmake > /dev/null 2>&1
if [ $? -eq 0 ]; then
sudo rm -rf rpi-fbcp
wget --spider -q -o /dev/null --tries=1 -T 10 https://github.com
if [ $? -eq 0 ]; then
sudo git clone https://github.com/tasanakorn/rpi-fbcp
if [ $? -ne 0 ]; then
echo "download fbcp failed, copy native fbcp!!!"
sudo cp -r ./usr/rpi-fbcp .
fi
else else
echo "bad network, copy native fbcp!!!" sudo cp ./usr/cmdline.txt /boot/
sudo cp -r ./usr/rpi-fbcp .
fi fi
sudo cp ./usr/inittab /etc/
sudo cp ./boot/config-mis35.txt /boot/config.txt
#FBCP install
sudo cp -rf ./etc/rc.local /etc/rc.local
sudo apt-get install git cmake -y
sudo rm -rf rpi-fbcp
sudo git clone https://github.com/tasanakorn/rpi-fbcp
sudo mkdir ./rpi-fbcp/build sudo mkdir ./rpi-fbcp/build
cd ./rpi-fbcp/build/ cd ./rpi-fbcp/build/
sudo cmake .. sudo cmake ..
sudo make sudo make
sudo install fbcp /usr/local/bin/fbcp sudo install fbcp /usr/local/bin/fbcp
cd - > /dev/null
type fbcp > /dev/null 2>&1
if [ $? -eq 0 ]; then
sudo cp -rf ./usr/99-fbturbo-fbcp.conf /usr/share/X11/xorg.conf.d/99-fbturbo.conf
sudo cp -rf ./etc/rc.local /etc/rc.local
fi
else
echo "install cmake error!!!!"
fi
else
echo "bad network, can't install cmake!!!"
fi
#evdev install #evdev install
#nodeplatform=`uname -n` nodeplatform=`uname -n`
#kernel=`uname -r` kernel=`uname -r`
version=`uname -v` version=`uname -v`
#if test "$nodeplatform" = "raspberrypi";then if test "$nodeplatform" = "raspberrypi";then
#echo "this is raspberrypi kernel" echo "this is raspberrypi kernel"
input_result=0 version=${version%% *}
version=${version##* } version=${version#*#}
#version=${version#*#}
echo $version echo $version
if test $version -lt 2017;then if test $version -lt 970;then
echo "reboot" echo "reboot"
else else
echo "need to update touch configuration" echo "need to update touch configuration"
wget --spider -q -o /dev/null --tries=1 -T 10 http://mirrors.zju.edu.cn/raspbian/raspbian sudo apt-get install xserver-xorg-input-evdev
if [ $? -ne 0 ]; then
input_result=1
else
sudo apt-get install xserver-xorg-input-evdev 2> error_output.txt
dpkg -l | grep xserver-xorg-input-evdev > /dev/null 2>&1
if [ $? -ne 0 ]; then
input_result=1
fi
fi
if [ $input_result -eq 1 ]; then
if [ $hardware_arch -eq 32 ]; then
sudo dpkg -i -B ./xserver-xorg-input-evdev_1%3a2.10.6-1+b1_armhf.deb 2> error_output.txt
elif [ $hardware_arch -eq 64 ]; then
sudo dpkg -i -B ./xserver-xorg-input-evdev_1%3a2.10.6-2_arm64.deb 2> error_output.txt
fi
fi
result=`cat ./error_output.txt`
echo -e "\033[31m$result\033[0m"
grep -q "error:" ./error_output.txt && exit
sudo cp -rf /usr/share/X11/xorg.conf.d/10-evdev.conf /usr/share/X11/xorg.conf.d/45-evdev.conf sudo cp -rf /usr/share/X11/xorg.conf.d/10-evdev.conf /usr/share/X11/xorg.conf.d/45-evdev.conf
#echo "reboot" echo "reboot"
fi fi
#else else
#echo "this is not raspberrypi kernel, no need to update touch configure, reboot" echo "this is not raspberrypi kernel, no need to update touch configure, reboot"
#fi
sudo sync
sudo sync
sleep 1
if [ $# -eq 1 ]; then
sudo ./rotate.sh $1
elif [ $# -gt 1 ]; then
echo "Too many parameters"
fi fi
echo "reboot now"
sudo reboot sudo reboot

View File

@ -2,16 +2,14 @@
sudo ./system_backup.sh sudo ./system_backup.sh
hw_version=`tr -d '\0' < /proc/device-tree/model` hw_version=`tr -d '\0' < /proc/device-tree/model`
#root_dev=`grep -oPr "root=[^\s]*" /boot/cmdline.txt | awk -F= '{printf $NF}'` root_dev=`grep -oPr "root=[^\s]*" /boot/cmdline.txt | awk -F= '{printf $NF}'`
#if test "$root_dev" = "/dev/mmcblk0p7";then if test "$root_dev" = "/dev/mmcblk0p7";then
#sudo cp -rf ./boot/config-noobs-nomal.txt ./boot/config.txt.bak sudo cp -rf ./boot/config-noobs-nomal.txt ./boot/config.txt.bak
#else else
#sudo cp -rf ./boot/config-nomal.txt ./boot/config.txt.bak sudo cp -rf ./boot/config-nomal.txt ./boot/config.txt.bak
#sudo echo "hdmi_force_hotplug=1" >> ./boot/config.txt.bak
#fi
source ./system_config.sh
sudo echo "hdmi_force_hotplug=1" >> ./boot/config.txt.bak sudo echo "hdmi_force_hotplug=1" >> ./boot/config.txt.bak
fi
[[ $hw_version =~ "Raspberry Pi 4 Model" ]] || (sed -i 's/^dtoverlay=/#&/g' ./boot/config.txt.bak;sed -i 's/^max_framebuffers=/#&/g' ./boot/config.txt.bak)
sudo echo "hdmi_force_edid_audio=1" >> ./boot/config.txt.bak sudo echo "hdmi_force_edid_audio=1" >> ./boot/config.txt.bak
sudo echo "dtparam=i2c_arm=on" >> ./boot/config.txt.bak sudo echo "dtparam=i2c_arm=on" >> ./boot/config.txt.bak
sudo echo "dtparam=spi=on" >> ./boot/config.txt.bak sudo echo "dtparam=spi=on" >> ./boot/config.txt.bak
@ -25,15 +23,14 @@ sudo echo "hdmi_mode=87" >> ./boot/config.txt.bak
sudo echo "hdmi_drive=2" >> ./boot/config.txt.bak sudo echo "hdmi_drive=2" >> ./boot/config.txt.bak
sudo echo "hdmi_cvt 480 320 60 6 0 0 0" >> ./boot/config.txt.bak sudo echo "hdmi_cvt 480 320 60 6 0 0 0" >> ./boot/config.txt.bak
sudo echo "dtoverlay=ads7846,cs=1,penirq=25,penirq_pull=2,speed=50000,keep_vref_on=0,swapxy=0,pmax=255,xohms=150,xmin=200,xmax=3900,ymin=200,ymax=3900" >> ./boot/config.txt.bak sudo echo "dtoverlay=ads7846,cs=1,penirq=25,penirq_pull=2,speed=50000,keep_vref_on=0,swapxy=0,pmax=255,xohms=150,xmin=200,xmax=3900,ymin=200,ymax=3900" >> ./boot/config.txt.bak
[[ $hw_version =~ "Raspberry Pi 4" ]] && sudo echo "hdmi_timings=600 0 20 28 48 400 0 13 3 32 0 0 0 30 0 25000000 5" >> ./boot/config.txt.bak
sudo cp -rf ./boot/config.txt.bak /boot/config.txt sudo cp -rf ./boot/config.txt.bak /boot/config.txt
#sudo cp -rf ./boot/config-35-480X320.txt /boot/config.txt #sudo cp -rf ./boot/config-35-480X320.txt /boot/config.txt
#if test "$root_dev" = "/dev/mmcblk0p7";then if test "$root_dev" = "/dev/mmcblk0p7";then
#sudo cp ./usr/cmdline.txt-noobs /boot/cmdline.txt sudo cp ./usr/cmdline.txt-noobs /boot/cmdline.txt
#else else
#sudo cp ./usr/cmdline.txt /boot/ sudo cp ./usr/cmdline.txt /boot/
#fi fi
sudo cp ./usr/inittab /etc/ sudo cp ./usr/inittab /etc/
sudo cp -rf ./usr/99-fbturbo.conf-HDMI /usr/share/X11/xorg.conf.d/99-fbturbo.conf sudo cp -rf ./usr/99-fbturbo.conf-HDMI /usr/share/X11/xorg.conf.d/99-fbturbo.conf
if [ ! -d /etc/X11/xorg.conf.d ]; then if [ ! -d /etc/X11/xorg.conf.d ]; then
@ -42,13 +39,11 @@ fi
sudo cp -rf ./usr/99-calibration.conf-3508-0 /etc/X11/xorg.conf.d/99-calibration.conf sudo cp -rf ./usr/99-calibration.conf-3508-0 /etc/X11/xorg.conf.d/99-calibration.conf
sudo touch ./.have_installed sudo touch ./.have_installed
echo "hdmi:resistance:3508:0:480:320" > ./.have_installed echo "hdmi:resistance:3508:0:480:320" > ./.have_installed
#nodeplatform=`uname -n` #nodeplatform=`uname -n`
#kernel=`uname -r` #kernel=`uname -r`
version=`uname -v` version=`uname -v`
#if test "$nodeplatform" = "raspberrypi";then #if test "$nodeplatform" = "raspberrypi";then
#echo "this is raspberrypi kernel" #echo "this is raspberrypi kernel"
input_result=0
version=${version##* } version=${version##* }
#version=${version#*#} #version=${version#*#}
echo $version echo $version
@ -56,23 +51,8 @@ if test $version -lt 2017;then
echo "reboot" echo "reboot"
else else
echo "need to update touch configuration" echo "need to update touch configuration"
wget --spider -q -o /dev/null --tries=1 -T 10 http://mirrors.zju.edu.cn/raspbian/raspbian sudo dpkg -i -B ./xserver-xorg-input-evdev_2.10.5-1_armhf.deb 2> error_output.txt
if [ $? -ne 0 ]; then #sudo apt-get install xserver-xorg-input-evdev 2> error_output.txt
input_result=1
else
sudo apt-get install xserver-xorg-input-evdev 2> error_output.txt
dpkg -l | grep xserver-xorg-input-evdev > /dev/null 2>&1
if [ $? -ne 0 ]; then
input_result=1
fi
fi
if [ $input_result -eq 1 ]; then
if [ $hardware_arch -eq 32 ]; then
sudo dpkg -i -B ./xserver-xorg-input-evdev_1%3a2.10.6-1+b1_armhf.deb 2> error_output.txt
elif [ $hardware_arch -eq 64 ]; then
sudo dpkg -i -B ./xserver-xorg-input-evdev_1%3a2.10.6-2_arm64.deb 2> error_output.txt
fi
fi
result=`cat ./error_output.txt` result=`cat ./error_output.txt`
echo -e "\033[31m$result\033[0m" echo -e "\033[31m$result\033[0m"
grep -q "error:" ./error_output.txt && exit grep -q "error:" ./error_output.txt && exit

View File

@ -2,16 +2,13 @@
sudo ./system_backup.sh sudo ./system_backup.sh
#root_dev=`grep -oPr "root=[^\s]*" /boot/cmdline.txt | awk -F= '{printf $NF}'` root_dev=`grep -oPr "root=[^\s]*" /boot/cmdline.txt | awk -F= '{printf $NF}'`
#if test "$root_dev" = "/dev/mmcblk0p7";then if test "$root_dev" = "/dev/mmcblk0p7";then
#sudo cp -rf ./boot/config-noobs-nomal.txt ./boot/config.txt.bak sudo cp -rf ./boot/config-noobs-nomal.txt ./boot/config.txt.bak
#else else
#sudo cp -rf ./boot/config-nomal.txt ./boot/config.txt.bak sudo cp -rf ./boot/config-nomal.txt ./boot/config.txt.bak
#sudo echo "hdmi_force_hotplug=1" >> ./boot/config.txt.bak
#fi
source ./system_config.sh
sudo echo "hdmi_force_hotplug=1" >> ./boot/config.txt.bak sudo echo "hdmi_force_hotplug=1" >> ./boot/config.txt.bak
fi
sudo echo "hdmi_force_edid_audio=1" >> ./boot/config.txt.bak sudo echo "hdmi_force_edid_audio=1" >> ./boot/config.txt.bak
sudo echo "dtparam=i2c_arm=on" >> ./boot/config.txt.bak sudo echo "dtparam=i2c_arm=on" >> ./boot/config.txt.bak
sudo echo "dtparam=spi=on" >> ./boot/config.txt.bak sudo echo "dtparam=spi=on" >> ./boot/config.txt.bak
@ -29,11 +26,11 @@ sudo cp -rf ./boot/config.txt.bak /boot/config.txt
#sudo cp -rf ./boot/config-397.txt /boot/config.txt #sudo cp -rf ./boot/config-397.txt /boot/config.txt
#if test "$root_dev" = "/dev/mmcblk0p7";then if test "$root_dev" = "/dev/mmcblk0p7";then
#sudo cp ./usr/cmdline.txt-noobs /boot/cmdline.txt sudo cp ./usr/cmdline.txt-noobs /boot/cmdline.txt
#else else
#sudo cp ./usr/cmdline.txt /boot/ sudo cp ./usr/cmdline.txt /boot/
#fi fi
sudo cp ./usr/inittab /etc/ sudo cp ./usr/inittab /etc/
sudo cp -rf ./usr/99-fbturbo.conf-HDMI /usr/share/X11/xorg.conf.d/99-fbturbo.conf sudo cp -rf ./usr/99-fbturbo.conf-HDMI /usr/share/X11/xorg.conf.d/99-fbturbo.conf
if [ ! -d /etc/X11/xorg.conf.d ]; then if [ ! -d /etc/X11/xorg.conf.d ]; then
@ -48,7 +45,6 @@ echo "hdmi:resistance:397:270:480:800" > ./.have_installed
version=`uname -v` version=`uname -v`
#if test "$nodeplatform" = "raspberrypi";then #if test "$nodeplatform" = "raspberrypi";then
#echo "this is raspberrypi kernel" #echo "this is raspberrypi kernel"
input_result=0
version=${version##* } version=${version##* }
#version=${version#*#} #version=${version#*#}
echo $version echo $version
@ -56,23 +52,8 @@ if test $version -lt 2017;then
echo "reboot" echo "reboot"
else else
echo "need to update touch configuration" echo "need to update touch configuration"
wget --spider -q -o /dev/null --tries=1 -T 10 http://mirrors.zju.edu.cn/raspbian/raspbian sudo dpkg -i -B ./xserver-xorg-input-evdev_2.10.5-1_armhf.deb 2> error_output.txt
if [ $? -ne 0 ]; then #sudo apt-get install xserver-xorg-input-evdev 2> error_output.txt
input_result=1
else
sudo apt-get install xserver-xorg-input-evdev 2> error_output.txt
dpkg -l | grep xserver-xorg-input-evdev > /dev/null 2>&1
if [ $? -ne 0 ]; then
input_result=1
fi
fi
if [ $input_result -eq 1 ]; then
if [ $hardware_arch -eq 32 ]; then
sudo dpkg -i -B ./xserver-xorg-input-evdev_1%3a2.10.6-1+b1_armhf.deb 2> error_output.txt
elif [ $hardware_arch -eq 64 ]; then
sudo dpkg -i -B ./xserver-xorg-input-evdev_1%3a2.10.6-2_arm64.deb 2> error_output.txt
fi
fi
result=`cat ./error_output.txt` result=`cat ./error_output.txt`
echo -e "\033[31m$result\033[0m" echo -e "\033[31m$result\033[0m"
grep -q "error:" ./error_output.txt && exit grep -q "error:" ./error_output.txt && exit

View File

@ -1,96 +0,0 @@
#!/bin/bash
sudo ./system_backup.sh
#root_dev=`grep -oPr "root=[^\s]*" /boot/cmdline.txt | awk -F= '{printf $NF}'`
#if test "$root_dev" = "/dev/mmcblk0p7";then
#sudo cp -rf ./boot/config-noobs-nomal.txt ./boot/config.txt.bak
#else
#sudo cp -rf ./boot/config-nomal.txt ./boot/config.txt.bak
#sudo echo "hdmi_force_hotplug=1" >> ./boot/config.txt.bak
#fi
source ./system_config.sh
sudo echo "hdmi_force_hotplug=1" >> ./boot/config.txt.bak
sudo echo "hdmi_force_edid_audio=1" >> ./boot/config.txt.bak
sudo echo "dtparam=i2c_arm=on" >> ./boot/config.txt.bak
sudo echo "dtparam=spi=on" >> ./boot/config.txt.bak
sudo echo "enable_uart=1" >> ./boot/config.txt.bak
sudo echo "display_rotate=3" >> ./boot/config.txt.bak
sudo echo "max_usb_current=1" >> ./boot/config.txt.bak
sudo echo "config_hdmi_boost=7" >> ./boot/config.txt.bak
sudo echo "hdmi_group=2" >> ./boot/config.txt.bak
sudo echo "hdmi_mode=1" >> ./boot/config.txt.bak
sudo echo "hdmi_mode=87" >> ./boot/config.txt.bak
sudo echo "hdmi_drive=2" >> ./boot/config.txt.bak
sudo echo "hdmi_cvt 480 800 65 6 0 0 0" >> ./boot/config.txt.bak
sudo echo "dtoverlay=ads7846,cs=1,penirq=25,penirq_pull=2,speed=50000,keep_vref_on=0,swapxy=0,pmax=255,xohms=150,xmin=200,xmax=3900,ymin=200,ymax=3900" >> ./boot/config.txt.bak
sudo cp -rf ./boot/config.txt.bak /boot/config.txt
#sudo cp -rf ./boot/config-397.txt /boot/config.txt
#if test "$root_dev" = "/dev/mmcblk0p7";then
#sudo cp ./usr/cmdline.txt-noobs /boot/cmdline.txt
#else
#sudo cp ./usr/cmdline.txt /boot/
#fi
sudo cp ./usr/inittab /etc/
sudo cp -rf ./usr/99-fbturbo.conf-HDMI /usr/share/X11/xorg.conf.d/99-fbturbo.conf
if [ ! -d /etc/X11/xorg.conf.d ]; then
sudo mkdir /etc/X11/xorg.conf.d
fi
sudo cp -rf ./usr/99-calibration.conf-3971-270 /etc/X11/xorg.conf.d/99-calibration.conf
sudo touch ./.have_installed
echo "hdmi:resistance:3971:270:480:800" > ./.have_installed
#nodeplatform=`uname -n`
#kernel=`uname -r`
version=`uname -v`
#if test "$nodeplatform" = "raspberrypi";then
#echo "this is raspberrypi kernel"
input_result=0
version=${version##* }
#version=${version#*#}
echo $version
if test $version -lt 2017;then
echo "reboot"
else
echo "need to update touch configuration"
wget --spider -q -o /dev/null --tries=1 -T 10 http://mirrors.zju.edu.cn/raspbian/raspbian
if [ $? -ne 0 ]; then
input_result=1
else
sudo apt-get install xserver-xorg-input-evdev 2> error_output.txt
dpkg -l | grep xserver-xorg-input-evdev > /dev/null 2>&1
if [ $? -ne 0 ]; then
input_result=1
fi
fi
if [ $input_result -eq 1 ]; then
if [ $hardware_arch -eq 32 ]; then
sudo dpkg -i -B ./xserver-xorg-input-evdev_1%3a2.10.6-1+b1_armhf.deb 2> error_output.txt
elif [ $hardware_arch -eq 64 ]; then
sudo dpkg -i -B ./xserver-xorg-input-evdev_1%3a2.10.6-2_arm64.deb 2> error_output.txt
fi
fi
result=`cat ./error_output.txt`
echo -e "\033[31m$result\033[0m"
grep -q "error:" ./error_output.txt && exit
sudo cp -rf /usr/share/X11/xorg.conf.d/10-evdev.conf /usr/share/X11/xorg.conf.d/45-evdev.conf
#echo "reboot"
fi
#else
#echo "this is not raspberrypi kernel, no need to update touch configure, reboot"
#fi
sudo sync
sudo sync
sleep 1
if [ $# -eq 1 ]; then
sudo ./rotate.sh $1
elif [ $# -gt 1 ]; then
echo "Too many parameters"
fi
echo "reboot now"
sudo reboot

View File

@ -2,16 +2,13 @@
sudo ./system_backup.sh sudo ./system_backup.sh
#root_dev=`grep -oPr "root=[^\s]*" /boot/cmdline.txt | awk -F= '{printf $NF}'` root_dev=`grep -oPr "root=[^\s]*" /boot/cmdline.txt | awk -F= '{printf $NF}'`
#if test "$root_dev" = "/dev/mmcblk0p7";then if test "$root_dev" = "/dev/mmcblk0p7";then
#sudo cp -rf ./boot/config-noobs-nomal.txt ./boot/config.txt.bak sudo cp -rf ./boot/config-noobs-nomal.txt ./boot/config.txt.bak
#else else
#sudo cp -rf ./boot/config-nomal.txt ./boot/config.txt.bak sudo cp -rf ./boot/config-nomal.txt ./boot/config.txt.bak
#sudo echo "hdmi_force_hotplug=1" >> ./boot/config.txt.bak
#fi
source ./system_config.sh
sudo echo "hdmi_force_hotplug=1" >> ./boot/config.txt.bak sudo echo "hdmi_force_hotplug=1" >> ./boot/config.txt.bak
fi
sudo echo "hdmi_force_edid_audio=1" >> ./boot/config.txt.bak sudo echo "hdmi_force_edid_audio=1" >> ./boot/config.txt.bak
sudo echo "dtparam=i2c_arm=on" >> ./boot/config.txt.bak sudo echo "dtparam=i2c_arm=on" >> ./boot/config.txt.bak
sudo echo "dtparam=spi=on" >> ./boot/config.txt.bak sudo echo "dtparam=spi=on" >> ./boot/config.txt.bak
@ -26,11 +23,11 @@ sudo echo "hdmi_drive=2" >> ./boot/config.txt.bak
sudo echo "hdmi_cvt 800 480 60 6 0 0 0" >> ./boot/config.txt.bak sudo echo "hdmi_cvt 800 480 60 6 0 0 0" >> ./boot/config.txt.bak
sudo cp -rf ./boot/config.txt.bak /boot/config.txt sudo cp -rf ./boot/config.txt.bak /boot/config.txt
#sudo cp -rf ./boot/config-MPI5001.txt /boot/config.txt #sudo cp -rf ./boot/config-MPI5001.txt /boot/config.txt
#if test "$root_dev" = "/dev/mmcblk0p7";then if test "$root_dev" = "/dev/mmcblk0p7";then
#sudo cp ./usr/cmdline.txt-noobs /boot/cmdline.txt sudo cp ./usr/cmdline.txt-noobs /boot/cmdline.txt
#else else
#sudo cp ./usr/cmdline.txt /boot/ sudo cp ./usr/cmdline.txt /boot/
#fi fi
sudo cp ./usr/inittab /etc/ sudo cp ./usr/inittab /etc/
sudo cp -rf ./usr/99-fbturbo.conf-HDMI /usr/share/X11/xorg.conf.d/99-fbturbo.conf sudo cp -rf ./usr/99-fbturbo.conf-HDMI /usr/share/X11/xorg.conf.d/99-fbturbo.conf

View File

@ -1,24 +0,0 @@
#!/bin/bash
#sudo cp -rf ./boot/config-nomal.txt ./boot/config.txt.bak
source ./system_config.sh
sudo echo "hdmi_force_hotplug=1" >> ./boot/config.txt.bak
sudo echo "dtparam=i2c_arm=on" >> ./boot/config.txt.bak
sudo echo "dtparam=spi=on" >> ./boot/config.txt.bak
sudo echo "hdmi_group=2" >> ./boot/config.txt.bak
sudo echo "hdmi_mode=87" >> ./boot/config.txt.bak
sudo echo "hdmi_cvt 800 480 60 6 0 0 0" >> ./boot/config.txt.bak
sudo echo "dtoverlay=goodix" >> ./boot/config.txt.bak
sudo cp -rf ./boot/config.txt.bak /boot/config.txt
if [ -f /boot/overlays/goodix.dtbo ]; then
sudo mv /boot/overlays/goodix.dtbo /boot/overlays/goodix.dtbo.bak
sudo cp ./usr/goodix.dtbo /boot/overlays/
fi
sudo sync
sudo sync
sleep 1
echo "reboot now"
sudo reboot

View File

@ -1,60 +0,0 @@
from pymouse import PyMouse
import time
import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BCM)
btn_up = 5
btn_down = 26
btn_left = 19
btn_right = 6
btn_key1 = 21
btn_key2 = 20
# Up, Down, left, right, Button
GPIO.setup(btn_up, GPIO.IN,GPIO.PUD_UP)
GPIO.setup(btn_down, GPIO.IN,GPIO.PUD_UP)
GPIO.setup(btn_left, GPIO.IN,GPIO.PUD_UP)
GPIO.setup(btn_right, GPIO.IN,GPIO.PUD_UP)
GPIO.setup(btn_key1, GPIO.IN,GPIO.PUD_UP)
GPIO.setup(btn_key2, GPIO.IN,GPIO.PUD_UP)
def main():
m = PyMouse()
KEY1_flag = False
KEY2_flag = False
KEY3_flag = False
while True:
nowxy = m.position()
if (not GPIO.input(btn_key1)): # button pressed
KEY1_flag = True
print("KEY1")
m.click(nowxy[0], nowxy[1], 1)
if KEY1_flag and GPIO.input(btn_key1): # button released
KEY1_flag = False
if (not GPIO.input(btn_key2)): # button pressed
KEY2_flag = True
print("KEY1")
m.click(nowxy[0], nowxy[1], 2)
if KEY2_flag and GPIO.input(btn_key2): # button released
KEY2_flag = False
if (not GPIO.input(btn_up)): # button pressed
m.move(nowxy[0] - 5, nowxy[1])
if (not GPIO.input(btn_down)): # button pressed
m.move(nowxy[0] + 5, nowxy[1])
if (not GPIO.input(btn_left)): # button pressed
m.move(nowxy[0], nowxy[1] + 5)
if (not GPIO.input(btn_right)): # button pressed
m.move(nowxy[0], nowxy[1] - 5)
time.sleep(0.02) # Poll every 20ms (otherwise CPU load gets too high)
if __name__ == "__main__":
main()

View File

@ -1,141 +0,0 @@
#!/bin/bash
sudo ./system_backup.sh
if [ -f /etc/X11/xorg.conf.d/40-libinput.conf ]; then
sudo rm -rf /etc/X11/xorg.conf.d/40-libinput.conf
fi
if [ ! -d /etc/X11/xorg.conf.d ]; then
sudo mkdir -p /etc/X11/xorg.conf.d
fi
sudo cp ./usr/tft7789-overlay.dtb /boot/overlays/
sudo cp ./usr/tft7789-overlay.dtb /boot/overlays/tft7789.dtbo
#root_dev=`grep -oPr "root=[^\s]*" /boot/cmdline.txt | awk -F= '{printf $NF}'`
#if test "$root_dev" = "/dev/mmcblk0p7";then
#sudo cp -rf ./boot/config-noobs-nomal.txt ./boot/config.txt.bak
#else
#sudo cp -rf ./boot/config-nomal.txt ./boot/config.txt.bak
#sudo echo "hdmi_force_hotplug=1" >> ./boot/config.txt.bak
#fi
source ./system_config.sh
sudo echo "hdmi_force_hotplug=1" >> ./boot/config.txt.bak
sudo echo "dtparam=i2c_arm=on" >> ./boot/config.txt.bak
sudo echo "dtparam=spi=on" >> ./boot/config.txt.bak
sudo echo "enable_uart=1" >> ./boot/config.txt.bak
sudo echo "dtoverlay=tft7789:rotate=90" >> ./boot/config.txt.bak
sudo echo "dtoverlay=ft6236" >> ./boot/config.txt.bak
sudo echo "hdmi_group=2" >> ./boot/config.txt.bak
sudo echo "hdmi_mode=1" >> ./boot/config.txt.bak
sudo echo "hdmi_mode=87" >> ./boot/config.txt.bak
sudo echo "hdmi_cvt 320 240 60 6 0 0 0" >> ./boot/config.txt.bak
sudo echo "hdmi_drive=2" >> ./boot/config.txt.bak
sudo echo "dtoverlay=spi0-2cs,cs1_pin=4,0x01" >> ./boot/config.txt.bak
sudo echo "gpio=18=op,dh" >> ./boot/config.txt.bak
sudo cp -rf ./boot/config.txt.bak /boot/config.txt
sudo cp ./usr/ft6236.dtb /boot/overlays/ft6236.dtbo
sudo cp -rf ./usr/99-calibration.conf-nano24-90 /etc/X11/xorg.conf.d/99-calibration.conf
sudo cp -rf ./usr/99-fbturbo.conf /usr/share/X11/xorg.conf.d/99-fbturbo.conf
#if test "$root_dev" = "/dev/mmcblk0p7";then
#sudo cp ./usr/cmdline.txt-noobs /boot/cmdline.txt
#else
#sudo cp ./usr/cmdline.txt /boot/
#fi
sudo cp ./usr/inittab /etc/
sudo touch ./.have_installed
echo "gpio:resistance:nano24:90:320:240" > ./.have_installed
sudo apt-get update
#FBCP install
wget --spider -q -o /dev/null --tries=1 -T 10 https://cmake.org/
if [ $? -eq 0 ]; then
sudo apt-get install cmake -y 2> error_output.txt
result=`cat ./error_output.txt`
echo -e "\033[31m$result\033[0m"
grep -q "^E:" ./error_output.txt
type cmake > /dev/null 2>&1
if [ $? -eq 0 ]; then
sudo rm -rf rpi-fbcp
wget --spider -q -o /dev/null --tries=1 -T 10 https://github.com
if [ $? -eq 0 ]; then
sudo git clone https://github.com/tasanakorn/rpi-fbcp
if [ $? -ne 0 ]; then
echo "download fbcp failed, copy native fbcp!!!"
sudo cp -r ./usr/rpi-fbcp .
fi
else
echo "bad network, copy native fbcp!!!"
sudo cp -r ./usr/rpi-fbcp .
fi
sudo mkdir ./rpi-fbcp/build
cd ./rpi-fbcp/build/
sudo cmake ..
sudo make
sudo install fbcp /usr/local/bin/fbcp
cd - > /dev/null
type fbcp > /dev/null 2>&1
if [ $? -eq 0 ]; then
sudo cp -rf ./usr/99-fbturbo-fbcp.conf /usr/share/X11/xorg.conf.d/99-fbturbo.conf
sudo cp -rf ./etc/rc.local /etc/rc.local
fi
else
echo "install cmake error!!!!"
fi
else
echo "bad network, can't install cmake!!!"
fi
#evdev install
#nodeplatform=`uname -n`
#kernel=`uname -r`
version=`uname -v`
#if test "$nodeplatform" = "raspberrypi";then
#echo "this is raspberrypi kernel"
input_result=0
version=${version##* }
#version=${version#*#}
echo $version
if test $version -lt 2017;then
echo "reboot"
else
echo "need to update touch configuration"
wget --spider -q -o /dev/null --tries=1 -T 10 http://mirrors.zju.edu.cn/raspbian/raspbian
if [ $? -ne 0 ]; then
input_result=1
else
sudo apt-get install xserver-xorg-input-evdev 2> error_output.txt
dpkg -l | grep xserver-xorg-input-evdev > /dev/null 2>&1
if [ $? -ne 0 ]; then
input_result=1
fi
fi
if [ $input_result -eq 1 ]; then
if [ $hardware_arch -eq 32 ]; then
sudo dpkg -i -B ./xserver-xorg-input-evdev_1%3a2.10.6-1+b1_armhf.deb 2> error_output.txt
elif [ $hardware_arch -eq 64 ]; then
sudo dpkg -i -B ./xserver-xorg-input-evdev_1%3a2.10.6-2_arm64.deb 2> error_output.txt
fi
fi
result=`cat ./error_output.txt`
echo -e "\033[31m$result\033[0m"
grep -q "error:" ./error_output.txt && exit
sudo cp -rf /usr/share/X11/xorg.conf.d/10-evdev.conf /usr/share/X11/xorg.conf.d/45-evdev.conf
#echo "reboot"
fi
#else
#echo "this is not raspberrypi kernel, no need to update touch configure, reboot"
#fi
sudo sync
sudo sync
sleep 1
if [ $# -eq 1 ]; then
sudo ./rotate.sh $1
elif [ $# -gt 1 ]; then
echo "Too many parameters"
fi
echo "reboot now"
sudo reboot

Binary file not shown.

214
README.md
View File

@ -1,49 +1,29 @@
### Install drivers in the Ubuntu system LCD driver for the Raspberry PI Installation<br>
https://github.com/lcdwiki/LCD-show-ubuntu
### Install drivers in the Kali system
https://github.com/lcdwiki/LCD-show-kali
### Install drivers in the RetroPie system
https://github.com/lcdwiki/LCD-show-retropie
Install drivers in the Raspbian system<br>
==================================================== ====================================================
Update: <br> Update: <br>
v2.1-20191106<br> v1.9-20181204<br>
Update to support MHS35B<br> Update to support MHS40 & MHS32<br>
Update: <br> Update: <br>
v2.0-20190704<br> v1.8-20180907<br>
Update to support rotate the display direction<br> Update to support MHS35<br>
Update: <br> Update: <br>
v1.9-20181204<br> v1.7-20180320<br>
Update to support MHS40 & MHS32<br> Update to support Raspbian Version:March 2018(Release date:2018-03-13)<br>
Update: <br>
v1.8-20180907<br>
Update to support MHS35<br>
Update: <br>
v1.7-20180320<br>
Update to support Raspbian Version: March 2018(Release date:2018-03-13)<br>
Update: <br> Update: <br>
v1.6-20170824<br> v1.6-20170824<br>
Update xserver to support Raspbian-2017-08-16<br> Update xserver to support Raspbian-2017-08-16<br>
Update: <br> Update: <br>
v1.5-20170706<br> v1.5-20170706<br>
Update to support Raspbian-2017-07-05, Raspbian-2017-06-21<br> Update to support Raspbian-2017-07-05,Raspbian-2017-06-21<br>
Update: <br> Update: <br>
v1.3-20170612<br> v1.3-20170612<br>
fixed to support Raspbian-2017-03-02, Raspbian-2017-04-10<br> fixed to support Raspbian-2017-03-02,Raspbian-2017-04-10<br>
Update: <br> Update: <br>
v1.2-20170302<br> v1.2-20170302<br>
Add xserver-xorg-input-evdev_1%3a2.10.3-1_armhf.deb to support Raspbian-2017-03-02<br> Add xserver-xorg-input-evdev_1%3a2.10.3-1_armhf.deb to support Raspbian-2017-03-02<br>
Update: <br> Update: <br>
v1.1-20160815<br><br> v1.1-20160815<br><br>
# How to install the LCD driver of Raspberry Pi
1.)Step1, Install Raspbian official mirror <br> 1.)Step1, Install Raspbian official mirror <br>
==================================================== ====================================================
a)Download Raspbian official mirror:<br> a)Download Raspbian official mirror:<br>
@ -53,8 +33,8 @@ Update: <br>
2.) Step2, Clone my repo onto your pi<br> 2.) Step2, Clone my repo onto your pi<br>
==================================================== ====================================================
Use SSH to connect the Raspberry Pi, <br> Use SSH to connect the raspberry pi, <br>
And Ensure that the Raspberry Pi is connected to the Internet before executing the following commands: And Ensure that the raspberry pi is connected to the Internet before executing the following commands:
----------------------------------------------------------------------------------------------------- -----------------------------------------------------------------------------------------------------
```sudo rm -rf LCD-show```<br> ```sudo rm -rf LCD-show```<br>
@ -62,143 +42,39 @@ And Ensure that the Raspberry Pi is connected to the Internet before executing t
```chmod -R 755 LCD-show```<br> ```chmod -R 755 LCD-show```<br>
```cd LCD-show/```<br> ```cd LCD-show/```<br>
3.)Step3, According to your LCD's type, excute the corresponding driver: 3.)Step3, According to your LCD's type, excute:
==================================================== ====================================================
In case of 2.4" RPi Display(MPI2401)<br>
```sudo ./LCD24-show```<br><br>
In case of 2.8" RPi Display(MPI2801)<br>
```sudo ./LCD28-show```<br><br>
In case of 3.2" RPi Display(MPI3201)<br>
```sudo ./LCD32-show```<br><br>
In case of 3.5inch RPi Display(MPI3501)<br>
```sudo ./LCD35-show```<br><br>
In case of 3.5" HDMI Display-B(MPI3508)<br>
```sudo ./MPI3508-show```<br><br>
In case of 3.2" High Speed display(MHS32)<br>
```sudo ./MHS32-show```<br><br>
In case of 3.5" High Speed display(MHS35)<br>
```sudo ./MHS35-show```<br><br>
In case of 4.0" High Speed display(MHS40)<br>
```sudo ./MHS40-show```<br><br>
In case of 4.0" HDMI Display(MPI4008)<br>
```sudo ./MPI4008-show```<br><br>
In case of 5inch HDMI Display-B(Capacitor touch)(MPI5001):<br>
```sudo ./MPI5001-show```<br><br>
In case of 5inch HDMI Display(Resistance touch)(MPI5008)<br>
```sudo ./LCD5-show```<br><br>
In case of 7inch HDMI Display-B-800X480(MPI7001)<br>
```sudo ./LCD7B-show```<br><br>
In case of 7inch HDMI Display-C-1024X600(MPI7002)<br>
```sudo ./LCD7C-show```<br><br><br>
If you need to switch back to the traditional HDMI display<br>
```sudo ./LCD-hdmi```<br>
# 2.4” RPi Display (MPI2401): Wait a few minutes,the system will restart automaticall , enjoy with your LCD.
### Driver install: -------------------------------------------------------------------------------
sudo ./LCD24-show The LCD-show.tar.gz also can be download from:
### WIKI: http://www.lcdwiki.com/RaspberryPi-LCD-Driver
CN: http://www.lcdwiki.com/zh/2.4inch_RPi_Display <br> <br><br>
EN: http://www.lcdwiki.com/2.4inch_RPi_Display
# 2.4” RPi Display For RPi 3A+ (MPI2411):
### Driver install:
sudo ./LCD24-3A+-show
### WIKI:
CN: http://www.lcdwiki.com/zh/2.4inch_RPi_Display_For_RPi_3A+ <br>
EN: http://www.lcdwiki.com/2.4inch_RPi_Display_For_RPi_3A+
# 2.8” RPi Display (MPI2801):
### Driver install:
sudo ./LCD28-show
### WIKI:
CN: http://www.lcdwiki.com/zh/2.8inch_RPi_Display <br>
EN: http://www.lcdwiki.com/2.8inch_RPi_Display
# 3.2” RPi Display (MPI3201):
### Driver install:
sudo ./LCD32-show
### WIKI:
CN: http://www.lcdwiki.com/zh/3.2inch_RPi_Display <br>
EN: http://www.lcdwiki.com/3.2inch_RPi_Display
# MHS-3.2” RPi Display (MHS3232):
### Driver install:
sudo ./MHS32-show
### WIKI:
CN: http://www.lcdwiki.com/zh/MHS-3.2inch_Display <br>
EN: http://www.lcdwiki.com/MHS-3.2inch_Display
# 3.5” RPi Display(MPI3501):
### Driver install:
sudo ./LCD35-show
### WIKI:
CN: http://www.lcdwiki.com/zh/3.5inch_RPi_Display <br>
EN: http://www.lcdwiki.com/3.5inch_RPi_Display
# 3.5” HDMI Display-B(MPI3508):
### Driver install:
sudo ./MPI3508-show
### WIKI:
CN: http://www.lcdwiki.com/zh/3.5inch_HDMI_Display-B <br>
EN: http://www.lcdwiki.com/3.5inch_HDMI_Display-B
# MHS-3.5” RPi Display(MHS3528):
### Driver install:
sudo ./MHS35-show
### WIKI:
CN: http://www.lcdwiki.com/zh/MHS-3.5inch_RPi_Display <br>
EN:http://www.lcdwiki.com/MHS-3.5inch_RPi_Display
# MHS-3.5” RPi Display-B(MHS35XX):
### Driver install:
sudo ./MHS35B-show
### WIKI:
CN: http://www.lcdwiki.com/zh/MHS-3.5inch_RPi_Display-B <br>
EN:http://www.lcdwiki.com/MHS-3.5inch_RPi_Display-B
# 4.0" HDMI Display(MPI4008):
### Driver install:
sudo ./MPI4008-show
### WIKI:
CN: http://www.lcdwiki.com/zh/4inch_HDMI_Display-C <br>
EN: http://www.lcdwiki.com/4inch_HDMI_Display-C
# MHS-4.0" HDMI Display-B(MHS4001):
### Driver install:
sudo ./MHS40-show
### WIKI:
CN: http://www.lcdwiki.com/zh/MHS-4.0inch_Display-B <br>
EN: http://www.lcdwiki.com/MHS-4.0inch_Display-B
# 5.0” HDMI Display(Resistance touch)(MPI5008):
### Driver install:
sudo ./LCD5-show
### WIKI:
CN: http://www.lcdwiki.com/zh/5inch_HDMI_Display <br>
EN: http://www.lcdwiki.com/5inch_HDMI_Display
# 5inch HDMI Display-B(Capacitor touch)(MPI5001):
### Driver install:
sudo ./MPI5001-show
### WIKI:
CN: http://www.lcdwiki.com/zh/5inch_HDMI_Display-B <br>
EN: http://www.lcdwiki.com/5inch_HDMI_Display-B
# 7inch HDMI Display-B-800X480(MPI7001):
### Driver install:
sudo ./LCD7B-show
### WIKI:
CN: http://www.lcdwiki.com/zh/7inch_HDMI_Display-B <br>
EN: http://www.lcdwiki.com/7inch_HDMI_Display-B
# 7inch HDMI Display-C-1024X600(MPI7002):
### Driver install:
sudo ./LCD7C-show
### WIKI:
CN: http://www.lcdwiki.com/zh/7inch_HDMI_Display-C <br>
EN: http://www.lcdwiki.com/7inch_HDMI_Display-C
Wait for a moment after executing the above command, then you can use the corresponding raspberry LCD.
# How to rotate the display direction
This method only applies to the Raspberry Pi series of display screens, other display screens do not apply.
### Method 1, If the driver is not installed, execute the following command (Raspberry Pi needs to connected to the Internet):
sudo rm -rf LCD-show<br>
git clone https://github.com/goodtft/LCD-show.git<br>
chmod -R 755 LCD-show<br>
cd LCD-show/<br>
sudo ./XXX-show 90<br>
After execution, the driver will be installed. The system will automatically restart, and the display screen will rotate 90 degrees to display and touch normally.<br>
( ' XXX-show ' can be changed to the corresponding driver, and ' 90 ' can be changed to 0, 90, 180 and 270, respectively representing rotation angles of 0 degrees, 90 degrees, 180 degrees, 270 degrees)<br>
### Method 2, If the driver is already installed, execute the following command:
cd LCD-show/<br>
sudo ./rotate.sh 90<br>
After execution, the system will automatically restart, and the display screen will rotate 90 degrees to display and touch normally.<br>
( ' 90 ' can be changed to 0, 90, 180 and 270, respectively representing rotation angles of 0 degrees, 90 degrees, 180 degrees, 270 degrees)<br>
(If the rotate.sh prompt cannot be found, use Method 1 to install the latest drivers)

View File

@ -1,65 +0,0 @@
# For more options and information see
# http://rpf.io/configtxt
# Some settings may impact device functionality. See link above for details
# uncomment if you get no picture on HDMI for a default "safe" mode
#hdmi_safe=1
# uncomment this if your display has a black border of unused pixels visible
# and your display can output without overscan
#disable_overscan=1
# uncomment the following to adjust overscan. Use positive numbers if console
# goes off screen, and negative if there is too much border
#overscan_left=16
#overscan_right=16
#overscan_top=16
#overscan_bottom=16
# uncomment to force a console size. By default it will be display's size minus
# overscan.
#framebuffer_width=1280
#framebuffer_height=720
# uncomment if hdmi display is not detected and composite is being output
#hdmi_force_hotplug=1
# uncomment to force a specific HDMI mode (this will force VGA)
#hdmi_group=1
#hdmi_mode=1
# uncomment to force a HDMI mode rather than DVI. This can make audio work in
# DMT (computer monitor) modes
#hdmi_drive=2
# uncomment to increase signal to HDMI, if you have interference, blanking, or
# no display
#config_hdmi_boost=4
# uncomment for composite PAL
#sdtv_mode=2
#uncomment to overclock the arm. 700 MHz is the default.
#arm_freq=800
# Uncomment some or all of these to enable the optional hardware interfaces
#dtparam=i2c_arm=on
#dtparam=i2s=on
#dtparam=spi=on
# Uncomment this to enable infrared communication.
#dtoverlay=gpio-ir,gpio_pin=17
#dtoverlay=gpio-ir-tx,gpio_pin=18
# Additional overlays and parameters are documented /boot/overlays/README
# Enable audio (loads snd_bcm2835)
dtparam=audio=on
[pi4]
# Enable DRM VC4 V3D driver on top of the dispmanx display stack
#dtoverlay=vc4-fkms-v3d
max_framebuffers=2
[all]
#dtoverlay=vc4-fkms-v3d

View File

@ -1,80 +0,0 @@
# For more options and information see
# http://rpf.io/configtxt
# Some settings may impact device functionality. See link above for details
# uncomment if you get no picture on HDMI for a default "safe" mode
#hdmi_safe=1
# uncomment the following to adjust overscan. Use positive numbers if console
# goes off screen, and negative if there is too much border
#overscan_left=16
#overscan_right=16
#overscan_top=16
#overscan_bottom=16
# uncomment to force a console size. By default it will be display's size minus
# overscan.
#framebuffer_width=1280
#framebuffer_height=720
# uncomment if hdmi display is not detected and composite is being output
#hdmi_force_hotplug=1
# uncomment to force a specific HDMI mode (this will force VGA)
#hdmi_group=1
#hdmi_mode=1
# uncomment to force a HDMI mode rather than DVI. This can make audio work in
# DMT (computer monitor) modes
#hdmi_drive=2
# uncomment to increase signal to HDMI, if you have interference, blanking, or
# no display
#config_hdmi_boost=4
# uncomment for composite PAL
#sdtv_mode=2
#uncomment to overclock the arm. 700 MHz is the default.
#arm_freq=800
# Uncomment some or all of these to enable the optional hardware interfaces
#dtparam=i2c_arm=on
#dtparam=i2s=on
#dtparam=spi=on
# Uncomment this to enable infrared communication.
#dtoverlay=gpio-ir,gpio_pin=17
#dtoverlay=gpio-ir-tx,gpio_pin=18
# Additional overlays and parameters are documented /boot/overlays/README
# Enable audio (loads snd_bcm2835)
dtparam=audio=on
# Automatically load overlays for detected cameras
camera_auto_detect=1
# Automatically load overlays for detected DSI displays
display_auto_detect=1
# Enable DRM VC4 V3D driver
#dtoverlay=vc4-kms-v3d
max_framebuffers=2
# Disable compensation for displays with overscan
disable_overscan=1
[cm4]
# Enable host mode on the 2711 built-in XHCI USB controller.
# This line should be removed if the legacy DWC2 controller is required
# (e.g. for USB device mode) or if USB support is not required.
otg_mode=1
[all]
[pi4]
# Run as fast as firmware / board allows
arm_boost=1
[all]

View File

@ -1,83 +0,0 @@
# For more options and information see
# http://rpf.io/configtxt
# Some settings may impact device functionality. See link above for details
# uncomment if you get no picture on HDMI for a default "safe" mode
#hdmi_safe=1
# uncomment the following to adjust overscan. Use positive numbers if console
# goes off screen, and negative if there is too much border
#overscan_left=16
#overscan_right=16
#overscan_top=16
#overscan_bottom=16
# uncomment to force a console size. By default it will be display's size minus
# overscan.
#framebuffer_width=1280
#framebuffer_height=720
# uncomment if hdmi display is not detected and composite is being output
#hdmi_force_hotplug=1
# uncomment to force a specific HDMI mode (this will force VGA)
#hdmi_group=1
#hdmi_mode=1
# uncomment to force a HDMI mode rather than DVI. This can make audio work in
# DMT (computer monitor) modes
#hdmi_drive=2
# uncomment to increase signal to HDMI, if you have interference, blanking, or
# no display
#config_hdmi_boost=4
# uncomment for composite PAL
#sdtv_mode=2
#uncomment to overclock the arm. 700 MHz is the default.
#arm_freq=800
# Uncomment some or all of these to enable the optional hardware interfaces
#dtparam=i2c_arm=on
#dtparam=i2s=on
#dtparam=spi=on
# Uncomment this to enable infrared communication.
#dtoverlay=gpio-ir,gpio_pin=17
#dtoverlay=gpio-ir-tx,gpio_pin=18
# Additional overlays and parameters are documented /boot/overlays/README
# Enable audio (loads snd_bcm2835)
dtparam=audio=on
# Automatically load overlays for detected cameras
camera_auto_detect=1
# Automatically load overlays for detected DSI displays
display_auto_detect=1
# Enable DRM VC4 V3D driver
#dtoverlay=vc4-kms-v3d
max_framebuffers=2
# Run in 64-bit mode
arm_64bit=1
# Disable compensation for displays with overscan
disable_overscan=1
[cm4]
# Enable host mode on the 2711 built-in XHCI USB controller.
# This line should be removed if the legacy DWC2 controller is required
# (e.g. for USB device mode) or if USB support is not required.
otg_mode=1
[all]
[pi4]
# Run as fast as firmware / board allows
arm_boost=1
[all]

View File

@ -47,9 +47,8 @@
#dtparam=i2s=on #dtparam=i2s=on
#dtparam=spi=on #dtparam=spi=on
# Uncomment this to enable infrared communication. # Uncomment this to enable the lirc-rpi module
#dtoverlay=gpio-ir,gpio_pin=17 #dtoverlay=lirc-rpi
#dtoverlay=gpio-ir-tx,gpio_pin=18
# Additional overlays and parameters are documented /boot/overlays/README # Additional overlays and parameters are documented /boot/overlays/README
@ -59,7 +58,7 @@ dtparam=audio=on
[pi4] [pi4]
# Enable DRM VC4 V3D driver on top of the dispmanx display stack # Enable DRM VC4 V3D driver on top of the dispmanx display stack
#dtoverlay=vc4-fkms-v3d #dtoverlay=vc4-fkms-v3d
max_framebuffers=2 #max_framebuffers=2
[all] [all]
#dtoverlay=vc4-fkms-v3d #dtoverlay=vc4-fkms-v3d

View File

@ -57,8 +57,8 @@ dtparam=audio=on
[pi4] [pi4]
# Enable DRM VC4 V3D driver on top of the dispmanx display stack # Enable DRM VC4 V3D driver on top of the dispmanx display stack
#dtoverlay=vc4-fkms-v3d dtoverlay=vc4-fkms-v3d
#max_framebuffers=2 max_framebuffers=2
[all] [all]
#dtoverlay=vc4-fkms-v3d #dtoverlay=vc4-fkms-v3d

View File

@ -1,2 +0,0 @@
options fbtft_device name=flexfb gpios=reset:25,dc:24,cs:8 speed=125000000 bgr=1 fps=60 custom=1 height=480 width=800
options flexfb setaddrwin=0 width=800 height=480 regwidth=16 init=-1,0x29,-3

View File

@ -1,9 +0,0 @@
# /etc/modules: kernel modules to load at boot time.
#
# This file contains the names of kernel modules that should be loaded
# at boot time, one per line. Lines beginning with "#" are ignored.
i2c-dev
spi-bcm2835
flexfb
fbtft_device

View File

@ -1,6 +0,0 @@
# /etc/modules: kernel modules to load at boot time.
#
# This file contains the names of kernel modules that should be loaded
# at boot time, one per line. Lines beginning with "#" are ignored.
i2c-dev

Binary file not shown.

View File

@ -119,42 +119,42 @@ fi
#setting touch screen rotate #setting touch screen rotate
if [ $touch_type = "resistance" ]; then if [ $touch_type = "resistance" ]; then
if [ $new_rotate_value -eq 0 ]; then if [ $new_rotate_value -eq 0 ]; then
sudo cp $cur_dir/usr/99-calibration.conf-$device_id-0 /etc/X11/xorg.conf.d/99-calibration.conf cp $cur_dir/usr/99-calibration.conf-$device_id-0 /etc/X11/xorg.conf.d/99-calibration.conf
echo "LCD rotate value is set to $1" echo "LCD rotate value is set to $1"
elif [ $new_rotate_value -eq 90 ]; then elif [ $new_rotate_value -eq 90 ]; then
sudo cp $cur_dir/usr/99-calibration.conf-$device_id-90 /etc/X11/xorg.conf.d/99-calibration.conf cp $cur_dir/usr/99-calibration.conf-$device_id-90 /etc/X11/xorg.conf.d/99-calibration.conf
echo "LCD rotate value is set to $1" echo "LCD rotate value is set to $1"
elif [ $new_rotate_value -eq 180 ]; then elif [ $new_rotate_value -eq 180 ]; then
sudo cp $cur_dir/usr/99-calibration.conf-$device_id-180 /etc/X11/xorg.conf.d/99-calibration.conf cp $cur_dir/usr/99-calibration.conf-$device_id-180 /etc/X11/xorg.conf.d/99-calibration.conf
echo "LCD rotate value is set to $1" echo "LCD rotate value is set to $1"
elif [ $new_rotate_value -eq 270 ]; then elif [ $new_rotate_value -eq 270 ]; then
sudo cp $cur_dir/usr/99-calibration.conf-$device_id-270 /etc/X11/xorg.conf.d/99-calibration.conf cp $cur_dir/usr/99-calibration.conf-$device_id-270 /etc/X11/xorg.conf.d/99-calibration.conf
echo "LCD rotate value is set to $1" echo "LCD rotate value is set to $1"
elif [ $new_rotate_value -eq 360 ]; then elif [ $new_rotate_value -eq 360 ]; then
sudo cp $cur_dir/usr/99-calibration.conf-$device_id-FLIP-H /etc/X11/xorg.conf.d/99-calibration.conf cp $cur_dir/usr/99-calibration.conf-$device_id-FLIP-H /etc/X11/xorg.conf.d/99-calibration.conf
echo "LCD rotate value is set to flip horizontally" echo "LCD rotate value is set to flip horizontally"
elif [ $new_rotate_value -eq 450 ]; then elif [ $new_rotate_value -eq 450 ]; then
sudo cp $cur_dir/usr/99-calibration.conf-$device_id-FLIP-V /etc/X11/xorg.conf.d/99-calibration.conf cp $cur_dir/usr/99-calibration.conf-$device_id-FLIP-V /etc/X11/xorg.conf.d/99-calibration.conf
echo "LCD rotate value is set to flip vertically" echo "LCD rotate value is set to flip vertically"
fi fi
elif [ $touch_type = "capacity" ]; then elif [ $touch_type = "capacity" ]; then
if [ $new_rotate_value -eq 0 ]; then if [ $new_rotate_value -eq 0 ]; then
sudo cp $cur_dir/usr/40-libinput.conf-0 /etc/X11/xorg.conf.d/40-libinput.conf cp $cur_dir/usr/40-libinput.conf-0 /etc/X11/xorg.conf.d/40-libinput.conf
echo "LCD rotate value is set to $1" echo "LCD rotate value is set to $1"
elif [ $new_rotate_value -eq 90 ]; then elif [ $new_rotate_value -eq 90 ]; then
sudo cp $cur_dir/usr/40-libinput.conf-90 /etc/X11/xorg.conf.d/40-libinput.conf cp $cur_dir/usr/40-libinput.conf-90 /etc/X11/xorg.conf.d/40-libinput.conf
echo "LCD rotate value is set to $1" echo "LCD rotate value is set to $1"
elif [ $new_rotate_value -eq 180 ]; then elif [ $new_rotate_value -eq 180 ]; then
sudo cp $cur_dir/usr/40-libinput.conf-180 /etc/X11/xorg.conf.d/40-libinput.conf cp $cur_dir/usr/40-libinput.conf-180 /etc/X11/xorg.conf.d/40-libinput.conf
echo "LCD rotate value is set to $1" echo "LCD rotate value is set to $1"
elif [ $new_rotate_value -eq 270 ]; then elif [ $new_rotate_value -eq 270 ]; then
sudo cp $cur_dir/usr/40-libinput.conf-270 /etc/X11/xorg.conf.d/40-libinput.conf cp $cur_dir/usr/40-libinput.conf-270 /etc/X11/xorg.conf.d/40-libinput.conf
echo "LCD rotate value is set to $1" echo "LCD rotate value is set to $1"
elif [ $new_rotate_value -eq 360 ]; then elif [ $new_rotate_value -eq 360 ]; then
sudo cp $cur_dir/usr/40-libinput.conf-FLIP-H /etc/X11/xorg.conf.d/40-libinput.conf cp $cur_dir/usr/40-libinput.conf-FLIP-H /etc/X11/xorg.conf.d/40-libinput.conf
echo "LCD rotate value is set to flip horizontally" echo "LCD rotate value is set to flip horizontally"
elif [ $new_rotate_value -eq 450 ]; then elif [ $new_rotate_value -eq 450 ]; then
sudo cp $cur_dir/usr/40-libinput.conf-FLIP-V /etc/X11/xorg.conf.d/40-libinput.conf cp $cur_dir/usr/40-libinput.conf-FLIP-V /etc/X11/xorg.conf.d/40-libinput.conf
echo "LCD rotate value is set to flip vertically" echo "LCD rotate value is set to flip vertically"
fi fi
else else

View File

@ -38,26 +38,16 @@ sudo cp -rf /boot/config.txt ./.system_backup
sudo cp -rf /boot/cmdline.txt ./.system_backup/ sudo cp -rf /boot/cmdline.txt ./.system_backup/
if test "$root_dev" = "/dev/mmcblk0p7";then if test "$root_dev" = "/dev/mmcblk0p7";then
sudo cp -rf ./boot/config-noobs-nomal.txt /boot/config.txt sudo cp -rf ./boot/config-noobs-nomal.txt /boot/config.txt
#sudo cp -rf ./usr/cmdline.txt-noobs-original /boot/cmdline.txt sudo cp -rf ./usr/cmdline.txt-noobs-original /boot/cmdline.txt
else else
sudo cp -rf ./boot/config-nomal.txt /boot/config.txt sudo cp -rf ./boot/config-nomal.txt /boot/config.txt
#sudo cp -rf ./usr/cmdline.txt-original /boot/cmdline.txt sudo cp -rf ./usr/cmdline.txt-original /boot/cmdline.txt
fi fi
if [ -f /usr/share/X11/xorg.conf.d/99-fbturbo.conf ]; then
sudo cp -rf /usr/share/X11/xorg.conf.d/99-fbturbo.conf ./.system_backup/ sudo cp -rf /usr/share/X11/xorg.conf.d/99-fbturbo.conf ./.system_backup/
fi
sudo cp -rf ./usr/99-fbturbo.conf-original /usr/share/X11/xorg.conf.d/99-fbturbo.conf sudo cp -rf ./usr/99-fbturbo.conf-original /usr/share/X11/xorg.conf.d/99-fbturbo.conf
sudo cp -rf /etc/rc.local ./.system_backup/ sudo cp -rf /etc/rc.local ./.system_backup/
sudo cp -rf ./etc/rc.local-original /etc/rc.local sudo cp -rf ./etc/rc.local-original /etc/rc.local
sudo cp -rf /etc/modules ./.system_backup/
sudo cp -rf ./etc/modules-original /etc/modules
if [ -f /etc/modprobe.d/fbtft.conf ]; then
sudo cp -rf /etc/modprobe.d/fbtft.conf ./.system_backup
sudo rm -rf /etc/modprobe.d/fbtft.conf
fi
if [ -f /etc/inittab ]; then if [ -f /etc/inittab ]; then
sudo cp -rf /etc/inittab ./.system_backup sudo cp -rf /etc/inittab ./.system_backup
sudo rm -rf /etc/inittab sudo rm -rf /etc/inittab

View File

@ -1,26 +0,0 @@
#!/bin/bash
big_version=`lsb_release -r | awk -F ' ' '{printf $NF}'`
deb_version=`cat /etc/debian_version | tr -d '\n'`
if [ $(getconf WORD_BIT) = '32' ] && [ $(getconf LONG_BIT) = '64' ] ; then
hardware_arch=64
else
hardware_arch=32
fi
if [ $hardware_arch -eq 32 ]; then
if [ $(($big_version)) -lt 10 ]; then
sudo cp -rf ./boot/config-nomal-10.9-32.txt ./boot/config.txt.bak
else
if [[ "$deb_version" < "10.9" ]] || [[ "$deb_version" = "10.9" ]]; then
sudo cp -rf ./boot/config-nomal-10.9-32.txt ./boot/config.txt.bak
else
sudo cp -rf ./boot/config-nomal-11.4-32.txt ./boot/config.txt.bak
fi
fi
elif [ $hardware_arch -eq 64 ]; then
sudo cp -rf ./boot/config-nomal-11.4-64.txt ./boot/config.txt.bak
fi

View File

@ -27,13 +27,10 @@ fi
ls -al ./.system_backup/*.dtb > /dev/null 2>&1 && sudo cp -rf ./.system_backup/*.dtb /boot/overlays/ ls -al ./.system_backup/*.dtb > /dev/null 2>&1 && sudo cp -rf ./.system_backup/*.dtb /boot/overlays/
ls -al ./.system_backup/*.dtbo > /dev/null 2>&1 && sudo cp -rf ./.system_backup/*.dtbo /boot/overlays/ ls -al ./.system_backup/*.dtbo > /dev/null 2>&1 && sudo cp -rf ./.system_backup/*.dtbo /boot/overlays/
if [ -f ./.system_backup/99-fbturbo.conf ];then
sudo cp -rf ./.system_backup/99-fbturbo.conf /usr/share/X11/xorg.conf.d sudo cp -rf ./.system_backup/99-fbturbo.conf /usr/share/X11/xorg.conf.d
fi
sudo cp -rf ./.system_backup/cmdline.txt /boot/ sudo cp -rf ./.system_backup/cmdline.txt /boot/
sudo cp -rf ./.system_backup/config.txt /boot/ sudo cp -rf ./.system_backup/config.txt /boot/
sudo cp -rf ./.system_backup/rc.local /etc/ sudo cp -rf ./.system_backup/rc.local /etc/
sudo cp -rf ./.system_backup/modules /etc/
if [ -f /etc/inittab ]; then if [ -f /etc/inittab ]; then
sudo rm -rf /etc/inittab sudo rm -rf /etc/inittab
@ -42,13 +39,6 @@ if [ -f ./.system_backup/inittab ]; then
sudo cp -rf ./.system_backup/inittab /etc sudo cp -rf ./.system_backup/inittab /etc
fi fi
if [ -f /etc/modprobe.d/fbtft.conf ]; then
sudo rm -rf /etc/modprobe.d/fbtft.conf
fi
if [ -f ./.system_backup/fbtft.conf ]; then
sudo cp -rf ./.system_backup/fbtft.conf /etc/modprobe.d
fi
type fbcp > /dev/null 2>&1 type fbcp > /dev/null 2>&1
if [ $? -eq 0 ]; then if [ $? -eq 0 ]; then
sudo rm -rf /usr/local/bin/fbcp sudo rm -rf /usr/local/bin/fbcp
@ -76,7 +66,7 @@ sudo dpkg -P xserver-xorg-input-evdev
#echo -e "\033[31m$result\033[0m" #echo -e "\033[31m$result\033[0m"
fi fi
if [ -f ./.system_backup/10-evdev.conf ]; then if [ -f ./.system_backup/10-evdev.conf ]; then
sudo dpkg -i -B ./xserver-xorg-input-evdev_1%3a2.10.6-1+b1_armhf.deb sudo dpkg -i -B ./xserver-xorg-input-evdev_2.10.5-1_armhf.deb
#sudo apt-get install xserver-xorg-input-evdev -y 2> error_output.txt #sudo apt-get install xserver-xorg-input-evdev -y 2> error_output.txt
#result=`cat ./error_output.txt` #result=`cat ./error_output.txt`
#echo -e "\033[31m$result\033[0m" #echo -e "\033[31m$result\033[0m"

View File

@ -1,6 +1,6 @@
Section "InputClass" Section "InputClass"
Identifier "calibration" Identifier "calibration"
MatchProduct "ADS7846 Touchscreen" MatchProduct "ADS7846 Touchscreen"
Option "Calibration" "137 3912 83 4023" Option "Calibration" "72 3916 182 4012"
Option "SwapAxes" "0" Option "SwapAxes" "0"
EndSection EndSection

View File

@ -1,6 +1,6 @@
Section "InputClass" Section "InputClass"
Identifier "calibration" Identifier "calibration"
MatchProduct "ADS7846 Touchscreen" MatchProduct "ADS7846 Touchscreen"
Option "Calibration" "3912 137 4023 83" Option "Calibration" "3916 72 4012 182"
Option "SwapAxes" "0" Option "SwapAxes" "0"
EndSection EndSection

View File

@ -1,6 +1,6 @@
Section "InputClass" Section "InputClass"
Identifier "calibration" Identifier "calibration"
MatchProduct "ADS7846 Touchscreen" MatchProduct "ADS7846 Touchscreen"
Option "Calibration" "4023 83 137 3912" Option "Calibration" "4012 182 72 3916"
Option "SwapAxes" "1" Option "SwapAxes" "1"
EndSection EndSection

View File

@ -1,6 +1,6 @@
Section "InputClass" Section "InputClass"
Identifier "calibration" Identifier "calibration"
MatchProduct "ADS7846 Touchscreen" MatchProduct "ADS7846 Touchscreen"
Option "Calibration" "83 4023 3912 137" Option "Calibration" "182 4012 3916 72"
Option "SwapAxes" "1" Option "SwapAxes" "1"
EndSection EndSection

View File

@ -1,6 +1,6 @@
Section "InputClass" Section "InputClass"
Identifier "calibration" Identifier "calibration"
MatchProduct "ADS7846 Touchscreen" MatchProduct "ADS7846 Touchscreen"
Option "Calibration" "3912 137 83 4023" Option "Calibration" "3916 72 182 4012"
Option "SwapAxes" "0" Option "SwapAxes" "0"
EndSection EndSection

View File

@ -1,6 +1,6 @@
Section "InputClass" Section "InputClass"
Identifier "calibration" Identifier "calibration"
MatchProduct "ADS7846 Touchscreen" MatchProduct "ADS7846 Touchscreen"
Option "Calibration" "137 3912 4023 83" Option "Calibration" "72 3916 4012 182"
Option "SwapAxes" "0" Option "SwapAxes" "0"
EndSection EndSection

View File

@ -1,6 +0,0 @@
Section "InputClass"
Identifier "calibration"
MatchProduct "ADS7846 Touchscreen"
Option "Calibration" "149 3861 135 3845"
Option "SwapAxes" "0"
EndSection

View File

@ -1,6 +0,0 @@
Section "InputClass"
Identifier "calibration"
MatchProduct "ADS7846 Touchscreen"
Option "Calibration" "3861 149 3845 135"
Option "SwapAxes" "0"
EndSection

View File

@ -1,6 +0,0 @@
Section "InputClass"
Identifier "calibration"
MatchProduct "ADS7846 Touchscreen"
Option "Calibration" "3845 135 149 3861"
Option "SwapAxes" "1"
EndSection

View File

@ -1,6 +0,0 @@
Section "InputClass"
Identifier "calibration"
MatchProduct "ADS7846 Touchscreen"
Option "Calibration" "135 3845 3861 149"
Option "SwapAxes" "1"
EndSection

View File

@ -1,6 +0,0 @@
Section "InputClass"
Identifier "calibration"
MatchProduct "ADS7846 Touchscreen"
Option "Calibration" "3861 149 135 3845"
Option "SwapAxes" "0"
EndSection

View File

@ -1,6 +0,0 @@
Section "InputClass"
Identifier "calibration"
MatchProduct "ADS7846 Touchscreen"
Option "Calibration" "149 3861 3845 135"
Option "SwapAxes" "0"
EndSection

View File

@ -1,9 +0,0 @@
Section "InputClass"
Identifier "calibration"
MatchProduct "Goodix Capacitive TouchScreen"
Option "Calibration" "315 7 479 18"
Option "SwapAxes" "0"
Option "EmulateThirdButton" "1"
Option "EmulateThirdButtonTimeout" "1000"
Option "EmulateThirdButtonMoveThreshold" "300"
EndSection

View File

@ -1,9 +0,0 @@
Section "InputClass"
Identifier "calibration"
MatchProduct "Goodix Capacitive TouchScreen"
Option "Calibration" "7 315 18 479"
Option "SwapAxes" "0"
Option "EmulateThirdButton" "1"
Option "EmulateThirdButtonTimeout" "1000"
Option "EmulateThirdButtonMoveThreshold" "300"
EndSection

View File

@ -1,9 +0,0 @@
Section "InputClass"
Identifier "calibration"
MatchProduct "Goodix Capacitive TouchScreen"
Option "Calibration" "315 7 18 479"
Option "SwapAxes" "1"
Option "EmulateThirdButton" "1"
Option "EmulateThirdButtonTimeout" "1000"
Option "EmulateThirdButtonMoveThreshold" "300"
EndSection

View File

@ -1,9 +0,0 @@
Section "InputClass"
Identifier "calibration"
MatchProduct "Goodix Capacitive TouchScreen"
Option "Calibration" "7 315 479 18"
Option "SwapAxes" "1"
Option "EmulateThirdButton" "1"
Option "EmulateThirdButtonTimeout" "1000"
Option "EmulateThirdButtonMoveThreshold" "300"
EndSection

View File

@ -1,9 +0,0 @@
Section "InputClass"
Identifier "calibration"
MatchProduct "ADS7846 Touchscreen"
Option "Calibration" "3880 268 227 3936"
Option "SwapAxes" "0"
Option "EmulateThirdButton" "1"
Option "EmulateThirdButtonTimeout" "1000"
Option "EmulateThirdButtonMoveThreshold" "300"
EndSection

View File

@ -1,9 +0,0 @@
Section "InputClass"
Identifier "calibration"
MatchProduct "ADS7846 Touchscreen"
Option "Calibration" "268 3880 3936 227"
Option "SwapAxes" "0"
Option "EmulateThirdButton" "1"
Option "EmulateThirdButtonTimeout" "1000"
Option "EmulateThirdButtonMoveThreshold" "300"
EndSection

View File

@ -1,9 +0,0 @@
Section "InputClass"
Identifier "calibration"
MatchProduct "ADS7846 Touchscreen"
Option "Calibration" "227 3936 268 3880"
Option "SwapAxes" "1"
Option "EmulateThirdButton" "1"
Option "EmulateThirdButtonTimeout" "1000"
Option "EmulateThirdButtonMoveThreshold" "300"
EndSection

View File

@ -1,9 +0,0 @@
Section "InputClass"
Identifier "calibration"
MatchProduct "ADS7846 Touchscreen"
Option "Calibration" "3936 227 3880 268"
Option "SwapAxes" "1"
Option "EmulateThirdButton" "1"
Option "EmulateThirdButtonTimeout" "1000"
Option "EmulateThirdButtonMoveThreshold" "300"
EndSection

View File

@ -1,9 +0,0 @@
Section "InputClass"
Identifier "calibration"
MatchProduct "ADS7846 Touchscreen"
Option "Calibration" "3968 61 188 3960"
Option "SwapAxes" "1"
Option "EmulateThirdButton" "1"
Option "EmulateThirdButtonTimeout" "1000"
Option "EmulateThirdButtonMoveThreshold" "300"
EndSection

View File

@ -1,9 +0,0 @@
Section "InputClass"
Identifier "calibration"
MatchProduct "ADS7846 Touchscreen"
Option "Calibration" "61 3968 3960 188"
Option "SwapAxes" "1"
Option "EmulateThirdButton" "1"
Option "EmulateThirdButtonTimeout" "1000"
Option "EmulateThirdButtonMoveThreshold" "300"
EndSection

View File

@ -1,9 +0,0 @@
Section "InputClass"
Identifier "calibration"
MatchProduct "ADS7846 Touchscreen"
Option "Calibration" "3971 205 4000 80"
Option "SwapAxes" "0"
Option "EmulateThirdButton" "1"
Option "EmulateThirdButtonTimeout" "1000"
Option "EmulateThirdButtonMoveThreshold" "300"
EndSection

View File

@ -1,9 +0,0 @@
Section "InputClass"
Identifier "calibration"
MatchProduct "ADS7846 Touchscreen"
Option "Calibration" "188 3960 61 3968"
Option "SwapAxes" "0"
Option "EmulateThirdButton" "1"
Option "EmulateThirdButtonTimeout" "1000"
Option "EmulateThirdButtonMoveThreshold" "300"
EndSection

View File

@ -1,9 +0,0 @@
Section "InputClass"
Identifier "calibration"
MatchProduct "ADS7846 Touchscreen"
Option "Calibration" "94 3973 183 3927"
Option "SwapAxes" "1"
Option "EmulateThirdButton" "1"
Option "EmulateThirdButtonTimeout" "1000"
Option "EmulateThirdButtonMoveThreshold" "300"
EndSection

View File

@ -1,9 +0,0 @@
Section "InputClass"
Identifier "calibration"
MatchProduct "ADS7846 Touchscreen"
Option "Calibration" "3961 69 3975 209"
Option "SwapAxes" "1"
Option "EmulateThirdButton" "1"
Option "EmulateThirdButtonTimeout" "1000"
Option "EmulateThirdButtonMoveThreshold" "300"
EndSection

View File

@ -1,9 +0,0 @@
Section "InputClass"
Identifier "calibration"
MatchProduct "ADS7846 Touchscreen"
Option "Calibration" "141 3838 264 3955"
Option "SwapAxes" "0"
Option "EmulateThirdButton" "1"
Option "EmulateThirdButtonTimeout" "1000"
Option "EmulateThirdButtonMoveThreshold" "300"
EndSection

View File

@ -1,9 +0,0 @@
Section "InputClass"
Identifier "calibration"
MatchProduct "ADS7846 Touchscreen"
Option "Calibration" "3838 141 3955 264"
Option "SwapAxes" "0"
Option "EmulateThirdButton" "1"
Option "EmulateThirdButtonTimeout" "1000"
Option "EmulateThirdButtonMoveThreshold" "300"
EndSection

View File

@ -1,9 +0,0 @@
Section "InputClass"
Identifier "calibration"
MatchProduct "ADS7846 Touchscreen"
Option "Calibration" "264 3955 3838 141"
Option "SwapAxes" "1"
Option "EmulateThirdButton" "1"
Option "EmulateThirdButtonTimeout" "1000"
Option "EmulateThirdButtonMoveThreshold" "300"
EndSection

View File

@ -1,9 +0,0 @@
Section "InputClass"
Identifier "calibration"
MatchProduct "ADS7846 Touchscreen"
Option "Calibration" "3955 264 141 3838"
Option "SwapAxes" "1"
Option "EmulateThirdButton" "1"
Option "EmulateThirdButtonTimeout" "1000"
Option "EmulateThirdButtonMoveThreshold" "300"
EndSection

View File

@ -1,9 +0,0 @@
Section "InputClass"
Identifier "calibration"
MatchProduct "generic ft5x06 (11)"
Option "Calibration" "0 239 0 319"
Option "SwapAxes" "0"
Option "EmulateThirdButton" "1"
Option "EmulateThirdButtonTimeout" "1000"
Option "EmulateThirdButtonMoveThreshold" "300"
EndSection

View File

@ -1,9 +0,0 @@
Section "InputClass"
Identifier "calibration"
MatchProduct "generic ft5x06 (11)"
Option "Calibration" "239 0 319 0"
Option "SwapAxes" "0"
Option "EmulateThirdButton" "1"
Option "EmulateThirdButtonTimeout" "1000"
Option "EmulateThirdButtonMoveThreshold" "300"
EndSection

View File

@ -1,9 +0,0 @@
Section "InputClass"
Identifier "calibration"
MatchProduct "generic ft5x06 (11)"
Option "Calibration" "0 239 319 0"
Option "SwapAxes" "1"
Option "EmulateThirdButton" "1"
Option "EmulateThirdButtonTimeout" "1000"
Option "EmulateThirdButtonMoveThreshold" "300"
EndSection

View File

@ -1,9 +0,0 @@
Section "InputClass"
Identifier "calibration"
MatchProduct "generic ft5x06 (11)"
Option "Calibration" "239 0 0 319"
Option "SwapAxes" "1"
Option "EmulateThirdButton" "1"
Option "EmulateThirdButtonTimeout" "1000"
Option "EmulateThirdButtonMoveThreshold" "300"
EndSection

View File

@ -1 +1 @@
console=serial0,115200 console=tty1 root=/dev/mmcblk0p7 rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait quiet splash plymouth.ignore-serial-consoles dwc_otg.lpm_enable=0 console=serial0,115200 console=tty1 root=/dev/mmcblk0p7 rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait quiet splash plymouth.ignore-serial-consoles

View File

@ -1 +1 @@
console=serial0,115200 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait quiet splash plymouth.ignore-serial-consoles dwc_otg.lpm_enable=0 console=serial0,115200 console=tty1 root=PARTUUID=f27bf3fc-02 rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait quiet splash plymouth.ignore-serial-consoles

BIN
usr/fbcp

Binary file not shown.

View File

@ -1,8 +0,0 @@
*.ko.cmd
*.o.cmd
.tmp_versions
*.ko
*.o
*.S
*.symvers
*.order

View File

@ -1,268 +0,0 @@
cmake_minimum_required(VERSION 2.8)
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel." FORCE)
endif()
include_directories(/opt/vc/include)
link_directories(/opt/vc/lib)
file(GLOB sourceFiles *.cpp)
message(STATUS "Doing a ${CMAKE_BUILD_TYPE} build")
if ("${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
message(STATUS "Pass -DCMAKE_BUILD_TYPE=Release to do a fast optimized build.")
endif()
# Detect if current hardware is Raspberry Pi Zero/Zero W, and enable targeting Zero with -DSINGLE_CORE_BOARD=ON if so.
execute_process(COMMAND cat /proc/cpuinfo OUTPUT_VARIABLE CPU_INFO)
STRING(REGEX MATCH "Revision[\t ]*:[\t ]*([0-9a-f]+)" BOARD_REVISION ${CPU_INFO})
set(BOARD_REVISION "${CMAKE_MATCH_1}")
message(STATUS "Board revision: ${CMAKE_MATCH_1}")
set(DEFAULT_TO_SINGLE_CORE_BOARD OFF)
set(DEFAULT_TO_ARMV6Z OFF)
set(DEFAULT_TO_ARMV7A OFF)
set(DEFAULT_TO_ARMV8A OFF)
# http://ozzmaker.com/check-raspberry-software-hardware-version-command-line/
if (BOARD_REVISION MATCHES "(0002)|(0003)|(0004)|(0005)|(0006)|(0007)|(0008)|(0009)" OR BOARD_REVISION MATCHES "(000d)|(000e)|(000f)|(0010)|(0011)|(0012)" OR BOARD_REVISION MATCHES "(900092)|(900093)|(9000c1)")
message(STATUS "Detected this Pi to be one of: Pi A, A+, B rev. 1, B rev. 2, B+, CM1, Zero or Zero W, with single hardware core and ARMv6Z instruction set CPU.")
set(DEFAULT_TO_SINGLE_CORE_BOARD ON)
set(DEFAULT_TO_ARMV6Z ON)
elseif(BOARD_REVISION MATCHES "(a01041)|(a21041)")
message(STATUS "Detected this board to be a Pi 2 Model B < rev 1.2 with ARMv7-A instruction set CPU.")
set(DEFAULT_TO_ARMV7A ON)
elseif(BOARD_REVISION MATCHES "(a02082)|(a22082)|(a020d3)|(9020e0)|(a03111)|(b03111)|(c03111)")
message(STATUS "Detected this Pi to be one of: Pi 2B rev. 1.2, 3B, 3B+, 3A+, CM3, CM3 lite or 4B(1GB,2GB,4GB RAM), with 4 hardware cores and ARMv8-A instruction set CPU.")
set(DEFAULT_TO_ARMV8A ON)
else()
message(WARNING "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)")
endif()
option(SINGLE_CORE_BOARD "Target a Raspberry Pi with only one hardware core (Pi Zero)" ${DEFAULT_TO_SINGLE_CORE_BOARD})
if (SINGLE_CORE_BOARD)
message(STATUS "Targeting a Raspberry Pi with only one hardware core")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSINGLE_CORE_BOARD=1")
endif()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -marm -mabi=aapcs-linux -mhard-float -mfloat-abi=hard -mlittle-endian -mtls-dialect=gnu2 -funsafe-math-optimizations")
option(ARMV6Z "Target a Raspberry Pi with ARMv6Z instruction set (Pi 1A, 1A+, 1B, 1B+, Zero, Zero W)" ${DEFAULT_TO_ARMV6Z})
if (ARMV6Z)
message(STATUS "Enabling optimization flags that target ARMv6Z instruction set (Pi Model A, Pi Model B, Compute Module 1, Pi Zero/Zero W)")
# Currently disabled, no test data to know if this would be faster
# set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=armv6z -mfpu=vfp")
endif()
option(ARMV7A "Target a Raspberry Pi with ARMv7-A instruction set (Pi 2B < rev 1.2)" ${DEFAULT_TO_ARMV7A})
if (ARMV7A)
message(STATUS "Enabling optimization flags that target ARMv7-A instruction set (Pi 2B < rev 1.2)")
# Currently disabled, no test data to know if this would be faster
# set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=cortex-a7 -mcpu=cortex-a7 -mtune=cortex-a7 -mfpu=neon-vfpv4")
endif()
option(ARMV8A "Target a Raspberry Pi with ARMv8-A instruction set (Pi 2B >= rev. 1.2, 3B, 3B+, CM3 or CM3 lite)" ${DEFAULT_TO_ARMV8A})
if (ARMV8A)
message(STATUS "Enabling optimization flags that target ARMv8-A instruction set (Pi 2B >= rev. 1.2, 3B, 3B+, CM3 or CM3 lite)")
# N.B. Here should be possible to set -mfpu=neon-vfpv4, though for some reason that generates really slow code, tested on gcc (Raspbian 6.3.0-18+rpi1+deb9u1) 6.3.0 20170516
# Currently disabled, seems to be a tiny 1-2% slower (or no difference, drown in noise)
# set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=armv8-a+crc -mcpu=cortex-a53 -mtune=cortex-a53")
endif()
set(GPIO_TFT_DATA_CONTROL 0 CACHE STRING "Explicitly specify the Data/Control GPIO pin (sometimes also called Register Select)")
if (GPIO_TFT_DATA_CONTROL GREATER 0)
message(STATUS "Using 4-wire SPI mode of communication, with GPIO pin ${GPIO_TFT_DATA_CONTROL} for Data/Control line")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DGPIO_TFT_DATA_CONTROL=${GPIO_TFT_DATA_CONTROL}")
elseif (GPIO_TFT_DATA_CONTROL LESS 0)
message(STATUS "Using 3-wire SPI mode of communication, i.e. a display that does not have a Data/Control line")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSPI_3WIRE_PROTOCOL=1")
endif()
set(GPIO_TFT_RESET_PIN 0 CACHE STRING "Explicitly specify the Reset GPIO pin (leave out if there is no Reset line)")
if (GPIO_TFT_RESET_PIN)
message(STATUS "Using GPIO pin ${GPIO_TFT_RESET_PIN} for Reset line")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DGPIO_TFT_RESET_PIN=${GPIO_TFT_RESET_PIN}")
endif()
set(GPIO_TFT_BACKLIGHT 0 CACHE STRING "Explicitly specify the Backlight GPIO pin (leave out if there is no controllable Backlight line)")
if (GPIO_TFT_BACKLIGHT)
message(STATUS "Using GPIO pin ${GPIO_TFT_BACKLIGHT} for backlight")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DGPIO_TFT_BACKLIGHT=${GPIO_TFT_BACKLIGHT}")
endif()
set(LOW_BATTERY_PIN 0 CACHE STRING "Explicitly specify the low batt GPIO pin (leave out if there is no low batt signal)")
if (LOW_BATTERY_PIN)
message(STATUS "Using GPIO pin ${LOW_BATTERY_PIN} for low battery status")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DLOW_BATTERY_PIN=${LOW_BATTERY_PIN}")
endif()
option(BACKLIGHT_CONTROL "If true, enables fbcp-ili9341 to take control of backlight" OFF)
if (BACKLIGHT_CONTROL)
message(STATUS "Enabling fbcp-ili9341 backlight control")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DBACKLIGHT_CONTROL")
endif()
option(DISPLAY_CROPPED_INSTEAD_OF_SCALING "If ON, displays the cropped center part of the source image on the SPI display. If OFF, scales the source image to the SPI display" OFF)
if (DISPLAY_CROPPED_INSTEAD_OF_SCALING)
message(STATUS "Cropping source image to view instead of scaling. This will produce crisp pixel perfect rendering, though edges of the display will be cut off if the HDMI and SPI display resolutions do not match. (pass -DDISPLAY_CROPPED_INSTEAD_OF_SCALING=OFF to scale instead of crop)")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DDISPLAY_CROPPED_INSTEAD_OF_SCALING")
else()
message(STATUS "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.")
endif()
option(DISPLAY_BREAK_ASPECT_RATIO_WHEN_SCALING "If ON, the display is scaled stretched to fit the screen, disregarding preserving aspect ratio." OFF)
if (DISPLAY_BREAK_ASPECT_RATIO_WHEN_SCALING)
message(STATUS "Ignoring aspect ratio when scaling source image to the SPI display (Pass -DDISPLAY_BREAK_ASPECT_RATIO_WHEN_SCALING=OFF to preserve aspect ratio)")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DDISPLAY_BREAK_ASPECT_RATIO_WHEN_SCALING")
else()
message(STATUS "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)")
endif()
set(STATISTICS 1 CACHE STRING "Set to 0, 1 or 2 to configure the level of statistics to display. 0=OFF, 1=regular statistics, 2=frame rate interval histogram")
if (STATISTICS GREATER 1)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DFRAME_COMPLETION_TIME_STATISTICS")
endif()
if (STATISTICS GREATER 0)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSTATISTICS")
endif()
set(SPI_BUS_CLOCK_DIVISOR 0 CACHE STRING "Specify the SPI0 CDIV register value that defines the SPI0 bus speed (No default value, try a safe setting, e.g. -DSPI_BUS_CLOCK_DIVISOR=40 first")
if (SPI_BUS_CLOCK_DIVISOR)
message(STATUS "SPI_BUS_CLOCK_DIVISOR set to ${SPI_BUS_CLOCK_DIVISOR}. 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). A safe starting default value may be -DSPI_BUS_CLOCK_DIVISOR=40")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSPI_BUS_CLOCK_DIVISOR=${SPI_BUS_CLOCK_DIVISOR}")
else()
message(FATAL_ERROR "Please define -DSPI_BUS_CLOCK_DIVISOR=<some even number> on the CMake command line! (see files ili9341.h/waveshare35b.h for details) This parameter along with core_freq=xxx in /boot/config.txt defines the SPI display speed. Smaller divisor number=faster speed, higher number=slower.")
endif()
option(KERNEL_MODULE_CLIENT "If enabled, run fbcp-ili9341 userland program against the kernel module found in kernel/ subdirectory (must be started before the userland program)" OFF)
if (KERNEL_MODULE_CLIENT)
message(STATUS "KERNEL_MODULE_CLIENT enabled, building userland program to operate against fbcp-ili9341 kernel module")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DKERNEL_MODULE_CLIENT=1")
endif()
option(DISPLAY_SWAP_BGR "If true, reverses RGB<->BGR color channels" OFF)
if (DISPLAY_SWAP_BGR)
message(STATUS "Swapping RGB<->BGR color channels")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DDISPLAY_SWAP_BGR")
endif()
option(DISPLAY_INVERT_COLORS "If true, inverts display colors (white=0, black=31/63" OFF)
if (DISPLAY_INVERT_COLORS)
message(STATUS "Inverting display colors (white=0, black=31/63)")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DDISPLAY_INVERT_COLORS")
endif()
option(DISPLAY_ROTATE_180_DEGREES "If true, rotates display upside down" OFF)
if (DISPLAY_ROTATE_180_DEGREES)
message(STATUS "Rotating display output by 180 degrees")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DDISPLAY_ROTATE_180_DEGREES")
endif()
option(KEDEI_V63_MPI3501 "Target KeDei 3.5 inch SPI TFTLCD 480*320 16bit/186bit version 6.3 2018/4/9 display (MPI3501)" OFF)
option(USE_DMA_TRANSFERS "If enabled, fbcp-ili9341 utilizes DMA to transfer data to the display. Otherwise, Polled SPI mode is used to drive communication with the SPI display" ON)
# KeDei does not do DMA well, since after each 32-bit word one needs to refresh the chip select signal, preventing DMA batch operations altogether.
if (KEDEI_V63_MPI3501)
set(USE_DMA_TRANSFERS OFF)
endif()
if (USE_DMA_TRANSFERS)
message(STATUS "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>.")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DUSE_DMA_TRANSFERS=1")
else()
message(STATUS "USE_DMA_TRANSFERS is disabled, this is not the most efficient mode. Try running CMake with -DUSE_DMA_TRANSFERS=ON to improve performance.")
endif()
set(DMA_TX_CHANNEL 0 CACHE STRING "Specifies the DMA send channel to use")
if (DMA_TX_CHANNEL)
message(STATUS "DMA_TX_CHANNEL=${DMA_TX_CHANNEL}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DDMA_TX_CHANNEL=${DMA_TX_CHANNEL}")
endif()
set(DMA_RX_CHANNEL 0 CACHE STRING "Specifies the DMA receive channel to use")
if (DMA_RX_CHANNEL)
message(STATUS "DMA_RX_CHANNEL=${DMA_RX_CHANNEL}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DDMA_RX_CHANNEL=${DMA_RX_CHANNEL}")
endif()
option(ADAFRUIT_ILI9341_PITFT "Target Adafruit's ILI9341-based PiTFT display" OFF)
option(FREEPLAYTECH_WAVESHARE32B "Target WaveShare32B ILI9341 display on Freeplaytech's CM3/Zero devices)" OFF)
option(WAVESHARE35B_ILI9486 "Target Waveshare's ILI9486-based Waveshare Wavepear 3.5 inch (B) display" OFF)
option(TONTEC_MZ61581 "Target Tontec's MZ61581-based 3.5 inch display" OFF)
if (ADAFRUIT_ILI9341_PITFT)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DILI9341 -DADAFRUIT_ILI9341_PITFT")
message(STATUS "Targeting Adafruit PiTFT with ILI9340/ILI9341")
elseif(FREEPLAYTECH_WAVESHARE32B)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DILI9341 -DFREEPLAYTECH_WAVESHARE32B")
message(STATUS "Targeting WaveShare 3.2 inch (B) display with ILI9341")
elseif(ADAFRUIT_HX8357D_PITFT)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DHX8357D -DADAFRUIT_HX8357D_PITFT")
message(STATUS "Targeting Adafruit 3.5 inch PiTFT with HX8357D")
elseif(WAVESHARE_ST7789VW_HAT)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DST7789 -DST7789VW -DWAVESHARE_ST7789VW_HAT")
message(STATUS "Targeting WaveShare 240x240 1.3inch IPS LCD Hat with ST7789VW controller")
elseif(WAVESHARE_ST7735S_HAT)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DST7735S -DWAVESHARE_ST7735S_HAT")
message(STATUS "Targeting WaveShare 128x128 1.44inch LCD Hat with ST7735S controller")
elseif(ILI9340)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DILI9340")
message(STATUS "Targeting ILI9340")
elseif(KEDEI_V63_MPI3501)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DMPI3501 -DKEDEI_V63_MPI3501")
message(STATUS "Targeting KeDei 3.5 inch SPI TFTLCD 480*320 16bit/18bit version 6.3 2018/4/9 display (MPI3501)")
if (USE_DMA_TRANSFERS)
message(FATAL_ERROR "DMA is unfortunately not possible with KeDei MPI3501. Please disable with -DUSE_DMA_TRANSFERS=OFF.")
endif()
elseif(ILI9341)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DILI9341")
message(STATUS "Targeting ILI9341")
elseif(ST7789)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DST7789")
message(STATUS "Targeting ST7789")
elseif(ST7789VW)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DST7789 -DST7789VW")
message(STATUS "Targeting ST7789VW (based as variant of ST7789)")
elseif(ST7735R)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DST7735R")
message(STATUS "Targeting ST7735R")
elseif(ST7735S)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DST7735S")
message(STATUS "Targeting ST7735S")
elseif(SSD1351)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSSD1351")
message(STATUS "Targeting SSD1351")
elseif(WAVESHARE35B_ILI9486)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DILI9486 -DWAVESHARE35B_ILI9486")
message(STATUS "Targeting WaveShare 3.5 inch (B) display with ILI9486")
elseif(ILI9486)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DILI9486")
message(STATUS "Targeting ILI9486")
elseif(ILI9486L)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DILI9486L")
message(STATUS "Targeting ILI9486L")
elseif(ILI9488)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DILI9488")
message(STATUS "Targeting ILI9488")
elseif(TONTEC_MZ61581)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DMZ61581 -DTONTEC_MZ61581")
message(STATUS "Targeting TONTEC_MZ61581")
elseif(MZ61581)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DMZ61581")
message(STATUS "Targeting MZ61581")
elseif(MPI3501)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DMPI3501")
message(STATUS "Targeting MPI3501")
if (USE_DMA_TRANSFERS)
message(FATAL_ERROR "DMA is unfortunately not possible with MPI3501. Please disable with -DUSE_DMA_TRANSFERS=OFF.")
endif()
else()
message(FATAL_ERROR "Please specify which display controller to use on command line to CMake!")
endif()
add_executable(fbcp-ili9341 ${sourceFiles})
target_link_libraries(fbcp-ili9341 pthread bcm_host atomic)

View File

@ -1,19 +0,0 @@
Copyright (c) Jukka Jylänki
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -1,690 +0,0 @@
# Introduction
This repository implements a driver for certain SPI-based LCD displays for Raspberry Pi A, B, 2, 3, 4 and Zero.
![PiTFT display](/example.jpg "Adafruit PiTFT 2.8 with ILI9341 controller")
The work was motivated by curiosity after seeing this series of videos on the RetroManCave YouTube channel:
- [RetroManCave: Waveshare 3.5" Raspberry Pi Screen | Review](https://www.youtube.com/watch?v=SGMC0t33C50)
- [RetroManCave: Waveshare 3.2" vs 3.5" LCD screen gaming test | Raspberry Pi / RetroPie](https://www.youtube.com/watch?v=8bazEcXemiA)
- [Elecrow 5 Inch LCD Review | RetroPie & Raspberry Pi](https://www.youtube.com/watch?v=8VgNBDMOssg)
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](https://www.adafruit.com/product/1601) 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:
- [fbcp-ili9341 frame delivery smoothness test on Pi 3B and Adafruit ILI9341 at 119Hz](https://youtu.be/IqzKT33Rwjc)
- [Latency and tearing test #2: GPIO input to display latency in fbcp-ili9341 and tearing modes](https://www.youtube.com/watch?v=EOICdpjiqv8)
- [Latency and tearing test: KeDei 3.5" 320x480 HDMI vs Adafruit 2.8" PiTFT ILI9341 240x320 SPI](https://www.youtube.com/watch?v=1yvmvv0KtNs)
- [fbcp-ili9341 ported to ILI9486 WaveShare 3.5" (B) SpotPear 320x480 SPI display](https://www.youtube.com/watch?v=dqOLIHOjLq4)
- [Quake 60 fps inside Gameboy Advance (ILI9341)](https://www.youtube.com/watch?v=xmO8t3XlxVM)
- First implementation of a statistics overlay: [fbcp-ili9341 SPI display driver on Adafruit PiTFT 2.8"](http://youtu.be/rKSH048XRjA)
- Initial proof of concept video: [fbcp-ili9341 driver first demo](https://youtu.be/h1jhuR-oZm0)
### 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](https://www.raspberrypi.org/forums/viewtopic.php?t=43442) (and not just powers of two), and the [SPI DLEN register is forced in non-DMA mode](https://www.raspberrypi.org/forums/viewtopic.php?t=181154) 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:
- [Adafruit 2.8" 320x240 TFT w/ Touch screen for Raspberry Pi](https://www.adafruit.com/product/1601) with ILI9341 controller
- [Adafruit PiTFT 2.2" HAT Mini Kit - 320x240 2.2" TFT - No Touch](https://www.adafruit.com/product/2315) with ILI9340 controller
- [Adafruit PiTFT - Assembled 480x320 3.5" TFT+Touchscreen for Raspberry Pi](https://www.adafruit.com/product/2097) with HX8357D controller
- [Adafruit 128x96 OLED Breakout Board - 16-bit Color 1.27" w/microSD holder](https://www.adafruit.com/product/1673) with SSD1351 controller
- [Waveshare 3.5inch RPi LCD (B) 320*480 Resolution Touch Screen IPS TFT Display](https://www.amazon.co.uk/dp/B01N48NOXI/ref=pe_3187911_185740111_TE_item) with ILI9486 controller
- [maithoga 3.5 inch 8PIN SPI TFT LCD Color Screen with Adapter Board ILI9486](https://www.aliexpress.com/item/3-5-inch-8P-SPI-TFT-LCD-Color-Screen-Module-ILI9486-Drive-IC-320-480-RGB/32828284227.html) with **ILI9486L** controller
- [BuyDisplay.com 320x480 Serial SPI 3.2"TFT LCD Module Display](https://www.buydisplay.com/default/serial-spi-3-2-inch-tft-lcd-module-display-ili9341-power-than-sainsmart) with ILI9341 controller
- [Arduino A000096 1.77" 160x128 LCD Screen](https://store.arduino.cc/arduino-lcd-screen) with ST7735R controller
- [Tontec 3.5" 320x480 LCD Display](https://www.ebay.com/p/Tontec-3-5-Inches-Touch-Screen-for-Raspberry-Pi-Display-TFT-Monitor-480x320-LCD/1649448059) with MZ61581-PI-EXT 2016.1.28 controller
- [Adafruit 1.54" 240x240 Wide Angle TFT LCD Display with MicroSD](https://www.adafruit.com/product/3787) with ST7789 controller
- [WaveShare 240x240, 1.3inch IPS LCD display HAT for Raspberry Pi](https://www.waveshare.com/1.3inch-lcd-hat.htm) with ST7789VW controller
- [WaveShare 128x128, 1.44inch LCD display HAT for Raspberry Pi](https://www.waveshare.com/1.44inch-lcd-hat.htm) with ST7735S controller
- [KeDei 3.5 inch SPI TFTLCD 480*320 16bit/18bit version 6.3 2018/4/9](https://github.com/juj/fbcp-ili9341/issues/40) with MPI3501 controller
- Unbranded 2.8" 320x240 display with ILI9340 controller
### Installation
Check the following sections to set up the driver.
##### Boot configuration
This driver does not utilize the [notro/fbtft](https://github.com/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:
```bash
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](https://github.com/juj/fbcp-ili9341/blob/master/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:
- `-DADAFRUIT_ILI9341_PITFT=ON`: If you are running on the [Adafruit 2.8" 320x240 TFT w/ Touch screen for Raspberry Pi](https://www.adafruit.com/product/1601) (or the [Adafruit PiTFT 2.2" HAT Mini Kit - 320x240 2.2" TFT - No Touch](https://www.adafruit.com/product/2315) display, which is compatible), pass this flag.
- `-DADAFRUIT_HX8357D_PITFT=ON`: If you have the [Adafruit PiTFT - Assembled 480x320 3.5" TFT+Touchscreen for Raspberry Pi](https://www.adafruit.com/product/2097) display, add this line.
- `-DFREEPLAYTECH_WAVESHARE32B=ON`: If you are running on the [Freeplay CM3 or Zero](https://www.freeplaytech.com/product/freeplay-cm3-diy-kit/) device, pass this flag. (this is not a hat, but still a preconfigured pin assignment)
- `-DWAVESHARE35B_ILI9486=ON`: If specified, targets a [Waveshare 3.5" 480x320 ILI9486](https://www.amazon.co.uk/dp/B01N48NOXI/ref=pe_3187911_185740111_TE_item) display.
- `-DTONTEC_MZ61581=ON`: If you are running on the [Tontec 3.5" 320x480 LCD Display](https://www.ebay.com/p/Tontec-3-5-Inches-Touch-Screen-for-Raspberry-Pi-Display-TFT-Monitor-480x320-LCD/1649448059) display, pass this.
- `-DWAVESHARE_ST7789VW_HAT=ON`: If specified, targets a [240x240, 1.3inch IPS LCD display HAT for Raspberry Pi](https://www.waveshare.com/1.3inch-lcd-hat.htm) with ST7789VW display controller.
- `-DWAVESHARE_ST7735S_HAT=ON`: If specified, targets a [128x128, 1.44inch LCD display HAT for Raspberry Pi](https://www.waveshare.com/1.3inch-lcd-hat.htm) with ST7735S display controller.
- `-DKEDEI_V63_MPI3501=ON`: If specified, targets a [KeDei 3.5 inch SPI TFTLCD 480*320 16bit/18bit version 6.3 2018/4/9](https://github.com/juj/fbcp-ili9341/issues/40) display with MPI3501 display controller.
###### 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=](https://www.raspberrypi.org/documentation/configuration/config-txt/overclocking.md) 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](https://github.com/juj/fbcp-ili9341/blob/master/ili9341.h#L13) and [waveshare35b.h](https://github.com/juj/fbcp-ili9341/blob/master/waveshare35b.h#L10) 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 or 4B). 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](https://github.com/juj/fbcp-ili9341/blob/master/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](https://www.adafruit.com/product/1601) with ILI9341 controller:
```bash
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
```bash
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
```bash
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)
##### 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](https://www.raspberrypi.org/documentation/configuration/config-txt/video.md) 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](https://www.raspberrypi.org/forums/viewtopic.php?f=29&t=82373) 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 https://github.com/raspberrypi/userland/issues/440 can cause stuttering. Disabling `#defined USE_GPU_VSYNC` produces less stuttering, but because of https://github.com/raspberrypi/userland/issues/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 https://github.com/raspberrypi/userland/issues/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](https://www.youtube.com/watch?v=EOICdpjiqv8) 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](https://github.com/raspberrypi/userland/issues/440). (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](https://www.youtube.com/watch?v=1yvmvv0KtNs). 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](https://www.youtube.com/watch?v=EOICdpjiqv8) 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](https://www.youtube.com/watch?v=1yvmvv0KtNs) - 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](https://github.com/raspberrypi/userland/issues/440), 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](/framerate_smoothness.jpg "Smoothness statistics")
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](https://youtu.be/IqzKT33Rwjc) 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 https://github.com/raspberrypi/userland/issues/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 https://github.com/raspberrypi/userland/issues/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 https://github.com/raspberrypi/firmware/issues/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](https://github.com/juj/fbcp-ili9341/issues/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](https://github.com/juj/fbcp-ili9341/issues), 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](https://www.youtube.com/watch?v=dqOLIHOjLq4) 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 https://github.com/raspberrypi/userland/issues/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 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](https://www.raspberrypi.org/forums/viewtopic.php?t=120793), which rotates both the SPI output and the HDMI output.
#### 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](https://github.com/juj/fbcp-ili9341/issues/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 `dtoverlay`s 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 `dtoverlay`s 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 https://github.com/raspberrypi/userland/issues/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](/wrong_colors.jpg)
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](https://www.raspberrypi.org/documentation/configuration/config-txt/memory.md) 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](https://www.adafruit.com/product/1601) | 2.8" | 240x320 | ILI9341 | 10MHz | 294MHz/4=73.50MHz | 59.81 fps |
| [Adafruit PiTFT](https://www.adafruit.com/product/2315) | 2.2" | 240x320 | ILI9340 | 15.15MHz | 338MHz/4=84.50MHz | 68.76 fps |
| [Adafruit PiTFT](https://www.adafruit.com/product/2097) | 3.5" | 320x480 | HX8357D | 15.15MHz | 314MHz/6=52.33MHz | 21.29 fps |
| [Adafruit OLED](https://www.adafruit.com/product/1673) | 1.27" | 128x96 | SSD1351 | 20MHz | 360MHz/20=18.00MHz | 91.55 fps |
| [Waveshare RPi LCD (B) IPS](https://www.amazon.co.uk/dp/B01N48NOXI/ref=pe_3187911_185740111_TE_item) | 3.5" | 320x480 | ILI9486 | 15.15MHz | 255MHz/8=31.88MHz | 12.97 fps |
| [maithoga TFT LCD](https://www.aliexpress.com/item/3-5-inch-8P-SPI-TFT-LCD-Color-Screen-Module-ILI9486-Drive-IC-320-480-RGB/32828284227.html) | 3.5" | 320x480 | ILI9486L | 15.15MHz | 400MHz/8=50.00MHz | 13.56 fps* |
| [BuyDisplay.com SPI TFT](https://www.buydisplay.com/default/serial-spi-3-2-inch-tft-lcd-module-display-ili9341-power-than-sainsmart) copy #1 | 3.2" | 240x320 | ILI9341 | 10MHz | 310MHz/4=77.50MHz | 63.07 fps |
| [BuyDisplay.com SPI TFT](https://www.buydisplay.com/default/serial-spi-3-2-inch-tft-lcd-module-display-ili9341-power-than-sainsmart) copy #2 | 3.2" | 240x320 | ILI9341 | 10MHz | 300MHz/4=75.00MHz | 61.03 fps |
| [Arduino A000096 LCD](https://store.arduino.cc/arduino-lcd-screen) | 1.77" | 128x160 | ST7735R | 15.15MHz | 355MHz/6=59.16MHz | 180.56 fps |
| [Tontec MZ61581-PI-EXT 2016.1.28](https://www.ebay.com/p/Tontec-3-5-Inches-Touch-Screen-for-Raspberry-Pi-Display-TFT-Monitor-480x320-LCD/1649448059) | 3.5" | 320x480 | MZ61581 | 128MHz | 280MHz/2=140.00MHz | 56.97 fps |
| [Adafruit 240x240 Wide Angle TFT](https://www.adafruit.com/product/3787) | 1.54" | 240x240 | ST7789 | ? | 340MHz/4=85.00MHz | 92.23 fps |
| [WaveShare 240x240 Display HAT](https://www.waveshare.com/1.3inch-lcd-hat.htm) | 1.3" | 240x240 | ST7789VW | 62.5MHz | 338MHz/4=84.50MHz | 91.69 fps |
| [WaveShare 128x128 Display HAT](https://www.waveshare.com/1.44inch-lcd-hat.htm) | 1.44" | 128x128 | ST7735S | 15.15MHz | (untested) | (untested) |
| [KeDei v6.3](https://github.com/juj/fbcp-ili9341/issues/40) | 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](https://www.youtube.com/watch?v=dqOLIHOjLq4) 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](https://github.com/juj/fbcp-ili9341/issues/40#issuecomment-441480557)), 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]([https://en.wikipedia.org/wiki/Composite_video](https://en.wikipedia.org/wiki/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)]([https://en.wikipedia.org/wiki/I%C2%B2C](https://en.wikipedia.org/wiki/I%C2%B2C))
- +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)]([https://en.wikipedia.org/wiki/Serial_Peripheral_Interface](https://en.wikipedia.org/wiki/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)]([https://www.raspberrypi.org/documentation/hardware/raspberrypi/dpi/README.md](https://www.raspberrypi.org/documentation/hardware/raspberrypi/dpi/README.md))
- +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)]([https://en.wikipedia.org/wiki/Display_Serial_Interface](https://en.wikipedia.org/wiki/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]([https://www.raspberrypi.org/forums/viewtopic.php?t=153954](https://www.raspberrypi.org/forums/viewtopic.php?t=153954))
- [-only one official display exists]([https://www.raspberrypi.org/documentation/hardware/display/](https://www.raspberrypi.org/documentation/hardware/display/))
6. [HDMI]([https://en.wikipedia.org/wiki/HDMI](https://en.wikipedia.org/wiki/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](https://github.com/notro/fbtft) + [tasanakorn/rpi-fbcp](https://github.com/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](https://github.com/adafruit/Adafruit_Python_ILI9341).
### Resources
The following links proved helpful when writing this:
- [ARM BCM2835 Peripherals Manual PDF](https://www.raspberrypi.org/app/uploads/2012/02/BCM2835-ARM-Peripherals.pdf),
- [ILI9341 Display Controller Manual PDF](https://cdn-shop.adafruit.com/datasheets/ILI9341.pdf),
- [notro/fbtft](https://github.com/notro/fbtft): Linux Framebuffer drivers for small TFT LCD display modules,
- [BCM2835 driver](http://www.airspayce.com/mikem/bcm2835/) for Raspberry Pi,
- [tasanakorn/rpi-fbcp](https://github.com/tasanakorn/rpi-fbcp), original framebuffer driver,
- [tasanakorn/rpi-fbcp/#16](https://github.com/tasanakorn/rpi-fbcp/issues/16), discussion about performance,
- [Tomáš Suk, Cyril Höschl IV, and Jan Flusser, Rectangular Decomposition of Binary Images.](http://library.utia.cas.cz/separaty/2012/ZOI/suk-rectangular%20decomposition%20of%20binary%20images.pdf), a useful research paper about merging monochrome bitmap images to rectangles, which gave good ideas for optimizing SPI span merges across multiple scan lines,
- [VC DispmanX source code](https://github.com/raspberrypi/userland/blob/master/interface/vmcs_host/vc_vchi_dispmanx.c) (more or less the only official documentation bit on DispmanX I could ever find)
### 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](https://github.com/raspberrypi/userland/issues/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](https://github.com/raspberrypi/userland/issues/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](https://github.com/raspberrypi/firmware/issues/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](https://github.com/juj/fbcp-ili9341/issues/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](https://github.com/juj/fbcp-ili9341/issues/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](https://github.com/juj/fbcp-ili9341/issues/43))
- Add support for building on 64-bit operating systems. (see [#43](https://github.com/juj/fbcp-ili9341/issues/43))
- Port fbcp-ili9341 over to a new single-board computer hardware. (e.g. [#30](https://github.com/juj/fbcp-ili9341/issues/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!
### Donating
I have been occassionally asked how to make a donation as a thank you for the work, so here is a PayPal link:
[![paypal](https://www.paypalobjects.com/en_US/i/btn/btn_donateCC_LG.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=DD8A74WY6Q4L2&currency_code=EUR)
Please note that a contribution is not expected, and you are free to use, publicize and redistribute the driver even without a payment.
### 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](https://sudomod.com/forum/viewtopic.php?f=42&t=438&sid=b868bb95ab5c3035b7810c71278637c6).

View File

@ -1,242 +0,0 @@
#pragma once
// Build options: Uncomment any of these, or set at the command line to configure:
// If defined, renders a performance overlay on top of the screen. This option is passed from CMake
// configuration script. If you are getting statistics printed on screen
// even when this is uncommented, pass -DSTATISTICS=0 to CMake invocation line. You can also try
// building with
// 'make VERBOSE=1'
// to see which config flags are coming from CMake to the build.
// #define STATISTICS
// How often the on-screen statistics is refreshed (in usecs)
#define STATISTICS_REFRESH_INTERVAL 200000
// How many usecs worth of past frame rate data do we preserve in the history buffer. Higher values
// make the frame rate display counter smoother and respond to changes with a delay, whereas smaller
// values can make the display fluctuate a bit erratically.
#define FRAMERATE_HISTORY_LENGTH 400000
// If enabled, displays a visual graph of frame completion times
// #define FRAME_COMPLETION_TIME_STATISTICS
// If defined, no sleeps are specified and the code runs as fast as possible. This should not improve
// performance, as the code has been developed with the mindset that sleeping should only occur at
// times when there is no work to do, rather than sleeping to reduce power usage. The only expected
// effect of this is that CPU usage shoots to 200%, while display update FPS is the same. Present
// here to allow toggling to debug this assumption.
// #define NO_THROTTLING
// If defined, display updates are synced to the vsync signal provided by the VideoCore GPU. That seems
// to occur quite precisely at 60 Hz. Testing on PAL NES games that run at 50Hz, this will not work well,
// since they produce new frames at every 20msecs, and the VideoCore functions for snapshotting also will
// output new frames at this vsync-detached interval, so there's a 50 Hz vs 60 Hz mismatch that results
// in visible microstuttering. Still, providing this as an option, this might be good for content that
// is known to run at native 60Hz.
// #define USE_GPU_VSYNC
// Always enable GPU VSync on the Pi Zero. Even though it is suboptimal and can cause stuttering, it saves battery.
#if defined(SINGLE_CORE_BOARD)
#if !defined(USE_GPU_VSYNC)
#define USE_GPU_VSYNC
#endif
#else // Multicore Pi boards (Pi 2, 3)
// If defined, communication with the SPI bus is handled with a dedicated thread. On the Pi Zero, this does
// not gain much, since it only has one hardware thread.
#define USE_SPI_THREAD
// If USE_GPU_VSYNC is defined, then enabling this causes new frames to be snapshot more often than at
// TARGET_FRAME_RATE interval to try to keep up smoother 60fps instead of stuttering. Consumes more CPU.
#define SELF_SYNCHRONIZE_TO_GPU_VSYNC_PRODUCED_NEW_FRAMES
#endif
// If enabled, the source video frame is not scaled to fit to the screen, but instead if the source frame
// is bigger than the SPI display, then content is cropped away, i.e. the source is displayed "centered"
// on the SPI screen:
// #define DISPLAY_CROPPED_INSTEAD_OF_SCALING
// If enabled, the main thread and SPI thread are executed with realtime priority
// #define RUN_WITH_REALTIME_THREAD_PRIORITY
// If defined, progressive updating is always used (at the expense of slowing down refresh rate if it's
// too much for the display to handle)
// #define NO_INTERLACING
#if (defined(FREEPLAYTECH_WAVESHARE32B) || (defined(ILI9341) && SPI_BUS_CLOCK_DIVISOR <= 4)) && defined(USE_DMA_TRANSFERS) && !defined(NO_INTERLACING)
// The Freeplaytech CM3/Zero displays actually only have a visible display resolution of 302x202, instead of
// 320x240, and this is enough to give them full progressive 320x240x60fps without ever resorting to
// interlacing. Also, ILI9341 displays running with clock divisor of 4 have enough bandwidth to never need
// interlacing either.
#define NO_INTERLACING
#endif
// If defined, all frames are always rendered as interlaced, and never use progressive rendering.
// #define ALWAYS_INTERLACING
// By default, if the SPI bus is idle after rendering an interlaced frame, but the GPU has not yet produced
// a new application frame to be displayed, the same frame will be rendered again for its other field.
// Define this option to disable this behavior, in which case when an interlaced frame is rendered, the
// remaining other field half of the image will never be uploaded.
// #define THROTTLE_INTERLACING
// The ILI9486 has to resort to interlacing as a rule rather than exception, and it works much smoother
// when applying throttling to interlacing, so enable it by default there.
#if defined(ILI9486) || defined(HX8357D)
#define THROTTLE_INTERLACING
#endif
// If defined, DMA usage is foremost used to save power consumption and CPU usage. If not defined,
// DMA usage is tailored towards maximum performance.
// #define ALL_TASKS_SHOULD_DMA
// If defined, screen updates are performed in strictly one update rectangle per frame.
// This reduces CPU consumption at the expense of sending more pixels. You can try enabling this
// if your SPI display runs at a good high SPI bus MHz speed with respect to the screen resolution.
// Useful on Pi Zero W and ILI9341 to conserve CPU power. If this is not defined, the default much
// more powerful diffing algorithm is used, which sends far fewer pixels each frame, (but that diffing
// costs more CPU time). Enabling this requires that ALL_TASKS_SHOULD_DMA is also enabled.
// #define UPDATE_FRAMES_IN_SINGLE_RECTANGULAR_DIFF
// If UPDATE_FRAMES_IN_SINGLE_RECTANGULAR_DIFF is used, controls whether the generated tasks are aligned for
// ARMv6 cache lines. This is good to be enabled for ARMv6 Pis, doesn't make much difference on ARMv7 and ARMv8 Pis.
#define ALIGN_DIFF_TASKS_FOR_32B_CACHE_LINES
// If defined, screen updates are performend without performing diffing at all, i.e. by doing
// full updates. This is very lightweight on CPU, but excessive on the SPI bus. Enabling this
// requires that ALL_TASKS_SHOULD_DMA is also enabled.
// #define UPDATE_FRAMES_WITHOUT_DIFFING
#if defined(SINGLE_CORE_BOARD) && defined(USE_DMA_TRANSFERS) && !defined(SPI_3WIRE_PROTOCOL) // TODO: 3-wire SPI displays are not yet compatible with ALL_TASKS_SHOULD_DMA option.
// These are prerequisites for good performance on Pi Zero
#ifndef ALL_TASKS_SHOULD_DMA
#define ALL_TASKS_SHOULD_DMA
#endif
#ifndef NO_INTERLACING
#define NO_INTERLACING
#endif
// This saves a lot of CPU, but if you don't care and your SPI display does not have much bandwidth, try uncommenting this for more performant
// screen updates
#ifndef UPDATE_FRAMES_IN_SINGLE_RECTANGULAR_DIFF
#define UPDATE_FRAMES_IN_SINGLE_RECTANGULAR_DIFF
#endif
#endif
// If per-pixel diffing is enabled (neither UPDATE_FRAMES_IN_SINGLE_RECTANGULAR_DIFF or UPDATE_FRAMES_WITHOUT_DIFFING
// are enabled), the following variable controls whether to lean towards more precise pixel diffing, or faster, but
// coarser pixel diffing. Coarse method is twice as fast than the precise method, but submits slightly more pixels.
// In most cases it is better to use the coarse method, since the increase in pixel counts is small (~5%-10%),
// so enabled by default. If your display is very constrained on SPI bus speed, and don't mind increased
// CPU consumption, comment this out to use the precise algorithm.
#if !defined(ALL_TASKS_SHOULD_DMA) // At the moment the coarse method is not good at producing long spans, so disable if all tasks should DMA
#define FAST_BUT_COARSE_PIXEL_DIFF
#endif
#if defined(ALL_TASKS_SHOULD_DMA)
// This makes all submitted tasks go through DMA, and not use a hybrid Polled SPI + DMA approach.
#define ALIGN_TASKS_FOR_DMA_TRANSFERS
#endif
// If defined, the GPU polling thread will be put to sleep for 1/TARGET_FRAMERATE seconds after receiving
// each new GPU frame, to wait for the earliest moment that the next frame could arrive.
#define SAVE_BATTERY_BY_SLEEPING_UNTIL_TARGET_FRAME
// Detects when the activity on the screen is mostly idle, and goes to low power mode, in which new
// frames will be polled first at 10fps, and ultimately at only 2fps.
#define SAVE_BATTERY_BY_SLEEPING_WHEN_IDLE
// Builds a histogram of observed frame intervals and uses that to sync to a known update rate. This aims
// to detect if an application uses a non-60Hz update rate, and synchronizes to that instead.
#define SAVE_BATTERY_BY_PREDICTING_FRAME_ARRIVAL_TIMES
// If defined, rotates the display 180 degrees. This might not rotate the panel scan order though,
// so adding this can cause up to one vsync worth of extra display latency. It is best to avoid this and
// install the display in its natural rotation order, if possible.
// #define DISPLAY_ROTATE_180_DEGREES
// If defined, displays in landscape. Undefine to display in portrait. When changing this, swap
// values of DISPLAY_WIDTH and DISPLAY_HEIGHT accordingly
#define DISPLAY_OUTPUT_LANDSCAPE
// If defined, the source video frame is scaled to fit the SPI display by stretching to fit, ignoring
// aspect ratio. Enabling this will cause e.g. 16:9 1080p source to be stretched to fully cover
// a 4:3 320x240 display. If disabled, scaling is performed preserving aspect ratio, so letterboxes or
// pillarboxes will be introduced if needed to retain proper width and height proportions.
// #define DISPLAY_BREAK_ASPECT_RATIO_WHEN_SCALING
// If defined, reverses RGB<->BGR color subpixel order. This is something that seems to be display panel
// specific, rather than display controller specific, and displays manufactured with the same controller
// can have different subpixel order (without the controller taking it automatically into account).
// If display colors come out reversed in blue vs red channels, define this to swap the two.
// #define DISPLAY_SWAP_BGR
// If defined, inverts display pixel colors (31=black, 0=white). Default is to have (0=black, 31=white)
// Pass this if the colors look like a photo negative of the actual image.
// #define DISPLAY_INVERT_COLORS
// If defined, flipping the display between portrait<->landscape is done in software, rather than
// asking the display controller to adjust its RAM write direction.
// Doing the flip in software reduces tearing, since neither the ILI9341 nor ILI9486 displays (and
// probably no other displays in existence?) allow one to adjust the direction that the scanline refresh
// cycle runs in, but the scanline refresh always runs in portrait mode in these displays. Not having
// this defined reduces CPU usage at the expense of more tearing, although it is debatable which
// effect is better - this can be subjective. Impact is around 0.5-1.0msec of extra CPU time.
// DISPLAY_FLIP_ORIENTATION_IN_SOFTWARE disabled: diagonal tearing
// DISPLAY_FLIP_ORIENTATION_IN_SOFTWARE enabled: traditional no-vsync tearing (tear line runs in portrait
// i.e. narrow direction)
#if !defined(SINGLE_CORE_BOARD)
#define DISPLAY_FLIP_ORIENTATION_IN_SOFTWARE
#endif
// If enabled, build to utilize DMA transfers to communicate with the SPI peripheral. Otherwise polling
// writes will be performed (possibly with interrupts, if using kernel side driver module)
// #define USE_DMA_TRANSFERS
// If defined, enables code to manage the backlight.
// #define BACKLIGHT_CONTROL
#if defined(BACKLIGHT_CONTROL)
// If enabled, reads keyboard for input events to detect when the system has gone inactive and backlight
// can be turned off
#define BACKLIGHT_CONTROL_FROM_KEYBOARD
// This device file is used to capture keyboard input. This may be "/dev/input/event0" or something else
// on some Pis
#define KEYBOARD_INPUT_FILE "/dev/input/event1"
// If enabled, the display backlight will be turned off after this many usecs of no activity on screen.
#define TURN_DISPLAY_OFF_AFTER_USECS_OF_INACTIVITY (1 * 60 * 1000000)
#endif
// If defined, enable a low battery icon triggered by a GPIO pin whose BCM number is given.
// #define LOW_BATTERY_PIN 19
// Which state of the LOW_BATTERY_PIN is considered to be low battery. Note that the GPIO pin must be
// in the correct state (input with pull-up/pull-down resistor) before the program is started.
#define LOW_BATTERY_IS_ACTIVE_HIGH 0
// Polling interval (in micro-second) for the low battery pin.
#define LOW_BATTERY_POLLING_INTERVAL 1000000
// If less than this much % of the screen changes per frame, the screen is considered to be inactive, and
// the display backlight can automatically turn off, if TURN_DISPLAY_OFF_AFTER_USECS_OF_INACTIVITY is
// defined.
#define DISPLAY_CONSIDERED_INACTIVE_PERCENTAGE (5.0 / 100.0)
#ifndef KERNEL_MODULE
// Define this if building the client side program to run against the kernel driver module, rather than
// as a self-contained userland program.
// #define KERNEL_MODULE_CLIENT
#endif
// Experimental/debugging: If defined, let the userland side program create and run the SPI peripheral
// driving thread. Otherwise, let the kernel drive SPI (e.g. via interrupts or its own thread)
// This should be unset, only available for debugging.
// #define KERNEL_MODULE_CLIENT_DRIVES

View File

@ -1,490 +0,0 @@
#include "config.h"
#include "diff.h"
#include "util.h"
#include "display.h"
#include "gpu.h"
#include "spi.h"
Span *spans = 0;
#ifdef UPDATE_FRAMES_WITHOUT_DIFFING
// Naive non-diffing functionality: just submit the whole display contents
void NoDiffChangedRectangle(Span *&head)
{
head = spans;
head->x = 0;
head->endX = head->lastScanEndX = gpuFrameWidth;
head->y = 0;
head->endY = gpuFrameHeight;
head->size = gpuFrameWidth*gpuFrameHeight;
head->next = 0;
}
#endif
#ifdef UPDATE_FRAMES_IN_SINGLE_RECTANGULAR_DIFF
// Coarse diffing of two framebuffers with tight stride, 16 pixels at a time
// Finds the first changed pixel, coarse result aligned down to 8 pixels boundary
static int coarse_linear_diff(uint16_t *framebuffer, uint16_t *prevFramebuffer, uint16_t *framebufferEnd)
{
uint16_t *endPtr;
asm volatile(
"mov r0, %[framebufferEnd]\n" // r0 <- pointer to end of current framebuffer
"mov r1, %[framebuffer]\n" // r1 <- current framebuffer
"mov r2, %[prevFramebuffer]\n" // r2 <- framebuffer of previous frame
"start_%=:\n"
"pld [r1, #128]\n" // preload data caches for both current and previous framebuffers 128 bytes ahead of time
"pld [r2, #128]\n"
"ldmia r1!, {r3,r4,r5,r6}\n" // load 4x32-bit elements (8 pixels) of current framebuffer
"ldmia r2!, {r7,r8,r9,r10}\n" // load corresponding 4x32-bit elements (8 pixels) of previous framebuffer
"cmp r3, r7\n" // compare all 8 pixels if they are different
"cmpeq r4, r8\n"
"cmpeq r5, r9\n"
"cmpeq r6, r10\n"
"bne end_%=\n" // if we found a difference, we are done
// Unroll once for another set of 4x32-bit elements. On Raspberry Pi Zero, data cache line is 32 bytes in size, so one iteration
// of the loop computes a single data cache line, with preloads in place at the top.
"ldmia r1!, {r3,r4,r5,r6}\n"
"ldmia r2!, {r7,r8,r9,r10}\n"
"cmp r3, r7\n"
"cmpeq r4, r8\n"
"cmpeq r5, r9\n"
"cmpeq r6, r10\n"
"bne end_%=\n" // if we found a difference, we are done
"cmp r0, r1\n" // framebuffer == framebufferEnd? did we finish through the array?
"bne start_%=\n"
"b done_%=\n"
"end_%=:\n"
"sub r1, r1, #16\n" // ldmia r1! increments r1 after load, so subtract back the last increment in order to not shoot past the first changed pixels
"done_%=:\n"
"mov %[endPtr], r1\n" // output endPtr back to C code
: [endPtr]"=r"(endPtr)
: [framebuffer]"r"(framebuffer), [prevFramebuffer]"r"(prevFramebuffer), [framebufferEnd]"r"(framebufferEnd)
: "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "cc"
);
return endPtr - framebuffer;
}
// Same as coarse_linear_diff, but finds the last changed pixel in linear order instead of first, i.e.
// Finds the last changed pixel, coarse result aligned up to 8 pixels boundary
static int coarse_backwards_linear_diff(uint16_t *framebuffer, uint16_t *prevFramebuffer, uint16_t *framebufferEnd)
{
uint16_t *endPtr;
asm volatile(
"mov r0, %[framebufferBegin]\n" // r0 <- pointer to beginning of current framebuffer
"mov r1, %[framebuffer]\n" // r1 <- current framebuffer (starting from end of framebuffer)
"mov r2, %[prevFramebuffer]\n" // r2 <- framebuffer of previous frame (starting from end of framebuffer)
"start_%=:\n"
"pld [r1, #-128]\n" // preload data caches for both current and previous framebuffers 128 bytes ahead of time
"pld [r2, #-128]\n"
"ldmdb r1!, {r3,r4,r5,r6}\n" // load 4x32-bit elements (8 pixels) of current framebuffer
"ldmdb r2!, {r7,r8,r9,r10}\n" // load corresponding 4x32-bit elements (8 pixels) of previous framebuffer
"cmp r3, r7\n" // compare all 8 pixels if they are different
"cmpeq r4, r8\n"
"cmpeq r5, r9\n"
"cmpeq r6, r10\n"
"bne end_%=\n" // if we found a difference, we are done
// Unroll once for another set of 4x32-bit elements. On Raspberry Pi Zero, data cache line is 32 bytes in size, so one iteration
// of the loop computes a single data cache line, with preloads in place at the top.
"ldmdb r1!, {r3,r4,r5,r6}\n"
"ldmdb r2!, {r7,r8,r9,r10}\n"
"cmp r3, r7\n"
"cmpeq r4, r8\n"
"cmpeq r5, r9\n"
"cmpeq r6, r10\n"
"bne end_%=\n" // if we found a difference, we are done
"cmp r0, r1\n" // framebuffer == framebufferEnd? did we finish through the array?
"bne start_%=\n"
"b done_%=\n"
"end_%=:\n"
"add r1, r1, #16\n" // ldmdb r1! decrements r1 before load, so add back the last decrement in order to not shoot past the first changed pixels
"done_%=:\n"
"mov %[endPtr], r1\n" // output endPtr back to C code
: [endPtr]"=r"(endPtr)
: [framebuffer]"r"(framebufferEnd), [prevFramebuffer]"r"(prevFramebuffer+(framebufferEnd-framebuffer)), [framebufferBegin]"r"(framebuffer)
: "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "cc"
);
return endPtr - framebuffer;
}
void DiffFramebuffersToSingleChangedRectangle(uint16_t *framebuffer, uint16_t *prevFramebuffer, Span *&head)
{
int minY = 0;
int minX = -1;
const int stride = gpuFramebufferScanlineStrideBytes>>1; // Stride as uint16 elements.
const int WidthAligned4 = (uint32_t)gpuFrameWidth & ~3u;
uint16_t *scanline = framebuffer;
uint16_t *prevScanline = prevFramebuffer;
static const bool framebufferSizeCompatibleWithCoarseDiff = gpuFramebufferScanlineStrideBytes == gpuFrameWidth*2 && gpuFramebufferScanlineStrideBytes*gpuFrameHeight % 32 == 0;
if (framebufferSizeCompatibleWithCoarseDiff)
{
int numPixels = gpuFrameWidth*gpuFrameHeight;
int firstDiff = coarse_linear_diff(framebuffer, prevFramebuffer, framebuffer + numPixels);
if (firstDiff == numPixels)
return; // No pixels changed, nothing to do.
// Coarse diff computes a diff at 8 adjacent pixels at a time, and returns the point to the 8-pixel aligned coordinate where the pixels began to differ.
// Compute the precise diff position here.
while(framebuffer[firstDiff] == prevFramebuffer[firstDiff]) ++firstDiff;
minX = firstDiff % gpuFrameWidth;
minY = firstDiff / gpuFrameWidth;
}
else
{
while(minY < gpuFrameHeight)
{
int x = 0;
// diff 4 pixels at a time
for(; x < WidthAligned4; x += 4)
{
uint64_t diff = *(uint64_t*)(scanline+x) ^ *(uint64_t*)(prevScanline+x);
if (diff)
{
minX = x + (__builtin_ctzll(diff) >> 4);
goto found_top;
}
}
// tail unaligned 0-3 pixels one by one
for(; x < gpuFrameWidth; ++x)
{
uint16_t diff = *(scanline+x) ^ *(prevScanline+x);
if (diff)
{
minX = x;
goto found_top;
}
}
scanline += stride;
prevScanline += stride;
++minY;
}
return; // No pixels changed, nothing to do.
}
found_top:
int maxX = -1;
int maxY = gpuFrameHeight-1;
if (framebufferSizeCompatibleWithCoarseDiff)
{
int numPixels = gpuFrameWidth*gpuFrameHeight;
int firstDiff = coarse_backwards_linear_diff(framebuffer, prevFramebuffer, framebuffer + numPixels);
// Coarse diff computes a diff at 8 adjacent pixels at a time, and returns the point to the 8-pixel aligned coordinate where the pixels began to differ.
// Compute the precise diff position here.
while(firstDiff > 0 && framebuffer[firstDiff] == prevFramebuffer[firstDiff]) --firstDiff;
maxX = firstDiff % gpuFrameWidth;
maxY = firstDiff / gpuFrameWidth;
}
else
{
scanline = framebuffer + (gpuFrameHeight - 1)*stride;
prevScanline = prevFramebuffer + (gpuFrameHeight - 1)*stride; // (same scanline from previous frame, not preceding scanline)
while(maxY >= minY)
{
int x = gpuFrameWidth-1;
// tail unaligned 0-3 pixels one by one
for(; x >= WidthAligned4; --x)
{
if (scanline[x] != prevScanline[x])
{
maxX = x;
goto found_bottom;
}
}
// diff 4 pixels at a time
x = x & ~3u;
for(; x >= 0; x -= 4)
{
uint64_t diff = *(uint64_t*)(scanline+x) ^ *(uint64_t*)(prevScanline+x);
if (diff)
{
maxX = x + 3 - (__builtin_clzll(diff) >> 4);
goto found_bottom;
}
}
scanline -= stride;
prevScanline -= stride;
--maxY;
}
}
found_bottom:
scanline = framebuffer + minY*stride;
prevScanline = prevFramebuffer + minY*stride;
int lastScanEndX = maxX;
if (minX > maxX) SWAPU32(minX, maxX);
int leftX = 0;
while(leftX < minX)
{
uint16_t *s = scanline + leftX;
uint16_t *prevS = prevScanline + leftX;
for(int y = minY; y <= maxY; ++y)
{
if (*s != *prevS)
goto found_left;
s += stride;
prevS += stride;
}
++leftX;
}
found_left:
int rightX = gpuFrameWidth-1;
while(rightX > maxX)
{
uint16_t *s = scanline + rightX;
uint16_t *prevS = prevScanline + rightX;
for(int y = minY; y <= maxY; ++y)
{
if (*s != *prevS)
goto found_right;
s += stride;
prevS += stride;
}
--rightX;
}
found_right:
head = spans;
head->x = leftX;
head->endX = rightX+1;
head->lastScanEndX = lastScanEndX+1;
head->y = minY;
head->endY = maxY+1;
#if defined(ALIGN_DIFF_TASKS_FOR_32B_CACHE_LINES) && defined(ALL_TASKS_SHOULD_DMA)
// Make sure the task is a multiple of 32 bytes wide so we can use a fast DMA copy
// algorithm later on. Currently this is only exploited in dma.cpp if ALL_TASKS_SHOULD_DMA
// option is enabled, so only enable it there.
head->x = MAX(0, ALIGN_DOWN(head->x, 16));
head->endX = MIN(gpuFrameWidth, ALIGN_UP(head->endX, 16));
head->lastScanEndX = ALIGN_UP(head->lastScanEndX, 16);
#endif
head->size = (head->endX-head->x)*(head->endY-head->y-1) + (head->lastScanEndX - head->x);
head->next = 0;
}
#endif
void DiffFramebuffersToScanlineSpansFastAndCoarse4Wide(uint16_t *framebuffer, uint16_t *prevFramebuffer, bool interlacedDiff, int interlacedFieldParity, Span *&head)
{
int numSpans = 0;
int y = interlacedDiff ? interlacedFieldParity : 0;
int yInc = interlacedDiff ? 2 : 1;
// If doing an interlaced update, skip over every second scanline.
int scanlineInc = interlacedDiff ? (gpuFramebufferScanlineStrideBytes>>2) : (gpuFramebufferScanlineStrideBytes>>3);
uint64_t *scanline = (uint64_t *)(framebuffer + y*(gpuFramebufferScanlineStrideBytes>>1));
uint64_t *prevScanline = (uint64_t *)(prevFramebuffer + y*(gpuFramebufferScanlineStrideBytes>>1)); // (same scanline from previous frame, not preceding scanline)
const int W = gpuFrameWidth>>2;
Span *span = spans;
while(y < gpuFrameHeight)
{
uint16_t *scanlineStart = (uint16_t *)scanline;
for(int x = 0; x < W;)
{
if (scanline[x] != prevScanline[x])
{
uint16_t *spanStart = (uint16_t *)(scanline + x) + (__builtin_ctzll(scanline[x] ^ prevScanline[x]) >> 4);
++x;
// We've found a start of a span of different pixels on this scanline, now find where this span ends
uint16_t *spanEnd;
for(;;)
{
if (x < W)
{
if (scanline[x] != prevScanline[x])
{
++x;
continue;
}
else
{
spanEnd = (uint16_t *)(scanline + x) + 1 - (__builtin_clzll(scanline[x-1] ^ prevScanline[x-1]) >> 4);
++x;
break;
}
}
else
{
spanEnd = scanlineStart + gpuFrameWidth;
break;
}
}
// Submit the span update task
span->x = spanStart - scanlineStart;
span->endX = span->lastScanEndX = spanEnd - scanlineStart;
span->y = y;
span->endY = y+1;
span->size = spanEnd - spanStart;
span->next = span+1;
++span;
++numSpans;
}
else
{
++x;
}
}
y += yInc;
scanline += scanlineInc;
prevScanline += scanlineInc;
}
if (numSpans > 0)
{
head = &spans[0];
spans[numSpans-1].next = 0;
}
else
head = 0;
}
void DiffFramebuffersToScanlineSpansExact(uint16_t *framebuffer, uint16_t *prevFramebuffer, bool interlacedDiff, int interlacedFieldParity, Span *&head)
{
int numSpans = 0;
int y = interlacedDiff ? interlacedFieldParity : 0;
int yInc = interlacedDiff ? 2 : 1;
// If doing an interlaced update, skip over every second scanline.
int scanlineInc = interlacedDiff ? gpuFramebufferScanlineStrideBytes : (gpuFramebufferScanlineStrideBytes>>1);
int scanlineEndInc = scanlineInc - gpuFrameWidth;
uint16_t *scanline = framebuffer + y*(gpuFramebufferScanlineStrideBytes>>1);
uint16_t *prevScanline = prevFramebuffer + y*(gpuFramebufferScanlineStrideBytes>>1); // (same scanline from previous frame, not preceding scanline)
while(y < gpuFrameHeight)
{
uint16_t *scanlineStart = scanline;
uint16_t *scanlineEnd = scanline + gpuFrameWidth;
while(scanline < scanlineEnd)
{
uint16_t *spanStart;
uint16_t *spanEnd;
int numConsecutiveUnchangedPixels = 0;
if (scanline + 1 < scanlineEnd)
{
uint32_t diff = (*(uint32_t *)scanline) ^ (*(uint32_t *)prevScanline);
scanline += 2;
prevScanline += 2;
if (diff == 0) // Both 1st and 2nd pixels are the same
continue;
if (diff & 0xFFFF == 0) // 1st pixels are the same, 2nd pixels are not
{
spanStart = scanline - 1;
spanEnd = scanline;
}
else // 1st pixels are different
{
spanStart = scanline - 2;
if ((diff & 0xFFFF0000u) != 0) // 2nd pixels are different?
{
spanEnd = scanline;
}
else
{
spanEnd = scanline - 1;
numConsecutiveUnchangedPixels = 1;
}
}
// We've found a start of a span of different pixels on this scanline, now find where this span ends
while(scanline < scanlineEnd)
{
if (*scanline++ != *prevScanline++)
{
spanEnd = scanline;
numConsecutiveUnchangedPixels = 0;
}
else
{
if (++numConsecutiveUnchangedPixels > SPAN_MERGE_THRESHOLD)
break;
}
}
}
else // handle the single last pixel on the row
{
if (*scanline++ == *prevScanline++)
break;
spanStart = scanline - 1;
spanEnd = scanline;
}
// Submit the span update task
Span *span = spans + numSpans;
span->x = spanStart - scanlineStart;
span->endX = span->lastScanEndX = spanEnd - scanlineStart;
span->y = y;
span->endY = y+1;
span->size = spanEnd - spanStart;
if (numSpans > 0) span[-1].next = span;
else head = span;
span->next = 0;
++numSpans;
}
y += yInc;
scanline += scanlineEndInc;
prevScanline += scanlineEndInc;
}
}
void MergeScanlineSpanList(Span *listHead)
{
for(Span *i = listHead; i; i = i->next)
{
Span *prev = i;
for(Span *j = i->next; j; j = j->next)
{
// If the spans i and j are vertically apart, don't attempt to merge span i any further, since all spans >= j will also be farther vertically apart.
// (the list is nondecreasing with respect to Span::y)
if (j->y > i->endY) break;
// Merge the spans i and j, and figure out the wastage of doing so
int x = MIN(i->x, j->x);
int y = MIN(i->y, j->y);
int endX = MAX(i->endX, j->endX);
int endY = MAX(i->endY, j->endY);
int lastScanEndX = (endY > i->endY) ? j->lastScanEndX : ((endY > j->endY) ? i->lastScanEndX : MAX(i->lastScanEndX, j->lastScanEndX));
int newSize = (endX-x)*(endY-y-1) + (lastScanEndX - x);
int wastedPixels = newSize - i->size - j->size;
if (wastedPixels <= SPAN_MERGE_THRESHOLD
#ifdef MAX_SPI_TASK_SIZE
&& newSize*SPI_BYTESPERPIXEL <= MAX_SPI_TASK_SIZE
#endif
)
{
i->x = x;
i->y = y;
i->endX = endX;
i->endY = endY;
i->lastScanEndX = lastScanEndX;
i->size = newSize;
prev->next = j->next;
j = prev;
}
else // Not merging - travel to next node remembering where we came from
prev = j;
}
}
}

View File

@ -1,44 +0,0 @@
#pragma once
#include <inttypes.h>
// Spans track dirty rectangular areas on screen
struct Span
{
uint16_t x, endX, y, endY, lastScanEndX;
uint32_t size; // Specifies a box of width [x, endX[ * [y, endY[, where scanline endY-1 can be partial, and ends in lastScanEndX.
Span *next; // Maintain a linked skip list inside the array for fast seek to next active element when pruning
};
extern Span *spans;
// Looking at SPI communication in a logic analyzer, it is observed that waiting for the finish of an SPI command FIFO causes pretty exactly one byte of delay to the command stream.
// Therefore the time/bandwidth cost of ending the current span and starting a new span is as follows:
// 1 byte to wait for the current SPI FIFO batch to finish,
// +1 byte to send the cursor X coordinate change command,
// +1 byte to wait for that FIFO to flush,
// +2 bytes to send the new X coordinate,
// +1 byte to wait for the FIFO to flush again,
// +1 byte to send the data_write command,
// +1 byte to wait for that FIFO to flush,
// after which the communication is ready to start pushing pixels. This totals to 8 bytes, or 4 pixels, meaning that if there are 4 unchanged pixels or less between two adjacent dirty
// spans, it is all the same to just update through those pixels as well to not have to wait to flush the FIFO.
#if defined(ALL_TASKS_SHOULD_DMA)
#define SPAN_MERGE_THRESHOLD 320
#elif defined(DISPLAY_SPI_BUS_IS_16BITS_WIDE)
#define SPAN_MERGE_THRESHOLD 10
#elif defined(HX8357D)
#define SPAN_MERGE_THRESHOLD 6
#else
#define SPAN_MERGE_THRESHOLD 4
#endif
void DiffFramebuffersToSingleChangedRectangle(uint16_t *framebuffer, uint16_t *prevFramebuffer, Span *&head);
void DiffFramebuffersToScanlineSpansExact(uint16_t *framebuffer, uint16_t *prevFramebuffer, bool interlacedDiff, int interlacedFieldParity, Span *&head);
void DiffFramebuffersToScanlineSpansFastAndCoarse4Wide(uint16_t *framebuffer, uint16_t *prevFramebuffer, bool interlacedDiff, int interlacedFieldParity, Span *&head);
void NoDiffChangedRectangle(Span *&head);
void MergeScanlineSpanList(Span *listHead);

View File

@ -1,39 +0,0 @@
#include "config.h"
#include "display.h"
#include "spi.h"
#include <memory.h>
void ClearScreen()
{
for(int y = 0; y < DISPLAY_HEIGHT; ++y)
{
#ifdef DISPLAY_SPI_BUS_IS_16BITS_WIDE
SPI_TRANSFER(DISPLAY_SET_CURSOR_X, 0, 0, 0, 0, 0, (DISPLAY_WIDTH-1) >> 8, 0, (DISPLAY_WIDTH-1) & 0xFF);
SPI_TRANSFER(DISPLAY_SET_CURSOR_Y, 0, (uint8_t)(y >> 8), 0, (uint8_t)(y & 0xFF), 0, (DISPLAY_HEIGHT-1) >> 8, 0, (DISPLAY_HEIGHT-1) & 0xFF);
#elif defined(DISPLAY_SET_CURSOR_IS_8_BIT)
SPI_TRANSFER(DISPLAY_SET_CURSOR_X, 0, DISPLAY_WIDTH-1);
SPI_TRANSFER(DISPLAY_SET_CURSOR_Y, (uint8_t)y, DISPLAY_HEIGHT-1);
#else
SPI_TRANSFER(DISPLAY_SET_CURSOR_X, 0, 0, (DISPLAY_WIDTH-1) >> 8, (DISPLAY_WIDTH-1) & 0xFF);
SPI_TRANSFER(DISPLAY_SET_CURSOR_Y, (uint8_t)(y >> 8), (uint8_t)(y & 0xFF), (DISPLAY_HEIGHT-1) >> 8, (DISPLAY_HEIGHT-1) & 0xFF);
#endif
SPITask *clearLine = AllocTask(DISPLAY_WIDTH*SPI_BYTESPERPIXEL);
clearLine->cmd = DISPLAY_WRITE_PIXELS;
memset(clearLine->data, 0, clearLine->size);
CommitTask(clearLine);
RunSPITask(clearLine);
DoneTask(clearLine);
}
#ifdef DISPLAY_SPI_BUS_IS_16BITS_WIDE
SPI_TRANSFER(DISPLAY_SET_CURSOR_X, 0, 0, 0, 0, 0, (DISPLAY_WIDTH-1) >> 8, 0, (DISPLAY_WIDTH-1) & 0xFF);
SPI_TRANSFER(DISPLAY_SET_CURSOR_Y, 0, 0, 0, 0, 0, (DISPLAY_HEIGHT-1) >> 8, 0, (DISPLAY_HEIGHT-1) & 0xFF);
#elif defined(DISPLAY_SET_CURSOR_IS_8_BIT)
SPI_TRANSFER(DISPLAY_SET_CURSOR_X, 0, DISPLAY_WIDTH-1);
SPI_TRANSFER(DISPLAY_SET_CURSOR_Y, 0, DISPLAY_HEIGHT-1);
#else
SPI_TRANSFER(DISPLAY_SET_CURSOR_X, 0, 0, (DISPLAY_WIDTH-1) >> 8, (DISPLAY_WIDTH-1) & 0xFF);
SPI_TRANSFER(DISPLAY_SET_CURSOR_Y, 0, 0, (DISPLAY_HEIGHT-1) >> 8, (DISPLAY_HEIGHT-1) & 0xFF);
#endif
}

View File

@ -1,121 +0,0 @@
#pragma once
#include "config.h"
// Configure the desired display update rate. Use 120 for max performance/minimized latency, and 60/50/30/24 etc. for regular content, or to save battery.
#define TARGET_FRAME_RATE 60
#if defined(ILI9341) || defined(ILI9340)
#include "ili9341.h"
#elif defined(ILI9486L)
#include "ili9486l.h"
#elif defined(ILI9488)
#include "ili9488.h"
#elif defined(ILI9486)
#include "ili9486.h"
#elif defined(HX8357D)
#include "hx8357d.h"
#elif defined(ST7735R) || defined(ST7735S) || defined(ST7789) || defined(ST7789VW)
#include "st7735r.h"
#elif defined(SSD1351)
#include "ssd1351.h"
#elif defined(MZ61581)
#include "mz61581.h"
#elif defined(MPI3501)
#include "mpi3501.h"
#else
#error Please reconfigure CMake with your display controller directive set!
#endif
// The native display resolution is in portrait/landscape, but we want to display in the opposite landscape/portrait orientation?
// Compare DISPLAY_NATIVE_WIDTH <= DISPLAY_NATIVE_HEIGHT in the first test to let users toggle DISPLAY_OUTPUT_LANDSCAPE directive in config.h to flip orientation on square displays with width=height
#if ((DISPLAY_NATIVE_WIDTH <= DISPLAY_NATIVE_HEIGHT && defined(DISPLAY_OUTPUT_LANDSCAPE)) || (DISPLAY_NATIVE_WIDTH > DISPLAY_NATIVE_HEIGHT && !defined(DISPLAY_OUTPUT_LANDSCAPE)))
#define DISPLAY_SHOULD_FLIP_ORIENTATION
#endif
#if defined(DISPLAY_SHOULD_FLIP_ORIENTATION) && !defined(DISPLAY_FLIP_ORIENTATION_IN_SOFTWARE)
// Need to do orientation flip, but don't want to do it on the CPU, so pretend the display dimensions are of the flipped form,
// and use display controller initialization sequence to do the flipping
#define DISPLAY_WIDTH DISPLAY_NATIVE_HEIGHT
#define DISPLAY_HEIGHT DISPLAY_NATIVE_WIDTH
#define DISPLAY_FLIP_ORIENTATION_IN_HARDWARE
#else
#define DISPLAY_WIDTH DISPLAY_NATIVE_WIDTH
#define DISPLAY_HEIGHT DISPLAY_NATIVE_HEIGHT
#endif
#if !defined(DISPLAY_SHOULD_FLIP_ORIENTATION) && defined(DISPLAY_FLIP_ORIENTATION_IN_SOFTWARE)
#undef DISPLAY_FLIP_ORIENTATION_IN_SOFTWARE
#endif
#ifndef DISPLAY_NATIVE_COVERED_LEFT_SIDE
#define DISPLAY_NATIVE_COVERED_LEFT_SIDE 0
#endif
#ifndef DISPLAY_NATIVE_COVERED_TOP_SIDE
#define DISPLAY_NATIVE_COVERED_TOP_SIDE 0
#endif
#ifndef DISPLAY_NATIVE_COVERED_BOTTOM_SIDE
#define DISPLAY_NATIVE_COVERED_BOTTOM_SIDE 0
#endif
#ifndef DISPLAY_NATIVE_COVERED_RIGHT_SIDE
#define DISPLAY_NATIVE_COVERED_RIGHT_SIDE 0
#endif
#if defined(DISPLAY_FLIP_ORIENTATION_IN_SOFTWARE) || !defined(DISPLAY_SHOULD_FLIP_ORIENTATION)
#define DISPLAY_COVERED_TOP_SIDE DISPLAY_NATIVE_COVERED_TOP_SIDE
#define DISPLAY_COVERED_LEFT_SIDE DISPLAY_NATIVE_COVERED_LEFT_SIDE
#define DISPLAY_COVERED_RIGHT_SIDE DISPLAY_NATIVE_COVERED_RIGHT_SIDE
#define DISPLAY_COVERED_BOTTOM_SIDE DISPLAY_NATIVE_COVERED_BOTTOM_SIDE
#else
#define DISPLAY_COVERED_TOP_SIDE DISPLAY_NATIVE_COVERED_LEFT_SIDE
#define DISPLAY_COVERED_LEFT_SIDE DISPLAY_NATIVE_COVERED_TOP_SIDE
#define DISPLAY_COVERED_RIGHT_SIDE DISPLAY_NATIVE_COVERED_BOTTOM_SIDE
#define DISPLAY_COVERED_BOTTOM_SIDE DISPLAY_NATIVE_COVERED_RIGHT_SIDE
#endif
#define DISPLAY_DRAWABLE_WIDTH (DISPLAY_WIDTH-DISPLAY_COVERED_LEFT_SIDE-DISPLAY_COVERED_RIGHT_SIDE)
#define DISPLAY_DRAWABLE_HEIGHT (DISPLAY_HEIGHT-DISPLAY_COVERED_TOP_SIDE-DISPLAY_COVERED_BOTTOM_SIDE)
#ifndef DISPLAY_SPI_DRIVE_SETTINGS
#define DISPLAY_SPI_DRIVE_SETTINGS (0)
#endif
#ifdef DISPLAY_COLOR_FORMAT_R6X2G6X2B6X2
// 18 bits per pixel padded to 3 bytes
#define SPI_BYTESPERPIXEL 3
#else
// 16 bits per pixel
#define SPI_BYTESPERPIXEL 2
#endif
#if (DISPLAY_DRAWABLE_WIDTH % 16 == 0) && defined(ALL_TASKS_SHOULD_DMA) &&!defined(USE_SPI_THREAD) && defined(USE_GPU_VSYNC) && !defined(DISPLAY_COLOR_FORMAT_R6X2G6X2B6X2) && !defined(SPI_3WIRE_PROTOCOL)
// If conditions are suitable, defer moving pixels until the very last moment in dma.cpp when we are about
// to kick off DMA tasks.
// TODO: 3-wire SPI displays are not yet compatible with this path. Implement support for this to optimize performance of 3-wire SPI displays on Pi Zero. (Pi 3B does not care that much)
#define OFFLOAD_PIXEL_COPY_TO_DMA_CPP
#endif
void ClearScreen(void);
void TurnBacklightOn(void);
void TurnBacklightOff(void);
void TurnDisplayOn(void);
void TurnDisplayOff(void);
void DeinitSPIDisplay(void);
#if !defined(SPI_BUS_CLOCK_DIVISOR)
#error Please define -DSPI_BUS_CLOCK_DIVISOR=<some even number> on the CMake command line! This parameter along with core_freq=xxx in /boot/config.txt defines the SPI display speed. (spi speed = core_freq / SPI_BUS_CLOCK_DIVISOR)
#endif
#if !defined(GPIO_TFT_DATA_CONTROL) && !defined(SPI_3WIRE_PROTOCOL)
#error Please reconfigure CMake with -DGPIO_TFT_DATA_CONTROL=<int> specifying which pin your display is using for the Data/Control line!
#endif
#if defined(SPI_3WIRE_PROTOCOL) && !defined(SPI_3WIRE_DATA_COMMAND_FRAMING_BITS)
// 3-wire SPI displays use 1 bit of D/C framing (unless otherwise specified. E.g. KeDei uses 16 bit instead)
#define SPI_3WIRE_DATA_COMMAND_FRAMING_BITS 1
#endif

View File

@ -1,760 +0,0 @@
#ifndef KERNEL_MODULE
#include <stdio.h> // fprintf, stderr
#include <stdlib.h> // exit
#include <memory.h> // memset, memcpy
#include <inttypes.h> // uint32_t
#include <syslog.h> // syslog
#include <sys/mman.h> // mmap, munmap, PROT_READ, PROT_WRITE
#endif
#include "config.h"
#include "dma.h"
#include "spi.h"
#include "gpu.h"
#include "util.h"
#include "mailbox.h"
#ifdef USE_DMA_TRANSFERS
#define BCM2835_PERI_BASE 0x3F000000
SharedMemory *dmaSourceMemory = 0;
volatile DMAChannelRegisterFile *dma0 = 0;
volatile DMAChannelRegisterFile *dmaTx = 0;
volatile DMAChannelRegisterFile *dmaRx = 0;
int dmaTxChannel = -1;
int dmaTxIrq = 0;
int dmaRxChannel = -1;
int dmaRxIrq = 0;
#define PAGE_SIZE 4096
struct GpuMemory
{
uint32_t allocationHandle;
void *virtualAddr;
uintptr_t busAddress;
uint32_t sizeBytes;
};
#define NUM_DMA_CBS 1024
GpuMemory dmaCb, dmaSourceBuffer, dmaConstantData;
volatile DMAControlBlock *dmaSendTail = 0;
volatile DMAControlBlock *dmaRecvTail = 0;
volatile DMAControlBlock *firstFreeCB = 0;
volatile uint8_t *dmaSourceEnd = 0;
volatile DMAControlBlock *GrabFreeCBs(int num)
{
volatile DMAControlBlock *firstCB = (volatile DMAControlBlock *)dmaCb.virtualAddr;
volatile DMAControlBlock *endCB = firstCB + NUM_DMA_CBS;
if ((uintptr_t)(firstFreeCB + num) >= (uintptr_t)dmaCb.virtualAddr + dmaCb.sizeBytes)
{
WaitForDMAFinished();
firstFreeCB = firstCB;
}
volatile DMAControlBlock *ret = firstFreeCB;
firstFreeCB += num;
return ret;
}
volatile uint8_t *GrabFreeDMASourceBytes(int bytes)
{
if ((uintptr_t)dmaSourceEnd + bytes >= (uintptr_t)dmaSourceBuffer.virtualAddr + dmaSourceBuffer.sizeBytes)
{
WaitForDMAFinished();
dmaSourceEnd = (volatile uint8_t *)dmaSourceBuffer.virtualAddr;
}
volatile uint8_t *ret = dmaSourceEnd;
dmaSourceEnd += bytes;
return ret;
}
static int AllocateDMAChannel(int *dmaChannel, int *irq)
{
// Snooping DMA, channels 3, 5 and 6 seen active.
// TODO: Actually reserve the DMA channel to the system using bcm_dma_chan_alloc() and bcm_dma_chan_free()?...
// Right now, use channels 1 and 4 which seem to be free.
// Note: The send channel could be a lite channel, but receive channel cannot, since receiving uses the IGNORE flag
// that lite DMA engines don't have.
#ifdef FREEPLAYTECH_WAVESHARE32B
// On FreePlayTech Zero, DMA channel 4 seen to be taken by SD HOST (peripheral mapping 13).
int freeChannels[] = { 5, 1 };
#else
int freeChannels[] = { 7, 1 };
#endif
#if defined(DMA_TX_CHANNEL)
freeChannels[0] = DMA_TX_CHANNEL;
#endif
#if defined(DMA_RX_CHANNEL)
freeChannels[1] = DMA_RX_CHANNEL;
#endif
if (freeChannels[0] == freeChannels[1]) FATAL_ERROR("DMA TX and RX channels cannot be the same channel!");
static int nextFreeChannel = 0;
if (nextFreeChannel >= sizeof(freeChannels) / sizeof(freeChannels[0])) FATAL_ERROR("No free DMA channels");
*dmaChannel = freeChannels[nextFreeChannel++];
LOG("Allocated DMA channel %d", *dmaChannel);
*irq = 0;
return 0;
}
void FreeDMAChannel(int channel)
{
volatile DMAChannelRegisterFile *dma = GetDMAChannel(channel);
dma->cb.ti = 0; // Clear the SPI TX & RX permaps for this DMA channel so that we don't think some other program is using these for SPI
}
// Message IDs for different mailbox GPU memory allocation messages
#define MEM_ALLOC_MESSAGE 0x3000c // This message is 3 u32s: numBytes, alignment and flags
#define MEM_FREE_MESSAGE 0x3000f // This message is 1 u32: handle
#define MEM_LOCK_MESSAGE 0x3000d // 1 u32: handle
#define MEM_UNLOCK_MESSAGE 0x3000e // 1 u32: handle
// Memory allocation flags
#define MEM_ALLOC_FLAG_DIRECT (1 << 2) // Allocate uncached memory that bypasses L1 and L2 cache on loads and stores
#define MEM_ALLOC_FLAG_COHERENT (1 << 3) // Non-allocating in L2 but coherent
#define BUS_TO_PHYS(x) ((x) & ~0xC0000000)
#define PHYS_TO_BUS(x) ((x) | 0xC0000000)
#define VIRT_TO_BUS(block, x) ((uintptr_t)(x) - (uintptr_t)((block).virtualAddr) + (block).busAddress)
uint64_t totalGpuMemoryUsed = 0;
// Allocates the given number of bytes in GPU side memory, and returns the virtual address and physical bus address of the allocated memory block.
// The virtual address holds an uncached view to the allocated memory, so writes and reads to that memory address bypass the L1 and L2 caches. Use
// this kind of memory to pass data blocks over to the DMA controller to process.
GpuMemory AllocateUncachedGpuMemory(uint32_t numBytes, const char *reason)
{
GpuMemory mem;
mem.sizeBytes = ALIGN_UP(numBytes, PAGE_SIZE);
uint32_t allocationFlags = MEM_ALLOC_FLAG_DIRECT | MEM_ALLOC_FLAG_COHERENT;
mem.allocationHandle = Mailbox(MEM_ALLOC_MESSAGE, /*size=*/mem.sizeBytes, /*alignment=*/PAGE_SIZE, /*flags=*/allocationFlags);
if (!mem.allocationHandle) FATAL_ERROR("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");
mem.busAddress = Mailbox(MEM_LOCK_MESSAGE, mem.allocationHandle);
if (!mem.busAddress) FATAL_ERROR("Failed to lock GPU memory!");
mem.virtualAddr = mmap(0, mem.sizeBytes, PROT_READ | PROT_WRITE, MAP_SHARED, mem_fd, BUS_TO_PHYS(mem.busAddress));
if (mem.virtualAddr == MAP_FAILED) FATAL_ERROR("Failed to mmap GPU memory!");
totalGpuMemoryUsed += mem.sizeBytes;
// printf("Allocated %u bytes of GPU memory for %s (bus address=%p). Total GPU memory used: %llu bytes\n", mem.sizeBytes, reason, (void*)mem.busAddress, totalGpuMemoryUsed);
return mem;
}
void FreeUncachedGpuMemory(GpuMemory mem)
{
totalGpuMemoryUsed -= mem.sizeBytes;
munmap(mem.virtualAddr, mem.sizeBytes);
Mailbox(MEM_UNLOCK_MESSAGE, mem.allocationHandle);
Mailbox(MEM_FREE_MESSAGE, mem.allocationHandle);
}
volatile DMAChannelRegisterFile *GetDMAChannel(int channelNumber)
{
if (channelNumber < 0 || channelNumber >= BCM2835_NUM_DMA_CHANNELS)
{
printf("Invalid DMA channel %d specified!\n", channelNumber);
FATAL_ERROR("Invalid DMA channel specified!");
}
return dma0 + channelNumber;
}
void DumpDMAPeripheralMap()
{
for(int i = 0; i < BCM2835_NUM_DMA_CHANNELS; ++i)
{
volatile DMAChannelRegisterFile *channel = GetDMAChannel(i);
printf("DMA channel %d has peripheral map %d (is lite channel: %d, currently active: %d, current control block: %p)\n", i, (channel->cb.ti & BCM2835_DMA_TI_PERMAP_MASK) >> BCM2835_DMA_TI_PERMAP_SHIFT, (channel->cb.debug & BCM2835_DMA_DEBUG_LITE) ? 1 : 0, (channel->cs & BCM2835_DMA_CS_ACTIVE) ? 1 : 0, channel->cbAddr);
}
}
// Verifies that no other program has stomped on the DMA channel that we are using.
void CheckDMAChannelNotStolen(int channelNumber, int expectedPeripheralMap)
{
volatile DMAChannelRegisterFile *channel = GetDMAChannel(channelNumber);
uint32_t peripheralMap = ((channel->cb.ti & BCM2835_DMA_TI_PERMAP_MASK) >> BCM2835_DMA_TI_PERMAP_SHIFT);
if (peripheralMap != expectedPeripheralMap && peripheralMap != 0)
{
DumpDMAPeripheralMap();
printf("DMA channel collision! DMA channel %d was expected to be assigned to our peripheral %d, but something else has assigned it to peripheral %d!\n", channelNumber, expectedPeripheralMap, peripheralMap);
FATAL_ERROR("System is likely unstable now, rebooting is advised.");
}
uint32_t cbAddr = channel->cbAddr;
if (cbAddr && (cbAddr < dmaCb.busAddress || cbAddr >= dmaCb.busAddress + dmaCb.sizeBytes))
{
DumpDMAPeripheralMap();
printf("DMA channel collision! Some other program has submitted a DMA task to our DMA channel %d! (DMA task at unknown control block address %p)\n", channelNumber, cbAddr);
FATAL_ERROR("System is likely unstable now, rebooting is advised.");
}
}
void CheckSPIDMAChannelsNotStolen()
{
CheckDMAChannelNotStolen(dmaTxChannel, BCM2835_DMA_TI_PERMAP_SPI_TX);
CheckDMAChannelNotStolen(dmaRxChannel, BCM2835_DMA_TI_PERMAP_SPI_RX);
}
void ResetDMAChannels()
{
dmaTx->cs = BCM2835_DMA_CS_RESET;
dmaTx->cb.debug = BCM2835_DMA_DEBUG_DMA_READ_ERROR | BCM2835_DMA_DEBUG_DMA_FIFO_ERROR | BCM2835_DMA_DEBUG_READ_LAST_NOT_SET_ERROR;
dmaRx->cs = BCM2835_DMA_CS_RESET;
dmaRx->cb.debug = BCM2835_DMA_DEBUG_DMA_READ_ERROR | BCM2835_DMA_DEBUG_DMA_FIFO_ERROR | BCM2835_DMA_DEBUG_READ_LAST_NOT_SET_ERROR;
}
int InitDMA()
{
#if defined(KERNEL_MODULE)
dma0 = (volatile DMAChannelRegisterFile*)ioremap(BCM2835_PERI_BASE+BCM2835_DMA0_OFFSET, BCM2835_NUM_DMA_CHANNELS*0x100);
#else
dma0 = (volatile DMAChannelRegisterFile*)((uintptr_t)bcm2835 + BCM2835_DMA0_OFFSET);
#endif
#ifdef KERNEL_MODULE_CLIENT
dmaTxChannel = spiTaskMemory->dmaTxChannel;
dmaRxChannel = spiTaskMemory->dmaRxChannel;
#else
int ret = AllocateDMAChannel(&dmaTxChannel, &dmaTxIrq);
if (ret != 0) FATAL_ERROR("Unable to allocate TX DMA channel!");
ret = AllocateDMAChannel(&dmaRxChannel, &dmaRxIrq);
if (ret != 0) FATAL_ERROR("Unable to allocate RX DMA channel!");
printf("Enabling DMA channels Tx:%d and Rx:%d\n", dmaTxChannel, dmaRxChannel);
volatile uint32_t *dmaEnableRegister = (volatile uint32_t *)((uintptr_t)dma0 + BCM2835_DMAENABLE_REGISTER_OFFSET);
// Enable the allocated DMA channels
*dmaEnableRegister |= (1 << dmaTxChannel);
*dmaEnableRegister |= (1 << dmaRxChannel);
#endif
#if !defined(KERNEL_MODULE)
dmaCb = AllocateUncachedGpuMemory(sizeof(DMAControlBlock) * NUM_DMA_CBS, "DMA control blocks");
memset(dmaCb.virtualAddr, 0, dmaCb.sizeBytes); // Some fields of the CBs (debug, reserved) are initialized to zero and assumed to stay so throughout app lifetime.
firstFreeCB = (volatile DMAControlBlock *)dmaCb.virtualAddr;
dmaSourceBuffer = AllocateUncachedGpuMemory(SHARED_MEMORY_SIZE*2, "DMA source data");
dmaSourceEnd = (volatile uint8_t *)dmaSourceBuffer.virtualAddr;
dmaConstantData = AllocateUncachedGpuMemory(2*sizeof(uint32_t), "DMA constant data");
uint32_t *constantData = (uint32_t *)dmaConstantData.virtualAddr;
constantData[0] = BCM2835_SPI0_CS_DMAEN; // constantData[0] is for disableTransferActive task
constantData[1] = BCM2835_DMA_CS_ACTIVE | BCM2835_DMA_CS_END; // constantData[1] is for startDMATxChannel task
#endif
LOG("DMA hardware register file is at ptr: %p, using DMA TX channel: %d and DMA RX channel: %d", dma0, dmaTxChannel, dmaRxChannel);
if (!dma0) FATAL_ERROR("Failed to map DMA!");
dmaTx = GetDMAChannel(dmaTxChannel);
dmaRx = GetDMAChannel(dmaRxChannel);
LOG("DMA hardware TX channel register file is at ptr: %p, DMA RX channel register file is at ptr: %p", dmaTx, dmaRx);
int dmaTxPeripheralMap = (dmaTx->cb.ti & BCM2835_DMA_TI_PERMAP_MASK) >> BCM2835_DMA_TI_PERMAP_SHIFT;
if (dmaTxPeripheralMap != 0 && dmaTxPeripheralMap != BCM2835_DMA_TI_PERMAP_SPI_TX)
{
DumpDMAPeripheralMap();
LOG("DMA TX channel %d was assigned another peripheral map %d!", dmaTxChannel, dmaTxPeripheralMap);
FATAL_ERROR("DMA TX channel was assigned another peripheral map!");
}
if (dmaTx->cbAddr != 0 && (dmaTx->cs & BCM2835_DMA_CS_ACTIVE))
FATAL_ERROR("DMA TX channel was in use!");
int dmaRxPeripheralMap = (dmaRx->cb.ti & BCM2835_DMA_TI_PERMAP_MASK) >> BCM2835_DMA_TI_PERMAP_SHIFT;
if (dmaRxPeripheralMap != 0 && dmaRxPeripheralMap != BCM2835_DMA_TI_PERMAP_SPI_RX)
{
LOG("DMA RX channel %d was assigned another peripheral map %d!", dmaRxChannel, dmaRxPeripheralMap);
DumpDMAPeripheralMap();
FATAL_ERROR("DMA RX channel was assigned another peripheral map!");
}
if (dmaRx->cbAddr != 0 && (dmaRx->cs & BCM2835_DMA_CS_ACTIVE))
FATAL_ERROR("DMA RX channel was in use!");
if ((dmaRx->cb.debug & BCM2835_DMA_DEBUG_LITE) != 0)
FATAL_ERROR("DMA RX channel cannot be a lite channel, because to get best performance we want to use BCM2835_DMA_TI_DEST_IGNORE DMA operation mode that lite DMA channels do not have. (Try using DMA RX channel value < 7)");
LOG("Resetting DMA channels for use");
ResetDMAChannels();
// TODO: Set up IRQ
LOG("DMA all set up");
return 0;
}
// Debugging functions to introspect SPI and DMA hardware registers:
void DumpCS(uint32_t reg)
{
PRINT_FLAG(BCM2835_DMA_CS_RESET);
PRINT_FLAG(BCM2835_DMA_CS_ABORT);
PRINT_FLAG(BCM2835_DMA_CS_DISDEBUG);
PRINT_FLAG(BCM2835_DMA_CS_WAIT_FOR_OUTSTANDING_WRITES);
PRINT_FLAG(BCM2835_DMA_CS_PANIC_PRIORITY);
PRINT_FLAG(BCM2835_DMA_CS_PRIORITY);
PRINT_FLAG(BCM2835_DMA_CS_ERROR);
PRINT_FLAG(BCM2835_DMA_CS_WAITING_FOR_OUTSTANDING_WRITES);
PRINT_FLAG(BCM2835_DMA_CS_DREQ_STOPS_DMA);
PRINT_FLAG(BCM2835_DMA_CS_PAUSED);
PRINT_FLAG(BCM2835_DMA_CS_DREQ);
PRINT_FLAG(BCM2835_DMA_CS_INT);
PRINT_FLAG(BCM2835_DMA_CS_END);
PRINT_FLAG(BCM2835_DMA_CS_ACTIVE);
}
void DumpDebug(uint32_t reg)
{
PRINT_FLAG(BCM2835_DMA_DEBUG_LITE);
PRINT_FLAG(BCM2835_DMA_DEBUG_VERSION);
PRINT_FLAG(BCM2835_DMA_DEBUG_DMA_STATE);
PRINT_FLAG(BCM2835_DMA_DEBUG_DMA_ID);
PRINT_FLAG(BCM2835_DMA_DEBUG_DMA_OUTSTANDING_WRITES);
PRINT_FLAG(BCM2835_DMA_DEBUG_DMA_READ_ERROR);
PRINT_FLAG(BCM2835_DMA_DEBUG_DMA_FIFO_ERROR);
PRINT_FLAG(BCM2835_DMA_DEBUG_READ_LAST_NOT_SET_ERROR);
}
void DumpTI(uint32_t reg)
{
PRINT_FLAG(BCM2835_DMA_TI_NO_WIDE_BURSTS);
PRINT_FLAG(BCM2835_DMA_TI_WAITS);
#define BCM2835_DMA_TI_PERMAP_MASK_SHIFT 16
PRINT_FLAG(BCM2835_DMA_TI_PERMAP_MASK);
// PRINT_FLAG(BCM2835_DMA_TI_BURST_LENGTH);
PRINT_FLAG(BCM2835_DMA_TI_SRC_IGNORE);
PRINT_FLAG(BCM2835_DMA_TI_SRC_DREQ);
PRINT_FLAG(BCM2835_DMA_TI_SRC_WIDTH);
PRINT_FLAG(BCM2835_DMA_TI_SRC_INC);
PRINT_FLAG(BCM2835_DMA_TI_DEST_IGNORE);
PRINT_FLAG(BCM2835_DMA_TI_DEST_DREQ);
PRINT_FLAG(BCM2835_DMA_TI_DEST_WIDTH);
PRINT_FLAG(BCM2835_DMA_TI_DEST_INC);
PRINT_FLAG(BCM2835_DMA_TI_WAIT_RESP);
PRINT_FLAG(BCM2835_DMA_TI_TDMODE);
PRINT_FLAG(BCM2835_DMA_TI_INTEN);
}
#define DMA_DMA0_CB_PHYS_ADDRESS 0x7E007000
#define DMA_SPI_CS_PHYS_ADDRESS 0x7E204000
#define DMA_SPI_FIFO_PHYS_ADDRESS 0x7E204004
#define DMA_SPI_DLEN_PHYS_ADDRESS 0x7E20400C
#define DMA_GPIO_SET_PHYS_ADDRESS 0x7E20001C
#define DMA_GPIO_CLEAR_PHYS_ADDRESS 0x7E200028
void DumpDMAState()
{
printf("---SPI:---\n");
DumpSPICS(spi->cs);
printf("---DMATX CS:---\n");
DumpCS(dmaTx->cs);
printf("---DMATX TI:---\n");
DumpTI(dmaTx->cb.ti);
printf("---DMATX DEBUG:---\n");
DumpDebug(dmaTx->cb.debug);
printf("****** DMATX cbAddr: %p\n", dmaTx->cbAddr);
printf("---DMARX CS:---\n");
DumpCS(dmaRx->cs);
printf("---DMARX TI:---\n");
DumpTI(dmaRx->cb.ti);
printf("---DMARX DEBUG:---\n");
DumpDebug(dmaRx->cb.debug);
printf("****** DMARX cbAddr: %p\n", dmaRx->cbAddr);
}
extern volatile bool programRunning;
void WaitForDMAFinished()
{
int spins = 0;
uint64_t t0 = tick();
while((dmaTx->cs & BCM2835_DMA_CS_ACTIVE) && programRunning)
{
usleep(100);
if (tick() - t0 > 2000000)
{
printf("TX stalled\n");
DumpDMAState();
exit(1);
}
}
spins = 0;
t0 = tick();
while((dmaRx->cs & BCM2835_DMA_CS_ACTIVE) && programRunning)
{
usleep(100);
if (tick() - t0 > 2000000)
{
printf("RX stalled\n");
DumpDMAState();
exit(1);
}
}
dmaSendTail = 0;
dmaRecvTail = 0;
}
#ifdef ALL_TASKS_SHOULD_DMA
// This function does a memcpy from one source buffer to two destination buffers simultaneously.
// It saves a lot of time on ARMv6 by avoiding to have to do two separate memory copies, because the ARMv6 L1 cache is so tiny (4K) that it cannot fit a whole framebuffer
// in memory at a time. Streaming through it only once instead of twice helps memory bandwidth immensely, this is profiled to be ~4x faster than a pair of memcpys or a simple CPU loop.
// In addition, this does a little endian->big endian conversion when copying data out to dstDma.
static void memcpy_to_dma_and_prev_framebuffer(uint16_t *dstDma, uint16_t **dstPrevFramebuffer, uint16_t **srcFramebuffer, int numBytes, int *taskStartX, int width, int stride)
{
int strideEnd = stride - width*2;
int xLeft = width-*taskStartX;
uint16_t *Src = *srcFramebuffer;
uint16_t *Dst1 = *dstPrevFramebuffer;
// TODO: Do the loops in aligned order with unaligned head and tail separate, and ensure that dstDma, dstPrevFramebuffer and srcFramebuffer are in same alignment phase.
asm volatile(
"start_%=:\n"
"ldrd r0, r1, [%[srcFramebuffer]], #8\n"
"pld [%[srcFramebuffer], #248]\n"
"strd r0, r1, [%[dstPrevFramebuffer]], #8\n"
"rev16 r0, r0\n"
"rev16 r1, r1\n"
"strd r0, r1, [%[dstDma]], #8\n"
"ldrd r0, r1, [%[srcFramebuffer]], #8\n"
"strd r0, r1, [%[dstPrevFramebuffer]], #8\n"
"rev16 r0, r0\n"
"rev16 r1, r1\n"
"strd r0, r1, [%[dstDma]], #8\n"
"ldrd r0, r1, [%[srcFramebuffer]], #8\n"
"strd r0, r1, [%[dstPrevFramebuffer]], #8\n"
"rev16 r0, r0\n"
"rev16 r1, r1\n"
"strd r0, r1, [%[dstDma]], #8\n"
"ldrd r0, r1, [%[srcFramebuffer]], #8\n"
"strd r0, r1, [%[dstPrevFramebuffer]], #8\n"
"rev16 r0, r0\n"
"rev16 r1, r1\n"
"strd r0, r1, [%[dstDma]], #8\n"
"subs %[xLeft], %[xLeft], #16\n"
"addls %[xLeft], %[xLeft], %[width]\n"
"addls %[dstPrevFramebuffer], %[dstPrevFramebuffer], %[strideEnd]\n"
"addls %[srcFramebuffer], %[srcFramebuffer], %[strideEnd]\n"
"subs %[numBytes], %[numBytes], #32\n"
"bhi start_%=\n"
: [dstDma]"+r"(dstDma), [dstPrevFramebuffer]"+r"(Dst1), [srcFramebuffer]"+r"(Src), [xLeft]"+r"(xLeft), [numBytes]"+r"(numBytes)
: [strideEnd]"r"(strideEnd), [width]"r"(width)
: "r0", "r1", "memory", "cc"
);
*taskStartX = width - xLeft;
*srcFramebuffer = Src;
*dstPrevFramebuffer = Dst1;
}
static void memcpy_to_dma_and_prev_framebuffer_in_c(uint16_t *dstDma, uint16_t **dstPrevFramebuffer, uint16_t **srcFramebuffer, int numBytes, int *taskStartX, int width, int stride)
{
static bool performanceWarningPrinted = false;
if (!performanceWarningPrinted)
{
printf("Performance warning: using slow memcpy_to_dma_and_prev_framebuffer_in_c() function. Check conditions in display.h that enable OFFLOAD_PIXEL_COPY_TO_DMA_CPP and configure to use that instead.\n");
performanceWarningPrinted = true;
}
int numPixels = numBytes>>1;
int endStridePixels = (stride>>1) - width;
uint16_t *prevData = *dstPrevFramebuffer;
uint16_t *data = *srcFramebuffer;
for(int i = 0; i < numPixels; ++i)
{
*prevData++ = *data;
dstDma[i] = __builtin_bswap16(*data++);
if (++*taskStartX >= width)
{
*taskStartX = 0;
data += endStridePixels;
prevData += endStridePixels;
}
}
*srcFramebuffer = data;
*dstPrevFramebuffer = prevData;
}
#if defined(ALL_TASKS_SHOULD_DMA) && defined(SPI_3WIRE_PROTOCOL)
// Bug: there is something about the chained DMA transfer mechanism that makes write window coordinate set commands not go through properly
// on 3-wire displays, but do not yet know what. (Remove this #error statement to debug)
#error ALL_TASKS_SHOULD_DMA and SPI_3WIRE_PROTOCOL are currently not mutually compatible!
#endif
#if defined(OFFLOAD_PIXEL_COPY_TO_DMA_CPP) && defined(SPI_3WIRE_PROTOCOL)
// We would have to convert 8-bit tasks to 9-bit tasks immediately after offloaded memcpy has been done below to implement this.
#error OFFLOAD_PIXEL_COPY_TO_DMA_CPP and SPI_3WIRE_PROTOCOL are not mutually compatible!
#endif
void SPIDMATransfer(SPITask *task)
{
// There is a limit to how many bytes can be sent in one DMA-based SPI task, so if the task
// is larger than this, we'll split the send into multiple individual DMA SPI transfers
// and chain them together. This should be a multiple of 32 bytes to keep tasks cache aligned on ARMv6.
#define MAX_DMA_SPI_TASK_SIZE 65504
const int numDMASendTasks = (task->PayloadSize() + MAX_DMA_SPI_TASK_SIZE - 1) / MAX_DMA_SPI_TASK_SIZE;
volatile uint32_t *dmaData = (volatile uint32_t *)GrabFreeDMASourceBytes(4*(numDMASendTasks-1)+4*numDMASendTasks+task->PayloadSize());
volatile uint32_t *setDMATxAddressData = dmaData;
volatile uint32_t *txData = dmaData+numDMASendTasks-1;
volatile DMAControlBlock *cb = GrabFreeCBs(numDMASendTasks*5-3);
volatile DMAControlBlock *rxTail = 0;
volatile DMAControlBlock *tx0 = &cb[0];
volatile DMAControlBlock *rx0 = &cb[1];
#ifdef OFFLOAD_PIXEL_COPY_TO_DMA_CPP
uint8_t *data = task->fb;
uint8_t *prevData = task->prevFb;
const bool taskAndFramebufferSizesCompatibleWithTightMemcpy = (task->PayloadSize() % 32 == 0) && (task->width % 16 == 0);
#else
uint8_t *data = task->PayloadStart();
#endif
int bytesLeft = task->PayloadSize();
int taskStartX = 0;
while(bytesLeft > 0)
{
int sendSize = MIN(bytesLeft, MAX_DMA_SPI_TASK_SIZE);
bytesLeft -= sendSize;
volatile DMAControlBlock *tx = cb++;
txData[0] = BCM2835_SPI0_CS_TA | DISPLAY_SPI_DRIVE_SETTINGS | (sendSize << 16); // The first four bytes written to the SPI data register control the DLEN and CS,CPOL,CPHA settings.
// This is really sad: we must do a memcpy to prepare for DMA controller to be able to do a memcpy. The reason for this is that the DMA source memory area must be in cache bypassing
// region of memory, which the SPI source ring buffer is not. It could be allocated to be so however, but bypassing the caches on the SPI ring buffer would cause a massive -51.5%
// profiled overall performance drop (tested on Pi3B+ and Tontec 3.5" 480x320 display on gpu test pattern, see branch non_intermediate_memcpy_for_dma). Therefore just keep doing
// this memcpy() to prepare for DMA to do its memcpy(), as it is faster overall. (If there was a way to map same physical memory to virtual address space twice, once cached, and
// another time uncached, and have writes bypass the cache and only write combine, but have reads follow the cache, then it might work without a perf hit, but not at all sure if
// that would be technically possible)
uint16_t *txPtr = (uint16_t*)(txData+1);
// If task->prevFb is present, the DMA backend is responsible for streaming pixel data from current framebuffer to old framebuffer, and the DMA task buffer.
// If not present, then that preparation has been already done by the caller.
#ifdef OFFLOAD_PIXEL_COPY_TO_DMA_CPP
if (prevData)
{
// For 2D pixel data, do a "everything in one pass"
if (taskAndFramebufferSizesCompatibleWithTightMemcpy)
memcpy_to_dma_and_prev_framebuffer((uint16_t*)txPtr, (uint16_t**)&prevData, (uint16_t**)&data, sendSize, &taskStartX, task->width, gpuFramebufferScanlineStrideBytes);
else
memcpy_to_dma_and_prev_framebuffer_in_c((uint16_t*)txPtr, (uint16_t**)&prevData, (uint16_t**)&data, sendSize, &taskStartX, task->width, gpuFramebufferScanlineStrideBytes);
}
else
#endif
{
memcpy(txPtr, data, sendSize);
data += sendSize;
}
tx->ti = BCM2835_DMA_TI_PERMAP(BCM2835_DMA_TI_PERMAP_SPI_TX) | BCM2835_DMA_TI_DEST_DREQ | BCM2835_DMA_TI_SRC_INC | BCM2835_DMA_TI_WAIT_RESP;
tx->src = VIRT_TO_BUS(dmaSourceBuffer, txData);
tx->dst = DMA_SPI_FIFO_PHYS_ADDRESS; // Write out to the SPI peripheral
tx->len = 4+sendSize;
tx->next = 0;
txData += 1+sendSize/4;
volatile DMAControlBlock *rx = cb++;
rx->ti = BCM2835_DMA_TI_PERMAP(BCM2835_DMA_TI_PERMAP_SPI_RX) | BCM2835_DMA_TI_SRC_DREQ | BCM2835_DMA_TI_DEST_IGNORE;
rx->src = DMA_SPI_FIFO_PHYS_ADDRESS;
rx->dst = 0;
rx->len = sendSize;
rx->next = 0;
if (rxTail)
{
volatile DMAControlBlock *setDMATxAddress = cb++;
volatile DMAControlBlock *disableTransferActive = cb++;
volatile DMAControlBlock *startDMATxChannel = cb++;
rxTail->next = VIRT_TO_BUS(dmaCb, setDMATxAddress);
setDMATxAddressData[0] = VIRT_TO_BUS(dmaCb, tx);
setDMATxAddress->ti = BCM2835_DMA_TI_SRC_INC | BCM2835_DMA_TI_DEST_INC | BCM2835_DMA_TI_WAIT_RESP;
setDMATxAddress->src = VIRT_TO_BUS(dmaSourceBuffer, setDMATxAddressData);
setDMATxAddress->dst = DMA_DMA0_CB_PHYS_ADDRESS + dmaTxChannel*0x100 + 4;
setDMATxAddress->len = 4;
setDMATxAddress->next = VIRT_TO_BUS(dmaCb, disableTransferActive);
++setDMATxAddressData;
disableTransferActive->ti = BCM2835_DMA_TI_SRC_INC | BCM2835_DMA_TI_DEST_INC | BCM2835_DMA_TI_WAIT_RESP;
disableTransferActive->src = dmaConstantData.busAddress;
disableTransferActive->dst = DMA_SPI_CS_PHYS_ADDRESS;
disableTransferActive->len = 4;
disableTransferActive->next = VIRT_TO_BUS(dmaCb, startDMATxChannel);
startDMATxChannel->ti = BCM2835_DMA_TI_SRC_INC | BCM2835_DMA_TI_DEST_INC | BCM2835_DMA_TI_WAIT_RESP;
startDMATxChannel->src = dmaConstantData.busAddress+4;
startDMATxChannel->dst = DMA_DMA0_CB_PHYS_ADDRESS + dmaTxChannel*0x100;
startDMATxChannel->len = 4;
startDMATxChannel->next = VIRT_TO_BUS(dmaCb, rx);
}
rxTail = rx;
}
static uint64_t taskStartTime = 0;
static int pendingTaskBytes = 1;
double pendingTaskUSecs = pendingTaskBytes * spiUsecsPerByte;
pendingTaskUSecs -= tick() - taskStartTime;
if (pendingTaskUSecs > 70)
usleep(pendingTaskUSecs-70);
uint64_t dmaTaskStart = tick();
CheckSPIDMAChannelsNotStolen();
while((dmaTx->cs & BCM2835_DMA_CS_ACTIVE) && programRunning)
{
usleep(250);
CheckSPIDMAChannelsNotStolen();
if (tick() - dmaTaskStart > 5000000)
{
DumpDMAState();
FATAL_ERROR("DMA TX channel has stalled!");
}
}
while((dmaRx->cs & BCM2835_DMA_CS_ACTIVE) && programRunning)
{
usleep(250);
CheckSPIDMAChannelsNotStolen();
if (tick() - dmaTaskStart > 5000000)
{
DumpDMAState();
FATAL_ERROR("DMA RX channel has stalled!");
}
}
if (!programRunning) return;
pendingTaskBytes = task->PayloadSize();
// First send the SPI command byte in Polled SPI mode
spi->cs = BCM2835_SPI0_CS_TA | BCM2835_SPI0_CS_CLEAR | DISPLAY_SPI_DRIVE_SETTINGS;
#ifndef SPI_3WIRE_PROTOCOL
CLEAR_GPIO(GPIO_TFT_DATA_CONTROL);
#ifdef DISPLAY_SPI_BUS_IS_16BITS_WIDE
spi->fifo = 0;
spi->fifo = task->cmd;
while(!(spi->cs & (BCM2835_SPI0_CS_DONE))) /*nop*/;
// spi->fifo; // Currently no need to flush these, the clear below clears the rx queue.
// spi->fifo;
#else
spi->fifo = task->cmd;
while(!(spi->cs & (BCM2835_SPI0_CS_RXD|BCM2835_SPI0_CS_DONE))) /*nop*/;
// spi->fifo; // Currently no need to flush this, the clear below clears the rx queue.
#endif
SET_GPIO(GPIO_TFT_DATA_CONTROL);
#endif
spi->cs = BCM2835_SPI0_CS_DMAEN | BCM2835_SPI0_CS_CLEAR | DISPLAY_SPI_DRIVE_SETTINGS;
dmaTx->cbAddr = VIRT_TO_BUS(dmaCb, tx0);
dmaRx->cbAddr = VIRT_TO_BUS(dmaCb, rx0);
__sync_synchronize();
dmaTx->cs = BCM2835_DMA_CS_ACTIVE | BCM2835_DMA_CS_END;
dmaRx->cs = BCM2835_DMA_CS_ACTIVE | BCM2835_DMA_CS_END;
taskStartTime = tick();
}
#else
void SPIDMATransfer(SPITask *task)
{
// Transition the SPI peripheral to enable the use of DMA
spi->cs = BCM2835_SPI0_CS_DMAEN | BCM2835_SPI0_CS_CLEAR | DISPLAY_SPI_DRIVE_SETTINGS;
uint32_t *headerAddr = task->DmaSpiHeaderAddress();
*headerAddr = BCM2835_SPI0_CS_TA | DISPLAY_SPI_DRIVE_SETTINGS | (task->PayloadSize() << 16); // The first four bytes written to the SPI data register control the DLEN and CS,CPOL,CPHA settings.
// TODO: Ideally we would be able to directly perform the DMA from the SPI ring buffer from 'task' pointer. However
// that pointer is shared to userland, and it is proving troublesome to make it both userland-writable as well as cache-bypassing DMA coherent.
// Therefore these two memory areas are separate for now, and we memcpy() from SPI ring buffer to an intermediate 'dmaSourceMemory' memory area to perform
// the DMA transfer. Is there a way to avoid this intermediate buffer? That would improve performance a bit.
memcpy(dmaSourceBuffer.virtualAddr, headerAddr, task->PayloadSize() + 4);
volatile DMAControlBlock *cb = (volatile DMAControlBlock *)dmaCb.virtualAddr;
volatile DMAControlBlock *txcb = &cb[0];
txcb->ti = BCM2835_DMA_TI_PERMAP(BCM2835_DMA_TI_PERMAP_SPI_TX) | BCM2835_DMA_TI_DEST_DREQ | BCM2835_DMA_TI_SRC_INC | BCM2835_DMA_TI_WAIT_RESP;
txcb->src = dmaSourceBuffer.busAddress;
txcb->dst = DMA_SPI_FIFO_PHYS_ADDRESS; // Write out to the SPI peripheral
txcb->len = task->PayloadSize() + 4;
txcb->stride = 0;
txcb->next = 0;
txcb->debug = 0;
txcb->reserved = 0;
dmaTx->cbAddr = dmaCb.busAddress;
volatile DMAControlBlock *rxcb = &cb[1];
rxcb->ti = BCM2835_DMA_TI_PERMAP(BCM2835_DMA_TI_PERMAP_SPI_RX) | BCM2835_DMA_TI_SRC_DREQ | BCM2835_DMA_TI_DEST_IGNORE;
rxcb->src = DMA_SPI_FIFO_PHYS_ADDRESS;
rxcb->dst = 0;
rxcb->len = task->PayloadSize();
rxcb->stride = 0;
rxcb->next = 0;
rxcb->debug = 0;
rxcb->reserved = 0;
dmaRx->cbAddr = dmaCb.busAddress + sizeof(DMAControlBlock);
__sync_synchronize();
dmaTx->cs = BCM2835_DMA_CS_ACTIVE;
dmaRx->cs = BCM2835_DMA_CS_ACTIVE;
__sync_synchronize();
double pendingTaskUSecs = task->PayloadSize() * spiUsecsPerByte;
if (pendingTaskUSecs > 70)
usleep(pendingTaskUSecs-70);
uint64_t dmaTaskStart = tick();
CheckSPIDMAChannelsNotStolen();
while((dmaTx->cs & BCM2835_DMA_CS_ACTIVE))
{
CheckSPIDMAChannelsNotStolen();
if (tick() - dmaTaskStart > 5000000)
FATAL_ERROR("DMA TX channel has stalled!");
}
while((dmaRx->cs & BCM2835_DMA_CS_ACTIVE))
{
CheckSPIDMAChannelsNotStolen();
if (tick() - dmaTaskStart > 5000000)
FATAL_ERROR("DMA RX channel has stalled!");
}
__sync_synchronize();
spi->cs = BCM2835_SPI0_CS_TA | BCM2835_SPI0_CS_CLEAR | DISPLAY_SPI_DRIVE_SETTINGS;
__sync_synchronize();
}
#endif
void DeinitDMA(void)
{
WaitForDMAFinished();
ResetDMAChannels();
FreeUncachedGpuMemory(dmaSourceBuffer);
FreeUncachedGpuMemory(dmaCb);
FreeUncachedGpuMemory(dmaConstantData);
if (dmaTxChannel != -1)
{
FreeDMAChannel(dmaTxChannel);
dmaTxChannel = -1;
}
if (dmaRxChannel != -1)
{
FreeDMAChannel(dmaRxChannel);
dmaRxChannel = -1;
}
}
#endif // ~USE_DMA_TRANSFERS

View File

@ -1,141 +0,0 @@
#pragma once
#ifdef USE_DMA_TRANSFERS
#define BCM2835_DMA0_OFFSET 0x7000 // DMA channels 0-14 live at 0x7E007000, offset of 0x7000 of BCM2835 peripherals base address
#define BCM2835_DMAENABLE_REGISTER_OFFSET 0xff0
typedef struct __attribute__ ((packed, aligned(4))) DMAControlBlock
{
uint32_t ti;
uint32_t src;
uint32_t dst;
uint32_t len;
uint32_t stride;
uint32_t next;
uint32_t debug;
uint32_t reserved;
} DMAControlBlock;
typedef struct __attribute__ ((packed, aligned(4))) DMAChannelRegisterFile
{
volatile uint32_t cs;
volatile uint32_t cbAddr;
volatile DMAControlBlock cb;
volatile uint8_t padding[216]; // Pad this structure to 256 bytes in size total for easy indexing into DMA channels.
} DMAChannelRegisterFile;
extern int dmaTxChannel, dmaTxIrq;
extern volatile DMAChannelRegisterFile *dmaTx; // DMA channel allocated to sending to SPI
extern int dmaRxChannel, dmaRxIrq;
extern volatile DMAChannelRegisterFile *dmaRx; // DMA channel allocated to reading from SPI
volatile DMAChannelRegisterFile *GetDMAChannel(int channelNumber);
#define BCM2835_DMA_CS_RESET (1<<31)
#define BCM2835_DMA_CS_ABORT (1<<30)
#define BCM2835_DMA_CS_DISDEBUG (1<<29)
#define BCM2835_DMA_CS_WAIT_FOR_OUTSTANDING_WRITES (1<<28)
#define BCM2835_DMA_CS_PANIC_PRIORITY (0xF<<20)
#define BCM2835_DMA_CS_PRIORITY (0xF<<16)
#define BCM2835_DMA_CS_ERROR (1<<8)
#define BCM2835_DMA_CS_WAITING_FOR_OUTSTANDING_WRITES (1<<6)
#define BCM2835_DMA_CS_DREQ_STOPS_DMA (1<<5)
#define BCM2835_DMA_CS_PAUSED (1<<4)
#define BCM2835_DMA_CS_DREQ (1<<3)
#define BCM2835_DMA_CS_INT (1<<2)
#define BCM2835_DMA_CS_END (1<<1)
#define BCM2835_DMA_CS_ACTIVE (1<<0)
#define BCM2835_DMA_CS_SET_PANIC_PRIORITY(p) ((p) << 20)
#define BCM2835_DMA_CS_SET_PRIORITY(p) ((p) << 16)
#define BCM2835_DMA_CS_RESET_SHIFT 31
#define BCM2835_DMA_CS_ABORT_SHIFT 30
#define BCM2835_DMA_CS_DISDEBUG_SHIFT 29
#define BCM2835_DMA_CS_WAIT_FOR_OUTSTANDING_WRITES_SHIFT 28
#define BCM2835_DMA_CS_PANIC_PRIORITY_SHIFT 20
#define BCM2835_DMA_CS_PRIORITY_SHIFT 16
#define BCM2835_DMA_CS_ERROR_SHIFT 8
#define BCM2835_DMA_CS_WAITING_FOR_OUTSTANDING_WRITES_SHIFT 6
#define BCM2835_DMA_CS_DREQ_STOPS_DMA_SHIFT 5
#define BCM2835_DMA_CS_PAUSED_SHIFT 4
#define BCM2835_DMA_CS_DREQ_SHIFT 3
#define BCM2835_DMA_CS_INT_SHIFT 2
#define BCM2835_DMA_CS_END_SHIFT 1
#define BCM2835_DMA_CS_ACTIVE_SHIFT 0
#define BCM2835_DMA_DEBUG_LITE (1<<28)
#define BCM2835_DMA_DEBUG_VERSION (7<<25)
#define BCM2835_DMA_DEBUG_DMA_STATE (0x1FF<<16)
#define BCM2835_DMA_DEBUG_DMA_ID (0xFF<<8)
#define BCM2835_DMA_DEBUG_DMA_OUTSTANDING_WRITES (0xF<<4)
#define BCM2835_DMA_DEBUG_DMA_READ_ERROR (1<<2)
#define BCM2835_DMA_DEBUG_DMA_FIFO_ERROR (1<<1)
#define BCM2835_DMA_DEBUG_READ_LAST_NOT_SET_ERROR (1<<0)
#define BCM2835_DMA_DEBUG_LITE_SHIFT 28
#define BCM2835_DMA_DEBUG_VERSION_SHIFT 25
#define BCM2835_DMA_DEBUG_DMA_STATE_SHIFT 16
#define BCM2835_DMA_DEBUG_DMA_ID_SHIFT 8
#define BCM2835_DMA_DEBUG_DMA_OUTSTANDING_WRITES_SHIFT 4
#define BCM2835_DMA_DEBUG_DMA_READ_ERROR_SHIFT 2
#define BCM2835_DMA_DEBUG_DMA_FIFO_ERROR_SHIFT 1
#define BCM2835_DMA_DEBUG_READ_LAST_NOT_SET_ERROR_SHIFT 0
#define BCM2835_DMA_TI_NO_WIDE_BURSTS (1<<26)
#define BCM2835_DMA_TI_WAITS (0x1F<<21)
#define BCM2835_DMA_TI_PERMAP(x) ((x)<<16)
#define BCM2835_DMA_TI_PERMAP_MASK (0x1F<<16)
#define BCM2835_DMA_TI_PERMAP_SPI_TX 6
#define BCM2835_DMA_TI_PERMAP_SPI_RX 7
#define BCM2835_DMA_TI_BURST_LENGTH(x) ((x)<<12)
#define BCM2835_DMA_TI_SRC_IGNORE (1<<11)
#define BCM2835_DMA_TI_SRC_DREQ (1<<10)
#define BCM2835_DMA_TI_SRC_WIDTH (1<<9)
#define BCM2835_DMA_TI_SRC_INC (1<<8)
#define BCM2835_DMA_TI_DEST_IGNORE (1<<7)
#define BCM2835_DMA_TI_DEST_DREQ (1<<6)
#define BCM2835_DMA_TI_DEST_WIDTH (1<<5)
#define BCM2835_DMA_TI_DEST_INC (1<<4)
#define BCM2835_DMA_TI_WAIT_RESP (1<<3)
#define BCM2835_DMA_TI_TDMODE (1<<1)
#define BCM2835_DMA_TI_INTEN (1<<0)
#define BCM2835_DMA_TI_NO_WIDE_BURSTS_SHIFT 26
#define BCM2835_DMA_TI_WAITS_SHIFT 21
#define BCM2835_DMA_TI_PERMAP_SHIFT 16
#define BCM2835_DMA_TI_BURST_LENGTH_SHIFT 12
#define BCM2835_DMA_TI_SRC_IGNORE_SHIFT 11
#define BCM2835_DMA_TI_SRC_DREQ_SHIFT 10
#define BCM2835_DMA_TI_SRC_WIDTH_SHIFT 9
#define BCM2835_DMA_TI_SRC_INC_SHIFT 8
#define BCM2835_DMA_TI_DEST_IGNORE_SHIFT 7
#define BCM2835_DMA_TI_DEST_DREQ_SHIFT 6
#define BCM2835_DMA_TI_DEST_WIDTH_SHIFT 5
#define BCM2835_DMA_TI_DEST_INC_SHIFT 4
#define BCM2835_DMA_TI_WAIT_RESP_SHIFT 3
#define BCM2835_DMA_TI_TDMODE_SHIFT 1
#define BCM2835_DMA_TI_INTEN_SHIFT 0
// Spec sheet says there's 16 channels, but last channel is unusable:
// https://www.raspberrypi.org/forums/viewtopic.php?t=170957
// So just behave as if there are only 15 channels
#define BCM2835_NUM_DMA_CHANNELS 15
void WaitForDMAFinished(void);
// Reserves and enables a DMA channel for SPI transfers.
int InitDMA(void);
void DeinitDMA(void);
typedef struct SPITask SPITask;
void SPIDMATransfer(SPITask *task);
extern int dmaTxChannel;
extern int dmaRxChannel;
extern uint64_t totalGpuMemoryUsed;
#endif

Binary file not shown.

Before

Width:  |  Height:  |  Size: 299 KiB

View File

@ -1,579 +0,0 @@
#include <fcntl.h>
#include <linux/fb.h>
#include <linux/futex.h>
#include <linux/spi/spidev.h>
#include <memory.h>
#include <stdio.h>
#include <stdlib.h>
#include <endian.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <sys/syscall.h>
#include <syslog.h>
#include <time.h>
#include <unistd.h>
#include <inttypes.h>
#include <math.h>
#include <signal.h>
#include "config.h"
#include "text.h"
#include "spi.h"
#include "gpu.h"
#include "statistics.h"
#include "tick.h"
#include "display.h"
#include "util.h"
#include "mailbox.h"
#include "diff.h"
#include "mem_alloc.h"
#include "keyboard.h"
#include "low_battery.h"
int CountNumChangedPixels(uint16_t *framebuffer, uint16_t *prevFramebuffer)
{
int changedPixels = 0;
for(int y = 0; y < gpuFrameHeight; ++y)
{
for(int x = 0; x < gpuFrameWidth; ++x)
if (framebuffer[x] != prevFramebuffer[x])
++changedPixels;
framebuffer += gpuFramebufferScanlineStrideBytes >> 1;
prevFramebuffer += gpuFramebufferScanlineStrideBytes >> 1;
}
return changedPixels;
}
uint64_t displayContentsLastChanged = 0;
bool displayOff = false;
volatile bool programRunning = true;
const char *SignalToString(int signal)
{
if (signal == SIGINT) return "SIGINT";
if (signal == SIGQUIT) return "SIGQUIT";
if (signal == SIGUSR1) return "SIGUSR1";
if (signal == SIGUSR2) return "SIGUSR2";
if (signal == SIGTERM) return "SIGTERM";
return "?";
}
void MarkProgramQuitting()
{
programRunning = false;
}
void ProgramInterruptHandler(int signal)
{
printf("Signal %s(%d) received, quitting\n", SignalToString(signal), signal);
static int quitHandlerCalled = 0;
if (++quitHandlerCalled >= 5)
{
printf("Ctrl-C handler invoked five times, looks like fbcp-ili9341 is not gracefully quitting - performing a forcible shutdown!\n");
exit(1);
}
MarkProgramQuitting();
__sync_synchronize();
// Wake the SPI thread if it was sleeping so that it can gracefully quit
if (spiTaskMemory)
{
__atomic_fetch_add(&spiTaskMemory->queueHead, 1, __ATOMIC_SEQ_CST);
__atomic_fetch_add(&spiTaskMemory->queueTail, 1, __ATOMIC_SEQ_CST);
syscall(SYS_futex, &spiTaskMemory->queueTail, FUTEX_WAKE, 1, 0, 0, 0); // Wake the SPI thread if it was sleeping to get new tasks
}
// Wake the main thread if it was sleeping for a new frame so that it can gracefully quit
__atomic_fetch_add(&numNewGpuFrames, 1, __ATOMIC_SEQ_CST);
syscall(SYS_futex, &numNewGpuFrames, FUTEX_WAKE, 1, 0, 0, 0);
}
int main()
{
signal(SIGINT, ProgramInterruptHandler);
signal(SIGQUIT, ProgramInterruptHandler);
signal(SIGUSR1, ProgramInterruptHandler);
signal(SIGUSR2, ProgramInterruptHandler);
signal(SIGTERM, ProgramInterruptHandler);
#ifdef RUN_WITH_REALTIME_THREAD_PRIORITY
SetRealtimeThreadPriority();
#endif
OpenMailbox();
InitSPI();
displayContentsLastChanged = tick();
displayOff = false;
InitLowBatterySystem();
// Track current SPI display controller write X and Y cursors.
int spiX = -1;
int spiY = -1;
int spiEndX = DISPLAY_WIDTH;
InitGPU();
spans = (Span*)Malloc((gpuFrameWidth * gpuFrameHeight / 2) * sizeof(Span), "main() task spans");
int size = gpuFramebufferSizeBytes;
#ifdef USE_GPU_VSYNC
// BUG in vc_dispmanx_resource_read_data(!!): If one is capturing a small subrectangle of a large screen resource rectangle, the destination pointer
// is in vc_dispmanx_resource_read_data() incorrectly still taken to point to the top-left corner of the large screen resource, instead of the top-left
// corner of the subrectangle to capture. Therefore do dirty pointer arithmetic to adjust for this. To make this safe, videoCoreFramebuffer is allocated
// double its needed size so that this adjusted pointer does not reference outside allocated memory (if it did, vc_dispmanx_resource_read_data() was seen
// to randomly fail and then subsequently hang if called a second time)
size *= 2;
#endif
uint16_t *framebuffer[2] = { (uint16_t *)Malloc(size, "main() framebuffer0"), (uint16_t *)Malloc(gpuFramebufferSizeBytes, "main() framebuffer1") };
memset(framebuffer[0], 0, size); // Doublebuffer received GPU memory contents, first buffer contains current GPU memory,
memset(framebuffer[1], 0, gpuFramebufferSizeBytes); // second buffer contains whatever the display is currently showing. This allows diffing pixels between the two.
#ifdef USE_GPU_VSYNC
// Due to the above bug. In USE_GPU_VSYNC mode, we directly snapshot to framebuffer[0], so it has to be prepared specially to work around the
// dispmanx bug.
framebuffer[0] += (gpuFramebufferSizeBytes>>1);
#endif
uint32_t curFrameEnd = spiTaskMemory->queueTail;
uint32_t prevFrameEnd = spiTaskMemory->queueTail;
bool prevFrameWasInterlacedUpdate = false;
bool interlacedUpdate = false; // True if the previous update we did was an interlaced half field update.
int frameParity = 0; // For interlaced frame updates, this is either 0 or 1 to denote evens or odds.
OpenKeyboard();
printf("All initialized, now running main loop...\n");
while(programRunning)
{
prevFrameWasInterlacedUpdate = interlacedUpdate;
// If last update was interlaced, it means we still have half of the image pending to be updated. In such a case,
// sleep only until when we expect the next new frame of data to appear, and then continue independent of whether
// a new frame was produced or not - if not, then we will submit the rest of the unsubmitted fields. If yes, then
// the half fields of the new frame will be sent (or full, if the new frame has very little content)
if (prevFrameWasInterlacedUpdate)
{
#ifdef THROTTLE_INTERLACING
timespec timeout = {};
timeout.tv_nsec = 1000 * MIN(1000000, MAX(1, 750/*0.75ms extra sleep so we know we should likely sleep long enough to see the next frame*/ + PredictNextFrameArrivalTime() - tick()));
if (programRunning) syscall(SYS_futex, &numNewGpuFrames, FUTEX_WAIT, 0, &timeout, 0, 0); // Start sleeping until we get new tasks
#endif
// If THROTTLE_INTERLACING is not defined, we'll fall right through and immediately submit the rest of the remaining content on screen to attempt to minimize the visual
// observable effect of interlacing, although at the expense of smooth animation (falling through here causes jitter)
}
else
{
uint64_t waitStart = tick();
while(__atomic_load_n(&numNewGpuFrames, __ATOMIC_SEQ_CST) == 0)
{
#if defined(BACKLIGHT_CONTROL) && defined(TURN_DISPLAY_OFF_AFTER_USECS_OF_INACTIVITY)
if (!displayOff && tick() - waitStart > TURN_DISPLAY_OFF_AFTER_USECS_OF_INACTIVITY)
{
TurnDisplayOff();
displayOff = true;
}
if (!displayOff)
{
timespec timeout = {};
timeout.tv_sec = ((uint64_t)TURN_DISPLAY_OFF_AFTER_USECS_OF_INACTIVITY * 1000) / 1000000000;
timeout.tv_nsec = ((uint64_t)TURN_DISPLAY_OFF_AFTER_USECS_OF_INACTIVITY * 1000) % 1000000000;
if (programRunning) syscall(SYS_futex, &numNewGpuFrames, FUTEX_WAIT, 0, &timeout, 0, 0); // Sleep until the next frame arrives
}
else
#endif
if (programRunning) syscall(SYS_futex, &numNewGpuFrames, FUTEX_WAIT, 0, 0, 0, 0); // Sleep until the next frame arrives
}
}
bool spiThreadWasWorkingHardBefore = false;
// At all times keep at most two rendered frames in the SPI task queue pending to be displayed. Only proceed to submit a new frame
// once the older of those has been displayed.
bool once = true;
while ((spiTaskMemory->queueTail + SPI_QUEUE_SIZE - spiTaskMemory->queueHead) % SPI_QUEUE_SIZE > (spiTaskMemory->queueTail + SPI_QUEUE_SIZE - prevFrameEnd) % SPI_QUEUE_SIZE)
{
if (spiTaskMemory->spiBytesQueued > 10000)
spiThreadWasWorkingHardBefore = true; // SPI thread had too much work in queue atm (2 full frames)
// Peek at the SPI thread's workload and throttle a bit if it has got a lot of work still to do.
double usecsUntilSpiQueueEmpty = spiTaskMemory->spiBytesQueued*spiUsecsPerByte;
if (usecsUntilSpiQueueEmpty > 0)
{
uint32_t bytesInQueueBefore = spiTaskMemory->spiBytesQueued;
uint32_t sleepUsecs = (uint32_t)(usecsUntilSpiQueueEmpty*0.4);
#ifdef STATISTICS
uint64_t t0 = tick();
#endif
if (sleepUsecs > 1000) usleep(500);
#ifdef STATISTICS
uint64_t t1 = tick();
uint32_t bytesInQueueAfter = spiTaskMemory->spiBytesQueued;
bool starved = (spiTaskMemory->queueHead == spiTaskMemory->queueTail);
if (starved) spiThreadWasWorkingHardBefore = false;
/*
if (once && starved)
{
printf("Had %u bytes in queue, asked to sleep for %u usecs, got %u usecs sleep, afterwards %u bytes in queue. (got %.2f%% work done)%s\n",
bytesInQueueBefore, sleepUsecs, (uint32_t)(t1 - t0), bytesInQueueAfter, (bytesInQueueBefore-bytesInQueueAfter)*100.0/bytesInQueueBefore,
starved ? " SLEPT TOO LONG, SPI THREAD STARVED" : "");
once = false;
}
*/
#endif
}
}
int expiredFrames = 0;
uint64_t now = tick();
while(expiredFrames < frameTimeHistorySize && now - frameTimeHistory[expiredFrames].time >= FRAMERATE_HISTORY_LENGTH) ++expiredFrames;
if (expiredFrames > 0)
{
frameTimeHistorySize -= expiredFrames;
for(int i = 0; i < frameTimeHistorySize; ++i) frameTimeHistory[i] = frameTimeHistory[i+expiredFrames];
}
#ifdef STATISTICS
int expiredSkippedFrames = 0;
while(expiredSkippedFrames < frameSkipTimeHistorySize && now - frameSkipTimeHistory[expiredSkippedFrames] >= 1000000/*FRAMERATE_HISTORY_LENGTH*/) ++expiredSkippedFrames;
if (expiredSkippedFrames > 0)
{
frameSkipTimeHistorySize -= expiredSkippedFrames;
for(int i = 0; i < frameSkipTimeHistorySize; ++i) frameSkipTimeHistory[i] = frameSkipTimeHistory[i+expiredSkippedFrames];
}
#endif
int numNewFrames = __atomic_load_n(&numNewGpuFrames, __ATOMIC_SEQ_CST);
bool gotNewFramebuffer = (numNewFrames > 0);
bool framebufferHasNewChangedPixels = true;
uint64_t frameObtainedTime;
if (gotNewFramebuffer)
{
#ifdef USE_GPU_VSYNC
// TODO: Hardcoded vsync interval to 60 for now. Would be better to compute yet another histogram of the vsync arrival times, if vsync is not set to 60hz.
// N.B. copying directly to videoCoreFramebuffer[1] that may be directly accessed by the main thread, so this could
// produce a visible tear between two adjacent frames, but since we don't have vsync anyways, currently not caring too much.
frameObtainedTime = tick();
uint64_t framePollingStartTime = frameObtainedTime;
#if defined(SAVE_BATTERY_BY_PREDICTING_FRAME_ARRIVAL_TIMES) || defined(SAVE_BATTERY_BY_SLEEPING_WHEN_IDLE)
uint64_t nextFrameArrivalTime = PredictNextFrameArrivalTime();
int64_t timeToSleep = nextFrameArrivalTime - tick();
if (timeToSleep > 0)
usleep(timeToSleep);
#endif
framebufferHasNewChangedPixels = SnapshotFramebuffer(framebuffer[0]);
#else
memcpy(framebuffer[0], videoCoreFramebuffer[1], gpuFramebufferSizeBytes);
#endif
PollLowBattery();
#ifdef STATISTICS
uint64_t now = tick();
for(int i = 0; i < numNewFrames - 1 && frameSkipTimeHistorySize < FRAMERATE_HISTORY_LENGTH; ++i)
frameSkipTimeHistory[frameSkipTimeHistorySize++] = now;
#endif
__atomic_fetch_sub(&numNewGpuFrames, numNewFrames, __ATOMIC_SEQ_CST);
DrawStatisticsOverlay(framebuffer[0]);
DrawLowBatteryIcon(framebuffer[0]);
#ifdef USE_GPU_VSYNC
#ifdef STATISTICS
uint64_t completelyUnnecessaryTimeWastedPollingGPUStart = tick();
#endif
// DispmanX PROBLEM! When latching onto the vsync signal, the DispmanX API sends the signal at arbitrary phase with respect to the application actually producing its frames.
// Therefore even while we do get a smooth 16.666.. msec interval vsync signal, we have no idea whether the application has actually produced a new frame at that time. Therefore
// we must keep polling for frames until we find one that it has produced.
#ifdef SELF_SYNCHRONIZE_TO_GPU_VSYNC_PRODUCED_NEW_FRAMES
framebufferHasNewChangedPixels = framebufferHasNewChangedPixels && IsNewFramebuffer(framebuffer[0], framebuffer[1]);
uint64_t timeToGiveUpThereIsNotGoingToBeANewFrame = framePollingStartTime + 1000000/TARGET_FRAME_RATE/2;
while(!framebufferHasNewChangedPixels && tick() < timeToGiveUpThereIsNotGoingToBeANewFrame)
{
usleep(2000);
frameObtainedTime = tick();
framebufferHasNewChangedPixels = SnapshotFramebuffer(framebuffer[0]);
DrawStatisticsOverlay(framebuffer[0]);
DrawLowBatteryIcon(framebuffer[0]);
framebufferHasNewChangedPixels = framebufferHasNewChangedPixels && IsNewFramebuffer(framebuffer[0], framebuffer[1]);
}
#else
framebufferHasNewChangedPixels = true;
#endif
numNewFrames = __atomic_load_n(&numNewGpuFrames, __ATOMIC_SEQ_CST);
__atomic_fetch_sub(&numNewGpuFrames, numNewFrames, __ATOMIC_SEQ_CST);
#ifdef STATISTICS
now = tick();
for(int i = 0; i < numNewFrames - 1 && frameSkipTimeHistorySize < FRAMERATE_HISTORY_LENGTH; ++i)
frameSkipTimeHistory[frameSkipTimeHistorySize++] = now;
uint64_t completelyUnnecessaryTimeWastedPollingGPUStop = tick();
__atomic_fetch_add(&timeWastedPollingGPU, completelyUnnecessaryTimeWastedPollingGPUStop-completelyUnnecessaryTimeWastedPollingGPUStart, __ATOMIC_RELAXED);
#endif
#else // !USE_GPU_VSYNC
if (!displayOff)
RefreshStatisticsOverlayText();
#endif
}
// If too many pixels have changed on screen, drop adaptively to interlaced updating to keep up the frame rate.
double inputDataFps = 1000000.0 / EstimateFrameRateInterval();
double desiredTargetFps = MAX(1, MIN(inputDataFps, TARGET_FRAME_RATE));
#ifdef SINGLE_CORE_BOARD
const double timesliceToUseForScreenUpdates = 250000;
#elif defined(ILI9486) || defined(ILI9486L) ||defined(HX8357D)
const double timesliceToUseForScreenUpdates = 750000;
#else
const double timesliceToUseForScreenUpdates = 1500000;
#endif
const double tooMuchToUpdateUsecs = timesliceToUseForScreenUpdates / desiredTargetFps; // If updating the current and new frame takes too many frames worth of allotted time, drop to interlacing.
#if !defined(NO_INTERLACING) || (defined(BACKLIGHT_CONTROL) && defined(TURN_DISPLAY_OFF_AFTER_USECS_OF_INACTIVITY))
int numChangedPixels = framebufferHasNewChangedPixels ? CountNumChangedPixels(framebuffer[0], framebuffer[1]) : 0;
#endif
#ifdef NO_INTERLACING
interlacedUpdate = false;
#elif defined(ALWAYS_INTERLACING)
interlacedUpdate = (numChangedPixels > 0);
#else
uint32_t bytesToSend = numChangedPixels * SPI_BYTESPERPIXEL + (DISPLAY_DRAWABLE_HEIGHT<<1);
interlacedUpdate = ((bytesToSend + spiTaskMemory->spiBytesQueued) * spiUsecsPerByte > tooMuchToUpdateUsecs); // Decide whether to do interlacedUpdate - only updates half of the screen
#endif
if (interlacedUpdate) frameParity = 1-frameParity; // Swap even-odd fields every second time we do an interlaced update (progressive updates ignore field order)
int bytesTransferred = 0;
Span *head = 0;
#if defined(ALL_TASKS_SHOULD_DMA) && defined(UPDATE_FRAMES_WITHOUT_DIFFING)
NoDiffChangedRectangle(head);
#elif defined(ALL_TASKS_SHOULD_DMA) && defined(UPDATE_FRAMES_IN_SINGLE_RECTANGULAR_DIFF)
DiffFramebuffersToSingleChangedRectangle(framebuffer[0], framebuffer[1], head);
#else
// Collect all spans in this image
if (framebufferHasNewChangedPixels || prevFrameWasInterlacedUpdate)
{
// If possible, utilize a faster 4-wide pixel diffing method
#ifdef FAST_BUT_COARSE_PIXEL_DIFF
if (gpuFrameWidth % 4 == 0 && gpuFramebufferScanlineStrideBytes % 8 == 0)
DiffFramebuffersToScanlineSpansFastAndCoarse4Wide(framebuffer[0], framebuffer[1], interlacedUpdate, frameParity, head);
else
#endif
DiffFramebuffersToScanlineSpansExact(framebuffer[0], framebuffer[1], interlacedUpdate, frameParity, head); // If disabled, or framebuffer width is not compatible, use the exact method
}
// Merge spans together on adjacent scanlines - works only if doing a progressive update
if (!interlacedUpdate)
MergeScanlineSpanList(head);
#endif
#ifdef USE_GPU_VSYNC
if (head) // do we have a new frame?
{
// If using vsync, this main thread is responsible for maintaining the frame histogram. If not using vsync,
// but instead are using a dedicated GPU thread, then that dedicated thread maintains the frame histogram,
// in which case this is not needed.
AddHistogramSample(frameObtainedTime);
// We got a new frame, so update contents of the statistics overlay as well
if (!displayOff)
RefreshStatisticsOverlayText();
}
#endif
// Submit spans
if (!displayOff)
for(Span *i = head; i; i = i->next)
{
#ifdef ALIGN_TASKS_FOR_DMA_TRANSFERS
// DMA transfers smaller than 4 bytes are causing trouble, so in order to ensure smooth DMA operation,
// make sure each message is at least 4 bytes in size, hence one pixel spans are forbidden:
if (i->size == 1)
{
if (i->endX < DISPLAY_DRAWABLE_WIDTH) { ++i->endX; ++i->lastScanEndX; }
else --i->x;
++i->size;
}
#endif
// Update the write cursor if needed
#ifndef DISPLAY_WRITE_PIXELS_CMD_DOES_NOT_RESET_WRITE_CURSOR
if (spiY != i->y)
#endif
{
#if defined(MUST_SEND_FULL_CURSOR_WINDOW) || defined(ALIGN_TASKS_FOR_DMA_TRANSFERS)
QUEUE_SET_WRITE_WINDOW_TASK(DISPLAY_SET_CURSOR_Y, displayYOffset + i->y, displayYOffset + gpuFrameHeight - 1);
#else
QUEUE_MOVE_CURSOR_TASK(DISPLAY_SET_CURSOR_Y, displayYOffset + i->y);
#endif
IN_SINGLE_THREADED_MODE_RUN_TASK();
spiY = i->y;
}
if (i->endY > i->y + 1 && (spiX != i->x || spiEndX != i->endX)) // Multiline span?
{
QUEUE_SET_WRITE_WINDOW_TASK(DISPLAY_SET_CURSOR_X, displayXOffset + i->x, displayXOffset + i->endX - 1);
IN_SINGLE_THREADED_MODE_RUN_TASK();
spiX = i->x;
spiEndX = i->endX;
}
else // Singleline span
{
#ifdef ALIGN_TASKS_FOR_DMA_TRANSFERS
if (spiX != i->x || spiEndX < i->endX)
{
QUEUE_SET_WRITE_WINDOW_TASK(DISPLAY_SET_CURSOR_X, displayXOffset + i->x, displayXOffset + gpuFrameWidth - 1);
IN_SINGLE_THREADED_MODE_RUN_TASK();
spiX = i->x;
spiEndX = gpuFrameWidth;
}
#else
if (spiEndX < i->endX) // Need to push the X end window?
{
// We are doing a single line span and need to increase the X window. If possible,
// peek ahead to cater to the next multiline span update if that will be compatible.
int nextEndX = gpuFrameWidth;
for(Span *j = i->next; j; j = j->next)
if (j->endY > j->y+1)
{
if (j->endX >= i->endX) nextEndX = j->endX;
break;
}
QUEUE_SET_WRITE_WINDOW_TASK(DISPLAY_SET_CURSOR_X, displayXOffset + i->x, displayXOffset + nextEndX - 1);
IN_SINGLE_THREADED_MODE_RUN_TASK();
spiX = i->x;
spiEndX = nextEndX;
}
else
#ifndef DISPLAY_WRITE_PIXELS_CMD_DOES_NOT_RESET_WRITE_CURSOR
if (spiX != i->x)
#endif
{
#ifdef MUST_SEND_FULL_CURSOR_WINDOW
QUEUE_SET_WRITE_WINDOW_TASK(DISPLAY_SET_CURSOR_X, displayXOffset + i->x, displayXOffset + spiEndX - 1);
#else
QUEUE_MOVE_CURSOR_TASK(DISPLAY_SET_CURSOR_X, displayXOffset + i->x);
#endif
IN_SINGLE_THREADED_MODE_RUN_TASK();
spiX = i->x;
}
#endif
}
// Submit the span pixels
SPITask *task = AllocTask(i->size*SPI_BYTESPERPIXEL);
task->cmd = DISPLAY_WRITE_PIXELS;
bytesTransferred += task->PayloadSize()+1;
uint16_t *scanline = framebuffer[0] + i->y * (gpuFramebufferScanlineStrideBytes>>1);
uint16_t *prevScanline = framebuffer[1] + i->y * (gpuFramebufferScanlineStrideBytes>>1);
#ifdef OFFLOAD_PIXEL_COPY_TO_DMA_CPP
// If running a singlethreaded build without a separate SPI thread, we can offload the whole flow of the pixel data out to the code in the dma.cpp backend,
// which does the pixel task handoff out to DMA in inline assembly. This is done mainly to save an extra memcpy() when passing data off from GPU to SPI,
// since in singlethreaded mode, snapshotting GPU and sending data to SPI is done sequentially in this main loop.
// In multithreaded builds, this approach cannot be used, since after we snapshot a frame, we need to send it off to SPI thread to process, and make a copy
// anways to ensure it does not get overwritten.
task->fb = (uint8_t*)(scanline + i->x);
task->prevFb = (uint8_t*)(prevScanline + i->x);
task->width = i->endX - i->x;
#else
uint16_t *data = (uint16_t*)task->data;
for(int y = i->y; y < i->endY; ++y, scanline += gpuFramebufferScanlineStrideBytes>>1, prevScanline += gpuFramebufferScanlineStrideBytes>>1)
{
int endX = (y + 1 == i->endY) ? i->lastScanEndX : i->endX;
int x = i->x;
#ifdef DISPLAY_COLOR_FORMAT_R6X2G6X2B6X2
// Convert from R5G6B5 to R6X2G6X2B6X2 on the fly
while(x < endX)
{
uint16_t pixel = scanline[x++];
uint16_t r = (pixel >> 8) & 0xF8;
uint16_t g = (pixel >> 3) & 0xFC;
uint16_t b = (pixel << 3) & 0xF8;
((uint8_t*)data)[0] = r | (r >> 5); // On red and blue color channels, need to expand 5 bits to 6 bits. Do that by duplicating the highest bit as lowest bit.
((uint8_t*)data)[1] = g;
((uint8_t*)data)[2] = b | (b >> 5);
data = (uint16_t*)((uintptr_t)data + 3);
}
#else
while(x < endX && (x&1)) *data++ = __builtin_bswap16(scanline[x++]);
while(x < (endX&~1U))
{
uint32_t u = *(uint32_t*)(scanline+x);
*(uint32_t*)data = ((u & 0xFF00FF00U) >> 8) | ((u & 0x00FF00FFU) << 8);
data += 2;
x += 2;
}
while(x < endX) *data++ = __builtin_bswap16(scanline[x++]);
#endif
#if !(defined(ALL_TASKS_SHOULD_DMA) && defined(UPDATE_FRAMES_WITHOUT_DIFFING)) // If not diffing, no need to maintain prev frame.
memcpy(prevScanline+i->x, scanline+i->x, (endX - i->x)*FRAMEBUFFER_BYTESPERPIXEL);
#endif
}
#endif
CommitTask(task);
IN_SINGLE_THREADED_MODE_RUN_TASK();
}
#ifdef KERNEL_MODULE_CLIENT
// Wake the kernel module up to run tasks. TODO: This might not be best placed here, we could pre-empt
// to start running tasks already half-way during task submission above.
if (spiTaskMemory->queueHead != spiTaskMemory->queueTail && !(spi->cs & BCM2835_SPI0_CS_TA))
spi->cs |= BCM2835_SPI0_CS_TA;
#endif
// Remember where in the command queue this frame ends, to keep track of the SPI thread's progress over it
if (bytesTransferred > 0)
{
prevFrameEnd = curFrameEnd;
curFrameEnd = spiTaskMemory->queueTail;
}
#if defined(BACKLIGHT_CONTROL) && defined(TURN_DISPLAY_OFF_AFTER_USECS_OF_INACTIVITY)
double percentageOfScreenChanged = (double)numChangedPixels/(DISPLAY_DRAWABLE_WIDTH*DISPLAY_DRAWABLE_HEIGHT);
bool displayIsActive = percentageOfScreenChanged > DISPLAY_CONSIDERED_INACTIVE_PERCENTAGE;
if (displayIsActive)
displayContentsLastChanged = tick();
bool keyboardIsActive = TimeSinceLastKeyboardPress() < TURN_DISPLAY_OFF_AFTER_USECS_OF_INACTIVITY;
if (displayIsActive || keyboardIsActive)
{
if (displayOff)
{
TurnDisplayOn();
displayOff = false;
}
}
else if (!displayOff && tick() - displayContentsLastChanged > TURN_DISPLAY_OFF_AFTER_USECS_OF_INACTIVITY)
{
TurnDisplayOff();
displayOff = true;
}
#endif
#ifdef STATISTICS
if (bytesTransferred > 0)
{
if (frameTimeHistorySize < FRAME_HISTORY_MAX_SIZE)
{
frameTimeHistory[frameTimeHistorySize].interlaced = interlacedUpdate || prevFrameWasInterlacedUpdate;
frameTimeHistory[frameTimeHistorySize++].time = tick();
}
AddFrameCompletionTimeMarker();
}
statsBytesTransferred += bytesTransferred;
#endif
}
DeinitGPU();
DeinitSPI();
CloseMailbox();
CloseKeyboard();
printf("Quit.\n");
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 922 KiB

View File

@ -1,24 +0,0 @@
#pragma once
// Data specific to the Waveshare32b display, as present on FreePlayTech's CM3/Zero devices (https://www.freeplaytech.com/)
#ifdef FREEPLAYTECH_WAVESHARE32B
#if !defined(GPIO_TFT_DATA_CONTROL)
#define GPIO_TFT_DATA_CONTROL 22
#endif
#if !defined(GPIO_TFT_RESET_PIN)
#define GPIO_TFT_RESET_PIN 27
#endif
// On FreePlayTech GBA devices, a part of the screen is hidden by the bezels, since the GBA has a 2.8" screen surface area, but a 3.2" display is enclosed inside the case.
// The hidden area is placed under the left edge of the display horizontally, and under top and bottom edges of the display vertically, so reduce those out from the drawable area.
// Effective display area is then 320-18=302 pixels horizontally, and 202 pixels vertically (in landscape direction).
// The meaning of top/left/right/bottom here should be interpreted as the display being oriented in its native direction (which is portrait mode for ILI9341, 240x320 direction).
#define DISPLAY_NATIVE_COVERED_TOP_SIDE 18
#define DISPLAY_NATIVE_COVERED_LEFT_SIDE 9
#define DISPLAY_NATIVE_COVERED_RIGHT_SIDE 29
#define DISPLAY_NATIVE_COVERED_BOTTOM_SIDE 0
#endif

Some files were not shown because too many files have changed in this diff Show More