Skip to content

Commit 62d6a19

Browse files
committed
Add MicroBitDisplay.on(), .off(), and .is_on().
Turning off the display will preserve the state of the display (pausing any animation). Turning on the display will restore the state (resuming any animation, not restarting). is_on() will return True if the display is on and False if the display is off. Also, add drive-by documentation for the display driver, especially of the PWM mechanism.
1 parent 9b93ffa commit 62d6a19

File tree

6 files changed

+91
-5
lines changed

6 files changed

+91
-5
lines changed

inc/genhdr/qstrdefs.generated.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -464,6 +464,9 @@ QDEF(MP_QSTR_crop, (const byte*)"\x0b\x04" "crop")
464464
QDEF(MP_QSTR_text, (const byte*)"\x98\x04" "text")
465465
QDEF(MP_QSTR_SlicedImage, (const byte*)"\xf6\x0b" "SlicedImage")
466466
QDEF(MP_QSTR_ScrollingString, (const byte*)"\xbd\x0f" "ScrollingString")
467+
QDEF(MP_QSTR_on, (const byte*)"\x64\x02" "on")
468+
QDEF(MP_QSTR_off, (const byte*)"\x8a\x03" "off")
469+
QDEF(MP_QSTR_is_on, (const byte*)"\x61\x05" "is_on")
467470
QDEF(MP_QSTR_MicroBitButton, (const byte*)"\x16\x0e" "MicroBitButton")
468471
QDEF(MP_QSTR_button_a, (const byte*)"\xed\x08" "button_a")
469472
QDEF(MP_QSTR_button_b, (const byte*)"\xee\x08" "button_b")

inc/microbit/microbitdisplay.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ typedef struct _microbit_display_obj_t {
99
mp_obj_base_t base;
1010
uint8_t image_buffer[5][5];
1111
uint8_t previous_brightness;
12+
bool active;
1213
/* Current row for strobing */
1314
uint8_t strobe_row;
1415
/* boolean histogram of brightness in buffer */

inc/microbit/modmicrobit.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,9 @@ MP_DECLARE_CONST_FUN_OBJ(microbit_display_scroll_obj);
179179
MP_DECLARE_CONST_FUN_OBJ(microbit_display_clear_obj);
180180
MP_DECLARE_CONST_FUN_OBJ(microbit_display_get_pixel_obj);
181181
MP_DECLARE_CONST_FUN_OBJ(microbit_display_set_pixel_obj);
182+
MP_DECLARE_CONST_FUN_OBJ(microbit_display_on_obj);
183+
MP_DECLARE_CONST_FUN_OBJ(microbit_display_off_obj);
184+
MP_DECLARE_CONST_FUN_OBJ(microbit_display_is_on_obj);
182185
MP_DECLARE_CONST_FUN_OBJ(microbit_pin_read_digital_obj);
183186
MP_DECLARE_CONST_FUN_OBJ(microbit_pin_write_digital_obj);
184187
MP_DECLARE_CONST_FUN_OBJ(microbit_pin_read_analog_obj);

inc/microbit/qstrdefsport.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,9 @@ Q(slice)
148148
Q(text)
149149
Q(SlicedImage)
150150
Q(ScrollingString)
151+
Q(on)
152+
Q(off)
153+
Q(is_on)
151154

152155
Q(MicroBitButton)
153156
Q(button_a)

source/microbit/help.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,9 @@ STATIC const mp_doc_t help_table_instances[] = {
105105
{&microbit_display_clear_obj, "Use clear() to clear micro:bit's display.\n"},
106106
{&microbit_display_get_pixel_obj, "Use get_pixel(x, y) to return the display's brightness at LED pixel (x,y).\nBrightness can be from 0 (LED is off) to 9 (maximum LED brightness).\n"},
107107
{&microbit_display_set_pixel_obj, "Use set_pixel(x, y, b) to set the display at LED pixel (x,y) to brightness 'b'\nwhich can be set between 0 (off) to 9 (full brightness).\n"},
108+
{&microbit_display_on_obj, "Use on() to turn on the display.\n"},
109+
{&microbit_display_off_obj, "Use off() to turn off the display.\n"},
110+
{&microbit_display_is_on_obj, "Use is_on() to query if the micro:bit's display is on (True) or off (False).\n"},
108111
// Pins
109112
{&microbit_p0_obj, "micro:bit's pin 0 on the gold edge connector.\n"},
110113
{&microbit_p1_obj, "micro:bit's pin 1 on the gold edge connector.\n"},

source/microbit/microbitdisplay.cpp

Lines changed: 78 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -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

185186
inline 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+
*/
193217
void 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. */
241270
static int32_t callback(void) {
242271
microbit_display_obj_t *display = &microbit_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. */
318349
void 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
}
378413
MP_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+
380449
void 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)&microbit_display_show_obj },
431500
{ MP_OBJ_NEW_QSTR(MP_QSTR_scroll), (mp_obj_t)&microbit_display_scroll_obj },
432501
{ MP_OBJ_NEW_QSTR(MP_QSTR_clear), (mp_obj_t)&microbit_display_clear_obj },
502+
{ MP_OBJ_NEW_QSTR(MP_QSTR_on), (mp_obj_t)&microbit_display_on_obj },
503+
{ MP_OBJ_NEW_QSTR(MP_QSTR_off), (mp_obj_t)&microbit_display_off_obj },
504+
{ MP_OBJ_NEW_QSTR(MP_QSTR_is_on), (mp_obj_t)&microbit_display_is_on_obj },
433505
};
434506

435507
STATIC 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
{&microbit_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

Comments
 (0)