Skip to content

Commit 1cf054e

Browse files
breakout: micropython.schedule() doesnt help
1 parent ff563b5 commit 1cf054e

2 files changed

Lines changed: 45 additions & 17 deletions

File tree

c_mpos/breakout/breakout.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
// Breakout native module renderer. Draws into a framebuffer that may be
2+
// smaller than the full display (partial framebuffer). Rendering is done
3+
// per-slice using a y-offset/row count so MicroPythonOS can refresh displays
4+
// larger than 320x230 without allocating a full-size framebuffer. This keeps
5+
// the simulation state global while allowing sequential chunk flushes.
6+
17
// Include the header file to get access to the MicroPython API
28
#include "py/dynruntime.h"
39
#include <stdbool.h>

internal_filesystem/apps/com.micropythonos.breakout/assets/breakout.py

Lines changed: 39 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
1+
# Breakout app UI/driver glue. This app renders into a framebuffer that may be
2+
# smaller than the full display (partial framebuffer). The draw loop is more
3+
# complex because it slices the screen into chunks, renders each slice in C,
4+
# and flushes them sequentially using a flush-ready IRQ callback. A scheduled
5+
# (non-IRQ) handler advances chunks so it can work on larger-than-320x230
6+
# displays without requiring a full-size framebuffer.
17
import lvgl as lv
28
import time
39
import mpos.ui
10+
import micropython
411
from mpos import Activity, DisplayMetrics, InputManager
512

613
import sys
@@ -30,8 +37,8 @@ class Breakout(Activity):
3037
chunk_rows_per = 0
3138
chunk_total = 0
3239
chunk_index = 0
33-
34-
refresh_timer = None
40+
_draw_scheduled = False
41+
_scheduled_draw_cb = None
3542

3643
# Widgets:
3744
screen = None
@@ -47,7 +54,7 @@ def onCreate(self):
4754

4855
d = lv.display_get_default()
4956
self.hor_res = d.get_horizontal_resolution()
50-
self.paddle_move_step = round(self.hor_res/16)
57+
self.paddle_move_step = round(self.hor_res/10)
5158
self.ver_res = d.get_vertical_resolution()
5259

5360
self.leftbutton = lv.button(self.screen)
@@ -74,25 +81,12 @@ def onCreate(self):
7481

7582
def onResume(self, screen):
7683
lv.log_register_print_cb(self.log_callback)
77-
lv.timer_create(self.startit, 4000, None).set_repeat_count(1) # this needs to be delayed, otherwise the whole thing hangs
84+
lv.timer_create(self.startit, 5000, None).set_repeat_count(1) # this needs to be delayed, otherwise the whole thing hangs
7885

7986
def onPause(self, screen):
80-
if self.refresh_timer:
81-
self.refresh_timer.delete()
82-
mpos.ui.task_handler.remove_event_cb(self.drawframe)
8387
lv.log_register_print_cb(None)
8488
mpos.ui.main_display._data_bus.register_callback(mpos.ui.main_display._flush_ready_cb)
8589

86-
def startit(self, arg1=None):
87-
print("starting it!")
88-
breakout.init(mpos.ui.main_display._frame_buffer1, self.hor_res, self.ver_res)
89-
mpos.ui.main_display._data_bus.register_callback(self.flush_ready_cb)
90-
mpos.ui.task_handler.add_event_cb(self.drawframe, mpos.ui.task_handler.TASK_HANDLER_STARTED)
91-
92-
def flush_ready_cb(self, arg1=None, arg2=None):
93-
mpos.ui.main_display._disp_drv.flush_ready() # with this, it hangs, and without it, the device crashes
94-
self.flush_ready = True
95-
9690
def move_left(self):
9791
breakout.move_paddle(-self.paddle_move_step)
9892

@@ -124,6 +118,21 @@ def unfocus(self):
124118
else:
125119
print("focus isn't on next or previous, leaving it...")
126120

121+
def startit(self, arg1=None):
122+
print("starting it!")
123+
breakout.init(mpos.ui.main_display._frame_buffer1, self.hor_res, self.ver_res)
124+
mpos.ui.main_display._data_bus.register_callback(self.flush_ready_cb)
125+
# Using a scheduled draw would be faster than a periodic one (lv.timer or mpos.ui.task_handler.add_event_cb) but no...
126+
self._scheduled_draw_cb = self._scheduled_draw
127+
self._request_draw()
128+
129+
def flush_ready_cb(self, arg1=None, arg2=None):
130+
# This is called in IRQ (interrupt) context so it can't allocate memory
131+
# So no printf, no calling drawframe() directly, just setting variables or scheduling...
132+
mpos.ui.main_display._disp_drv.flush_ready()
133+
self.flush_ready = True
134+
self._request_draw()
135+
127136
def send_to_display(self, y_offset=0, rows=None, is_last=True):
128137
x1 = 0
129138
x2 = mpos.ui.main_display.get_horizontal_resolution() - 1
@@ -159,6 +168,7 @@ def drawframe(self, arg1=None, arg2=None):
159168
if self.chunk_index >= self.chunk_total:
160169
self.chunk_in_progress = False
161170
self.render_next = True
171+
self._request_draw()
162172
else:
163173
self._render_and_send_chunk()
164174
return
@@ -212,6 +222,18 @@ def _render_and_send_chunk(self):
212222
breakout.render(y_offset, rows, advance)
213223
self.send_to_display(y_offset, rows, is_last)
214224

225+
def _request_draw(self):
226+
if not self._draw_scheduled and self._scheduled_draw_cb:
227+
self._draw_scheduled = True
228+
try:
229+
micropython.schedule(self._scheduled_draw_cb, 0)
230+
except Exception:
231+
self._draw_scheduled = False
232+
233+
def _scheduled_draw(self, _):
234+
self._draw_scheduled = False
235+
self.drawframe()
236+
215237
def touch_cb(self, event):
216238
event_code = event.get_code()
217239
if event_code == lv.EVENT.PRESSED:

0 commit comments

Comments
 (0)