diff --git a/python_payload/apps/demo_worms.py b/python_payload/apps/demo_worms.py
index 2231c077b73cf30614b8a0c7db2371a933464964..e4009551592d76f6d41d31b4ad23325fb38acc3f 100644
--- a/python_payload/apps/demo_worms.py
+++ b/python_payload/apps/demo_worms.py
@@ -72,7 +72,7 @@ class AppWorms(application.Application):
         self.last_render = now
 
     def handle_input(self,data):
-        worms = app.worms
+        worms = self.worms
         worms.append(Worm(data.get("index",0)*2*math.pi/10+math.pi ))
         if len(worms)>10:
             worms.pop(0)
diff --git a/python_payload/apps/flow3r/__init__.py b/python_payload/apps/flow3r/__init__.py
index 3f6aa3969f3404cdd25b08de5f59458a96043663..f96eb2b44d0ed3e493f25b717ea9ee7419b1b1df 100644
--- a/python_payload/apps/flow3r/__init__.py
+++ b/python_payload/apps/flow3r/__init__.py
@@ -1,10 +1,16 @@
-from st3m.application import Application,menu
+from st3m import logging
+log = logging.Log(__name__,level=logging.INFO)
+log.info(f"running {__name__}")
+from st3m.application import Application
+log.info(f"import app")
 from . import menu_main
+log.info(f"import menu")
+
 class myApp(Application):
     def on_init(self):
         self.menu = menu_main.get_menu()
 
     def on_foreground(self):
-        menu.set_active_menu(self.menu)
+        self.menu.start()
 
-app=myApp("flow3r")
+app=myApp("flow3r", exit_on_menu_enter=False)
diff --git a/python_payload/apps/flow3r/menu_main.py b/python_payload/apps/flow3r/menu_main.py
index 5fb3177c42c1b14313b1969adb72d738719e24a0..9aa7e1c0f2af8170aa05bde084213025963dd0ae 100644
--- a/python_payload/apps/flow3r/menu_main.py
+++ b/python_payload/apps/flow3r/menu_main.py
@@ -13,7 +13,7 @@ def get_menu():
     menu_apps = menu.Menu("apps")
     menu_music = menu.Menu("music")
 
-
+    #Skipping for mem constraints
     #for app_module in [demo_sparabo,melodic_demo,harmonic_demo]:
     #    menu_music.add(menu.MenuItemApp(app_module.app))
 
diff --git a/python_payload/main.py b/python_payload/main.py
index 49f8af1acb866900bd10fb1d996340c4a1adca24..17ff616650da93a90c2e7c5817be62d2f2739f5f 100644
--- a/python_payload/main.py
+++ b/python_payload/main.py
@@ -1,9 +1,27 @@
-from st3m.system import hardware,audio
+import gc,time
+from st3m import logging
+log = logging.Log(__name__,level=logging.INFO)
+log.info(f"starting main")
+from st3m import control,application,ui,menu
+gc.collect()
+time.sleep_ms(100)
+log.info(f"free memory: {gc.mem_free()}")
 from apps import flow3r
+log.info(f"free memory: {gc.mem_free()}")
+log.info("import apps done")
+
+gc.collect()
+
+
 
 #TODO persistent settings
+from st3m.system import hardware,audio
+log.info("calibrating captouch, reset volume")
 hardware.captouch_autocalib()
 audio.set_volume_dB(0)
 
 #Start default app
-flow3r.app.run()
\ No newline at end of file
+default_app = flow3r.app
+
+#log.info(f"running default app '{default_app.title}'")
+default_app.run()
\ No newline at end of file
diff --git a/python_payload/st3m/application.py b/python_payload/st3m/application.py
index 45c8aef0b0ea70c90c270d55a091fa91f3d5de53..97ec2cf7d3030abb4e0b8567a8dad71b3c35be44 100644
--- a/python_payload/st3m/application.py
+++ b/python_payload/st3m/application.py
@@ -1,3 +1,6 @@
+from st3m import logging
+log = logging.Log(__name__,level=logging.INFO)
+log.info("import")
 from . import ui,event,menu
 
 STATE_OFF = 0
@@ -6,9 +9,10 @@ STATE_BACKGROUND = 200
 STATE_FOREGROUND = 300
 STATE_ERROR = 500
 
-
+log.info("setting up application")
 class Application():
-    def __init__(self,title="badge23 app", author="someone@earth"):
+    def __init__(self,title="badge23 app", author="someone@earth", exit_on_menu_enter=True):
+        log.info(f"__init__ app '{title}'")
         self.title = title
         self.author = author
         self.state = STATE_OFF
@@ -20,21 +24,19 @@ class Application():
         self.icon = ui.Icon(label=self.title, size=100)
         self.engine = event.the_engine
         self.menu = None
-
-        self.add_event(event.Event(
-                name="exit",
-            action=self.exit,
-            condition=lambda e: e["type"]=="button" and e.get("from")==2 and e["change"]
-        ))
+        if exit_on_menu_enter:
+            self.add_event(event.Event(
+                    name="exit",
+                action=self.exit,
+                condition=lambda e: e["type"]=="button" and e.get("from")==2 and e["change"]
+            ))
         
     def __repr__(self):
         return "App "+self.title
     def init(self):
-        print("INIT")
+        log.info(f"init app '{self.title}'")
         self.state = STATE_INIT
-        print("before on_init")
         self.on_init()
-        print("after on_init")
         if self.has_background:
             if self._events_background:
                 self._set_events(self._events_background,True)
@@ -42,25 +44,25 @@ class Application():
 
 
     def run(self):
-        print ("RUN from",self.state)
+        log.info(f"run app '{self.title}' from state {self.state}")
         if self.state == STATE_OFF:
-            print("go init")
+            log.info("from STATE_OFF, doing init()")
             self.init()
-        
         if self.has_foreground:
             self._to_foreground()
         elif self.has_background:
             self._to_background()
-            print ("App {} has no foreground, running in background".format(self.title))
         else:
-            print("App has neither foreground nor background, not doing anything")
+            log.warning(f"App {self.title} has neither foreground nor background, not doing anything")
 
         #start the eventloop if it is not already running
-        event.the_engine.eventloop()
+        if not event.the_engine.is_running:
+            log.info("eventloop not yet running, starting")
+            event.the_engine.eventloop()
 
         
     def exit(self,data={}):
-        print("EXIT")
+        log.info(f"exit app '{self.title}' from state {self.state}")
         self.on_exit()
         if self.state == STATE_FOREGROUND:
             self._to_background()
@@ -68,6 +70,7 @@ class Application():
     
     def kill(self):
         #disable all events
+        log.info(f"kill app '{self.title}' from state {self.state}")
         engine.register_service_loop(self.main_always,False)
         
         engine.foreground_app = None
@@ -92,9 +95,9 @@ class Application():
         return self.state == STATE_FOREGROUND
 
     def _to_foreground(self):
-        print ("to foreground", self)
+        log.info(f"to_foreground app '{self.title}' from state {self.state}")
         if not self.has_foreground:
-            #TODO log
+            log.error(f"app has no foreground!")
             return
         
         if self._events_background:
@@ -105,10 +108,10 @@ class Application():
             self._set_events(self._events_foreground,True)
         self.on_foreground()
         
-        #self.engine.register_main_loop(self.main_foreground,True)
         self.engine.foreground_app = self
           
     def _to_background(self):
+        log.info(f"to_background app '{self.title}' from state {self.state}")
         self.state = STATE_BACKGROUND
         if self._events_foreground:
             self._set_events(self._events_foreground,False)
@@ -123,25 +126,24 @@ class Application():
             e.set_enabled(enabled)
 
     def on_init(self):
-        print("nothing to init")
-        pass
+        log.info(f"app {self.title}: on_init()")
 
     def on_foreground(self):
-        pass
+        log.info(f"app {self.title}: on_foreground()")
 
     def on_background(self):
-        pass
+        log.info(f"app {self.title}: on_background()")
     
     def on_exit(self):
-        pass
+        log.info(f"app {self.title}: on_exit()")
 
     def on_kill(self): 
-        pass
+        log.info(f"app {self.title}: on_kill()")
 
     def on_draw(self):
         #self.ui.ctx.rgb(*ui.RED).rectangle(-120,-120,120,120).fill()
         #self.icon.draw()
-        pass
+        log.debug(f"app {self.title}: on_draw()")
 
     def main_foreground(self):
         pass
diff --git a/python_payload/st3m/control.py b/python_payload/st3m/control.py
index fe3febc9a68a8ae410256f2d6e86226dcd5d7376..59663340e78c19f5956cb2e8abcae101c880beaa 100644
--- a/python_payload/st3m/control.py
+++ b/python_payload/st3m/control.py
@@ -1,3 +1,7 @@
+from st3m import logging
+log = logging.Log(__name__,level=logging.INFO)
+log.info("import")
+
 from . import ui
 
 class Control():
@@ -15,7 +19,6 @@ class Control():
 
     def draw(self):
         self.ui.value = self.get_value()
-        print("draw: value", self.get_value())
         self.ui.draw()
 
     def get_normal_value(self):
@@ -70,10 +73,14 @@ class ControlFloat(Control):
     def get_normal_value(self):
         v = self.get_value()
         n = (v-self.min)/(self.max-self.min)
-        #print("normal:",v,n)
         return n
 
 class ControlKnob(ControlFloat):
+    def __init__(self, *args, **kwargs):
+        super().__init__(*args, **kwargs)
+        self._x_init = 0
+        self._touch_started_here = False
+
     def enter(self):
         #repeat action with current value
         self.set_value(self.get_value())
@@ -93,13 +100,16 @@ class ControlKnob(ControlFloat):
     def touch_1d(self,x,z):
         if z>0: #Inital Contact
             self._x_init = x
+            self._touch_started_here=True
 
         if z==0: #Continous contact
+            if not self._touch_started_here: 
+                return
             diff = self._x_init-x
             self.scroll(5*diff)
             
         if z<0: #Release
-            pass
+            self._touch_started_here = False
 
 
 class ControlSlide(ControlFloat):
@@ -114,7 +124,7 @@ class ControlSlide(ControlFloat):
         if z==0: #Continous contact
             v = (self.max-self.min)*x+self.min
             self.set_value(v)
-            print("c",x,v,self.max,self.min)
+            #print("c",x,v,self.max,self.min)
 
         if z<0: #Release
             if self.do_reset:
diff --git a/python_payload/st3m/event.py b/python_payload/st3m/event.py
index 6aa5f8be947261b9d28beda0e50f62d6a20089f4..a7fd51e40708c08f218a0c832760033c251e7073 100644
--- a/python_payload/st3m/event.py
+++ b/python_payload/st3m/event.py
@@ -1,4 +1,9 @@
-import hardware
+from st3m import logging
+log = logging.Log(__name__,level=logging.INFO)
+log.info("import")
+
+from st3m.system import hardware
+
 import time 
 import math
 import random
@@ -47,15 +52,6 @@ class Engine():
     def remove_input(self,group_id):
         self.events_input = [event for event in self.events_input if event.group_id!=group_id]
 
-    def register_main_loop(self,loop,enable=True):
-        if enable:
-            #print ("new userloop",loop)
-            #loop()
-            self.userloop = loop
-        elif self.userloop == loop:
-            #print ("removed userloop")
-            self.userloop = None
-
     def _sort_timed(self):
         self.events_timed = sorted(self.events_timed, key = lambda event: event.deadline)
 
@@ -149,11 +145,10 @@ class Engine():
         
         
     def eventloop(self):
+        log.info("starting eventloop")
         if self.is_running:
-            print ("eventloop already running")
+            log.warning("eventloop already running, doing nothing")
             return
-        else:
-            print("eventloop started")
         self.is_running=True
         last_draw = 0
         while self.is_running:
@@ -190,7 +185,7 @@ class Event():
             
         
     def trigger(self,triggerdata={}):
-        print ("triggered {} (with {})".format(self.name,triggerdata))
+        log.debug("triggered {} (with {})".format(self.name,triggerdata))
         if not self.action is None:
             triggerdata.update(self.data)
             self.action(triggerdata)
@@ -203,12 +198,12 @@ class Event():
             self.remove()
 
     def remove(self):
-        print ("remove",self)
+        log.info(f"remove {self}")
         while self in the_engine.events_input:
-            print ("from input")
+            #print ("from input")
             the_engine.events_input.remove(self)
         while self in the_engine.events_timed:
-            print("from timed")
+            #print("from timed")
             the_engine.events_timed.remove(self)
             the_engine._sort_timed()
 
@@ -245,7 +240,7 @@ class Sequence():
         self.is_running = False
         
         if not action:
-            self.action = lambda data: print("step {}".format(data.get("step")))
+            self.action = lambda data: log.info("step {}".format(data.get("step")))
         else:
             self.action = action
     
@@ -253,7 +248,7 @@ class Sequence():
         if self.is_running: self.stop()
         stepsize_ms = int(60*1000/self.bpm)
         for i in range(self.steps):
-            print("adding sequence event ", i)
+            log.debug("adding sequence event ", i)
             self.events.append(EventTimed(stepsize_ms*i,name="seq{}".format(i),action=self.action, data={'step':i}, group_id=self.group_id,enabled=True))
         if self.loop:
             self.repeat_event=EventTimed(stepsize_ms*self.steps,name="loop", group_id=self.group_id, enabled=True, action=on_restart, data={"object":self})
@@ -261,7 +256,7 @@ class Sequence():
     
     def stop(self):
         #for e in self.events: e.remove()
-        print("sequence stop")
+        log.info("sequence stop")
         the_engine.remove_timed(group_id=self.group_id)
         self.events = []
         if self.repeat_event: self.repeat_event.remove()
diff --git a/python_payload/st3m/menu.py b/python_payload/st3m/menu.py
index f3c2c57395d23a9b2ce37f471a3a989579346ae7..0749abbe4ea05c0bf66dee819617cef1c5f1adef 100644
--- a/python_payload/st3m/menu.py
+++ b/python_payload/st3m/menu.py
@@ -1,5 +1,8 @@
+from st3m import logging
+log = logging.Log(__name__,level=logging.INFO)
+log.info("import")
+
 from . import ui,event
-import hardware
 
 
 import time
@@ -41,7 +44,7 @@ class Menu():
         self.ui.children.pop()
 
     def start(self):
-        print(self)
+        log.info(f"starting menu {self.name}")
         set_active_menu(self)
 
     def scroll(self, n=0):
@@ -119,7 +122,7 @@ class MenuItem():
         return "item: {} (action: {})".format(self.name,"?")
 
     def enter(self,data={}):
-        print("Enter MenuItem {}".format(self.name))
+        log.info("enter MenuItem {}".format(self.name))
         if self.action:
             self.action(data)
 
@@ -142,8 +145,9 @@ class MenuItemSubmenu(MenuItem):
         self.target = submenu
     
     def enter(self,data={}):
-        print("Enter Submenu {}".format(self.target.name))
         menu_stack.append(get_active_menu())
+        log.info(f"enter submenu {self.target.name} (Stack: {len(menu_stack)})")
+
         set_active_menu(self.target)
         
 class MenuItemBack(MenuItem):
@@ -161,7 +165,7 @@ class MenuItemControl(MenuItem):
         self.ui=control.ui
 
     def enter(self):
-        print("menu enter")
+        log.info(f"item {self.name} (MenuItemControl): enter")
         self.control.enter()
 
     def scroll(self,delta):
@@ -178,7 +182,6 @@ def on_scroll(d):
     if d["index"]==0:#right button
         hovered=active_menu.get_hovered_item()
         if hasattr(hovered, "scroll"):
-            print("has_scroll")
             hovered.scroll(d["value"])
 
     else: #index=1, #left button
@@ -199,7 +202,6 @@ def on_scroll_captouch(d):
     return
     if abs(d["radius"]) < 10000:
         return
-    print(d["angle"])
     active_menu.rotate_to(d["angle"]+math.pi)
 
 def on_release(d):
@@ -217,14 +219,14 @@ def on_touch_1d(d):
     
     if active_menu is None:
         return
-    #print(d["radius"])
+
     v = min(1.0,max(0.0,((d["radius"]+25000.0)/50000.0)))
     z = 0
     if d["change"]:
         if d["value"] == 1: z=1
         else: z=-1
     
-    print("menu: touch_1d",v,z)
+    log.debug(f"menu: touch_1d ({v},{z})")
     hovered=active_menu.get_hovered_item()
     
 
@@ -235,7 +237,6 @@ def on_touch_1d(d):
 
     
     if hasattr(hovered, "touch_1d"):
-        print("hastouch")
         hovered.touch_1d(v,z)
     
 
@@ -243,13 +244,12 @@ def on_enter(d):
     active_menu = get_active_menu()
     
     if active_menu is None:
-        
-        #TODO this should not bee needed...
-        event.the_engine.userloop=None
+        log.info("menu enter without active menu, opening last menu")
         menu_back()
         return
 
     if active_menu:
+        log.info("menu enter, opening item")
         active_menu.get_hovered_item().enter()
     
     
@@ -279,16 +279,6 @@ event.Event(name="menu button enter",group_id="menu",
     action=on_enter, enabled=True
 )
 
-def old_render():
-
-    print (active_menu)
-    return
-    if active_menu is None:
-        return
-    
-    ui.the_ctx.rectangle(-120,-120,240,240).rgb(*ui.BLACK).fill()
-    active_menu.draw()
-    #hardware.display_update()
 
 def set_active_menu(menu):
     event.the_engine.active_menu = menu
@@ -296,16 +286,9 @@ def set_active_menu(menu):
 def get_active_menu():
     return event.the_engine.active_menu
 
-#def menu_disable():
-#    global active_menu
-#    if active_menu:
-#        menu_stack.append(active_menu)
-#        active_menu=None
-
 def menu_back():
-    if not menu_stack:
-        return
-
     previous = menu_stack.pop()
+    log.info(f"back to previous menu {previous.name} (Stack: {len(menu_stack)})")
+
     set_active_menu(previous)
     
\ No newline at end of file
diff --git a/python_payload/st3m/system/__init__.py b/python_payload/st3m/system/__init__.py
index 93c01cec089e843cc4dd252e3d521b6feadd0345..2960c66a23714654ef01cabbbbcdb8d490e9ba20 100644
--- a/python_payload/st3m/system/__init__.py
+++ b/python_payload/st3m/system/__init__.py
@@ -26,5 +26,15 @@ except ModuleNotFoundError:
     print("no real audio, using mock module")
     _audio = MockObject("audio")
 
+
+try:
+    import audio as _audio
+except ModuleNotFoundError:
+    print("no real audio, using mock module")
+    _audio = MockObject("audio")
+
+
 hardware = _hardware
-audio = _audio
\ No newline at end of file
+audio = _audio
+
+ctx =hardware.get_ctx()
\ No newline at end of file
diff --git a/python_payload/st3m/ui.py b/python_payload/st3m/ui.py
index ea187b94ef694f18144eb334f439eda997042c85..063a9f4453d0dab5cfaec791032f05d5a41aa7c6 100644
--- a/python_payload/st3m/ui.py
+++ b/python_payload/st3m/ui.py
@@ -1,4 +1,8 @@
-import hardware
+from st3m import logging
+log = logging.Log(__name__,level=logging.INFO)
+log.info("import")
+
+from st3m.system import ctx
 import random
 import math
 import time
@@ -19,7 +23,7 @@ GREY = (0.5,0.5,0.5)
 GO_GREEN = (63/255,255/255,33/53)
 PUSH_RED = (251/255,72/255,196/255)
 
-the_ctx = hardware.get_ctx()
+the_ctx = ctx
 
 # Utility functions
 def xy_from_polar(r,phi):
diff --git a/python_payload/st3m/utils.py b/python_payload/st3m/utils.py
index 0be418b9e617a8150934c75705afee918b3d2aff..687835af5ba10217833798c636ad3a9fc2e6d6a4 100644
--- a/python_payload/st3m/utils.py
+++ b/python_payload/st3m/utils.py
@@ -1,3 +1,7 @@
+from st3m import logging
+log = logging.Log(__name__,level=logging.INFO)
+log.info("import")
+
 import time
 from hardware import *
 from st3m.system import audio