Skip to content

Commit 1a4ebae

Browse files
Mark Shannondpgeorge
authored andcommitted
Fix rendering of low brightness pixels.
1 parent 48c8415 commit 1a4ebae

File tree

3 files changed

+67
-60
lines changed

3 files changed

+67
-60
lines changed

examples/conway.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ def show():
1414
for y in range(5):
1515
for x in range(5):
1616
img.set_pixel(x, y, arena1[8 + y * 7 + x]*9)
17-
microbit.display.print(img)
17+
microbit.display.print(img)
1818

1919
# do 1 iteration of Conway's Game of Life
2020
def conway_step():

inc/microbit/microbitdisplay.h

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,24 @@
22

33
typedef struct _microbit_display_obj_t {
44
mp_obj_base_t base;
5+
uint8_t image_buffer[5][5];
6+
uint8_t row_brightness[MICROBIT_DISPLAY_COLUMN_COUNT];
7+
uint8_t previous_brightness;
8+
/* Current row for strobing */
9+
uint8_t strobe_row;
510
/* boolean histogram of brightness in buffer */
611
uint16_t brightnesses;
7-
uint8_t image_buffer[5][5];
12+
uint16_t strobe_mask;
13+
14+
void advanceRow();
15+
void renderRow();
16+
inline void setPinsForRow(uint8_t brightness);
17+
818
} microbit_display_obj_t;
919

20+
#define ASYNC_MODE_STOPPED 0
21+
#define ASYNC_MODE_ANIMATION 1
22+
#define ASYNC_MODE_CLEAR 2
1023

1124
extern microbit_display_obj_t microbit_display_obj;
1225

source/microbit/microbitdisplay.cpp

Lines changed: 52 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -97,23 +97,14 @@ mp_obj_t microbit_display_print_func(mp_uint_t n_args, const mp_obj_t *args) {
9797
}
9898
MP_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;
105101
static mp_obj_t async_repeat_iterable = NULL;
106102
static mp_obj_t async_iterator = NULL;
107103
/* Record if an error occurs in async animation -- Unfortunately there is no way to report this */
108104
static bool async_error = false;
109105
static 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

118109
STATIC 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, &microbit_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+
291280
void 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

301291
void 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

448438
microbit_display_obj_t microbit_display_obj = {
449439
{&microbit_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

454448
static void ticker(void) {

0 commit comments

Comments
 (0)