@@ -97,23 +97,14 @@ mp_obj_t microbit_display_print_func(mp_uint_t n_args, const mp_obj_t *args) {
9797}
9898MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN (microbit_display_print_obj, 2 , 3 , microbit_display_print_func);
9999
100- #define ASYNC_MODE_STOPPED 0
101- #define ASYNC_MODE_ANIMATION 1
102- #define ASYNC_MODE_CLEAR 2
103-
104- static int async_mode = ASYNC_MODE_STOPPED;
100+ static uint8_t async_mode;
105101static mp_obj_t async_repeat_iterable = NULL ;
106102static mp_obj_t async_iterator = NULL ;
107103/* Record if an error occurs in async animation -- Unfortunately there is no way to report this */
108104static bool async_error = false ;
109105static uint16_t async_nonce = 0 ;
110- static int async_delay = 1000 ;
111- static int async_tick = 0 ;
112- static int strobe_row = 0 ;
113- static int strobe_mask = 0x20 ;
114- static int previous_brightness = 0 ;
115- static Ticker renderTimer;
116-
106+ static mp_uint_t async_delay = 1000 ;
107+ static mp_uint_t async_tick = 0 ;
117108
118109STATIC void wakeup_event () {
119110 // Wake up any fibers that were blocked on the animation (if any).
@@ -156,17 +147,14 @@ static const DisplayPoint display_map[MICROBIT_DISPLAY_COLUMN_COUNT][MICROBIT_DI
156147 {{1 ,2 }, {NO_CONN,NO_CONN}, {3 ,2 }}
157148};
158149
159- static void set_pins_for_pixels ( int brightness) {
150+ inline void microbit_display_obj_t::setPinsForRow ( uint8_t brightness) {
160151
161152 int column_strobe = 0 ;
162153
163154 // Calculate the bitpattern to write.
164155 for (int i = 0 ; i<MICROBIT_DISPLAY_COLUMN_COUNT; i++)
165156 {
166- int x = display_map[i][strobe_row].x ;
167- int y = display_map[i][strobe_row].y ;
168-
169- if (microbit_display_obj.image_buffer [x][y] >= brightness)
157+ if (row_brightness[i] >= brightness)
170158 column_strobe |= (1 << i);
171159 }
172160
@@ -179,20 +167,16 @@ static void set_pins_for_pixels(int brightness) {
179167
180168}
181169
182- static void clear_row ()
183- {
170+ void microbit_display_obj_t::advanceRow () {
171+
172+ /* Clear the old row */
173+
184174 // clear the old bit pattern for this row.
185175 // clear port 0 4-7 and retain lower 4 bits
186176 nrf_gpio_port_write (NRF_GPIO_PORT_SELECT_PORT0, 0xF0 | nrf_gpio_port_read (NRF_GPIO_PORT_SELECT_PORT0) & 0x0F );
187177
188178 // clear port 1 8-12 for the current row
189179 nrf_gpio_port_write (NRF_GPIO_PORT_SELECT_PORT1, strobe_mask | 0x1F );
190- }
191-
192- static void microbit_display_advance_row (void ) {
193-
194- /* Clear the old row */
195- clear_row ();
196180
197181 // Move on to the next row.
198182 strobe_mask <<= 1 ;
@@ -203,41 +187,44 @@ static void microbit_display_advance_row(void) {
203187 strobe_row = 0 ;
204188 strobe_mask = 0x20 ;
205189 }
190+
191+ // prepare row for rendering
192+ for (int i = 0 ; i<MICROBIT_DISPLAY_COLUMN_COUNT; i++)
193+ {
194+ int x = display_map[i][strobe_row].x ;
195+ int y = display_map[i][strobe_row].y ;
196+
197+ row_brightness[i] = microbit_display_obj.image_buffer [x][y];
198+ }
206199 /* Turn on any pixels that are at max */
207- set_pins_for_pixels (MAX_BRIGHTNESS);
200+ setPinsForRow (MAX_BRIGHTNESS);
208201
209202}
210203
211- static const int render_timings[] =
212- { 0 , /* Brightness*/
213- 32 , /* 1 */
214- 64 , /* 2 */
215- 128 , /* 3 */
216- 256 , /* 4 */
217- 512 , /* 5 */
218- 992 , /* 6 */
219- 1916 , /* 7 */
220- 3700 , /* 8 */
221- /* Always on 9 */
204+ static const uint16_t render_timings[] =
205+ // The timer precision is only about 32us, so these timing will be rounded.
206+ // The scale is exponential, each step is approx x1.9 greater than the previous.
207+ { 0 , // Brightness, Duration (approx)
208+ 35 , // 1, 35
209+ 32 , // 2, 67
210+ 61 , // 3, 128
211+ 115 , // 4, 243
212+ 219 , // 5, 462
213+ 417 , // 6, 879
214+ 791 , // 7, 1670
215+ 1500 , // 8, 3170
216+ // Always on 9, ~6000
222217};
223218
224- #define GREYSCALE_MASK ((1 <<MAX_BRIGHTNESS)-2 )
225219
226- static void render_row () {
227- mp_int_t next_brightness = previous_brightness+1 ;
228- uint16_t brightnesses = microbit_display_obj.brightnesses ;
229- for (; next_brightness < MAX_BRIGHTNESS; ++next_brightness) {
230- if ((1 << next_brightness) & brightnesses) {
231- break ;
232- }
233- }
220+ void microbit_display_obj_t::renderRow () {
221+ mp_uint_t brightness = previous_brightness+1 ;
222+ setPinsForRow (brightness);
223+ if (brightness == MAX_BRIGHTNESS)
224+ return ;
225+ previous_brightness = brightness;
234226 // Attach to timer
235- if (next_brightness < MAX_BRIGHTNESS) {
236- mp_int_t interval = render_timings[next_brightness] - render_timings[previous_brightness];
237- renderTimer.attach_us (render_row, interval);
238- }
239- set_pins_for_pixels (next_brightness);
240- previous_brightness = next_brightness;
227+ uBit.display .renderTimer .attach_us (this , µbit_display_obj_t ::renderRow, render_timings[brightness]);
241228
242229}
243230
@@ -288,14 +275,17 @@ static void microbit_display_update(void) {
288275 }
289276}
290277
278+ #define GREYSCALE_MASK ((1 <<MAX_BRIGHTNESS)-2 )
279+
291280void microbit_display_tick (void ) {
292281
293- microbit_display_advance_row ();
282+ microbit_display_obj. advanceRow ();
294283
295284 microbit_display_update ();
296- previous_brightness = 0 ;
297- if (microbit_display_obj.brightnesses & GREYSCALE_MASK)
298- render_row ();
285+ microbit_display_obj.previous_brightness = 0 ;
286+ if (microbit_display_obj.brightnesses & GREYSCALE_MASK) {
287+ microbit_display_obj.renderRow ();
288+ }
299289}
300290
301291void microbit_display_animate (microbit_display_obj_t *self, mp_obj_t iterable, mp_int_t delay, bool wait, bool loop) {
@@ -447,8 +437,12 @@ STATIC const mp_obj_type_t microbit_display_type = {
447437
448438microbit_display_obj_t microbit_display_obj = {
449439 {µbit_display_type},
450- 0 ,
451- { 0 }
440+ { 0 },
441+ .row_brightness = { 0 },
442+ .previous_brightness = 0 ,
443+ .strobe_row = 0 ,
444+ .brightnesses = 0 ,
445+ .strobe_mask = 0x20
452446};
453447
454448static void ticker (void ) {
0 commit comments