adafruit / Adafruit_Blinka_Displayio

Displayio for Blinka
MIT License
14 stars 20 forks source link

SPI ST7735 float/int errors #128

Closed nailyk-fr closed 9 months ago

nailyk-fr commented 9 months ago

Hello,

I am trying to set up a ST7735 128x160 display through SPI on a Raspberry pi. Found multiples examples online. The most obvious non working one is : https://github.com/educ8s/CircuitPython-Clock-with-DS3231-and-ST7735-display.git

This is a simple label test display.

In each example, the setup (aka initial drawing on the display) is going fine. However, randomly, on the text update in the labels, there are crash about 'float' not being 'integers' (leads to various errors about multiplications, drawing, and so on)

Used code :

import time                                                                                                                                                                                                                                                                                                                                                               
import board, busio, displayio                                                                                                                                                                                                                                                                                                                                            
from adafruit_st7735r import ST7735R                                                                                                                                                                                                                                                                                                                                      
from adafruit_display_text import label                                                                                                                                                                                                                                                                                                                                   
from adafruit_bitmap_font import bitmap_font                                                                                                                                                                                                                                                                                                                              

def c_to_f(celsius):                                                                                                                                                                                                                                                                                                                                                      
    fahrenheit = (celsius * 1.8) + 32                                                                                                                                                                                                                                                                                                                                     
    return fahrenheit                                                                                                                                                                                                                                                                                                                                                     

def update_labels():                                                                                                                                                                                                                                                                                                                                                      
    global temperature                                                                                                                                                                                                                                                                                                                                                    
    minutes = "{:02}".format(t.tm_min)                                                                                                                                                                                                                                                                                                                                    
    date_label.text = f"{days[int(t.tm_wday)]}, {t.tm_mday}/{t.tm_mon}/{t.tm_year}"                                                                                                                                                                                                                                                                                       
    time_label.text = f"{t.tm_hour}:{minutes}"                                                                                                                                                                                                                                                                                                                            
    temperature = 33                                                                                                                                                                                                                                                                                                                                                      
    temperature_string = f"{temperature}C"                                                                                                                                                                                                                                                                                                                               
    if not metric:                                                                                                                                                                                                                                                                                                                                                        
        temperature = round(c_to_f(temperature),1)                                                                                                                                                                                                                                                                                                                        
        temperature_string = f"{temperature}F"                                                                                                                                                                                                                                                                                                                           

    temperature_value_label.text = temperature_string                                                                                                                                                                                                                                                                                                                     

    set_min_max_temperature()                                                                                                                                                                                                                                                                                                                                             

    if metric:                                                                                                                                                                                                                                                                                                                                                            
        max_temperature_value_label.text = f"{str(max_temperature)}C"                                                                                                                                                                                                                                                                                                    
        min_temperature_value_label.text = f"{str(min_temperature)}C"                                                                                                                                                                                                                                                                                                    
    else:                                                                                                                                                                                                                                                                                                                                                                 
        max_temperature_value_label.text = f"{str(max_temperature)}F"                                                                                                                                                                                                                                                                                                    
        min_temperature_value_label.text = f"{str(min_temperature)}F"                                                                                                                                                                                                                                                                                                    

    print(f"The date is {days[int(t.tm_wday)]} {t.tm_mday}/{t.tm_mon}/{t.tm_year}")                                                                                                                                                                                                                                                                                       
    print("The time is {}:{:02}:{:02}".format(t.tm_hour, t.tm_min, t.tm_sec))                                                                                                                                                                                                                                                                                             
#    print(f"Temperature: {temperature}")                                                                                                                                                                                                                                                                                                                                 
#    print(f"Min Temperature: {min_temperature}")                                                                                                                                                                                                                                                                                                                         
#    print(f"Max Temperature: {max_temperature}")                                                                                                                                                                                                                                                                                                                         
#    print(f"Temperature: {temperature}\n\n")                                                                                                                                                                                                                                                                                                                             

def set_min_max_temperature():                                                                                                                                                                                                                                                                                                                                            
    global min_temperature, max_temperature                                                                                                                                                                                                                                                                                                                               
    if temperature > max_temperature:                                                                                                                                                                                                                                                                                                                                     
        max_temperature = temperature                                                                                                                                                                                                                                                                                                                                     
    if temperature < min_temperature:                                                                                                                                                                                                                                                                                                                                     
        min_temperature = temperature                                                                                                                                                                                                                                                                                                                                     

mosi_pin, clk_pin, reset_pin, cs_pin, dc_pin = board.MOSI, board.SCK, board.D25, board.D22, board.D23                                                                                                                                                                                                                                                                     
days = ("Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday")                                                                                                                                                                                                                                                                                     

metric = True # Set to False for degrees Fahrenheit                                                                                                                                                                                                                                                                                                                       

# UNCOMMENT THE FOLLOWING THREE LINES THE FIRST TIME YOU RUN THE CODE TO SET THE TIME!                                                                                                                                                                                                                                                                                    
#set_time = time.struct_time((2022, 8, 30, 12, 35, 45, 2, -1, -1)) # Year, Month, Date, Hour, Minutes, Seconds, Week Day                                                                                                                                                                                                                                                  
#print("Setting time to:", set_time)                                                                                                                                                                                                                                                                                                                                      
#rtc.datetime = set_time                                                                                                                                                                                                                                                                                                                                                  

# Comment out the above three lines again after setting the time!                                                                                                                                                                                                                                                                                                         

displayio.release_displays()                                                                                                                                                                                                                                                                                                                                              
spi = busio.SPI(clock=clk_pin, MOSI=mosi_pin)                                                                                                                                                                                                                                                                                                                             
display_bus = displayio.FourWire(spi, command=dc_pin, chip_select=cs_pin, reset=reset_pin)                                                                                                                                                                                                                                                                                

t = time.localtime()                                                                                                                                                                                                                                                                                                                                                      

min_temperature = 100.0                                                                                                                                                                                                                                                                                                                                                   
max_temperature = 0.0                                                                                                                                                                                                                                                                                                                                                     
temperature = 0                                                                                                                                                                                                                                                                                                                                                           

font_file = "fonts/terminal.bdf"                                                                                                                                                                                                                                                                                                                                          
font = bitmap_font.load_font(font_file)                                                                                                                                                                                                                                                                                                                                   

display = ST7735R(display_bus, width=160, height=128, rotation=270, bgr = True)                                                                                                                                                                                                                                                                                           

# Create date label                                                                                                                                                                                                                                                                                                                                                       
date_label = label.Label(font, color=0x00FF00, text = "Date")                                                                                                                                                                                                                                                                                                             
date_label.anchor_point = (0, 0)                                                                                                                                                                                                                                                                                                                                          
date_label.anchored_position = (10, 5)                                                                                                                                                                                                                                                                                                                                    

print("created date")                                                                                                                                                                                                                                                                                                                                                     

# Create time label                                                                                                                                                                                                                                                                                                                                                       
time_label = label.Label(font, color=0xFFFFFF)                                                                                                                                                                                                                                                                                                                            
time_label.anchor_point = (0, 0)                                                                                                                                                                                                                                                                                                                                          
time_label.anchored_position = (10, 20)                                                                                                                                                                                                                                                                                                                                   
time_label.scale = (3)                                                                                                                                                                                                                                                                                                                                                    
print("created time")                                                                                                                                                                                                                                                                                                                                                     

# Create temperature label                                                                                                                                                                                                                                                                                                                                                
temperature_label = label.Label(font, color=0x00FF00, text = "TEMPERATURE")                                                                                                                                                                                                                                                                                               
temperature_label.anchor_point = (0.5, 0)                                                                                                                                                                                                                                                                                                                                 
temperature_label.anchored_position = (64, 64)                                                                                                                                                                                                                                                                                                                            
print("created temperature")                                                                                                                                                                                                                                                                                                                                              

# Create min_temperature label                                                                                                                                                                                                                                                                                                                                            
min_temperature_label = label.Label(font, color=0x0000FF, text = "MIN")                                                                                                                                                                                                                                                                                                   
min_temperature_label.anchor_point = (0.0, 0.0)                                                                                                                                                                                                                                                                                                                           
min_temperature_label.anchored_position = (80, 100)                                                                                                                                                                                                                                                                                                                       
min_temperature_label.verbose = True                                                                                                                                                                                                                                                                                                                                      
print("created min temp")                                                                                                                                                                                                                                                                                                                                                 

# Create max_temperature label                                                                                                                                                                                                                                                                                                                                            
max_temperature_label = label.Label(font, color=0xFF0000, text = "MAX")                                                                                                                                                                                                                                                                                                   
max_temperature_label.anchor_point = (0.0, 0.0)                                                                                                                                                                                                                                                                                                                           
max_temperature_label.anchored_position = (18, 100)                                                                                                                                                                                                                                                                                                                       
print("created max temp")                                                                                                                                                                                                                                                                                                                                                 

# Create temperature value label                                                                                                                                                                                                                                                                                                                                          
temperature_value_label = label.Label(font, color=0xFFFFFF)                                                                                                                                                                                                                                                                                                               
temperature_value_label.anchor_point = (0.5, 0)                                                                                                                                                                                                                                                                                                                           
temperature_value_label.anchored_position = (64, 75)                                                                                                                                                                                                                                                                                                                      
temperature_value_label.scale = (3)                                                                                                                                                                                                                                                                                                                                       
print("created temp value")                                                                                                                                                                                                                                                                                                                                               

# Create max_temperature value label                                                                                                                                                                                                                                                                                                                                      
max_temperature_value_label = label.Label(font, color=0xFFFFFF)                                                                                                                                                                                                                                                                                                           
max_temperature_value_label.anchor_point = (0.0, 0.0)                                                                                                                                                                                                                                                                                                                     
max_temperature_value_label.anchored_position = (10, 140)                                                                                                                                                                                                                                                                                                                 
print("created max temp value")                                                                                                                                                                                                                                                                                                                                           

# Create min_temperature value label                                                                                                                                                                                                                                                                                                                                      
min_temperature_value_label = label.Label(font, color=0xFFFFFF)                                                                                                                                                                                                                                                                                                           
min_temperature_value_label.anchor_point = (1.0, 0.0)                                                                                                                                                                                                                                                                                                                     
min_temperature_value_label.anchored_position = (120, 140)                                                                                                                                                                                                                                                                                                                
print("created min temp value")                                                                                                                                                                                                                                                                                                                                           

ui = displayio.Group()                                                                                                                                                                                                                                                                                                                                                    
#display.show(ui)                                                                                                                                                                                                                                                                                                                                                         

# ui.append(min_temperature_value_label)                                                                                                                                                                                                                                                                                                                                  
# print("ui.append(min_temperature_value_label)")                                                                                                                                                                                                                                                                                                                         
# ui.append(max_temperature_value_label)                                                                                                                                                                                                                                                                                                                                  
# print("ui.append(max_temperature_value_label)")                                                                                                                                                                                                                                                                                                                         
ui.append(time_label)                                                                                                                                                                                                                                                                                                                                                     
print("ui.append(time_label)")                                                                                                                                                                                                                                                                                                                                            
ui.append(date_label)                                                                                                                                                                                                                                                                                                                                                     
print("ui.append(date_label)")                                                                                                                                                                                                                                                                                                                                            
# ui.append(temperature_value_label)                                                                                                                                                                                                                                                                                                                                      
# print("ui.append(temperature_value_label)")                                                                                                                                                                                                                                                                                                                             
ui.append(max_temperature_label)                                                                                                                                                                                                                                                                                                                                          
print("ui.append(max_temperature_label)")                                                                                                                                                                                                                                                                                                                                 
ui.append(min_temperature_label)                                                                                                                                                                                                                                                                                                                                          
print("ui.append(min_temperature_label)")                                                                                                                                                                                                                                                                                                                                 
# ui.append(temperature_label)                                                                                                                                                                                                                                                                                                                                            
# print("ui.append(temperature_label)")                                                                                                                                                                                                                                                                                                                                   

display.root_group = ui                                                                                                                                                                                                                                                                                                                                                   

while True:                                                                                                                                                                                                                                                                                                                                                               
    t = time.localtime()                                                                                                                                                                                                                                                                                                                                                  
    update_labels()                                                                                                                                                                                                                                                                                                                                                       
    time.sleep(1)  # wait a second                                                                                                                                                                                                                                                                                                                                        

Output :

created date
created time
created temperature
created min temp
created max temp
created temp value
created max temp value
created min temp value
ui.append(time_label)
ui.append(date_label)
ui.append(max_temperature_label)
ui.append(min_temperature_label)
The date is Sunday 25/2/2024
The time is 10:10:38
The date is Sunday 25/2/2024
The time is 10:10:40
Exception in thread Thread-1 (_background):
Traceback (most recent call last):
  File "/usr/lib/python3.11/threading.py", line 1038, in _bootstrap_inner
    self.run()
  File "/usr/lib/python3.11/threading.py", line 975, in run
    self._target(*self._args, **self._kwargs)
  File "/home/nailyk/display/st7735/Adafruit_CircuitPython_ST7735R/st7735/lib/python3.11/site-packages/displayio/__init__.py", line 48, in _background
    display._background()  # pylint: disable=protected-access
    ^^^^^^^^^^^^^^^^^^^^^
  File "/home/nailyk/display/st7735/Adafruit_CircuitPython_ST7735R/st7735/lib/python3.11/site-packages/displayio/_display.py", line 342, in _background
    self.refresh()
  File "/home/nailyk/display/st7735/Adafruit_CircuitPython_ST7735R/st7735/lib/python3.11/site-packages/displayio/_display.py", line 309, in refresh
    self._refresh_display()
  File "/home/nailyk/display/st7735/Adafruit_CircuitPython_ST7735R/st7735/lib/python3.11/site-packages/displayio/_display.py", line 318, in _refresh_display
    self._refresh_area(area)
  File "/home/nailyk/display/st7735/Adafruit_CircuitPython_ST7735R/st7735/lib/python3.11/site-packages/displayio/_display.py", line 399, in _refresh_area
    self._core.set_region_to_update(subrectangle)
  File "/home/nailyk/display/st7735/Adafruit_CircuitPython_ST7735R/st7735/lib/python3.11/site-packages/displayio/_displaycore.py", line 309, in set_region_to_update
    data += struct.pack(">HH", region_x1, region_x2)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
struct.error: required argument is not an integer
The date is Sunday 25/2/2024
The time is 10:10:41
The date is Sunday 25/2/2024
The time is 10:10:42
^CTraceback (most recent call last):
  File "/home/nailyk/display/st7735/CircuitPython-Clock-with-DS3231-and-ST7735-display/code.py", line 154, in <module>
    time.sleep(1)  # wait a second
    ^^^^^^^^^^^^^
KeyboardInterrupt

My Python knowledge being very basic, I was not able to do much except introduce some print (including in the library). Printing region_x1 & region_x2 gives float values for integral number (like 24.0 or 107.0)

Forcing int conversion with int(region_x1), etc... makes the library run a bit further, but still leads to errors.

--- /home/nailyk/display/st7735/Adafruit_CircuitPython_ST7735R/st7735/lib/python3.11/site-packages/displayio/_displaycore.py.orig       2024-02-25 10:18:56.365362427 +0000
+++ /home/nailyk/display/st7735/Adafruit_CircuitPython_ST7735R/st7735/lib/python3.11/site-packages/displayio/_displaycore.py    2024-02-25 10:17:35.957953486 +0000
@@ -275,6 +275,16 @@ class _DisplayCore:
         region_y1 = area.y1 + self.rowstart
         region_y2 = area.y2 + self.rowstart

+        print("region_x1 : " + str(region_x1))
+        print("region_x2 : " + str(region_x2))
+        print("region_y1 : " + str(region_y1))
+        print("region_y2 : " + str(region_y2))
+
+        region_x1 = int(region_x1)
+        region_x2 = int(region_x2)
+        region_y1 = int(region_y1)
+        region_y2 = int(region_y2)
+
         if self.colorspace.depth < 8:
             pixels_per_byte = 8 // self.colorspace.depth
             if self.colorspace.pixels_in_byte_share_row:

now gives the following error :

region_x1 : 20.0
region_x2 : 56.0
region_y1 : 60
region_y2 : 78
Exception in thread Thread-1 (_background):
Traceback (most recent call last):
  File "/usr/lib/python3.11/threading.py", line 1038, in _bootstrap_inner
    self.run()
  File "/usr/lib/python3.11/threading.py", line 975, in run
    self._target(*self._args, **self._kwargs)
  File "/home/nailyk/display/st7735/Adafruit_CircuitPython_ST7735R/st7735/lib/python3.11/site-packages/displayio/__init__.py", line 48, in _background
    display._background()  # pylint: disable=protected-access
    ^^^^^^^^^^^^^^^^^^^^^
  File "/home/nailyk/display/st7735/Adafruit_CircuitPython_ST7735R/st7735/lib/python3.11/site-packages/displayio/_display.py", line 342, in _background
    self.refresh()
  File "/home/nailyk/display/st7735/Adafruit_CircuitPython_ST7735R/st7735/lib/python3.11/site-packages/displayio/_display.py", line 309, in refresh
    self._refresh_display()
  File "/home/nailyk/display/st7735/Adafruit_CircuitPython_ST7735R/st7735/lib/python3.11/site-packages/displayio/_display.py", line 318, in _refresh_display
    self._refresh_area(area)
  File "/home/nailyk/display/st7735/Adafruit_CircuitPython_ST7735R/st7735/lib/python3.11/site-packages/displayio/_display.py", line 409, in _refresh_area
    buffer = memoryview(bytearray([0] * (buffer_size * 4))).cast("I")
                                  ~~~~^~~~~~~~~~~~~~~~~~~
TypeError: can't multiply sequence by non-int of type 'float'

And so on....

My question is : Where would be the best way/place to cast the regions to prevent that float issue (or, even better, to prevent the region to be set as a float) ?

Thanks a lot in advance !

Edit : Libraries versions :

Package                             Version
----------------------------------- -------
Adafruit-Blinka                     8.32.0
adafruit-blinka-displayio           1.2.1
adafruit-circuitpython-bitmap-font  2.1.1
adafruit-circuitpython-busdevice    5.2.6
adafruit-circuitpython-display-text 3.0.6
adafruit-circuitpython-matrixkeypad 1.2.16
adafruit-circuitpython-requests     2.0.5
adafruit-circuitpython-st7735r      1.6.2
adafruit-circuitpython-typing       1.10.2
Adafruit-PlatformDetect             3.60.0
Adafruit-PureIO                     1.1.11
gpiod                               2.1.3
gpiodevice                          0.0.3
numpy                               1.26.4
pillow                              10.2.0
pip                                 24.0
pyftdi                              0.55.0
pyserial                            3.5
pyusb                               1.2.1
RPi.GPIO                            0.7.1
rpi_ws281x                          5.0.0
setuptools                          69.1.1
spidev                              3.6
st7735                              1.0.0
sysv_ipc                            1.1.0
typing_extensions                   4.9.0
makermelissa commented 9 months ago

Rather than just respond about where to possibly fix the issue, it was easier to trace it down to the root cause and fix it there.