├── .gitignore ├── README.md ├── dist ├── hyperpixel2r-init ├── hyperpixel2r-init.service └── hyperpixel2r-rotate ├── hyperpixel-wallpaper.jpg ├── install.sh ├── src ├── Makefile ├── README.md └── hyperpixel2r-overlay.dts └── uninstall.sh /.gitignore: -------------------------------------------------------------------------------- 1 | dist/*.dtbo 2 | src/*.dtbo 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # HyperPixel 2.0" Round Drivers for Raspberry Pi 4 2 | 3 | HyperPixel 2.0r is an 480x480 pixel display for the Raspberry Pi, with optional capacitive touchscreen. 4 | 5 | These drivers are for the Raspberry Pi 4 specifically, and include new tools to take advantage of the "Screen Configuration" (xrandr) support that Pi 4's 3D accelerated desktop enables. 6 | 7 | ## Installing / Uninstalling 8 | 9 | First, clone this GitHub repository branch to your Pi: 10 | 11 | ``` 12 | git clone https://github.com/pimoroni/hyperpixel2r 13 | ``` 14 | 15 | Then run the installer to install: 16 | 17 | ``` 18 | cd hyperpixel2r 19 | sudo ./install.sh 20 | ``` 21 | 22 | ## Rotation 23 | 24 | To keep your touchscreen rotated with the display, you should rotate HyperPixel2r using the `hyperpixel2r-rotate` command rather than "Screen Configuration." 25 | 26 | This command will update your touch settings and screen configuration settings to match, and you can rotate between four modes: left, right, normal, inverted. 27 | 28 | * left - landscape, power/HDMI on bottom 29 | * right - landscape, power/HDMI on top 30 | * normal - portrait, USB ports on top 31 | * inverted - portrait, USB ports on bottom 32 | 33 | If you want to change the position of your HyperPixel2r in a multi-display setup, you can use "Screen Configuration" as normal. 34 | 35 | ## Touch rotation 36 | 37 | Touch is only supported via the Python library - https://github.com/pimoroni/hyperpixel2r-python 38 | -------------------------------------------------------------------------------- /dist/hyperpixel2r-init: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # For some reason this script needs to be run twice - needs some debugging... 4 | 5 | 6 | # Backlight on BCM19: 7 | # gpio write 24 0 8 | # gpio write 24 1 9 | 10 | # config.txt: 11 | 12 | # dtoverlay=hyperpixel4 13 | # overscan_left=0 14 | # overscan_right=0 15 | # overscan_top=0 16 | # overscan_bottom=0 17 | # enable_dpi_lcd=1 18 | # display_default_lcd=1 19 | # display_rotate=0 20 | # dpi_group=2 21 | # dpi_mode=87 22 | # dpi_output_format=0x7f216 23 | 24 | # hdmi_timings=480 0 10 16 55 480 0 15 60 15 0 0 0 60 0 19200000 6 25 | 26 | import RPi.GPIO as GPIO 27 | import time 28 | 29 | 30 | CLK = 11 31 | MOSI = 10 32 | CS = 18 33 | DELAY = 0.00001 34 | 35 | 36 | def setupSpiPins(clkPin, mosiPin, csPin): 37 | GPIO.setmode(GPIO.BCM) 38 | GPIO.setwarnings(False) 39 | GPIO.setup(clkPin, GPIO.OUT) 40 | GPIO.output(clkPin, GPIO.LOW) 41 | GPIO.setup(mosiPin, GPIO.OUT) 42 | GPIO.setup(csPin, GPIO.OUT, initial=GPIO.HIGH) 43 | 44 | 45 | def sendBits(data, numBits=8, csPin=CS, clkPin=CLK, mosiPin=MOSI): 46 | # print("{:09b}".format(data)) 47 | data <<= (9 - numBits) 48 | 49 | for bit in range(numBits): 50 | # Set RPi's output bit high or low depending on highest bit of data field 51 | GPIO.output(mosiPin, GPIO.HIGH if data & 0x100 else GPIO.LOW) 52 | 53 | # Advance data to the next bit 54 | data <<= 1 55 | 56 | # Pulse the clock pin HIGH then immediately low 57 | time.sleep(DELAY) 58 | GPIO.output(clkPin, GPIO.HIGH) 59 | time.sleep(DELAY) 60 | GPIO.output(clkPin, GPIO.LOW) 61 | 62 | GPIO.output(mosiPin, GPIO.LOW) # 00 is NOP, so set data pin low to make sure read operations don't cause weirdness 63 | 64 | 65 | def SPI_Write(output): 66 | sendBits(output, 9, CS, CLK, MOSI) 67 | 68 | 69 | def SPI_WriteComm(b): 70 | SPI_Write(b) 71 | 72 | 73 | def SPI_WriteData(b): 74 | SPI_Write(b | 0x100) 75 | 76 | 77 | def Delay(ms): 78 | time.sleep(ms / 1000.0) 79 | 80 | # BCM 2 = vsync, sync spike high 81 | # BCM 3 = hsync, sync spike high 82 | # BCM 0 = DPI clock 83 | # BCM 1 = display enable, enabled when high 84 | 85 | 86 | # DPI_OUTPUT_FORMAT = 0x6f016 87 | # 6 = DPI_OUTPUT_FORMAT_18BIT_666_CFG2 88 | # 1 = DPI_RGB_ORDER_RGB 89 | # 0 = output_enable_mode, invert_pixel_clock are default 90 | # f = hsync_disable, vsync_disable, output_enable_disable are all 1??? 91 | # 6 = hsync_polarity=0, vsync_polarity=1, output_enable_polarity=1 92 | 93 | # 7 = hsync_polarity=1, vsync_polarity=1, output_enable_polarity=1 94 | 95 | # R2 = BCM 20 = gpio mode 28 down 96 | # R3 = BCM 21 = wpi 29 97 | # R4 = BCM 22 = wpi 3 98 | # R5 = BCM 23 = wpi 4 99 | # R6 = BCM 24 = wpi 5 100 | # R7 = BCM 25 = wpi 6 101 | 102 | 103 | def setup_hp2_round(CLK, MOSI, CS): 104 | # #****************************************************************************// 105 | # #****************************** Page 1 Command ******************************// 106 | # #****************************************************************************// 107 | GPIO.output(CS, GPIO.LOW) 108 | 109 | # ST7701S: 110 | # HW_Reset() # VBP>=11, VFP>=7 111 | 112 | SPI_WriteComm(0x01) # Niko added reset 113 | 114 | Delay(240) 115 | 116 | SPI_WriteComm(0xFF) 117 | SPI_WriteData(0x77) 118 | SPI_WriteData(0x01) 119 | SPI_WriteData(0x00) 120 | SPI_WriteData(0x00) 121 | SPI_WriteData(0x10) 122 | 123 | SPI_WriteComm(0xC0) 124 | SPI_WriteData(0x3B) # Scan line 125 | SPI_WriteData(0x00) 126 | 127 | SPI_WriteComm(0xC1) 128 | SPI_WriteData(0x0B) # VBP 129 | SPI_WriteData(0x02) 130 | 131 | SPI_WriteComm(0xC2) 132 | SPI_WriteData(0x00) # 07 OR 00 133 | SPI_WriteData(0x02) 134 | 135 | SPI_WriteComm(0xCC) 136 | SPI_WriteData(0x10) 137 | 138 | # Gamma option A: 139 | # SPI_WriteComm(0xB0) # IPS 140 | # SPI_WriteData(0x00) # 255 141 | # SPI_WriteData(0x11) # 251 142 | # SPI_WriteData(0x16) # 247 down 143 | # SPI_WriteData(0x0e) # 239 144 | # SPI_WriteData(0x11) # 231 145 | # SPI_WriteData(0x06) # 203 146 | # SPI_WriteData(0x05) # 175 147 | # SPI_WriteData(0x09) # 147 148 | # SPI_WriteData(0x08) # 108 149 | # SPI_WriteData(0x21) # 80 150 | # SPI_WriteData(0x06) # 52 151 | # SPI_WriteData(0x13) # 24 152 | # SPI_WriteData(0x10) # 16 153 | # SPI_WriteData(0x29) # 8 down 154 | # SPI_WriteData(0x31) # 4 155 | # SPI_WriteData(0x18) # 0 156 | 157 | # SPI_WriteComm(0xB1)# IPS 158 | # SPI_WriteData(0x00)# 255 159 | # SPI_WriteData(0x11)# 251 160 | # SPI_WriteData(0x16)# 247 down 161 | # SPI_WriteData(0x0e)# 239 162 | # SPI_WriteData(0x11)# 231 163 | # SPI_WriteData(0x07)# 203 164 | # SPI_WriteData(0x05)# 175 165 | # SPI_WriteData(0x09)# 147 166 | # SPI_WriteData(0x09)# 108 167 | # SPI_WriteData(0x21)# 80 168 | # SPI_WriteData(0x05)# 52 169 | # SPI_WriteData(0x13)# 24 170 | # SPI_WriteData(0x11)# 16 171 | # SPI_WriteData(0x2a)# 8 down 172 | # SPI_WriteData(0x31)# 4 173 | # SPI_WriteData(0x18)# 0 174 | 175 | # Gamma option B: 176 | SPI_WriteComm(0xB0) # Positive Voltage Gamma Control 177 | SPI_WriteData(0x02) 178 | SPI_WriteData(0x13) 179 | SPI_WriteData(0x1B) 180 | SPI_WriteData(0x0D) 181 | SPI_WriteData(0x10) 182 | SPI_WriteData(0x05) 183 | SPI_WriteData(0x08) 184 | SPI_WriteData(0x07) 185 | SPI_WriteData(0x07) 186 | SPI_WriteData(0x24) 187 | SPI_WriteData(0x04) 188 | SPI_WriteData(0x11) 189 | SPI_WriteData(0x0E) 190 | SPI_WriteData(0x2C) 191 | SPI_WriteData(0x33) 192 | SPI_WriteData(0x1D) 193 | 194 | SPI_WriteComm(0xB1) # Negative Voltage Gamma Control 195 | SPI_WriteData(0x05) 196 | SPI_WriteData(0x13) 197 | SPI_WriteData(0x1B) 198 | SPI_WriteData(0x0D) 199 | SPI_WriteData(0x11) 200 | SPI_WriteData(0x05) 201 | SPI_WriteData(0x08) 202 | SPI_WriteData(0x07) 203 | SPI_WriteData(0x07) 204 | SPI_WriteData(0x24) 205 | SPI_WriteData(0x04) 206 | SPI_WriteData(0x11) 207 | SPI_WriteData(0x0E) 208 | SPI_WriteData(0x2C) 209 | SPI_WriteData(0x33) 210 | SPI_WriteData(0x1D) 211 | 212 | SPI_WriteComm(0xFF) 213 | SPI_WriteData(0x77) 214 | SPI_WriteData(0x01) 215 | SPI_WriteData(0x00) 216 | SPI_WriteData(0x00) 217 | SPI_WriteData(0x11) 218 | 219 | SPI_WriteComm(0xB0) # VOP 3.5375+ *x 0.0125 220 | SPI_WriteData(0x5D) # 6D OR 5D 221 | 222 | SPI_WriteComm(0xB1) # VCOM amplitude setting 223 | SPI_WriteData(0x43) # 37 OR 43 224 | 225 | SPI_WriteComm(0xB2) # VGH Voltage setting 226 | SPI_WriteData(0x81) # 12V 227 | 228 | SPI_WriteComm(0xB3) 229 | SPI_WriteData(0x80) 230 | 231 | SPI_WriteComm(0xB5) # VGL Voltage setting 232 | SPI_WriteData(0x43) # -8.3V 233 | 234 | SPI_WriteComm(0xB7) 235 | SPI_WriteData(0x85) 236 | 237 | SPI_WriteComm(0xB8) 238 | SPI_WriteData(0x20) 239 | 240 | SPI_WriteComm(0xC1) 241 | SPI_WriteData(0x78) 242 | 243 | SPI_WriteComm(0xC2) 244 | SPI_WriteData(0x78) 245 | 246 | SPI_WriteComm(0xD0) 247 | SPI_WriteData(0x88) 248 | 249 | SPI_WriteComm(0xE0) 250 | SPI_WriteData(0x00) 251 | SPI_WriteData(0x00) 252 | SPI_WriteData(0x02) 253 | 254 | SPI_WriteComm(0xE1) 255 | SPI_WriteData(0x03) 256 | SPI_WriteData(0xA0) 257 | SPI_WriteData(0x00) 258 | SPI_WriteData(0x00) 259 | SPI_WriteData(0x04) 260 | SPI_WriteData(0xA0) 261 | SPI_WriteData(0x00) 262 | SPI_WriteData(0x00) 263 | SPI_WriteData(0x00) 264 | SPI_WriteData(0x20) 265 | SPI_WriteData(0x20) 266 | 267 | SPI_WriteComm(0xE2) 268 | SPI_WriteData(0x00) 269 | SPI_WriteData(0x00) 270 | SPI_WriteData(0x00) 271 | SPI_WriteData(0x00) 272 | SPI_WriteData(0x00) 273 | SPI_WriteData(0x00) 274 | SPI_WriteData(0x00) 275 | SPI_WriteData(0x00) 276 | SPI_WriteData(0x00) 277 | SPI_WriteData(0x00) 278 | SPI_WriteData(0x00) 279 | SPI_WriteData(0x00) 280 | SPI_WriteData(0x00) 281 | 282 | SPI_WriteComm(0xE3) 283 | SPI_WriteData(0x00) 284 | SPI_WriteData(0x00) 285 | SPI_WriteData(0x11) 286 | SPI_WriteData(0x00) 287 | 288 | SPI_WriteComm(0xE4) 289 | SPI_WriteData(0x22) 290 | SPI_WriteData(0x00) 291 | 292 | SPI_WriteComm(0xE5) 293 | SPI_WriteData(0x05) 294 | SPI_WriteData(0xEC) 295 | SPI_WriteData(0xA0) 296 | SPI_WriteData(0xA0) 297 | SPI_WriteData(0x07) 298 | SPI_WriteData(0xEE) 299 | SPI_WriteData(0xA0) 300 | SPI_WriteData(0xA0) 301 | SPI_WriteData(0x00) 302 | SPI_WriteData(0x00) 303 | SPI_WriteData(0x00) 304 | SPI_WriteData(0x00) 305 | SPI_WriteData(0x00) 306 | SPI_WriteData(0x00) 307 | SPI_WriteData(0x00) 308 | SPI_WriteData(0x00) 309 | 310 | SPI_WriteComm(0xE6) 311 | SPI_WriteData(0x00) 312 | SPI_WriteData(0x00) 313 | SPI_WriteData(0x11) 314 | SPI_WriteData(0x00) 315 | 316 | SPI_WriteComm(0xE7) 317 | SPI_WriteData(0x22) 318 | SPI_WriteData(0x00) 319 | 320 | SPI_WriteComm(0xE8) 321 | SPI_WriteData(0x06) 322 | SPI_WriteData(0xED) 323 | SPI_WriteData(0xA0) 324 | SPI_WriteData(0xA0) 325 | SPI_WriteData(0x08) 326 | SPI_WriteData(0xEF) 327 | SPI_WriteData(0xA0) 328 | SPI_WriteData(0xA0) 329 | SPI_WriteData(0x00) 330 | SPI_WriteData(0x00) 331 | SPI_WriteData(0x00) 332 | SPI_WriteData(0x00) 333 | SPI_WriteData(0x00) 334 | SPI_WriteData(0x00) 335 | SPI_WriteData(0x00) 336 | SPI_WriteData(0x00) 337 | 338 | SPI_WriteComm(0xEB) 339 | SPI_WriteData(0x00) 340 | SPI_WriteData(0x00) 341 | SPI_WriteData(0x40) 342 | SPI_WriteData(0x40) 343 | SPI_WriteData(0x00) 344 | SPI_WriteData(0x00) 345 | SPI_WriteData(0x00) 346 | 347 | SPI_WriteComm(0xED) 348 | SPI_WriteData(0xFF) 349 | SPI_WriteData(0xFF) 350 | SPI_WriteData(0xFF) 351 | SPI_WriteData(0xBA) 352 | SPI_WriteData(0x0A) 353 | SPI_WriteData(0xBF) 354 | SPI_WriteData(0x45) 355 | SPI_WriteData(0xFF) 356 | SPI_WriteData(0xFF) 357 | SPI_WriteData(0x54) 358 | SPI_WriteData(0xFB) 359 | SPI_WriteData(0xA0) 360 | SPI_WriteData(0xAB) 361 | SPI_WriteData(0xFF) 362 | SPI_WriteData(0xFF) 363 | SPI_WriteData(0xFF) 364 | 365 | SPI_WriteComm(0xEF) 366 | SPI_WriteData(0x10) 367 | SPI_WriteData(0x0D) 368 | SPI_WriteData(0x04) 369 | SPI_WriteData(0x08) 370 | SPI_WriteData(0x3F) 371 | SPI_WriteData(0x1F) 372 | 373 | SPI_WriteComm(0xFF) 374 | SPI_WriteData(0x77) 375 | SPI_WriteData(0x01) 376 | SPI_WriteData(0x00) 377 | SPI_WriteData(0x00) 378 | SPI_WriteData(0x13) 379 | 380 | SPI_WriteComm(0xEF) 381 | SPI_WriteData(0x08) 382 | 383 | SPI_WriteComm(0xFF) 384 | SPI_WriteData(0x77) 385 | SPI_WriteData(0x01) 386 | SPI_WriteData(0x00) 387 | SPI_WriteData(0x00) 388 | SPI_WriteData(0x00) 389 | 390 | SPI_WriteComm(0xCD) # RGB format COLCTRL 391 | SPI_WriteData(0x08) 392 | # SPI_WriteData(0x00) 393 | 394 | SPI_WriteComm(0x36) # MadCtl 395 | SPI_WriteData(0x08) 396 | 397 | SPI_WriteComm(0x3A) # Colmod 398 | SPI_WriteData(0x66) 399 | 400 | SPI_WriteComm(0x11) 401 | Delay(120) 402 | 403 | SPI_WriteComm(0x29) 404 | Delay(20) 405 | 406 | GPIO.output(CS, GPIO.HIGH) 407 | 408 | 409 | if __name__ == '__main__': 410 | setupSpiPins(CLK, MOSI, CS) 411 | 412 | setup_hp2_round(CLK, MOSI, CS) 413 | -------------------------------------------------------------------------------- /dist/hyperpixel2r-init.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=HyperPixel 2.0" Round LCD Display Initialization 3 | DefaultDependencies=no 4 | After=basic.target 5 | 6 | [Service] 7 | Type=oneshot 8 | ExecStart=/usr/bin/hyperpixel2r-init 9 | 10 | [Install] 11 | WantedBy=multi-user.target 12 | -------------------------------------------------------------------------------- /dist/hyperpixel2r-rotate: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | UTILITY="hyperpixel2r-rotate (Round)" 4 | ORIENTATION=$1 5 | DO_XORG=$2 6 | DEVICE="generic ft5x06 (00)" 7 | UDEV_FILE="/etc/udev/rules.d/98-hyperpixel2r-calibration.rules" 8 | DISP_FILE="/usr/share/dispsetup.sh" 9 | XORG_TOUCH_CONF_FILE="/usr/share/X11/xorg.conf.d/88-hyperpixel2r-touch.conf" 10 | XORG_CONF_FILE="/usr/share/X11/xorg.conf.d/88-dsi-1-rotate.conf" 11 | LIGHTDM_CONF_FILE="/etc/lightdm/lightdm.conf" 12 | XHOST_AUTH_DISABLED=false 13 | 14 | function success() { 15 | echo -e "$(tput setaf 2)$1$(tput sgr0)" 16 | } 17 | 18 | function inform() { 19 | echo -e "$(tput setaf 6)$1$(tput sgr0)" 20 | } 21 | 22 | function warning() { 23 | echo -e "$(tput setaf 1)$1$(tput sgr0)" 24 | } 25 | 26 | function compatibility_check { 27 | grep -e "^dtoverlay=vc4-.*kms-v3d.*" /boot/config.txt > /dev/null 28 | if [ $? -ne 0 ]; then 29 | warning "Rotation requires hardware support on the Pi 4 or Pi 400" 30 | warning "Ensure \"dtoverlay=vc4-fkms-v3d\" is enabled in /boot/config.txt" 31 | exit 1 32 | fi 33 | } 34 | 35 | function set_xorg_conf { 36 | inform "Rotating display $1"; 37 | xrandr --output DSI-1 --rotate $1 38 | 39 | inform "Setting libinput Calibration Matrix: 1 0 0 0 1 0"; 40 | xinput set-prop "pointer:$DEVICE" "libinput Calibration Matrix" 1 0 0 0 1 0 0 0 1 41 | 42 | inform "Setting Coordinate Transformation Matrix: $2 $3 $4 $5 $6 $7"; 43 | xinput set-prop "pointer:$DEVICE" "Coordinate Transformation Matrix" $2 $3 $4 $5 $6 $7 0 0 1 44 | 45 | inform "Saving xorg touch config to $XORG_TOUCH_CONF_FILE"; 46 | sudo tee $XORG_TOUCH_CONF_FILE > /dev/null < /dev/null < /dev/null 68 | if [ $? -eq 0 ]; then 69 | warning "You might want to comment-out \"display-setup-script\" from $LIGHTDM_CONF_FILE\n" 70 | fi 71 | } 72 | 73 | function set_matrix { 74 | inform "Setting touch transform matrix: $1 $2 $3 $4 $5 $6"; 75 | xinput set-prop "pointer:$DEVICE" "libinput Calibration Matrix" $1 $2 $3 $4 $5 $6 0 0 1 76 | 77 | inform "Saving touch settings to $UDEV_FILE"; 78 | echo "ATTRS{name}==\"$DEVICE\", ENV{LIBINPUT_CALIBRATION_MATRIX}=\"$1 $2 $3 $4 $5 $6\"" | sudo tee $UDEV_FILE > /dev/null 79 | # Square only? 80 | # echo "ATTRS{name}==\"EP0110M09\", ENV{LIBINPUT_CALIBRATION_MATRIX}=\"$1 $2 $3 $4 $5 $6\"" | sudo tee -a $UDEV_FILE > /dev/null 81 | } 82 | 83 | function xhost_auth { 84 | if [ "$1" == "disable" ]; then 85 | xhost | grep disabled > /dev/null 86 | if [ $? -ne 0 ]; then 87 | xhost + > /dev/null 88 | warning "Disabling xhost access control..." 89 | XHOST_AUTH_DISABLED=true 90 | fi 91 | fi 92 | if [ "$1" == "enable" ] && [ "$XHOST_AUTH_DISABLED" = true ]; then 93 | xhost - > /dev/null 94 | warning "Re-enabling xhost access control..." 95 | fi 96 | } 97 | 98 | function set_display { 99 | xhost_auth "disable" 100 | inform "Rotating display $1"; 101 | xrandr --output DSI-1 --rotate $1 102 | 103 | grep -e "^display-setup-script=$DISP_FILE*" $LIGHTDM_CONF_FILE > /dev/null 104 | if [ $? -ne 0 ]; then 105 | warning "The display setup script is not configured in $LIGHTDM_CONF_FILE so your saved settings *will not be restored upon reboot*" 106 | warning "Maybe you're not using Raspberry Pi OS/lightdm?" 107 | warning "Add \"display-setup-script=$DISP_FILE\" to $LIGHTDM_CONF_FILE or use the Xorg config method (add --xorg to this command)\n" 108 | fi 109 | 110 | inform "Saving display settings to $DISP_FILE"; 111 | sudo chown `whoami` $DISP_FILE 112 | python2 - < /dev/null || grep -q okay /proc/device-tree/soc/firmwarekms@7e600000/status 2> /dev/null ; then", 121 | "if %(xrandr)s --dryrun ; then", 122 | "%(xrandr)s", 123 | "fi", 124 | "fi", 125 | "exit 0"] 126 | 127 | x = xrandr.XRandR() 128 | x.load_from_x() 129 | data = x.save_to_shellscript_string(template=template) 130 | open(file, 'w').write(data) 131 | os.chmod(file, stat.S_IRWXU) 132 | EOF 133 | STATUS=$? 134 | sudo chown root $DISP_FILE 135 | sudo chmod 755 $DISP_FILE 136 | if [ $STATUS -eq 1 ]; then 137 | warning "Failed to persist display orientation." 138 | warning "Make sure you're running Rasperry Pi OS desktop on a Pi 4 or Pi 400" 139 | xhost_auth "enable" 140 | exit 1 141 | fi 142 | 143 | if [ -f $XORG_CONF_FILE ]; then 144 | warning "There may be conflicting config in $XORG_CONF_FILE" 145 | warning "You might want to remove this file!" 146 | fi 147 | 148 | if [ -f $XORG_TOUCH_CONF_FILE ]; then 149 | warning "There may be conflicting config in $XORG_TOUCH_CONF_FILE" 150 | warning "You might want to remove this file!" 151 | fi 152 | 153 | xhost_auth "enable" 154 | } 155 | 156 | printf "HyperPixel 4: Square - Display/Touch Rotation\n" 157 | printf "This rotate utility only works with the Raspberry Pi OS desktop version or X-based alternatives.\n\n" 158 | 159 | compatibility_check 160 | 161 | if [ "$DISPLAY" == "" ]; then 162 | warning "No DISPLAY variable set, trying :0.0" 163 | export DISPLAY=:0.0 164 | fi 165 | 166 | if [ "$ORIENTATION" == "right" ]; then 167 | if [ "$DO_XORG" == "--xorg" ]; then 168 | set_xorg_conf $ORIENTATION 0 1 0 -1 0 1 169 | else 170 | set_display $ORIENTATION 171 | set_matrix 0 1 0 -1 0 1 172 | fi 173 | exit 0 174 | fi 175 | 176 | if [ "$ORIENTATION" == "left" ]; then 177 | if [ "$DO_XORG" == "--xorg" ]; then 178 | set_xorg_conf $ORIENTATION 0 -1 1 1 0 0 179 | else 180 | set_display $ORIENTATION 181 | set_matrix 0 -1 1 1 0 0 182 | fi 183 | exit 0 184 | fi 185 | 186 | if [ "$ORIENTATION" == "inverted" ]; then 187 | if [ "$DO_XORG" == "--xorg" ]; then 188 | set_xorg_conf $ORIENTATION -1 0 1 0 -1 1 189 | else 190 | set_display $ORIENTATION 191 | set_matrix -1 0 1 0 -1 1 192 | fi 193 | exit 0 194 | fi 195 | 196 | if [ "$ORIENTATION" == "normal" ]; then 197 | if [ "$DO_XORG" == "--xorg" ]; then 198 | set_xorg_conf $ORIENTATION 1 0 0 0 1 0 199 | else 200 | set_display $ORIENTATION 201 | set_matrix 1 0 0 0 1 0 202 | fi 203 | exit 0 204 | fi 205 | 206 | printf "Unsupported orientation: $ORIENTATION\n"; 207 | printf "Try one of: left, right, normal, inverted\n"; 208 | -------------------------------------------------------------------------------- /hyperpixel-wallpaper.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pimoroni/hyperpixel2r/2af6cafbdaf4a8e44509ae45517a373f488adc02/hyperpixel-wallpaper.jpg -------------------------------------------------------------------------------- /install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | SERVICE_NAME="hyperpixel2r-init.service" 4 | SERVICE_PATH="/etc/systemd/system" 5 | BINARY_NAME="hyperpixel2r-init" 6 | ROTATE_NAME="hyperpixel2r-rotate" 7 | BINARY_PATH="/usr/bin" 8 | OVERLAY_PATH="/boot/overlays" 9 | OVERLAY_NAME="hyperpixel2r.dtbo" 10 | OVERLAY_SRC="hyperpixel2r-overlay.dts" 11 | 12 | CONFIG="/boot/config.txt" 13 | 14 | CONFIG_LINES=( 15 | "dtoverlay=hyperpixel2r" 16 | "enable_dpi_lcd=1" 17 | "dpi_group=2" 18 | "dpi_mode=87" 19 | "dpi_output_format=0x7f216" 20 | "dpi_timings=480 0 10 16 55 480 0 15 60 15 0 0 0 60 0 19200000 6" 21 | ) 22 | 23 | if [ $(id -u) -ne 0 ]; then 24 | printf "Script must be run as root. Try 'sudo ./install.sh'\n" 25 | exit 1 26 | fi 27 | 28 | if [ ! -f "dist/$OVERLAY_NAME" ]; then 29 | if [ ! -f "/usr/bin/dtc" ]; then 30 | printf "This script requires device-tree-compiler, please \"sudo apt install device-tree-compiler\"\n"; 31 | exit 1 32 | fi 33 | printf "Notice: building $OVERLAY_NAME\n"; 34 | dtc -@ -I dts -O dtb -o dist/$OVERLAY_NAME src/$OVERLAY_SRC > /dev/null 2>&1 35 | fi 36 | 37 | cp dist/$ROTATE_NAME $BINARY_PATH 38 | 39 | if [ -d "$SERVICE_PATH" ]; then 40 | cp dist/$BINARY_NAME $BINARY_PATH 41 | cp dist/$SERVICE_NAME $SERVICE_PATH 42 | systemctl daemon-reload 43 | systemctl enable $SERVICE_NAME 44 | systemctl start $SERVICE_NAME 45 | printf "Installed: $BINARY_PATH/$BINARY_NAME\n" 46 | printf "Installed: $SERVICE_PATH/$SERVICE_NAME\n" 47 | else 48 | printf "Warning: cannot find $SERVICE_PATH for $SERVICE_NAME\n" 49 | fi 50 | 51 | if [ -d "$OVERLAY_PATH" ]; then 52 | cp dist/$OVERLAY_NAME $OVERLAY_PATH 53 | printf "Installed: $OVERLAY_PATH/$OVERLAY_NAME\n" 54 | else 55 | printf "Warning: unable to copy $OVERLAY_NAME to $OVERLAY_PATH\n" 56 | fi 57 | 58 | if [ -f "$CONFIG" ]; then 59 | NEWLINE=0 60 | for ((i = 0; i < ${#CONFIG_LINES[@]}; i++)); do 61 | CONFIG_LINE="${CONFIG_LINES[$i]}" 62 | grep -e "^#$CONFIG_LINE" $CONFIG > /dev/null 63 | STATUS=$? 64 | if [ $STATUS -eq 1 ]; then 65 | grep -e "^$CONFIG_LINE" $CONFIG > /dev/null 66 | STATUS=$? 67 | if [ $STATUS -eq 1 ]; then 68 | # Line is missing from config file 69 | if [ ! $NEWLINE -eq 1 ]; then 70 | # Add newline if this is the first new entry 71 | echo "" >> $CONFIG 72 | NEWLINE=1 73 | fi 74 | # Add the config line 75 | echo "$CONFIG_LINE" >> $CONFIG 76 | printf "Config: Added $CONFIG_LINE to $CONFIG\n" 77 | else 78 | printf "Skipped: $CONFIG_LINE already exists in $CONFIG\n" 79 | fi 80 | else 81 | sed $CONFIG -i -e "s/^#$CONFIG_LINE/$CONFIG_LINE/" 82 | printf "Config: Uncommented $CONFIG_LINE in $CONFIG\n" 83 | fi 84 | done 85 | else 86 | printf "Warning: unable to find $CONFIG, is /boot not mounted?\n" 87 | printf "Please add $OVERLAY_CONFIG to your config.txt\n" 88 | fi 89 | 90 | printf "\nAfter rebooting, use 'hyperpixel2r-rotate left/right/normal/inverted' to rotate your display!\n\n" 91 | printf " left - Landscape, power/HDMI on bottom\n" 92 | printf " right - Landscape, power/HDMI on top\n" 93 | printf " normal - Portrait, USB ports on top\n" 94 | printf " inverted - Portrait, USB ports on bottom\n\n" 95 | -------------------------------------------------------------------------------- /src/Makefile: -------------------------------------------------------------------------------- 1 | build: 2 | dtc -I dts -O dtb -Wno-unit_address_vs_reg -o hyperpixel2r.dtbo hyperpixel2r-overlay.dts 3 | 4 | install: 5 | cp hyperpixel2r.dtbo /boot/overlays/ 6 | 7 | test: 8 | dtoverlay hyperpixel2r.dtbo 9 | 10 | remove: 11 | dtoverlay -r hyperpixel2r 12 | -------------------------------------------------------------------------------- /src/README.md: -------------------------------------------------------------------------------- 1 | # HyperPixel 4.0" Drivers 2 | 3 | ## hyperpixel4-init.c 4 | 5 | Source for the hyperpixel4-init binary. 6 | 7 | It's designed to be statically linked against bcm2835 and runs all of the init routine required for HyperPixel 4.0" 8 | 9 | ## hyperpixel4.dts 10 | 11 | Source for hyperpixel4.dtbo device-tree overlay. 12 | 13 | This overlay sets up: 14 | 15 | * GPIO backlight (on/off) functionality 16 | * Goodix multitouch digitiser 17 | -------------------------------------------------------------------------------- /src/hyperpixel2r-overlay.dts: -------------------------------------------------------------------------------- 1 | /dts-v1/; 2 | /plugin/; 3 | / { 4 | compatible = "brcm,bcm2835"; 5 | 6 | fragment@0 { 7 | target = <&gpio>; 8 | __overlay__ { 9 | dpi18_pins: dpi18_pins { 10 | brcm,pins = <0 1 2 3 4 5 6 7 8 9 12 13 14 15 16 17 20 21 22 23 24 25>; 11 | brcm,function = <0x6>; 12 | brcm,pull = <0x0>; 13 | }; 14 | }; 15 | }; 16 | fragment@1 { 17 | target-path = "/"; 18 | __overlay__ { 19 | rpi_backlight: rpi_backlight { 20 | compatible = "gpio-backlight"; 21 | gpios = <&gpio 19 0>; 22 | default-on; 23 | pinctrl-names = "default"; 24 | pinctrl-0 = <&dpi18_pins>; 25 | }; 26 | }; 27 | }; 28 | fragment@3 { 29 | target-path = "/"; 30 | __overlay__ { 31 | i2c_gpio: i2c@0 { 32 | compatible = "i2c-gpio"; 33 | gpios = <&gpio 10 0 34 | &gpio 11 0 35 | >; 36 | i2c-gpio,delay-us = <4>; 37 | #address-cells = <1>; 38 | #size-cells = <0>; 39 | }; 40 | }; 41 | }; 42 | fragment@4 { 43 | target = <&i2c_gpio>; 44 | __overlay__ { 45 | #address-cells = <1>; 46 | #size-cells = <0>; 47 | touch: edt-ft5x06@15 { 48 | compatible = "edt,edt-ft5x06"; 49 | reg = <0x15>; 50 | interrupt-parent = <&gpio>; 51 | interrupts = <27 2>; 52 | touchscreen-size-x = <480>; 53 | touchscreen-size-y = <480>; 54 | touchscreen-x-mm = <50>; 55 | touchscreen-y-mm = <50>; 56 | }; 57 | }; 58 | }; 59 | __overrides__ { 60 | disable-i2c = <0>,"-3,-4"; 61 | disable-touch = <0>,"-4"; 62 | }; 63 | }; 64 | -------------------------------------------------------------------------------- /uninstall.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | SERVICE_NAME="hyperpixel2r-init.service" 4 | SERVICE_PATH="/etc/systemd/system" 5 | BINARY_NAME="hyperpixel2r-init" 6 | ROTATE_NAME="hyperpixel2r-rotate" 7 | BINARY_PATH="/usr/bin" 8 | OVERLAY_PATH="/boot/overlays" 9 | OVERLAY_NAME="hyperpixel2r.dtbo" 10 | OVERLAY_SRC="hyperpixel2r-overlay.dts" 11 | 12 | CONFIG="/boot/config.txt" 13 | 14 | CONFIG_LINES=( 15 | "dtoverlay=hyperpixel2r" 16 | "enable_dpi_lcd=1" 17 | "dpi_group=2" 18 | "dpi_mode=87" 19 | "dpi_output_format=0x7f216" 20 | "dpi_timings=480 0 10 16 55 480 0 15 60 15 0 0 0 60 0 19200000 6" 21 | ) 22 | 23 | if [ $(id -u) -ne 0 ]; then 24 | printf "Script must be run as root. Try 'sudo ./uninstall.sh'\n" 25 | exit 1 26 | fi 27 | 28 | if [ -f "$SERVICE_PATH/$SERVICE_NAME" ]; then 29 | systemctl stop $SERVICE_NAME 30 | systemctl disable $SERVICE_NAME 31 | rm -f "$SERVICE_PATH/$SERVICE_NAME" 32 | systemctl daemon-reload 33 | printf "Removed: $SERVICE_PATH/$SERVICE_NAME\n" 34 | else 35 | printf "Skipped: $SERVICE_PATH/$SERVICE_NAME, not installed\n" 36 | fi 37 | 38 | if [ -f "$BINARY_PATH/$ROTATE_NAME" ]; then 39 | rm -rf "$BINARY_PATH/$ROTATE_NAME" 40 | printf "Removed: $BINARY_PATH/$ROTATE_NAME\n" 41 | else 42 | printf "Skipped: $BINARY_PATH/$ROTATE_NAME, not installed\n" 43 | fi 44 | 45 | if [ -f "$BINARY_PATH/$BINARY_NAME" ]; then 46 | rm -f "$BINARY_PATH/$BINARY_NAME" 47 | printf "Removed: $BINARY_PATH/$BINARY_NAME\n" 48 | else 49 | printf "Skipped $BINARY_PATH/$BINARY_NAME, not installed\n" 50 | fi 51 | 52 | if [ -f "$OVERLAY_PATH/$OVERLAY_NAME" ]; then 53 | rm -f "$OVERLAY_PATH/$OVERLAY_NAME" 54 | printf "Removed: $OVERLAY_PATH/$OVERLAY_NAME\n" 55 | else 56 | printf "Skipped: $OVERLAY_PATH/$OVERLAY_NAME, not installed\n" 57 | fi 58 | 59 | if [ -f "$CONFIG" ]; then 60 | for ((i = 0; i < ${#CONFIG_LINES[@]}; i++)); do 61 | CONFIG_LINE="${CONFIG_LINES[$i]}" 62 | 63 | grep -e "^$CONFIG_LINE" $CONFIG > /dev/null 64 | STATUS=$? 65 | if [ $STATUS -eq 0 ]; then 66 | sed -i "/^$CONFIG_LINE/d" $CONFIG 67 | printf "Removed: line $CONFIG_LINE from $CONFIG\n" 68 | else 69 | printf "Skipped: $CONFIG, line $CONFIG_LINE not found\n" 70 | fi 71 | done 72 | fi 73 | --------------------------------------------------------------------------------