From b80e6f31a385bf9d61a1fdd466b422bc61465f9b Mon Sep 17 00:00:00 2001 From: Thomas Farstrike Date: Tue, 20 Jan 2026 15:02:32 +0100 Subject: [PATCH] Update fri3d_2026.py --- .../lib/mpos/board/fri3d_2024.py | 2 +- .../lib/mpos/board/fri3d_2026.py | 135 +++--------------- .../lib/mpos/hardware/drivers/wsen_isds.py | 2 +- 3 files changed, 22 insertions(+), 117 deletions(-) diff --git a/internal_filesystem/lib/mpos/board/fri3d_2024.py b/internal_filesystem/lib/mpos/board/fri3d_2024.py index f8e59351..9dc86e6d 100644 --- a/internal_filesystem/lib/mpos/board/fri3d_2024.py +++ b/internal_filesystem/lib/mpos/board/fri3d_2024.py @@ -93,7 +93,7 @@ btn_y = Pin(41, Pin.IN, Pin.PULL_UP) # Y btn_a = Pin(39, Pin.IN, Pin.PULL_UP) # A btn_b = Pin(40, Pin.IN, Pin.PULL_UP) # B btn_start = Pin(0, Pin.IN, Pin.PULL_UP) # START -btn_menu = Pin(45, Pin.IN, Pin.PULL_UP) # START +btn_menu = Pin(45, Pin.IN, Pin.PULL_UP) # MENU ADC_KEY_MAP = [ {'key': 'UP', 'unit': 1, 'channel': 2, 'min': 3072, 'max': 4096}, diff --git a/internal_filesystem/lib/mpos/board/fri3d_2026.py b/internal_filesystem/lib/mpos/board/fri3d_2026.py index 873e550d..d71a745a 100644 --- a/internal_filesystem/lib/mpos/board/fri3d_2026.py +++ b/internal_filesystem/lib/mpos/board/fri3d_2026.py @@ -2,7 +2,7 @@ # TODO: # - touch screen / touch pad -# - IMU is different from fri3d_2024 (also address 0x6A instead of 0x6B) +# - IMU (LSM6DSO) is different from fri3d_2024 (and address 0x6A instead of 0x6B) but the API seems the same, except different chip ID (0x6C iso 0x6A) # - I2S audio (communicator) is the same # - headphone jack audio? # - headphone jack microphone? @@ -12,6 +12,7 @@ # - digital buttons (X,Y,A,B, MENU) # - buzzer # - audio DAC emulation using buzzer might be slow or need specific buffered protocol +# - test it on the Waveshare to make sure no syntax / variable errors from machine import Pin, SPI, SDCard import st7789 @@ -30,33 +31,20 @@ import task_handler import mpos.ui import mpos.ui.focus_direction - -# Pin configuration -SPI_BUS = 2 -SPI_FREQ = 40000000 -#SPI_FREQ = 20000000 # also works but I guess higher is better -LCD_SCLK = 7 -LCD_MOSI = 6 -LCD_MISO = 8 -LCD_DC = 4 -LCD_CS = 5 -#LCD_BL = 1 # backlight can't be controlled on this hardware -LCD_RST = 48 - TFT_HOR_RES=320 TFT_VER_RES=240 spi_bus = machine.SPI.Bus( - host=SPI_BUS, - mosi=LCD_MOSI, - miso=LCD_MISO, - sck=LCD_SCLK + host=2, + mosi=6, + miso=8, + sck=7 ) display_bus = lcd_bus.SPIBus( spi_bus=spi_bus, - freq=SPI_FREQ, - dc=LCD_DC, - cs=LCD_CS + freq=40000000, + dc=4, + cs=5 ) # lv.color_format_get_size(lv.COLOR_FORMAT.RGB565) = 2 bytes per pixel * 320 * 240 px = 153600 bytes @@ -84,8 +72,8 @@ mpos.ui.main_display = st7789.ST7789( color_space=lv.COLOR_FORMAT.RGB565, color_byte_order=st7789.BYTE_ORDER_BGR, rgb565_byte_swap=True, - reset_pin=LCD_RST, # doesn't seem needed - reset_state=STATE_LOW # doesn't seem needed + reset_pin=48, # LCD reset: TODO: this is now on the CH32 + reset_state=STATE_LOW # TODO: is this correct? ) mpos.ui.main_display.init() @@ -96,77 +84,18 @@ mpos.ui.main_display.set_color_inversion(False) # Touch handling: # touch pad interrupt TP Int is on ESP.IO13 i2c_bus = i2c.I2C.Bus(host=I2C_BUS, scl=TP_SCL, sda=TP_SDA, freq=I2C_FREQ, use_locks=False) -touch_dev = i2c.I2C.Device(bus=i2c_bus, dev_id=TP_ADDR, reg_bits=TP_REGBITS) +touch_dev = i2c.I2C.Device(bus=i2c_bus, dev_id=0x15, reg_bits=TP_REGBITS) indev=cst816s.CST816S(touch_dev,startup_rotation=lv.DISPLAY_ROTATION._180) # button in top left, good lv.init() mpos.ui.main_display.set_rotation(lv.DISPLAY_ROTATION._270) # must be done after initializing display and creating the touch drivers, to ensure proper handling mpos.ui.main_display.set_params(0x36, bytearray([0x28])) -# Button and joystick handling code: +# Button handling code: from machine import ADC, Pin import time -btn_x = Pin(38, Pin.IN, Pin.PULL_UP) # X -btn_y = Pin(41, Pin.IN, Pin.PULL_UP) # Y -btn_a = Pin(39, Pin.IN, Pin.PULL_UP) # A -btn_b = Pin(40, Pin.IN, Pin.PULL_UP) # B btn_start = Pin(0, Pin.IN, Pin.PULL_UP) # START -btn_menu = Pin(45, Pin.IN, Pin.PULL_UP) # START - -ADC_KEY_MAP = [ - {'key': 'UP', 'unit': 1, 'channel': 2, 'min': 3072, 'max': 4096}, - {'key': 'DOWN', 'unit': 1, 'channel': 2, 'min': 0, 'max': 1024}, - {'key': 'RIGHT', 'unit': 1, 'channel': 0, 'min': 3072, 'max': 4096}, - {'key': 'LEFT', 'unit': 1, 'channel': 0, 'min': 0, 'max': 1024}, -] - -# Initialize ADC for the two channels -adc_up_down = ADC(Pin(3)) # ADC1_CHANNEL_2 (GPIO 33) -adc_up_down.atten(ADC.ATTN_11DB) # 0-3.3V range -adc_left_right = ADC(Pin(1)) # ADC1_CHANNEL_0 (GPIO 36) -adc_left_right.atten(ADC.ATTN_11DB) # 0-3.3V range - -def read_joystick(): - # Read ADC values - val_up_down = adc_up_down.read() - val_left_right = adc_left_right.read() - - # Check each key's range - for mapping in ADC_KEY_MAP: - adc_val = val_up_down if mapping['channel'] == 2 else val_left_right - if mapping['min'] <= adc_val <= mapping['max']: - return mapping['key'] - return None # No key triggered - -# Rotate: UP = 0°, RIGHT = 90°, DOWN = 180°, LEFT = 270° -def read_joystick_angle(threshold=0.1): - # Read ADC values - val_up_down = adc_up_down.read() - val_left_right = adc_left_right.read() - - #if time.time() < 60: - # print(f"val_up_down: {val_up_down}") - # print(f"val_left_right: {val_left_right}") - - # Normalize to [-1, 1] - x = (val_left_right - 2048) / 2048 # Positive x = RIGHT - y = (val_up_down - 2048) / 2048 # Positive y = UP - #if time.time() < 60: - # print(f"x,y = {x},{y}") - - # Check if joystick is near center - magnitude = math.sqrt(x*x + y*y) - #if time.time() < 60: - # print(f"magnitude: {magnitude}") - if magnitude < threshold: - return None # Neutral position - - # Calculate angle in degrees with UP = 0°, clockwise - angle_rad = math.atan2(x, y) - angle_deg = math.degrees(angle_rad) - angle_deg = (angle_deg + 360) % 360 # Normalize to [0, 360) - return angle_deg # Key repeat configuration # This whole debounce logic is only necessary because LVGL 9.2.2 seems to have an issue where @@ -186,37 +115,13 @@ def keypad_read_cb(indev, data): data.continue_reading = False since_last_repeat = 0 - # Check buttons and joystick + # Check buttons current_key = None current_time = time.ticks_ms() # Check buttons - if btn_x.value() == 0: - current_key = lv.KEY.ESC - elif btn_y.value() == 0: - current_key = ord("Y") - elif btn_a.value() == 0: - current_key = lv.KEY.ENTER - elif btn_b.value() == 0: - current_key = ord("B") - elif btn_menu.value() == 0: - current_key = lv.KEY.HOME - elif btn_start.value() == 0: + if btn_start.value() == 0: current_key = lv.KEY.END - else: - # Check joystick - angle = read_joystick_angle(0.30) # 0.25-0.27 is right on the edge so 0.30 should be good - if angle: - if angle > 45 and angle < 135: - current_key = lv.KEY.RIGHT - elif angle > 135 and angle < 225: - current_key = lv.KEY.DOWN - elif angle > 225 and angle < 315: - current_key = lv.KEY.LEFT - elif angle < 45 or angle > 315: - current_key = lv.KEY.UP - else: - print(f"WARNING: unhandled joystick angle {angle}") # maybe we could also handle diagonals? # Key repeat logic if current_key: @@ -294,7 +199,7 @@ mpos.sdcard.init(spi_bus, cs_pin=14) from machine import PWM, Pin from mpos import AudioFlinger -# Initialize buzzer: sits on PC14/CC1 of the CH32X035GxUx +# Initialize buzzer: now sits on PC14/CC1 of the CH32X035GxUx so needs custom code #buzzer = PWM(Pin(46), freq=550, duty=0) # I2S pin configuration for audio output (DAC) and input (microphone) @@ -303,7 +208,7 @@ from mpos import AudioFlinger # See schematics: DAC has BCK=2, WS=47, SD=16; Microphone has SCLK=17, WS=47, DIN=15 i2s_pins = { # Output (DAC/speaker) pins - 'sck': 2, # BCK - Bit Clock for DAC output + 'sck': 2, # MCLK / BCK - Bit Clock for DAC output 'ws': 47, # Word Select / LRCLK (shared between DAC and mic) 'sd': 16, # Serial Data OUT (speaker/DAC) # Input (microphone) pins @@ -311,8 +216,8 @@ i2s_pins = { 'sd_in': 15, # DIN - Serial Data IN (microphone) } -# Initialize AudioFlinger with I2S and buzzer -#AudioFlinger(i2s_pins=i2s_pins, buzzer_instance=buzzer) +# Initialize AudioFlinger with I2S (buzzer TODO) +AudioFlinger(i2s_pins=i2s_pins) # === LED HARDWARE === import mpos.lights as LightsManager @@ -323,7 +228,7 @@ LightsManager.init(neopixel_pin=12, num_leds=5) # === SENSOR HARDWARE === import mpos.sensor_manager as SensorManager -# Create I2C bus for IMU +# Create I2C bus for IMU (LSM6DSOTR-C / LSM6DSO) from machine import I2C imu_i2c = I2C(0, sda=Pin(9), scl=Pin(18)) SensorManager.init(imu_i2c, address=0x6A, mounted_position=SensorManager.FACING_EARTH) diff --git a/internal_filesystem/lib/mpos/hardware/drivers/wsen_isds.py b/internal_filesystem/lib/mpos/hardware/drivers/wsen_isds.py index 7f6f7be9..58938e85 100644 --- a/internal_filesystem/lib/mpos/hardware/drivers/wsen_isds.py +++ b/internal_filesystem/lib/mpos/hardware/drivers/wsen_isds.py @@ -104,7 +104,7 @@ class Wsen_Isds: 'reg': 0x5E, 'mask': 0b11110111, 'shift_left': 3, 'val_to_bits': {0: 0b00, 1: 0b01} }, - 'int1_on_int0': { + 'int1_on_int0': { # on the LSM6DSO, this is called "INT2_on_INT1" 'reg': 0x13, 'mask': 0b11011111, 'shift_left': 5, 'val_to_bits': {0: 0b00, 1: 0b01} },