character lcd – LCD Display Corruption on Raspberry Pi Pico (MicroPython) – Lines Overwriting Each Other

I am building a system using a Waveshare RP2040-Zero ( like a Raspberry Pi Pico ) with an HD44780-2004 LCD over I2C. I’m facing a strange issue where the text on one line of the display occasionally gets overwritten by text from another line after the main loop runs for a while.

My sample code has two main parts:

  • A Timer interrupt that updates the time and date on line 1 every second.
  • A main loop that updates the thermostat status on line 2
    every 5 seconds.

The Problem:

After approximately 10 loops, the text intended for line 3 (“Status: …”) is sometimes printed on line 2. Later this happens again, every 6-12 loops after the first occurrence with even half words but not clearing existing text (it looks like that the added spaces are removed ). Line 1 (the time) continues to update correctly.

Here is my simplified test code that reproduces the issue:

# micro python
# lcd row test
import machine
import time
from machine import I2C, Pin, Timer
from time import sleep
from pico_i2c_lcd import I2cLcd

LCD_HD44780_2004_ADDR = 0x27
i2c = I2C(0, sda=Pin(0), scl=Pin(1), freq=400000)
devices = i2c.scan()

if LCD_HD44780_2004_ADDR in devices:
    lcd = I2cLcd(i2c, LCD_HD44780_2004_ADDR, 4, 20)
else:
    lcd = None

def update_tijd_datum(timer):
    """Show time and date on line 1 of the LCD - independent of main loop"""
    if lcd is None:
        return
        
    current_time = time.localtime()
    tijd_str = "{:02d}-{:02d}-{} {:02d}:{:02d}:{:02d}".format(
        current_time[2], current_time[1], current_time[0],
        current_time[3], current_time[4], current_time[5]
    )
    lcd.move_to(0, 0)
    tijd_str = tijd_str + ' ' * (20 - len(tijd_str))
    lcd.putstr(tijd_str)

# INITIALIZE TIMER INTERRUPT
tijd_timer = Timer()
tijd_timer.init(period=1000, mode=Timer.PERIODIC, callback=update_tijd_datum)

def toon_thermostaat_info():
    if lcd is None:
        return
        
    lcd.move_to(0, 1)
    lcd.putstr("Temp: 21.5C" + ' ' * (20 - len("Temp: 21.5C")))
    lcd.move_to(0, 2)
    lcd.putstr("Status: Verwarming" + ' ' * (20 - len("Status: Verwarming")))
    lcd.move_to(0, 3)
    lcd.putstr("Set: 22.0C" + ' ' * (20 - len("Set: 22.0C")))

toon_thermostaat_info()
counter = 0
try:
    while True:
        sleep(5)
        counter += 1
        if lcd:
            lcd.move_to(0, 2)  # Intend to write to line 3
            import random
            status = random.choice(["Status: Verwarming", "Status: Koeling", "Status: Uit"])
            print(f"{counter}, {status}")
            status = status + ' ' * (20 - len(status))
            lcd.putstr(status)  # This text sometimes appears on line 2!
            
except KeyboardInterrupt:
    print("Programma gestopt")
    tijd_timer.deinit()

What I’ve Investigated:

I am padding the strings with spaces to clear the entire line, so it shouldn’t be leftover characters.
The move_to(0, 2) command is correctly placed before writing the status.
The problem is intermittent, which makes me suspect a race condition or a shared resource conflict.

As a side note, I did try it with a different same type/model brand new display but same result.
The timer interrupt (updating line 1) and the main loop (updating line 2) are both accessing the same lcd object. I suspect they might be interfering with each other, even though they are writing to different lines.

My Questions:

What is the root cause of this “line jumping” behavior? Is my suspicion about a race condition between the interrupt and the main loop correct?

How can I make this solid? What is the best practice for handling concurrent access to an I2C LCD from both a timer interrupt and the main loop in MicroPython?

Any insights or suggestions would be greatly appreciated

Read more here: Source link