Skip to content

Screen occasionally goes black on image swap #116

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
BillMerryman opened this issue Oct 26, 2023 · 2 comments
Open

Screen occasionally goes black on image swap #116

BillMerryman opened this issue Oct 26, 2023 · 2 comments

Comments

@BillMerryman
Copy link

I have a simple application that updates a screen (Adafruit 1.14" 240x135 Color TFT Display + MicroSD Card Breakout - ST7789 Product ID: 4383) from a Pi Zero W 2, every 1/2 to 1 second, rendering moving 'eyes'. It consists of a main program (face_test.py) and a threaded class (face.py). The updating is done from a thread. The eyes are transparent PNG files that are enumerated from a text file and loaded at startup. In the thread, the code creates a green background, pastes the 'eyes' onto it, and then displays the image to the screen. This part appears to work fine. The main program can call a method on the class that tells it which PNG it should be using. At random times, this part appears to be resetting the screen, as it goes black and doesn't display anything else for the remainder of the run. I've attached all files, with the Python files as txt files.

The main program:

import os
import time

import face

def main():
	face_animate = face.FaceAnimate()
	face_animate.start()
	for x in range(100):
		time.sleep(2)
		face_animate.set_face("squint")
		time.sleep(2)	
		face_animate.set_face("regular")
	face_animate.stop()
	face_animate.join()

if __name__ == "__main__":
    main()

The threaded class:

import os
import threading
import random
import time
import digitalio
import board
from PIL import Image, ImageDraw
from adafruit_rgb_display import st7789

# Configuration for CS and DC pins (these are PiTFT defaults):
cs_pin = digitalio.DigitalInOut(board.CE0)
dc_pin = digitalio.DigitalInOut(board.D25)
reset_pin = digitalio.DigitalInOut(board.D24)

# Config for display baudrate (default max is 24mhz):
BAUDRATE = 24000000

# Setup SPI bus using hardware SPI:
spi = board.SPI()

disp = st7789.ST7789(spi, 
        rotation=270, 
        width=135, 
        height=240, 
        x_offset=53, 
	y_offset=40, # 1.14" ST7789
	cs=cs_pin,
	dc=dc_pin,
	rst=reset_pin,
	baudrate=BAUDRATE,
	)

if disp.rotation % 180 == 90:
    height = disp.width  # we swap height/width to rotate it to landscape!
    width = disp.height
else:
    width = disp.width  # we swap height/width to rotate it to landscape!
    height = disp.height

class FaceAnimate(threading.Thread):
	def __init__(self):
		threading.Thread.__init__(self)
		self.face_offset_x = 0
		self.face_offset_y = 0
		self.images = {}
		self.load_images(os.getcwd() + "/images.txt")
		self.face_key = list(self.images.keys())[0]
		self.face = self.images[self.face_key]		
		self.running = True
		random.seed()

	def load_images(self, file_list_path):
		try:
			with open(file_list_path, 'r') as file:
				for line in file:
					image_filename = line.strip()
					key = image_filename.split('.')[0]
					image = Image.open(os.getcwd() + "/" + image_filename)
					self.images[key] = image
		except Exception as e:
			print(f"{e}")

	def run(self):
		while self.running:
			time.sleep(random.uniform(.5, 1))
			self.face_offset_x = random.randint(-5, 5)
			self.face_offset_y = random.randint(-5, 5)
			self.show_face()

	def set_face(self, face_name):
		self.face = self.images[face_name]
		self.show_face()

	def get_background(self, R, G, B):
		image = Image.new("RGB", (width, height))
		draw = ImageDraw.Draw(image)
		draw.rectangle((0, 0, width, height), outline=0, fill=(R, G, B))
		return image

	def show_face(self):
		background = self.get_background(int("6B", 16), int("8E", 16), int("23",16))
		background.paste(self.face, (self.face_offset_x, self.face_offset_y), self.face)
		disp.image(background)

	def stop(self):
		self.running = False

face.txt
images.txt
regular
squint
face_test.txt

@BillMerryman
Copy link
Author

Okay, guess I rubber-duck debugged. I implemented a lock and acquired the lock before each call to 'show_face' and that appears to have resolved it. Is ST7789 not thread-safe? Or is it just the ST7789.image method that isn't thread safe?

@BillMerryman
Copy link
Author

Yep, deleted the 'with self.lock:' statements from everywhere and added it just in the line before setting the image:

		with self.lock:		
			disp.image(background)

Problem remains resolved.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant