@@ -181,6 +181,7 @@ static const DisplayPoint display_map[COLUMN_COUNT][ROW_COUNT] = {
181181#define COLUMN_PINS_MASK 0x1ff0
182182#define MIN_ROW_PIN 13
183183#define MAX_ROW_PIN 15
184+ #define ROW_PINS_MASK 0xe000
184185
185186inline void microbit_display_obj_t::setPinsForRow (uint8_t brightness) {
186187 if (brightness == 0 ) {
@@ -190,13 +191,39 @@ inline void microbit_display_obj_t::setPinsForRow(uint8_t brightness) {
190191 }
191192}
192193
194+ /* This is the primary PWM driver/display driver. It will operate on one row
195+ * (9 pins) per invocation. It will turn on LEDs with maximum brightness,
196+ * then let the "callback" callback turn off the LEDs as appropriate for the
197+ * required brightness level.
198+ *
199+ * For each row
200+ * Turn off all the LEDs in the previous row
201+ * Set the column bits high (off)
202+ * Set the row strobe low (off)
203+ * Turn on all the LEDs in the current row that have maximum brightness
204+ * Set the row strobe high (on)
205+ * Set some/all column bits low (on)
206+ * Register the PWM callback
207+ * For each callback start with brightness 0
208+ * If brightness 0
209+ * Turn off the LEDs specified at this level
210+ * Else
211+ * Turn on the LEDs specified at this level
212+ * If brightness max
213+ * Disable the PWM callback
214+ * Else
215+ * Re-queue the PWM callback after the appropriate delay
216+ */
193217void microbit_display_obj_t::advanceRow () {
194- // First, clear the old row.
218+ /* Clear all of the column bits */
195219 nrf_gpio_pins_set (COLUMN_PINS_MASK);
196- // Clear the old bit pattern for this row.
220+ /* Clear the strobe bit for this row */
197221 nrf_gpio_pin_clear (strobe_row+MIN_ROW_PIN);
198222
199- // Move on to the next row.
223+ /* Move to the next row. Before this, "this row" refers to the row
224+ * manipulated by the previous invocation of this function. After this,
225+ * "this row" refers to the row manipulated by the current invocation of
226+ * this function. */
200227 strobe_row++;
201228
202229 // Reset the row counts and bit mask when we have hit the max.
@@ -215,9 +242,9 @@ void microbit_display_obj_t::advanceRow() {
215242 uint8_t brightness = microbit_display_obj.image_buffer [x][y];
216243 pins_for_brightness[brightness] |= (1 <<(i+MIN_COLUMN_PIN));
217244 }
218- // Set pin for row
245+ /* Enable the strobe bit for this row */
219246 nrf_gpio_pin_set (strobe_row+MIN_ROW_PIN);
220- // Turn on any pixels that are at max
247+ /* Enable the column bits for all pins that need to be on. */
221248 nrf_gpio_pins_clear (pins_for_brightness[MAX_BRIGHTNESS]);
222249}
223250
@@ -238,6 +265,8 @@ static const uint16_t render_timings[] =
238265
239266#define DISPLAY_TICKER_SLOT 1
240267
268+ /* This is the PWM callback. It is registered by the animation callback and
269+ * will unregister itself when all of the brightness steps are complete. */
241270static int32_t callback (void ) {
242271 microbit_display_obj_t *display = µbit_display_obj;
243272 mp_uint_t brightness = display->previous_brightness ;
@@ -315,7 +344,13 @@ static void microbit_display_update(void) {
315344
316345#define GREYSCALE_MASK ((1 <<MAX_BRIGHTNESS)-2 )
317346
347+ /* This is the top-level animation/display callback. It is not a registered
348+ * callback. */
318349void microbit_display_tick (void ) {
350+ /* Do nothing if the display is not active. */
351+ if (!microbit_display_obj.active ) {
352+ return ;
353+ }
319354
320355 microbit_display_obj.advanceRow ();
321356
@@ -377,6 +412,40 @@ mp_obj_t microbit_display_scroll_func(mp_uint_t n_args, const mp_obj_t *pos_args
377412}
378413MP_DEFINE_CONST_FUN_OBJ_KW (microbit_display_scroll_obj, 1 , microbit_display_scroll_func);
379414
415+ mp_obj_t microbit_display_on_func (mp_obj_t obj) {
416+ microbit_display_obj_t *self = (microbit_display_obj_t *)obj;
417+ /* Re-enable the display loop. This will resume any animations in
418+ * progress and display any static image. */
419+ self->active = true ;
420+ return mp_const_none;
421+ }
422+ MP_DEFINE_CONST_FUN_OBJ_1 (microbit_display_on_obj, microbit_display_on_func);
423+
424+ mp_obj_t microbit_display_off_func (mp_obj_t obj) {
425+ microbit_display_obj_t *self = (microbit_display_obj_t *)obj;
426+ /* Disable the display loop. This will pause any animations in progress.
427+ * It will not prevent a user from attempting to modify the state, but
428+ * modifications will not appear to have any effect until the display loop
429+ * is re-enabled. */
430+ self->active = false ;
431+ /* Disable the row strobes, allowing the columns to be used freely for
432+ * GPIO. */
433+ nrf_gpio_pins_clear (ROW_PINS_MASK);
434+ return mp_const_none;
435+ }
436+ MP_DEFINE_CONST_FUN_OBJ_1 (microbit_display_off_obj, microbit_display_off_func);
437+
438+ mp_obj_t microbit_display_is_on_func (mp_obj_t obj) {
439+ microbit_display_obj_t *self = (microbit_display_obj_t *)obj;
440+ if (self->active ) {
441+ return mp_const_true;
442+ }
443+ else {
444+ return mp_const_false;
445+ }
446+ }
447+ MP_DEFINE_CONST_FUN_OBJ_1 (microbit_display_is_on_obj, microbit_display_is_on_func);
448+
380449void microbit_display_clear (void ) {
381450 // Reset repeat state, cancel animation and clear screen.
382451 wakeup_event = false ;
@@ -430,6 +499,9 @@ STATIC const mp_map_elem_t microbit_display_locals_dict_table[] = {
430499 { MP_OBJ_NEW_QSTR (MP_QSTR_show), (mp_obj_t )µbit_display_show_obj },
431500 { MP_OBJ_NEW_QSTR (MP_QSTR_scroll), (mp_obj_t )µbit_display_scroll_obj },
432501 { MP_OBJ_NEW_QSTR (MP_QSTR_clear), (mp_obj_t )µbit_display_clear_obj },
502+ { MP_OBJ_NEW_QSTR (MP_QSTR_on), (mp_obj_t )µbit_display_on_obj },
503+ { MP_OBJ_NEW_QSTR (MP_QSTR_off), (mp_obj_t )µbit_display_off_obj },
504+ { MP_OBJ_NEW_QSTR (MP_QSTR_is_on), (mp_obj_t )µbit_display_is_on_obj },
433505};
434506
435507STATIC MP_DEFINE_CONST_DICT (microbit_display_locals_dict, microbit_display_locals_dict_table);
@@ -456,6 +528,7 @@ microbit_display_obj_t microbit_display_obj = {
456528 {µbit_display_type},
457529 { 0 },
458530 .previous_brightness = 0 ,
531+ .active = 1 ,
459532 .strobe_row = 0 ,
460533 .brightnesses = 0 ,
461534 .pins_for_brightness = { 0 },
0 commit comments