26
26
27
27
#include " MicroBit.h"
28
28
#include " microbitobj.h"
29
+ #include " nrf_gpio.h"
29
30
30
31
extern " C" {
31
32
32
33
#include " py/runtime.h"
33
34
#include " modmicrobit.h"
34
35
#include " microbitimage.h"
35
36
37
+
38
+
36
39
typedef struct _microbit_display_obj_t {
37
40
mp_obj_base_t base;
38
- MicroBitDisplay *display ;
41
+ mp_int_t image_buffer[ 5 ][ 5 ] ;
39
42
} microbit_display_obj_t ;
40
43
41
- STATIC void display_print ( const microbit_display_obj_t *display, microbit_image_obj_t *image) {
42
- MicroBitImage *display_image = &display-> display -> image ;
44
+
45
+ STATIC void display_print ( microbit_display_obj_t *display, microbit_image_obj_t * image) {
43
46
mp_int_t w = min (image->width (), 5 );
44
47
mp_int_t h = min (image->height (), 5 );
45
48
mp_int_t x = 0 ;
46
49
for (; x < w; ++x) {
47
50
mp_int_t y = 0 ;
48
51
for (; y < h; ++y) {
49
- display_image-> setPixelValue (x, y, BRIGHTNESS_SCALE[ image->getPixelValue (x, y)] );
52
+ display-> image_buffer [x][y] = image->getPixelValue (x, y);
50
53
}
51
54
for (; y < 5 ; ++y) {
52
- display_image-> setPixelValue (x, y, 0 ) ;
55
+ display-> image_buffer [x][y] = 0 ;
53
56
}
54
57
}
55
58
for (; x < 5 ; ++x) {
56
59
for (mp_int_t y = 0 ; y < 5 ; ++y) {
57
- display_image-> setPixelValue (x, y, 0 ) ;
60
+ display-> image_buffer [x][y] = 0 ;
58
61
}
59
62
}
60
63
}
@@ -111,6 +114,11 @@ static bool async_error = false;
111
114
static uint16_t async_nonce = 0 ;
112
115
static int async_delay = 1000 ;
113
116
static int async_tick = 0 ;
117
+ static int strobe_row = 0 ;
118
+ static int strobe_mask = 0x20 ;
119
+ static int minimum_brightness = 0 ;
120
+ static Ticker renderTimer;
121
+
114
122
115
123
STATIC void wakeup_event () {
116
124
// Wake up any fibers that were blocked on the animation (if any).
@@ -134,7 +142,103 @@ STATIC void async_stop(void) {
134
142
wakeup_event ();
135
143
}
136
144
137
- void microbit_display_tick (void ) {
145
+ struct DisplayPoint {
146
+ uint8_t x;
147
+ uint8_t y;
148
+ };
149
+
150
+ #define NO_CONN 0
151
+
152
+ DisplayPoint display_map[MICROBIT_DISPLAY_COLUMN_COUNT][MICROBIT_DISPLAY_ROW_COUNT] = {
153
+ {{0 ,0 }, {4 ,2 }, {2 ,4 }},
154
+ {{2 ,0 }, {0 ,2 }, {4 ,4 }},
155
+ {{4 ,0 }, {2 ,2 }, {0 ,4 }},
156
+ {{4 ,3 }, {1 ,0 }, {0 ,1 }},
157
+ {{3 ,3 }, {3 ,0 }, {1 ,1 }},
158
+ {{2 ,3 }, {3 ,4 }, {2 ,1 }},
159
+ {{1 ,3 }, {1 ,4 }, {3 ,1 }},
160
+ {{0 ,3 }, {NO_CONN,NO_CONN}, {4 ,1 }},
161
+ {{1 ,2 }, {NO_CONN,NO_CONN}, {3 ,2 }}
162
+ };
163
+
164
+ static void set_pins_for_pixels (int brightness) {
165
+
166
+ int column_strobe = 0 ;
167
+
168
+ // Calculate the bitpattern to write.
169
+ for (int i = 0 ; i<MICROBIT_DISPLAY_COLUMN_COUNT; i++)
170
+ {
171
+ int x = display_map[i][strobe_row].x ;
172
+ int y = display_map[i][strobe_row].y ;
173
+
174
+ if (microbit_display_obj.image_buffer [x][y] >= brightness)
175
+ column_strobe |= (1 << i);
176
+ }
177
+
178
+ // write the new bit pattern
179
+ // set port 0 4-7 and retain lower 4 bits
180
+ nrf_gpio_port_write (NRF_GPIO_PORT_SELECT_PORT0, ~column_strobe<<4 & 0xF0 | nrf_gpio_port_read (NRF_GPIO_PORT_SELECT_PORT0) & 0x0F );
181
+
182
+ // set port 1 8-12 for the current row
183
+ nrf_gpio_port_write (NRF_GPIO_PORT_SELECT_PORT1, strobe_mask | (~column_strobe>>4 & 0x1F ));
184
+
185
+ }
186
+
187
+ static void clear_row ()
188
+ {
189
+ // clear the old bit pattern for this row.
190
+ // clear port 0 4-7 and retain lower 4 bits
191
+ nrf_gpio_port_write (NRF_GPIO_PORT_SELECT_PORT0, 0xF0 | nrf_gpio_port_read (NRF_GPIO_PORT_SELECT_PORT0) & 0x0F );
192
+
193
+ // clear port 1 8-12 for the current row
194
+ nrf_gpio_port_write (NRF_GPIO_PORT_SELECT_PORT1, strobe_mask | 0x1F );
195
+ }
196
+
197
+ static void microbit_display_advance_row (void ) {
198
+
199
+ /* Clear the old row */
200
+ clear_row ();
201
+
202
+ // Move on to the next row.
203
+ strobe_mask <<= 1 ;
204
+ strobe_row++;
205
+
206
+ // reset the row counts and bit mask when we have hit the max.
207
+ if (strobe_row == MICROBIT_DISPLAY_ROW_COUNT) {
208
+ strobe_row = 0 ;
209
+ strobe_mask = 0x20 ;
210
+ }
211
+ /* Turn on any pixels that are at max */
212
+ set_pins_for_pixels (MAX_BRIGHTNESS);
213
+
214
+ }
215
+
216
+ static const int render_timings[] =
217
+ { 0 , /* Brightness, Duration */
218
+ 32 , /* 1, 32 */
219
+ 32 , /* 2, 64 */
220
+ 64 , /* 3, 128 */
221
+ 128 , /* 4, 256 */
222
+ 256 , /* 5, 512 */
223
+ 480 , /* 6, 992 */
224
+ 924 , /* 7, 1916 */
225
+ 1784 , /* 8, 3700 */
226
+ /* Always on 9, 6000 */
227
+ };
228
+
229
+ static void render_row () {
230
+
231
+ // Attach to timer
232
+ if (minimum_brightness < MAX_BRIGHTNESS) {
233
+ renderTimer.attach_us (render_row, render_timings[minimum_brightness]);
234
+ }
235
+ set_pins_for_pixels (minimum_brightness);
236
+ ++minimum_brightness;
237
+
238
+ }
239
+
240
+
241
+ static void microbit_display_update (void ) {
138
242
async_tick += FIBER_TICK_PERIOD_MS;
139
243
if (async_tick < async_delay)
140
244
return ;
@@ -183,6 +287,17 @@ void microbit_display_tick(void) {
183
287
}
184
288
}
185
289
290
+ void microbit_display_tick (void ) {
291
+
292
+ microbit_display_advance_row ();
293
+
294
+ microbit_display_update ();
295
+
296
+ minimum_brightness = 1 ;
297
+ render_row ();
298
+
299
+ }
300
+
186
301
STATIC void do_synchronous_animation_once (microbit_display_obj_t *display, mp_obj_t iterator, mp_int_t delay) {
187
302
do {
188
303
async_tick = 0 ;
@@ -301,51 +416,27 @@ mp_obj_t microbit_display_clear(void) {
301
416
}
302
417
MP_DEFINE_CONST_FUN_OBJ_1 (microbit_display_clear_obj, microbit_display_clear);
303
418
304
- mp_obj_t microbit_display_set_pixel_raw (mp_uint_t n_args, const mp_obj_t *args) {
305
- (void )n_args;
306
- microbit_display_obj_t *self = (microbit_display_obj_t *)args[0 ];
307
- self->display ->image .setPixelValue (mp_obj_get_int (args[1 ]), mp_obj_get_int (args[2 ]), mp_obj_get_int (args[3 ]));
308
- return mp_const_none;
309
- }
310
- MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN (microbit_display_set_pixel_raw_obj, 4 , 4 , microbit_display_set_pixel_raw);
311
-
312
419
mp_obj_t microbit_display_set_pixel (mp_uint_t n_args, const mp_obj_t *args) {
313
420
(void )n_args;
314
421
microbit_display_obj_t *self = (microbit_display_obj_t *)args[0 ];
315
422
mp_int_t bright = mp_obj_get_int (args[3 ]);
316
423
if (bright < 0 || bright > MAX_BRIGHTNESS)
317
424
nlr_raise (mp_obj_new_exception_msg (&mp_type_ValueError, " brightness out of bounds." ));
318
- self->display -> image . setPixelValue ( mp_obj_get_int (args[1 ]), mp_obj_get_int (args[2 ]), BRIGHTNESS_SCALE[ bright]) ;
425
+ self->image_buffer [ mp_obj_get_int (args[1 ])][ mp_obj_get_int (args[2 ])] = bright;
319
426
return mp_const_none;
320
427
}
321
428
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN (microbit_display_set_pixel_obj, 4 , 4 , microbit_display_set_pixel);
322
429
323
- mp_obj_t microbit_display_get_pixel_raw (mp_obj_t self_in, mp_obj_t x_in, mp_obj_t y_in) {
324
- microbit_display_obj_t *self = (microbit_display_obj_t *)self_in;
325
- mp_int_t raw = self->display ->image .getPixelValue (mp_obj_get_int (x_in), mp_obj_get_int (y_in));
326
- return MP_OBJ_NEW_SMALL_INT (raw);
327
- }
328
- MP_DEFINE_CONST_FUN_OBJ_3 (microbit_display_get_pixel_raw_obj, microbit_display_get_pixel_raw);
329
-
330
430
mp_obj_t microbit_display_get_pixel (mp_obj_t self_in, mp_obj_t x_in, mp_obj_t y_in) {
331
431
microbit_display_obj_t *self = (microbit_display_obj_t *)self_in;
332
- mp_int_t raw = self->display ->image .getPixelValue (mp_obj_get_int (x_in), mp_obj_get_int (y_in));
333
- for (int i = 0 ; i < MAX_BRIGHTNESS; ++i) {
334
- mp_int_t bright = BRIGHTNESS_SCALE[i];
335
- mp_int_t next = BRIGHTNESS_SCALE[i+1 ];
336
- if (raw < (bright + next)/2 )
337
- return MP_OBJ_NEW_SMALL_INT (i);
338
- }
339
- return MP_OBJ_NEW_SMALL_INT (MAX_BRIGHTNESS);
432
+ return MP_OBJ_NEW_SMALL_INT (self->image_buffer [mp_obj_get_int (x_in)][mp_obj_get_int (y_in)]);
340
433
}
341
434
MP_DEFINE_CONST_FUN_OBJ_3 (microbit_display_get_pixel_obj, microbit_display_get_pixel);
342
435
343
436
STATIC const mp_map_elem_t microbit_display_locals_dict_table[] = {
344
437
345
438
{ MP_OBJ_NEW_QSTR (MP_QSTR_get_pixel), (mp_obj_t )µbit_display_get_pixel_obj },
346
- { MP_OBJ_NEW_QSTR (MP_QSTR_get_pixel_raw), (mp_obj_t )µbit_display_get_pixel_raw_obj },
347
439
{ MP_OBJ_NEW_QSTR (MP_QSTR_set_pixel), (mp_obj_t )µbit_display_set_pixel_obj },
348
- { MP_OBJ_NEW_QSTR (MP_QSTR_set_pixel_raw), (mp_obj_t )µbit_display_set_pixel_raw_obj },
349
440
{ MP_OBJ_NEW_QSTR (MP_QSTR_print), (mp_obj_t )µbit_display_print_obj },
350
441
{ MP_OBJ_NEW_QSTR (MP_QSTR_scroll), (mp_obj_t )µbit_display_scroll_obj },
351
442
{ MP_OBJ_NEW_QSTR (MP_QSTR_animate), (mp_obj_t )µbit_display_animate_obj },
@@ -372,14 +463,16 @@ STATIC const mp_obj_type_t microbit_display_type = {
372
463
/* .locals_dict = */ (mp_obj_t )µbit_display_locals_dict,
373
464
};
374
465
375
- const microbit_display_obj_t microbit_display_obj = {
466
+ microbit_display_obj_t microbit_display_obj = {
376
467
{µbit_display_type},
377
- . display = &uBit. display
468
+ { 0 }
378
469
};
379
470
380
471
void microbit_display_init (void ) {
381
- microbit_display_obj.display ->setBrightness (255 );
382
- microbit_display_obj.display ->setDisplayMode (DISPLAY_MODE_GREYSCALE);
472
+ // set pins as output
473
+ nrf_gpio_range_cfg_output (MICROBIT_DISPLAY_COLUMN_START,MICROBIT_DISPLAY_COLUMN_START + MICROBIT_DISPLAY_COLUMN_COUNT + MICROBIT_DISPLAY_ROW_COUNT);
474
+
475
+ uBit.display .disable ();
383
476
}
384
477
385
478
}
0 commit comments