I asked Grok Ai to make me a code example of an Interrupt based script for rpi Pi5.
I want an Bourns PEC11R to work as navigational tool. Clock go left(arrow left) Anticlock go right(arrow right) Short press = left mouse click(Enter) Long press = go back(go up one folder).
Grok knows I have a mcp23017 already connected and should use GPa0,1,2 to connect the encoder. This what it came out with… it didn’t work…
Also I tried this on Pi5 Os, and not Zynthian OS.
It also gives you indications for to install all needed libraries, but it completely screws up when he has to filter out working instructions viable for Pi5 and the rp1 monitor chip…
to get to this code I had to “feed” Grok with multiple datasheets, github pages with working examples, and a lot of other errors I got from Pi5 Os feedback and new corrected codes…
it got into a loop where it couldn’t determine the cause of Pull=True errors and Digitalio not working. After a while I abandoned the project and the Ai.
It is really time-consuming try to teach the Ai for most basic errors every time, and it has zero memory. Every time mixes up Pi4 infos with Pi5 request code…
It also assumed some info I don’t know how… my 23017 address is 0x21 and not 0x20.
it failed to ask me to check wether this info was right or not.
Completely skipping all tests basic procedures.
Probably working with a simpler 2040 chipset such as that of a Pi Pico can get some working results, nut I seriously doubt it can be of any use on Zynthian, which is even harder then Pi5 Os himself…
import time
import board
import busio
from adafruit_mcp230xx.mcp23017 import MCP23017
import lgpio
from evdev import UInput, ecodes as e
Initialize virtual input device (mouse and keyboard)
ui = UInput(
{
e.EV_KEY: [e.BTN_LEFT, e.KEY_PAGEUP],
e.EV_REL: [e.REL_WHEEL],
},
name=“rotary-input”,
vendor=0x1234,
product=0x5678
)
Initialize I2C bus
i2c = busio.I2C(board.SCL, board.SDA)
Initialize MCP23017 at address 0x20
mcp = MCP23017(i2c, address=0x20)
Configure pins: GPA0 (CLK), GPA1 (DT), GPA2 (SW) as inputs with pull-ups
clk_pin = mcp.get_pin(0) # GPA0
dt_pin = mcp.get_pin(1) # GPA1
sw_pin = mcp.get_pin(2) # GPA2
clk_pin.switch_to_input(pull=True)
dt_pin.switch_to_input(pull=True)
sw_pin.switch_to_input(pull=True)
Configure MCP23017 interrupts for GPA0, GPA1, GPA2
mcp.interrupt_enable = 0x07 # Enable interrupts on GPA0–GPA2 (0b00000111)
mcp.interrupt_configuration = 0x00 # Interrupt on change
mcp.default_value = 0x00 # Compare against previous value
mcp.clear_ints() # Clear pending interrupts
Set up lgpio for interrupt detection
INTA_PIN = 17 # GPIO 17 (pin 11) connected to MCP23017 INTA
chip = lgpio.gpiochip_open(0) # Open GPIO chip
lgpio.gpio_claim_input(chip, INTA_PIN, lgpio.SET_PULL_UP) # Input with pull-up
Encoder state variables
last_clk = clk_pin.value
Switch state variables
last_sw_state = sw_pin.value
press_start_time = 0
is_pressed = False
def handle_interrupt(chip, gpio, level, timestamp):
global last_clk, last_sw_state, press_start_time, is_pressed
Read interrupt flags
int_flag = mcp.int_flag
mcp.clear_ints() # Clear interrupts
Read current pin states
current_clk = clk_pin.value
dt_state = dt_pin.value
sw_state = sw_pin.value
Handle encoder (CLK or DT interrupt)
if int_flag & 0x03: # GPA0 or GPA1 changed
if current_clk != last_clk:
if dt_state != current_clk:
Clockwise: scroll up
ui.write(e.EV_REL, e.REL_WHEEL, 1)
else:
Counterclockwise: scroll down
ui.write(e.EV_REL, e.REL_WHEEL,
ui.syn() # Sync events
last_clk = current_clk
-1)
Handle switch (SW interrupt)
if int_flag & 0x04: # GPA2 changed
if not sw_state and last_sw_state: # High to low (press)
press_start_time = time.time()
is_pressed = True
elif sw_state and not last_sw_state: # Low to high (release)
if is_pressed:
press_duration = time.time() - press_start_time
if press_duration < 0.5:
Short press: left click
ui.write(e.EV_KEY, e.BTN_LEFT, 1) # Press
ui.write(e.EV_KEY, e.BTN_LEFT, 0) # Release
else:
Long press: Page Up
ui.write(e.EV_KEY, e.KEY_PAGEUP, 1) # Press
ui.write(e.EV_KEY, e.KEY_PAGEUP, 0) # Release
ui.syn() # Sync events
is_pressed = False
last_sw_state = sw_state
Register interrupt callback (falling edge)
lgpio.callback(chip, INTA_PIN, lgpio.FALLING_EDGE, handle_interrupt)
try:
while True:
time.sleep(1) # Idle loop
except KeyboardInterrupt:
pass
finally:
ui.close()
Close virtual input device
lgpio.gpiochip_close(chip) # Close GPIO chip
mcp.deinit()