juj / fbcp-ili9341

A blazing fast display driver for SPI-based LCD displays for Raspberry Pi A, B, 2, 3, 4 and Zero
MIT License
1.55k stars 257 forks source link

pygame.error: No available video device #307

Open Georodin opened 10 months ago

Georodin commented 10 months ago

Hey guys, I have the ST7796S running with fbcp-ili9341 < on my Raspi Zero W. Now I wanted to print a lightweight GUI to the ST7796S using pygame.

But pygame cannot find the correct video driver. How can I link it correctly and use pygame with fbcp-ili9341? I can directly write images and stuff to the framebuffer fb0.

And I tried a ton of stuff from forums and ChatGPT but in the end it did not work.

But I always get the error like this when running my python:

python3 game.py
pygame 2.5.1 (SDL 2.0.14, Python 3.9.2)
Hello from the pygame community. https://www.pygame.org/contribute.html
The path /dev/dri/ cannot be opened or is not available
The path /dev/dri/ cannot be opened or is not available
The path /dev/dri/ cannot be opened or is not available
The path /dev/dri/ cannot be opened or is not available
Traceback (most recent call last):
  File "/home/pi/game.py", line 12, in <module>
    screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.error: No available video device

This script im using at the moment:

import pygame
import os

# Initialize pygame
pygame.init()

# Use fb0 for display
os.environ["SDL_FBDEV"] = "/dev/fb0"
os.environ["SDL_VIDEODRIVER"] = "rpi"

# Set up display dimensions
WIDTH, HEIGHT = 480, 320
screen = pygame.display.set_mode((WIDTH, HEIGHT))

# Colors
WHITE = (255, 255, 255)
RED = (255, 0, 0)

running = True
while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False

    screen.fill(WHITE)
    pygame.draw.circle(screen, RED, (WIDTH // 2, HEIGHT // 2), 50)
    pygame.display.flip()

pygame.quit()

When I activate this in the boot/config.txt, then the game.py does no longer throw errors, but the fbcp-ili9341 does not work any longer.

# Enable DRM VC4 V3D driver
#dtoverlay=vc4-kms-v3d

Any ideas or obvious mistakes on my side? Much appreciated.

Georodin commented 10 months ago

@juj if you read this I would love to tip you a coffee if you can provide some feedback :)

userkazoo commented 4 months ago

Greetings!

I have the same situation and the same display. I made the driver according to the instruction https://github.com/jobitjoseph/fbcp-ST7796. It took a long time with pygame - as a result everything worked through framebuffer. As an example of pygame work - the code below:

#!/usr/bin/python3

import pygame, time

# Very important: the exact pixel size of the TFT screen must be known so we can build graphics at this exact format
surfaceSize = (480, 320)

# Note that we don't instantiate any display!
pygame.init()

# The pygame surface we are going to draw onto. 
# /!\ It must be the exact same size of the target display /!\
lcd = pygame.Surface(surfaceSize)

# This is the important bit
def refresh():
    # We open the TFT screen's framebuffer as a binary file. Note that we will write bytes into it, hence the "wb" operator
    f = open("/dev/fb0","wb")
    # According to the TFT screen specs, it supports only 16bits pixels depth
    # Pygame surfaces use 24bits pixels depth by default, but the surface itself provides a very handy method to convert it.
    # once converted, we write the full byte buffer of the pygame surface into the TFT screen framebuffer like we would in a plain file:
    f.write(lcd.convert(16,0).get_buffer())
    # We can then close our access to the framebuffer
    f.close()
    time.sleep(0.1)

# Now we've got a function that can get the bytes from a pygame surface to the TFT framebuffer, 
# we can use the usual pygame primitives to draw on our surface before calling the refresh function.

# Here we just blink the screen background in a few colors with the "Hello World!" text
pygame.font.init()
defaultFont = pygame.font.SysFont(None,30)

lcd.fill((255,0,0))
lcd.blit(defaultFont.render("Hello World1!", False, (0, 0, 0)),(0, 0))
refresh()

lcd.fill((0, 255, 0))
lcd.blit(defaultFont.render("Hello World2!", False, (0, 0, 0)),(0, 0))
refresh()

lcd.fill((0,0,255))
lcd.blit(defaultFont.render("Hello World3!", False, (0, 0, 0)),(0, 0))
refresh()

lcd.fill((128, 128, 128))
lcd.blit(defaultFont.render("Hello World4!", False, (0, 0, 0)),(0, 0))
refresh()

pygame.draw.circle(lcd, (0,128,0), (200,200), 55)
# your picture
#image = pygame.image.load('guizero_flash.gif') # your picture
#lcd.blit(image, (0, 0))
refresh()

exit()
Georodin commented 4 months ago

Thank you very much, I will try it as soon as I have a free Raspberry Pi again, my three are bound in projects atm