Skip to content

Commit c3fdeb4

Browse files
committed
drv2605 support and fixes
1 parent 5e64f62 commit c3fdeb4

File tree

5 files changed

+122
-69
lines changed

5 files changed

+122
-69
lines changed

README.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,11 @@
1111
- MicroPython Human Interface Device library
1212
- png 'Pure Python PNG Reader/Writer'
1313
- itertools.py (required by png)
14-
- Compiling with T-Watch board folder for MPY from this repository (not strictly necessary, but let you use the full esp's flash and sets options that might do something)
14+
- DRV2605 driver from https://github.com/VynDragon/Adafruit_MicroPython_DRV2605
15+
- axp2101 and i2cinterface files from lewis he at: https://github.com/lewisxhe/XPowersLib/tree/master/Micropython/src
16+
- Compiling with T-Watch board folder for MPY from this repository
17+
### YOU CAN ALSO USE THE MODULES.TAR.GZ FILE IN THIS REPOSITORY
18+
1519

1620
## Installing:
1721
- Go to micropython folder from this repository and follow instructions

micropython/modules.tar.gz

16.9 KB
Binary file not shown.

programs/home.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,11 @@ def think(self):
4040
self.sleep_counter = 0
4141
if isinstance(event, Events.GestureEvent):
4242
if self.mode != 1 and event.gesture == 2:
43-
switchProgram(self.id)
43+
Single.Kernel.switchProgram(self.id)
4444
self.mode = 1
4545
elif self.mode == 1 and event.gesture == 3:
4646
self.mode = 0
47-
switchProgram()
47+
Single.Kernel.switchProgram()
4848
except IndexError:
4949
self.sleep_counter += 1
5050
if self.sleep_counter > self.cycle_sleep:

system/Hardware.py

Lines changed: 103 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,17 @@
55

66
import machine, micropython, json, time, _thread, network, os
77
import Logger
8-
import st7789, axp202, axp202_constants, ft6x36, pcf8563, bma423
8+
import st7789, axp202, axp202_constants, ft6x36, pcf8563, bma423, adafruit_drv2605
99
import TextMode
1010
import Events
1111
import esp, esp32
1212
import Single
1313

14+
WATCHV1 = int(0)
15+
WATCHV2 = int(1)
16+
WATCHV3 = int(2)
17+
WATCHS3 = int(3)
18+
1419
# Remember to write irq handlers for SPEED, we have SO MUCH RAM
1520
# also everything that has to do with hardware probably should be lbyl
1621

@@ -23,23 +28,16 @@ class Hardware:
2328

2429
def identify_version(self):
2530
try:
26-
self.pmu.disablePower(axp202_constants.AXP202_LDO3)
27-
touch = ft6x36.FT6x36(machine.SoftI2C(scl=machine.Pin(32, machine.Pin.OUT), sda=machine.Pin(23, machine.Pin.OUT), freq=100000))
28-
touch.power_mode = 0
29-
return 0 #V1
31+
drv_i2c = machine.SoftI2C(scl=machine.Pin(22, machine.Pin.OUT), sda=machine.Pin(21, machine.Pin.OUT), freq=100000)
32+
vibration_controller = adafruit_drv2605.DRV2605(drv_i2c)
3033
except OSError:
31-
pass
32-
self.pmu.setLDO3Voltage(3300)
33-
self.pmu.enablePower(axp202_constants.AXP202_LDO3)
34-
self.pmu.disablePower(axp202_constants.AXP202_EXTEN); # reset touch
35-
time.sleep_ms(10)
36-
self.pmu.enablePower(axp202_constants.AXP202_EXTEN);
37-
touch = ft6x36.FT6x36(machine.SoftI2C(scl=machine.Pin(32, machine.Pin.OUT), sda=machine.Pin(23, machine.Pin.OUT), freq=100000))
38-
touch.power_mode = 0
39-
return 1 #V2
34+
return WATCHV1
35+
if "S3" in os.uname()[4]:
36+
return WATCHS3 #S3
37+
return WATCHV2 #V2
4038

4139
def init_ft6336(self):
42-
if self.WatchVersion == 1:
40+
if self.WatchVersion == WATCHV2:
4341
self.pmu.disablePower(axp202_constants.AXP202_EXTEN); # reset touch
4442
time.sleep_ms(15)
4543
self.pmu.enablePower(axp202_constants.AXP202_EXTEN);
@@ -63,36 +61,37 @@ def init_st7789(self):
6361
# shameful display of 3 wire SPI and slow updates
6462
# why not 2-line or 4-line SPI lilygo?
6563
# also uses wrong MOSI pin, slowing it down even more, fixed on TWATCH S3
66-
cs = machine.Pin(5, machine.Pin.OUT)
67-
dc = machine.Pin(27, machine.Pin.OUT)
68-
if self.WatchVersion == 1:
64+
if self.WatchVersion == WATCHV2:
65+
cs = machine.Pin(5, machine.Pin.OUT)
66+
dc = machine.Pin(27, machine.Pin.OUT)
6967
display_spi = machine.SPI(1,baudrate=40000000,sck=machine.Pin(18, machine.Pin.OUT),mosi=machine.Pin(19, machine.Pin.OUT)) # will only work with modded MPY to add flag for dummy bit, otherwise use baudrate 27000000, ESP32 limit is 80Mhz
7068
self.display = st7789.ST7789(display_spi, Hardware.DISPLAY_WIDTH, Hardware.DISPLAY_HEIGHT, cs=cs, dc=dc, backlight=machine.Pin(25, machine.Pin.OUT), rotation=2, buffer_size=Hardware.DISPLAY_WIDTH*Hardware.DISPLAY_HEIGHT*2,)
69+
elif self.WatchVersion == WATCHS3:
70+
cs = machine.Pin(12, machine.Pin.OUT)
71+
dc = machine.Pin(38, machine.Pin.OUT)
72+
display_spi = machine.SPI(0,baudrate=80000000,sck=machine.Pin(18, machine.Pin.OUT),mosi=machine.Pin(13, machine.Pin.OUT)) # will only work with modded MPY to add flag for dummy bit, otherwise use baudrate 27000000, ESP32 limit is 80Mhz
73+
self.display = st7789.ST7789(display_spi, Hardware.DISPLAY_WIDTH, Hardware.DISPLAY_HEIGHT, cs=cs, dc=dc, backlight=machine.Pin(45, machine.Pin.OUT), rotation=2, buffer_size=Hardware.DISPLAY_WIDTH*Hardware.DISPLAY_HEIGHT*2,)
7174
else:
75+
cs = machine.Pin(5, machine.Pin.OUT)
76+
dc = machine.Pin(27, machine.Pin.OUT)
7277
display_spi = machine.SPI(1,baudrate=80000000,sck=machine.Pin(18, machine.Pin.OUT),mosi=machine.Pin(19, machine.Pin.OUT)) # will only work with modded MPY to add flag for dummy bit, otherwise use baudrate 27000000, ESP32 limit is 80Mhz
7378
self.display = st7789.ST7789(display_spi, Hardware.DISPLAY_WIDTH, Hardware.DISPLAY_HEIGHT, cs=cs, dc=dc, backlight=machine.Pin(12, machine.Pin.OUT), rotation=2, buffer_size=Hardware.DISPLAY_WIDTH*Hardware.DISPLAY_HEIGHT*2,)
7479
self.display.init()
7580
self.display.on()
7681
#self.display.fill(st7789.BLACK)
82+
Logger.log("Hi! Display initialized.")
7783

78-
def __init__(self):
79-
self.WatchVersion = 0 # V1
80-
self.hardware = []
84+
def init_axp202(self):
85+
Logger.log("Initializing AXP202 PMU...")
8186
sObject = Single.Settings.getSettingObject(Single.Settings.hardware)
8287
if sObject == None:
8388
sObject = {}
84-
Logger.log("Initializing Hardware...")
85-
machine.freq(240000000)
86-
87-
88-
Logger.log("Initializing AXP202 PMU...")
89-
# BackLight Poweif fb[i*2*DISPLAY_HEIGHT + j*2] > 0 or fb[i*2*DISPLAY_HEIGHT + j*2 + 1] > 0:r
9089
self.pmu = axp202.PMU()
91-
self.pmu.enablePower(axp202.AXP202_LDO2)
9290
if sObject.get("BacklightVoltage") != None:
9391
self.pmu.setLDO2Voltage(sObject["BacklightVoltage"])
9492
else:
9593
self.pmu.setLDO2Voltage(2800) #default backlight level todo: load from settings (or load it from app 0)
94+
self.pmu.enablePower(axp202_constants.AXP202_LDO2)
9695
self.pmu.setDC3Voltage(Hardware.Vc3V3)
9796
'''very low 3.3v rail to minimize power consumption,
9897
esp can go down to 2.3v (and might be fine down to 1.8v too)
@@ -105,7 +104,8 @@ def __init__(self):
105104
mic: 1.6v
106105
psram: 2.7v :(
107106
'''
108-
self.pmu.disablePower(axp202_constants.AXP202_LDO3) # on V2, Touch+ TFT
107+
if self.WatchVersion != WATCHV2:
108+
self.pmu.disablePower(axp202_constants.AXP202_LDO3) # on V2, Touch+ TFT
109109
self.pmu.disablePower(axp202_constants.AXP202_LDO4) # on V2, GPS
110110
self.pmu.disablePower(axp202_constants.AXP202_DCDC2)
111111
self.pmu.clearIRQ()
@@ -121,23 +121,60 @@ def __init__(self):
121121
#self.pmu.setlongPressTime(axp202_constants.AXP_LONGPRESS_TIME_2S)
122122
#self.pmu.setTimeOutShutdown(True)
123123
#self.pmu.enableIRQ(axp202_constants.AXP202_ALL_IRQ)
124-
125124
self.pmu.setChargingTargetVoltage(axp202_constants.AXP202_TARGET_VOL_4_2V) # sane voltage values for battery management
125+
if self.WatchVersion == WATCHV2:
126+
self.pmu.setLDO3Voltage(3300)
127+
self.pmu.enablePower(axp202_constants.AXP202_LDO3)
128+
self.pmu.write_byte(axp202_constants.AXP202_GPIO0_CTL, 1) # everything to 0 except first byte, enable GPIO as high so it desinhibit DRV2605... why was this necessary, and only on V2 ?
129+
130+
def init_irq(self):
131+
pin38 = machine.Pin(38, machine.Pin.IN) #irq touch
132+
pin37 = machine.Pin(37, machine.Pin.IN) #irq external rtc
133+
pin39 = machine.Pin(39, machine.Pin.IN) #irq IMU
134+
pin35 = machine.Pin(35, machine.Pin.IN) #irq axp202
135+
#esp32.wake_on_ext1((pin35, pin39, pin38, pin37), esp32.WAKEUP_ANY_HIGH)
136+
#esp32.wake_on_ext0(pin35, esp32.WAKEUP_ALL_LOW)
137+
pin35.irq(self.irq_pmu, trigger=machine.Pin.IRQ_FALLING, wake=machine.DEEPSLEEP | machine.SLEEP)
138+
pin38.irq(self.irq_touch, trigger= machine.Pin.IRQ_RISING)
139+
pin39.irq(self.irq_imu, trigger= machine.Pin.IRQ_RISING, wake=machine.DEEPSLEEP | machine.SLEEP)
140+
#print("pin 39 is", pin39.value())
141+
142+
self.irq_touch_buffer_pos1 = bytearray(4) #pre-allocation
143+
self.irq_touch_buffer_pos2 = bytearray(4)
144+
self.irq_touch_present = False
145+
#self.irq_touch_time = 0
146+
#self.irq_touch_fired_release = True
147+
148+
def init_irq_s3(self):
149+
pin16 = machine.Pin(16, machine.Pin.IN) #irq touch
150+
pin17 = machine.Pin(17, machine.Pin.IN) #irq external rtc
151+
pin14 = machine.Pin(14, machine.Pin.IN) #irq IMU
152+
pin21 = machine.Pin(21, machine.Pin.IN) #irq axp2101
153+
pin21.irq(self.irq_pmu, trigger=machine.Pin.IRQ_FALLING, wake=machine.DEEPSLEEP | machine.SLEEP)
154+
pin16.irq(self.irq_touch, trigger= machine.Pin.IRQ_RISING)
155+
pin14.irq(self.irq_imu, trigger= machine.Pin.IRQ_RISING, wake=machine.DEEPSLEEP | machine.SLEEP)
156+
157+
self.irq_touch_buffer_pos1 = bytearray(4) #pre-allocation
158+
self.irq_touch_buffer_pos2 = bytearray(4)
159+
self.irq_touch_present = False
160+
161+
def __init__(self):
162+
self.WatchVersion = 0 # V1
163+
self.hardware = []
164+
Logger.log("Initializing Hardware...")
165+
machine.freq(240000000)
126166

127167
self.WatchVersion = self.identify_version()
128168
self.display_lock = _thread.allocate_lock() # for locking render while we sleep, notably on V2 watch where we need to re-initialize at wake up
129169
self.display_lock.acquire()
130-
131-
if self.WatchVersion == 1:
132-
self.pmu.setLDO3Voltage(3300)
133-
self.pmu.enablePower(axp202_constants.AXP202_LDO3)
134-
time.sleep_ms(10)
135-
136-
Logger.log("Initializing firmware pre-init graphics.")
170+
if self.WatchVersion < WATCHS3:
171+
self.init_axp202()
172+
time.sleep_ms(20)
173+
else:
174+
self.init_axp2101()
137175

138176
self.init_st7789()
139177

140-
Logger.log("Hi! Display initialized.")
141178
Logger.log("CPU frequ: " + str(machine.freq()))
142179
Logger.log("Flash Size: " + str(esp.flash_size()))
143180
Logger.log("Unique ID: " + str(int.from_bytes(machine.unique_id(), 'big', False)))
@@ -204,29 +241,21 @@ def __init__(self):
204241

205242
self.gesture_startpos = (0,0) # gesture emulation
206243

207-
pin38 = machine.Pin(38, machine.Pin.IN) #irq touch
208-
pin37 = machine.Pin(37, machine.Pin.IN) #irq external rtc
209-
pin39 = machine.Pin(39, machine.Pin.IN) #irq IMU
210-
pin35 = machine.Pin(35, machine.Pin.IN) #irq axp202
211-
#esp32.wake_on_ext1((pin35, pin39, pin38, pin37), esp32.WAKEUP_ANY_HIGH)
212-
#esp32.wake_on_ext0(pin35, esp32.WAKEUP_ALL_LOW)
213-
pin35.irq(self.irq_pmu, trigger=machine.Pin.IRQ_FALLING, wake=machine.DEEPSLEEP | machine.SLEEP)
214-
pin38.irq(self.irq_touch, trigger= machine.Pin.IRQ_RISING)
215-
pin39.irq(self.irq_imu, trigger= machine.Pin.IRQ_RISING, wake=machine.DEEPSLEEP | machine.SLEEP)
216-
#print("pin 39 is", pin39.value())
217-
218-
self.irq_touch_buffer_pos1 = bytearray(4) #pre-allocation
219-
self.irq_touch_buffer_pos2 = bytearray(4)
220-
self.irq_touch_present = False
221-
#self.irq_touch_time = 0
222-
#self.irq_touch_fired_release = True
244+
if self.WatchVersion < WATCHS3:
245+
self.init_irq()
246+
else:
247+
self.init_irq_s3()
223248

224-
#self.oldfb = bytearray(DISPLAY_WIDTH * DISPLAY_HEIGHT * 2)
225249

226250
self.wifi_lock = _thread.allocate_lock()
227251
self.wifi = None
228252

229-
self.vibrator = machine.Pin(4, machine.Pin.OUT)
253+
if self.WatchVersion == WATCHV1 or self.WatchVersion == WATCHV3:
254+
self.vibrator = machine.Pin(4, machine.Pin.OUT)
255+
else:
256+
self.vibration_controller = adafruit_drv2605.DRV2605(sensor_i2c)
257+
self.vibration_controller.mode = adafruit_drv2605.MODE_REALTIME # i really cant be bothered lol drv looks like it has nice functions but i have other priorities rn
258+
self.vibrator = None
230259

231260
machine.freq(80000000) #todo: set to user value (give a slider with choice between 240, 160, and 80 mhz?)
232261
self.display_lock.release()
@@ -263,7 +292,8 @@ def lightsleep(self, time_ms, force = False, callback = None):
263292
self.display.off()
264293
self.display.sleep_mode(True)
265294
self.pmu.disablePower(axp202_constants.AXP202_LDO2)
266-
self.pmu.disablePower(axp202_constants.AXP202_LDO3) # shutdown full LCD in case of V2 watch
295+
if self.WatchVersion == WATCHV2:
296+
self.pmu.disablePower(axp202_constants.AXP202_LDO3) # shutdown full LCD in case of V2 watch
267297
self.pmu.disablePower(axp202_constants.AXP202_LDO4)
268298
self.pmu.disablePower(axp202_constants.AXP202_DCDC2)
269299
self.pmu.clearIRQ()
@@ -275,19 +305,19 @@ def lightsleep(self, time_ms, force = False, callback = None):
275305
# monitor mode low rate of update good workaround?
276306
should_sleep = True
277307
while should_sleep:
278-
if self.WatchVersion == 0:
308+
if self.WatchVersion == WATCHV1:
279309
self.touch.monitor_period = 254 # low refresh? Seems to work (datasheet says 25 time a second and default value is 40, i suppose that's milliseconds)
280310
self.touch.power_mode = 1
281311
machine.lightsleep(time_ms)
282312
if callback != None:
283313
should_sleep = callback()
284314
else:
285315
should_sleep = False
286-
if self.WatchVersion == 0:
316+
if self.WatchVersion == WATCHV1:
287317
self.touch.power_mode = 0
288318
self.pmu.setDC3Voltage(Hardware.Vc3V3)
289319
self.pmu.enablePower(axp202_constants.AXP202_LDO2)
290-
if self.WatchVersion == 1:
320+
if self.WatchVersion == WATCHV2:
291321
self.pmu.setLDO3Voltage(3300)
292322
self.pmu.enablePower(axp202_constants.AXP202_LDO3)
293323
time.sleep_ms(20) # wait for potaaytoes to be warmed up
@@ -304,15 +334,24 @@ def blit_buffer_rgb565(self, array):
304334
# seems like to get more speed would need to do quite a lot on the C side of things
305335

306336
def feedback1(self):
307-
self.vibrator.on()
337+
if self.vibrator:
338+
self.vibrator.on()
339+
elif self.vibration_controller:
340+
self.vibration_controller.realtime_value = 127
308341
machine.Timer(3, mode=machine.Timer.ONE_SHOT, period=20, callback=self.feedback_frame)
309342

310343
def feedback2(self):
311-
self.vibrator.on()
344+
if self.vibrator:
345+
self.vibrator.on()
346+
elif self.vibration_controller:
347+
self.vibration_controller.realtime_value = 127
312348
machine.Timer(3, mode=machine.Timer.ONE_SHOT, period=50, callback=self.feedback_frame)
313349

314350
def feedback_frame(self, _):
315-
self.vibrator.off()
351+
if self.vibrator:
352+
self.vibrator.off()
353+
elif self.vibration_controller:
354+
self.vibration_controller.realtime_value = 0
316355

317356
def sync_ntp(self):
318357
try:
@@ -386,7 +425,7 @@ def irq_touch(self, pin):
386425
#self.irq_touch_fired_release = False
387426
self.irq_touch_time = time.ticks_ms()
388427
except OSError as e:
389-
if self.WatchVersion != 1: # that's a possibility on V2 because we cant check lock in irq without causing issues so we do EAFP, since it's only a problem when going to sleep
428+
if self.WatchVersion != WATCHV2: # that's a possibility on V2 because we cant check lock in irq without causing issues so we do EAFP, since it's only a problem when going to sleep
390429
print(e)
391430
except Exception as e:
392431
print("we shaint be there... And it's not okay, you might need to reboot(touch irq)")

system/Kernel.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -132,8 +132,18 @@ def stopProgram(self, id = None):
132132

133133
def switchProgram(self, id = -1): # switches back to 'last' program by default
134134
# todo add a thing to not switch away from keyboard
135-
self.running_front = id
136-
return True
135+
if id == -1:
136+
self.running_front = id
137+
return True
138+
self.running_lock.acquire()
139+
if len(self.running) > 0:
140+
for x in range(0, len(self.running)):
141+
if self.running[x].id == id:
142+
self.running_lock.release()
143+
self.running_front = x
144+
return True
145+
self.running_lock.release()
146+
return False
137147

138148

139149

0 commit comments

Comments
 (0)