# test of printing multiple fonts to the ILI9341 on an M5Stack using H/W SP # MIT License; Copyright (c) 2017 Jeffrey N. Magee from ili934xnew import ILI9341, color565 from machine import Pin, SPI,Timer from ST7735 import TFT import m5stack import tt14 import glcdfont import tt14 import tt24 import tt32 import uasyncio from rotary_irq_esp import RotaryIRQ fonts = [glcdfont,tt14,tt24,tt32] from sysfont import sysfont import json from enum import Enum class EditMenu(Enum): DEPOSIT = 1 COATING = 2 TIME = 3 def splash(): # display.fill(0) # display.fill_rect(0, 0, 32, 32, 1) # display.fill_rect(2, 2, 28, 28, 0) # display.vline(9, 8, 22, 1) # display.vline(16, 2, 22, 1) # display.vline(23, 8, 22, 1) # display.fill_rect(26, 24, 2, 4, 1) # display.text("MicroPython", 40, 0, 1) # display.text("SSD1306", 40, 12, 1) # display.text("OLED 128x64", 40, 24, 1) #display.fill(0) # display.text("SPIN", 34, 4, 1) # display.text("COATER", 50, 14, 1) # display.print("Spinner") # display.print("COATER") # tft.text((0,y),"Spin Coater",TFT.RED,sysfont,1,nowrap=True) display.print("Spincoater",size=1,nowrap=True) display.print("Spincoater",size=3,nowrap=True) # #display.show() # def tftprinttest(): # tft.fill(TFT.BLACK); # v = 30 # tft.text((0, v), "Hello World!", TFT.RED, sysfont, 1, nowrap=True) # v += sysfont["Height"] # tft.text((0, v), "Hello World!", TFT.YELLOW, sysfont, 2, nowrap=True) # v += sysfont["Height"] * 2 # tft.text((0, v), "Hello World!", TFT.GREEN, sysfont, 3, nowrap=True) # v += sysfont["Height"] * 3 # tft.text((0, v), str(1234.567), TFT.BLUE, sysfont, 4, nowrap=True) # time.sleep_ms(1500) # tft.fill(TFT.BLACK); # v = 0 # tft.text((0, v), "Hello World!", TFT.RED, sysfont) # v += sysfont["Height"] # tft.text((0, v), str(math.pi), TFT.GREEN, sysfont) # v += sysfont["Height"] # tft.text((0, v), " Want pi?", TFT.GREEN, sysfont) # v += sysfont["Height"] * 2 # tft.text((0, v), hex(8675309), TFT.GREEN, sysfont) # v += sysfont["Height"] # tft.text((0, v), " Print HEX!", TFT.GREEN, sysfont) # v += sysfont["Height"] * 2 # tft.text((0, v), "Sketch has been", TFT.WHITE, sysfont) # v += sysfont["Height"] # tft.text((0, v), "running for: ", TFT.WHITE, sysfont) # v += sysfont["Height"] # tft.text((0, v), str(time.ticks_ms() / 1000), TFT.PURPLE, sysfont) # v += sysfont["Height"] # tft.text((0, v), " seconds.", TFT.WHITE, sysfont) def start_view(state, rotary): display.set_pos(0,0) text="Spin Coater" display.print(text,size=2) #display.set_font(tt14) before = "> " if rotary.value() == 0 else " " display.print(before + "Edit") before = "> " if rotary.value() == 1 else " " display.print(before + "Start") #print(rotary.value()) def draw_edit_menu(state, rotary): display.print("Deposit speed:") display.print("{: >{w}} RPM".format(config["deposit_rpm"], w=5)) display.print("Coating speed:") display.print("{: >{w}} RPM".format(config["coating_rpm"], w=5)) display.print("Coating time:") display.print("{: >{w}} sec".format(config["coating_time"],w=2)) display.reset_pos() def edit_deposit_view(state, rotary): config["deposit_rpm"] = rotary.value() * 100 draw_edit_menu(state, rotary) def edit_coating_rpm_view(state, rotary): config["coating_rpm"] = rotary.value() * 100 draw_edit_menu(state, rotary) def edit_coating_time_view(state, rotary): config["coating_time"] = rotary.value() draw_edit_menu(state, rotary) def draw_rpm(rpm): display.print("RPM:{: >{w}.0f}".format(rpm, w=5)) def deposit_view(state, rotary): # display.fill_rect(0, 0, 127, 14, 1) display.text("Deposit") draw_rpm(state["rpm"]) display.text("Press to") display.text("continue") def coating_view(state, rotary): # display.fill_rect() display.text("Coating") draw_rpm(state["rpm"]) display.text("{: >{w}} sec".format(state["timer"], w=4)) def decode_ESC_telemetry(data, motor_poles=14): if len(data) > 10: # use latest telemetry data = data[-10:] temperature = int(data[0]) # degrees Celsius voltage = int((data[1] << 8) | data[2]) * 0.01 # Volt current = ( int((data[3] << 8) | data[4]) * 0.01 ) # Amps, only available if the ESC has a current meter consumption = int( (data[5] << 8) | data[6] ) # mAh, only available if the ESC has a current meter erpm = int((data[7] << 8) | data[8]) * 100 rpm = erpm / (motor_poles / 2) crc = data[9] print(" Temp (C):", temperature) print(" Voltage (V):", voltage) print(" Current (A):", current) print("Consumption (mAh):", consumption) print(" Erpm:", erpm) print(" RPM:", rpm) print(" CRC:", crc) print() return temperature, voltage, current, consumption, erpm, rpm async def update_display(): global state global rotary while True: display.fill(color565(0,0,0)) state["view"](state, rotary) # display.show() await uasyncio.sleep_ms(33) async def update_motor(): global state #we want to use 18 for the SPI-Bus! #https://docs.micropython.org/en/latest/esp32/quickref.html#hardware-spi-bus dshot = Dshot(pin=Pin(26)) rpm_pid = PID( Kp=config["PID"]["Kp"], Ki=config["PID"]["Ki"], Kd=config["PID"]["Kd"], setpoint=0, sample_time=None, output_limits=(0.0, 1.0), # proportional_on_measurement=True, ) while True: rpm_pid.setpoint = state["target_rpm"] # read ESC telemetry if uart.any() >= 10: telemetry = decode_ESC_telemetry(uart.read()) if telemetry is not None: state["rpm"] = telemetry[5] throttle = rpm_pid(state["rpm"]) # print( # "Throttle:", # throttle, # "pid components:", # rpm_pid.components, # "RPM:", # state["rpm"], # ) if state["target_rpm"] == 0 and state["rpm"] < 1000: throttle = 0 rpm_pid.reset() dshot.set_throttle(throttle) await uasyncio.sleep_ms(1) def debounce_button(p): p.irq(trigger=Pin.IRQ_FALLING, handler=None) # remove irq timer0 = Timer(0) timer0.init(period=20, mode=Timer.ONE_SHOT, callback=lambda t: on_button_press(p)) def on_button_press(p): p.irq(trigger=Pin.IRQ_FALLING, handler=debounce_button) # restore irq if p.value() == 1: # debounce return global state global config global rotary if state["view"] == start_view: if rotary.value() == 0: state["view"] = edit_deposit_view rotary.set( min_val=0, max_val=1000, range_mode=RotaryIRQ.RANGE_BOUNDED, value=int(0.01 * config["deposit_rpm"]), ) return if rotary.value() == 1: state["view"] = deposit_view state["target_rpm"] = config["deposit_rpm"] return if state["view"] == edit_deposit_view: state["view"] = edit_coating_rpm_view rotary.set( min_val=0, max_val=1000, range_mode=RotaryIRQ.RANGE_BOUNDED, value=int(0.01 * config["coating_rpm"]), ) return if state["view"] == edit_coating_rpm_view: state["view"] = edit_coating_time_view rotary.set( min_val=0, max_val=9999, range_mode=RotaryIRQ.RANGE_BOUNDED, value=config["coating_time"], ) return if state["view"] == edit_coating_time_view: save_config() rotary.set(min_val=0, max_val=1, range_mode=RotaryIRQ.RANGE_BOUNDED, value=0) state["view"] = start_view return if state["view"] == deposit_view: state["view"] = coating_view start_coating(state) return if state["view"] == coating_view: stop_coating() return def start_coating(state): global timer1 global timer2 state["timer"] = config["coating_time"] timer1.init( period=config["coating_time"] * 1000, mode=Timer.ONE_SHOT, callback=lambda t: stop_coating(), ) def decrement_timer(t): state["timer"] -= 1 timer2.init(period=1000, mode=Timer.PERIODIC, callback=decrement_timer) # state["throttle"] = 0.10 state["target_rpm"] = config["coating_rpm"] def stop_coating(): global state global rotary global timer1 global timer2 timer1.deinit() timer2.deinit() state["target_rpm"] = 0 rotary.set(min_val=0, max_val=1, range_mode=RotaryIRQ.RANGE_BOUNDED, value=0) state["view"] = start_view def save_config(): global config with open("config.json", "w") as f: json.dump(config, f) text = 'Now is the time for all good men to come to the aid of the party.' power = Pin(m5stack.TFT_LED_PIN, Pin.OUT) power.value(1) timer1 = Timer(1) timer2 = Timer(2) # No need to change the software. It's just a matter of different names.. Use this translation: # SDO(MISO) # LED BL # SCK CLK/SCK # SDI(MOSI) DIN/SDA # DC D/C (A0) # RESET RST # CS CS # GND GND # VCC VCC print("BOOOOOOTTT2T") spi = SPI( 2, baudrate=40000000, miso=Pin(m5stack.TFT_MISO_PIN), mosi=Pin(m5stack.TFT_MOSI_PIN), sck=Pin(m5stack.TFT_CLK_PIN)) # display = ILI9341( # spi, # cs=Pin(m5stack.TFT_CS_PIN), # dc=Pin(m5stack.TFT_DC_PIN), # rst=Pin(m5stack.TFT_RST_PIN), # w=160, # h=128, # r=5) tft = TFT(spi,m5stack.TFT_DC_PIN,m5stack.TFT_RST_PIN,m5stack.TFT_CS_PIN) display = tft tft.initr() tft.rgb(True) #tftprinttest() rotary = RotaryIRQ( pin_num_clk=25, pin_num_dt=13, min_val=0, max_val=1, range_mode=RotaryIRQ.RANGE_BOUNDED, pull_up=True, ) button = Pin(15, Pin.IN, Pin.PULL_UP) button.irq(trigger=Pin.IRQ_FALLING, handler=on_button_press) state = { "view": start_view, "rpm": 0, "target_rpm": 0, "timer": 0, "rotary_val":-1 } with open("config.json", "r") as f: config = json.load(f) #display.erase() #display.set_pos(0,0) #display.set_font(tt32) tft.fill(TFT.BLACK) splash() # for ff in fonts: # display.set_font(ff) # display.print(text) event_loop = uasyncio.get_event_loop() event_loop.create_task(update_display()) #event_loop.create_task(update_motor()) event_loop.run_forever()