22
33# TODO:
44# - touch screen / touch pad
5- # - IMU is different from fri3d_2024 (also address 0x6A instead of 0x6B)
5+ # - 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 )
66# - I2S audio (communicator) is the same
77# - headphone jack audio?
88# - headphone jack microphone?
1212# - digital buttons (X,Y,A,B, MENU)
1313# - buzzer
1414# - audio DAC emulation using buzzer might be slow or need specific buffered protocol
15+ # - test it on the Waveshare to make sure no syntax / variable errors
1516
1617from machine import Pin , SPI , SDCard
1718import st7789
3031import mpos .ui
3132import mpos .ui .focus_direction
3233
33-
34- # Pin configuration
35- SPI_BUS = 2
36- SPI_FREQ = 40000000
37- #SPI_FREQ = 20000000 # also works but I guess higher is better
38- LCD_SCLK = 7
39- LCD_MOSI = 6
40- LCD_MISO = 8
41- LCD_DC = 4
42- LCD_CS = 5
43- #LCD_BL = 1 # backlight can't be controlled on this hardware
44- LCD_RST = 48
45-
4634TFT_HOR_RES = 320
4735TFT_VER_RES = 240
4836
4937spi_bus = machine .SPI .Bus (
50- host = SPI_BUS ,
51- mosi = LCD_MOSI ,
52- miso = LCD_MISO ,
53- sck = LCD_SCLK
38+ host = 2 ,
39+ mosi = 6 ,
40+ miso = 8 ,
41+ sck = 7
5442)
5543display_bus = lcd_bus .SPIBus (
5644 spi_bus = spi_bus ,
57- freq = SPI_FREQ ,
58- dc = LCD_DC ,
59- cs = LCD_CS
45+ freq = 40000000 ,
46+ dc = 4 ,
47+ cs = 5
6048)
6149
6250# lv.color_format_get_size(lv.COLOR_FORMAT.RGB565) = 2 bytes per pixel * 320 * 240 px = 153600 bytes
8472 color_space = lv .COLOR_FORMAT .RGB565 ,
8573 color_byte_order = st7789 .BYTE_ORDER_BGR ,
8674 rgb565_byte_swap = True ,
87- reset_pin = LCD_RST , # doesn't seem needed
88- reset_state = STATE_LOW # doesn't seem needed
75+ reset_pin = 48 , # LCD reset: TODO: this is now on the CH32
76+ reset_state = STATE_LOW # TODO: is this correct?
8977)
9078
9179mpos .ui .main_display .init ()
9684# Touch handling:
9785# touch pad interrupt TP Int is on ESP.IO13
9886i2c_bus = i2c .I2C .Bus (host = I2C_BUS , scl = TP_SCL , sda = TP_SDA , freq = I2C_FREQ , use_locks = False )
99- touch_dev = i2c .I2C .Device (bus = i2c_bus , dev_id = TP_ADDR , reg_bits = TP_REGBITS )
87+ touch_dev = i2c .I2C .Device (bus = i2c_bus , dev_id = 0x15 , reg_bits = TP_REGBITS )
10088indev = cst816s .CST816S (touch_dev ,startup_rotation = lv .DISPLAY_ROTATION ._180 ) # button in top left, good
10189
10290lv .init ()
10391mpos .ui .main_display .set_rotation (lv .DISPLAY_ROTATION ._270 ) # must be done after initializing display and creating the touch drivers, to ensure proper handling
10492mpos .ui .main_display .set_params (0x36 , bytearray ([0x28 ]))
10593
106- # Button and joystick handling code:
94+ # Button handling code:
10795from machine import ADC , Pin
10896import time
10997
110- btn_x = Pin (38 , Pin .IN , Pin .PULL_UP ) # X
111- btn_y = Pin (41 , Pin .IN , Pin .PULL_UP ) # Y
112- btn_a = Pin (39 , Pin .IN , Pin .PULL_UP ) # A
113- btn_b = Pin (40 , Pin .IN , Pin .PULL_UP ) # B
11498btn_start = Pin (0 , Pin .IN , Pin .PULL_UP ) # START
115- btn_menu = Pin (45 , Pin .IN , Pin .PULL_UP ) # START
116-
117- ADC_KEY_MAP = [
118- {'key' : 'UP' , 'unit' : 1 , 'channel' : 2 , 'min' : 3072 , 'max' : 4096 },
119- {'key' : 'DOWN' , 'unit' : 1 , 'channel' : 2 , 'min' : 0 , 'max' : 1024 },
120- {'key' : 'RIGHT' , 'unit' : 1 , 'channel' : 0 , 'min' : 3072 , 'max' : 4096 },
121- {'key' : 'LEFT' , 'unit' : 1 , 'channel' : 0 , 'min' : 0 , 'max' : 1024 },
122- ]
123-
124- # Initialize ADC for the two channels
125- adc_up_down = ADC (Pin (3 )) # ADC1_CHANNEL_2 (GPIO 33)
126- adc_up_down .atten (ADC .ATTN_11DB ) # 0-3.3V range
127- adc_left_right = ADC (Pin (1 )) # ADC1_CHANNEL_0 (GPIO 36)
128- adc_left_right .atten (ADC .ATTN_11DB ) # 0-3.3V range
129-
130- def read_joystick ():
131- # Read ADC values
132- val_up_down = adc_up_down .read ()
133- val_left_right = adc_left_right .read ()
134-
135- # Check each key's range
136- for mapping in ADC_KEY_MAP :
137- adc_val = val_up_down if mapping ['channel' ] == 2 else val_left_right
138- if mapping ['min' ] <= adc_val <= mapping ['max' ]:
139- return mapping ['key' ]
140- return None # No key triggered
141-
142- # Rotate: UP = 0°, RIGHT = 90°, DOWN = 180°, LEFT = 270°
143- def read_joystick_angle (threshold = 0.1 ):
144- # Read ADC values
145- val_up_down = adc_up_down .read ()
146- val_left_right = adc_left_right .read ()
147-
148- #if time.time() < 60:
149- # print(f"val_up_down: {val_up_down}")
150- # print(f"val_left_right: {val_left_right}")
151-
152- # Normalize to [-1, 1]
153- x = (val_left_right - 2048 ) / 2048 # Positive x = RIGHT
154- y = (val_up_down - 2048 ) / 2048 # Positive y = UP
155- #if time.time() < 60:
156- # print(f"x,y = {x},{y}")
157-
158- # Check if joystick is near center
159- magnitude = math .sqrt (x * x + y * y )
160- #if time.time() < 60:
161- # print(f"magnitude: {magnitude}")
162- if magnitude < threshold :
163- return None # Neutral position
164-
165- # Calculate angle in degrees with UP = 0°, clockwise
166- angle_rad = math .atan2 (x , y )
167- angle_deg = math .degrees (angle_rad )
168- angle_deg = (angle_deg + 360 ) % 360 # Normalize to [0, 360)
169- return angle_deg
17099
171100# Key repeat configuration
172101# 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):
186115 data .continue_reading = False
187116 since_last_repeat = 0
188117
189- # Check buttons and joystick
118+ # Check buttons
190119 current_key = None
191120 current_time = time .ticks_ms ()
192121
193122 # Check buttons
194- if btn_x .value () == 0 :
195- current_key = lv .KEY .ESC
196- elif btn_y .value () == 0 :
197- current_key = ord ("Y" )
198- elif btn_a .value () == 0 :
199- current_key = lv .KEY .ENTER
200- elif btn_b .value () == 0 :
201- current_key = ord ("B" )
202- elif btn_menu .value () == 0 :
203- current_key = lv .KEY .HOME
204- elif btn_start .value () == 0 :
123+ if btn_start .value () == 0 :
205124 current_key = lv .KEY .END
206- else :
207- # Check joystick
208- angle = read_joystick_angle (0.30 ) # 0.25-0.27 is right on the edge so 0.30 should be good
209- if angle :
210- if angle > 45 and angle < 135 :
211- current_key = lv .KEY .RIGHT
212- elif angle > 135 and angle < 225 :
213- current_key = lv .KEY .DOWN
214- elif angle > 225 and angle < 315 :
215- current_key = lv .KEY .LEFT
216- elif angle < 45 or angle > 315 :
217- current_key = lv .KEY .UP
218- else :
219- print (f"WARNING: unhandled joystick angle { angle } " ) # maybe we could also handle diagonals?
220125
221126 # Key repeat logic
222127 if current_key :
@@ -294,7 +199,7 @@ def adc_to_voltage(adc_value):
294199from machine import PWM , Pin
295200from mpos import AudioFlinger
296201
297- # Initialize buzzer: sits on PC14/CC1 of the CH32X035GxUx
202+ # Initialize buzzer: now sits on PC14/CC1 of the CH32X035GxUx so needs custom code
298203#buzzer = PWM(Pin(46), freq=550, duty=0)
299204
300205# I2S pin configuration for audio output (DAC) and input (microphone)
@@ -303,16 +208,16 @@ def adc_to_voltage(adc_value):
303208# See schematics: DAC has BCK=2, WS=47, SD=16; Microphone has SCLK=17, WS=47, DIN=15
304209i2s_pins = {
305210 # Output (DAC/speaker) pins
306- 'sck' : 2 , # BCK - Bit Clock for DAC output
211+ 'sck' : 2 , # MCLK / BCK - Bit Clock for DAC output
307212 'ws' : 47 , # Word Select / LRCLK (shared between DAC and mic)
308213 'sd' : 16 , # Serial Data OUT (speaker/DAC)
309214 # Input (microphone) pins
310215 'sck_in' : 17 , # SCLK - Serial Clock for microphone input
311216 'sd_in' : 15 , # DIN - Serial Data IN (microphone)
312217}
313218
314- # Initialize AudioFlinger with I2S and buzzer
315- # AudioFlinger(i2s_pins=i2s_pins, buzzer_instance=buzzer )
219+ # Initialize AudioFlinger with I2S ( buzzer TODO)
220+ AudioFlinger (i2s_pins = i2s_pins )
316221
317222# === LED HARDWARE ===
318223import mpos .lights as LightsManager
@@ -323,7 +228,7 @@ def adc_to_voltage(adc_value):
323228# === SENSOR HARDWARE ===
324229import mpos .sensor_manager as SensorManager
325230
326- # Create I2C bus for IMU
231+ # Create I2C bus for IMU (LSM6DSOTR-C / LSM6DSO)
327232from machine import I2C
328233imu_i2c = I2C (0 , sda = Pin (9 ), scl = Pin (18 ))
329234SensorManager .init (imu_i2c , address = 0x6A , mounted_position = SensorManager .FACING_EARTH )
0 commit comments