Merge pull request #325 from MichaelBell/improve-performance

Badger2040: system_speed call, plus performance improvements
pull/328/head
Philip Howard 2022-03-30 13:58:19 +01:00 zatwierdzone przez GitHub
commit 7c523f82df
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 4AEE18F83AFDEB23
11 zmienionych plików z 225 dodań i 30 usunięć

Wyświetl plik

@ -461,6 +461,10 @@ namespace pimoroni {
*p |= b; // set bit value *p |= b; // set bit value
} }
uint8_t* UC8151::get_frame_buffer() {
return frame_buffer;
}
void UC8151::invert(bool inv) { void UC8151::invert(bool inv) {
inverted = inv; inverted = inv;
command(CDI, {(uint8_t)(inverted ? 0b01'01'1100 : 0b01'00'1100)}); // vcom and data interval command(CDI, {(uint8_t)(inverted ? 0b01'01'1100 : 0b01'00'1100)}); // vcom and data interval
@ -477,15 +481,15 @@ namespace pimoroni {
uint32_t UC8151::update_time() { uint32_t UC8151::update_time() {
switch(_update_speed) { switch(_update_speed) {
case 0: case 0:
return 5500; return 4500;
case 1: case 1:
return 2600; return 2000;
case 2: case 2:
return 1000; return 800;
case 3: case 3:
return 300; return 250;
default: default:
return 5500; return 4500;
} }
} }

Wyświetl plik

@ -208,6 +208,7 @@ namespace pimoroni {
void off(); void off();
void pixel(int x, int y, int v); void pixel(int x, int y, int v);
uint8_t* get_frame_buffer();
}; };
} }

Wyświetl plik

@ -69,14 +69,6 @@ namespace pimoroni {
// TODO: set default image? // TODO: set default image?
} }
void Badger2040::clear() {
for(uint32_t y = 0; y < 128; y++) {
for(uint32_t x = 0; x < 296; x++) {
pixel(x, y);
}
}
}
void Badger2040::halt() { void Badger2040::halt() {
gpio_put(ENABLE_3V3, 0); gpio_put(ENABLE_3V3, 0);
@ -100,15 +92,54 @@ namespace pimoroni {
15, 7, 13, 5 15, 7, 13, 5
}; };
if (p == 0) {
return 1;
}
if (p == 15) {
return 0;
}
// calculate dither matrix offset // calculate dither matrix offset
uint32_t dmo = (x & 0b11) | ((y & 0b11) << 2); uint32_t dmo = (x & 0b11) | ((y & 0b11) << 2);
if(p == 0) { return p <= _odm[dmo] ? 1 : 0;
return 1; }
}else if(p == 15) {
// Return dither values for an entire byte in the column
uint8_t _dither_column_value(int32_t x, uint8_t p) {
if (p == 0) {
return 0xff;
}
if (p == 15) {
return 0; return 0;
}else{ }
return p <= _odm[dmo] ? 1 : 0;
uint8_t val = 0;
for (int32_t y = 0; y < 4; ++y) {
val |= _dither_value(x, y, p) << (7 - y);
}
val |= val >> 4;
return val;
}
void Badger2040::clear() {
const uint32_t column_len = 128 / 8;
const uint32_t buf_len = column_len * 296;
uint8_t* buf = uc8151.get_frame_buffer();
if (_pen == 0) {
memset(buf, 0xff, buf_len);
}
else if (_pen == 15) {
memset(buf, 0, buf_len);
}
else {
for(uint32_t x = 0; x < 296; x++) {
uint8_t val = _dither_column_value(x, _pen);
memset(buf, val, column_len);
buf += column_len;
}
} }
} }
@ -130,14 +161,38 @@ namespace pimoroni {
image(data, sheet_width, icon_size * index, 0, icon_size, icon_size, dx, dy); image(data, sheet_width, icon_size * index, 0, icon_size, icon_size, dx, dy);
} }
// Display an image that fills the screen (286*128) // Display an image that fills the screen (296*128)
void Badger2040::image(const uint8_t* data) { void Badger2040::image(const uint8_t* data) {
image(data, 296, 0, 0, 296, 128, 0, 0); uint8_t* ptr = uc8151.get_frame_buffer();
for (uint32_t x = 0; x < 296; ++x) {
// extract bitmask for this pixel
uint32_t bm = 0b10000000 >> (x & 0b111);
for (uint32_t y = 0; y < 128; y += 8) {
uint8_t val = 0;
for (uint32_t cy = 0; cy < 8; ++cy) {
// work out byte offset in source data
uint32_t o = ((y + cy) * (296 >> 3)) + (x >> 3);
// Set bit in val if set in source data
if (data[o] & bm) {
val |= 0b10000000 >> cy;
}
}
*ptr++ = val;
}
}
} }
// Display an image smaller than the screen (sw*sh) at dx, dy // Display an image smaller than the screen (sw*sh) at dx, dy
void Badger2040::image(const uint8_t *data, int w, int h, int x, int y) { void Badger2040::image(const uint8_t *data, int w, int h, int x, int y) {
image(data, w, 0, 0, w, h, x, y); if (x == 0 && y == 0 && w == 296 && h == 128) {
image(data);
}
else {
image(data, w, 0, 0, w, h, x, y);
}
} }
void Badger2040::image(const uint8_t *data, int stride, int sx, int sy, int dw, int dh, int dx, int dy) { void Badger2040::image(const uint8_t *data, int stride, int sx, int sy, int dw, int dh, int dx, int dy) {
@ -156,9 +211,44 @@ namespace pimoroni {
} }
void Badger2040::rectangle(int32_t x, int32_t y, int32_t w, int32_t h) { void Badger2040::rectangle(int32_t x, int32_t y, int32_t w, int32_t h) {
for(int cy = y; cy < y + h; cy++) { // Adjust for thickness
uint32_t ht = _thickness / 2;
x -= ht;
if (x < 0) {
w += x;
x = 0;
}
y -= ht;
if (y < 0) {
h += y;
y = 0;
}
w += _thickness - 1;
h += _thickness - 1;
if (h >= 8) {
// Directly write to the frame buffer when clearing a large area
uint8_t* buf = uc8151.get_frame_buffer();
for(int cx = x; cx < x + w; cx++) { for(int cx = x; cx < x + w; cx++) {
pixel(cx, cy); uint8_t* buf_ptr = &buf[cx * 16 + y / 8];
uint8_t first_mask = 0xff >> (y & 7);
uint8_t last_mask = 0xff >> ((y + h) & 7);
uint32_t val = _dither_column_value(cx, _pen);
*buf_ptr &= ~first_mask;
*buf_ptr++ |= (val & first_mask);
for (int32_t c = h - (8 - (y & 7)); c >= 8; c -= 8) {
*buf_ptr++ = val;
}
*buf_ptr &= last_mask;
*buf_ptr |= (val & (~last_mask));
}
}
else {
for(int cx = x; cx < x + w; cx++) {
for(int cy = y; cy < y + h; cy++) {
uc8151.pixel(cx, cy, _dither_value(cx, cy, _pen));
}
} }
} }
} }

Wyświetl plik

@ -2,6 +2,8 @@ import time
import machine import machine
import badger2040 import badger2040
# We're going to keep the badger on, so slow down the system clock if on battery
badger2040.system_speed(badger2040.SYSTEM_SLOW)
rtc = machine.RTC() rtc = machine.RTC()
display = badger2040.Badger2040() display = badger2040.Badger2040()

Wyświetl plik

@ -6,6 +6,9 @@ import machine
import badger2040 import badger2040
# Overclock the RP2040 to run the sim faster
badger2040.system_speed(badger2040.SYSTEM_TURBO)
# ------------------------------ # ------------------------------
# Program setup # Program setup
# ------------------------------ # ------------------------------
@ -16,6 +19,7 @@ INITIAL_DENSITY = 0.3 # Density of cells at start
# Create a new Badger and set it to update TURBO # Create a new Badger and set it to update TURBO
screen = badger2040.Badger2040() screen = badger2040.Badger2040()
screen.led(128)
screen.update_speed(badger2040.UPDATE_TURBO) screen.update_speed(badger2040.UPDATE_TURBO)
restart = False # should sim be restarted restart = False # should sim be restarted

Wyświetl plik

@ -1,14 +1,13 @@
import gc import gc
import time import time
import math import math
import machine
import badger2040 import badger2040
from badger2040 import WIDTH from badger2040 import WIDTH
import launchericons import launchericons
import badger_os import badger_os
# Reduce clock speed to 48MHz, that's fast enough! # Reduce clock speed to 48MHz
machine.freq(48000000) badger2040.system_speed(badger2040.SYSTEM_NORMAL)
changed = False changed = False
exited_to_launcher = False exited_to_launcher = False

Wyświetl plik

@ -67,7 +67,19 @@ Badger 2040 features five buttons on its front, labelled A, B, C, ↑ (up), ↓
* `BUTTON_DOWN` = `11` * `BUTTON_DOWN` = `11`
* `BUTTON_USER` = `23` * `BUTTON_USER` = `23`
Note, due to the BOOT/USR button performing both BOOT and USER functions, the output of reading it with `pressed()` will be inverted from the others. ## System speed
The system clock speed of the RP2040 can be controlled, allowing power to be saved if on battery, or faster computations to be performed. Use `badger2040.system_speed(speed)` where `speed` is one of the following constants:
* `SYSTEM_VERY_SLOW` = `0` _4 MHz if on battery, 48 MHz if connected to USB_
* `SYSTEM_SLOW` = `1` _12 MHz if on battery, 48 MHz if connected to USB_
* `SYSTEM_NORMAL` = `2` _48 MHz_
* `SYSTEM_FAST` = `3` _133 MHz_
* `SYSTEM_TURBO` = `4` _250 MHz_
On USB, the system will not run slower than 48MHz, as that is the minimum clock speed required to keep the USB connection stable.
Note that `SYSTEM_TURBO` overclocks the RP2040 to 250MHz, and applies a small over voltage to ensure this is stable. We've found that every RP2040 we've tested is happy to run at this speed without any issues.
## Other Functions ## Other Functions
@ -95,7 +107,6 @@ icon(data, icon_index, sheet_size, icon_size)
clear() clear()
update() update()
partial_update(x, y, w, h) partial_update(x, y, w, h)
update_speed(speed)
invert(inverted) invert(inverted)
``` ```

Wyświetl plik

@ -35,6 +35,7 @@ MP_DEFINE_CONST_FUN_OBJ_3(Badger2040_command_obj, Badger2040_command);
MP_DEFINE_CONST_FUN_OBJ_1(Badger2040_pressed_to_wake_obj, Badger2040_pressed_to_wake); MP_DEFINE_CONST_FUN_OBJ_1(Badger2040_pressed_to_wake_obj, Badger2040_pressed_to_wake);
MP_DEFINE_CONST_FUN_OBJ_1(Badger2040_halt_obj, Badger2040_halt); MP_DEFINE_CONST_FUN_OBJ_1(Badger2040_halt_obj, Badger2040_halt);
MP_DEFINE_CONST_FUN_OBJ_0(Badger2040_woken_by_button_obj, Badger2040_woken_by_button); MP_DEFINE_CONST_FUN_OBJ_0(Badger2040_woken_by_button_obj, Badger2040_woken_by_button);
MP_DEFINE_CONST_FUN_OBJ_1(Badger2040_system_speed_obj, Badger2040_system_speed);
/***** Binding of Methods *****/ /***** Binding of Methods *****/
STATIC const mp_rom_map_elem_t Badger2040_locals_dict_table[] = { STATIC const mp_rom_map_elem_t Badger2040_locals_dict_table[] = {
@ -90,6 +91,7 @@ STATIC const mp_rom_map_elem_t badger2040_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR_pressed_to_wake), MP_ROM_PTR(&Badger2040_pressed_to_wake_obj) }, { MP_ROM_QSTR(MP_QSTR_pressed_to_wake), MP_ROM_PTR(&Badger2040_pressed_to_wake_obj) },
{ MP_ROM_QSTR(MP_QSTR_woken_by_button), MP_ROM_PTR(&Badger2040_woken_by_button_obj) }, { MP_ROM_QSTR(MP_QSTR_woken_by_button), MP_ROM_PTR(&Badger2040_woken_by_button_obj) },
{ MP_ROM_QSTR(MP_QSTR_system_speed), MP_ROM_PTR(&Badger2040_system_speed_obj) },
{ MP_ROM_QSTR(MP_QSTR_UPDATE_NORMAL), MP_ROM_INT(0) }, { MP_ROM_QSTR(MP_QSTR_UPDATE_NORMAL), MP_ROM_INT(0) },
{ MP_ROM_QSTR(MP_QSTR_UPDATE_MEDIUM), MP_ROM_INT(1) }, { MP_ROM_QSTR(MP_QSTR_UPDATE_MEDIUM), MP_ROM_INT(1) },
@ -97,6 +99,12 @@ STATIC const mp_rom_map_elem_t badger2040_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR_UPDATE_TURBO), MP_ROM_INT(3) }, { MP_ROM_QSTR(MP_QSTR_UPDATE_TURBO), MP_ROM_INT(3) },
{ MP_ROM_QSTR(MP_QSTR_UPDATE_SUPER_EXTRA_TURBO), MP_ROM_INT(3) }, // ho ho placebo! { MP_ROM_QSTR(MP_QSTR_UPDATE_SUPER_EXTRA_TURBO), MP_ROM_INT(3) }, // ho ho placebo!
{ MP_ROM_QSTR(MP_QSTR_SYSTEM_VERY_SLOW), MP_ROM_INT(0) },
{ MP_ROM_QSTR(MP_QSTR_SYSTEM_SLOW), MP_ROM_INT(1) },
{ MP_ROM_QSTR(MP_QSTR_SYSTEM_NORMAL), MP_ROM_INT(2) },
{ MP_ROM_QSTR(MP_QSTR_SYSTEM_FAST), MP_ROM_INT(3) },
{ MP_ROM_QSTR(MP_QSTR_SYSTEM_TURBO), MP_ROM_INT(4) },
{ MP_ROM_QSTR(MP_QSTR_WIDTH), MP_ROM_INT(296) }, { MP_ROM_QSTR(MP_QSTR_WIDTH), MP_ROM_INT(296) },
{ MP_ROM_QSTR(MP_QSTR_HEIGHT), MP_ROM_INT(128) }, { MP_ROM_QSTR(MP_QSTR_HEIGHT), MP_ROM_INT(128) },

Wyświetl plik

@ -139,7 +139,7 @@ MICROPY_EVENT_POLL_HOOK
// Ensure blocking for the minimum amount of time // Ensure blocking for the minimum amount of time
// in cases where "is_busy" is unreliable. // in cases where "is_busy" is unreliable.
while(self->badger2040->is_busy() || absolute_time_diff_us(t_end, get_absolute_time()) > 0) { while(self->badger2040->is_busy() || absolute_time_diff_us(get_absolute_time(), t_end) > 0) {
#ifdef MICROPY_EVENT_POLL_HOOK #ifdef MICROPY_EVENT_POLL_HOOK
MICROPY_EVENT_POLL_HOOK MICROPY_EVENT_POLL_HOOK
#endif #endif
@ -517,4 +517,75 @@ mp_obj_t Badger2040_measure_glyph(size_t n_args, const mp_obj_t *pos_args, mp_ma
return mp_obj_new_int(self->badger2040->measure_glyph(c, scale)); return mp_obj_new_int(self->badger2040->measure_glyph(c, scale));
} }
#include "hardware/vreg.h"
#include "hardware/clocks.h"
#include "hardware/pll.h"
mp_obj_t Badger2040_system_speed(mp_obj_t speed) {
uint32_t sys_freq;
uint32_t selected_speed = mp_obj_get_int(speed);
if (gpio_get(pimoroni::Badger2040::VBUS_DETECT) && selected_speed < 2) {
// If on USB never go slower than normal speed.
selected_speed = 2;
}
switch (selected_speed)
{
case 4: // TURBO: 250 MHZ, 1.2V
vreg_set_voltage(VREG_VOLTAGE_1_20);
set_sys_clock_khz(250000, true);
return mp_const_none;
case 3: // FAST: 133 MHZ
vreg_set_voltage(VREG_VOLTAGE_1_10);
set_sys_clock_khz(133000, true);
return mp_const_none;
default:
case 2: // NORMAL: 48 MHZ
vreg_set_voltage(VREG_VOLTAGE_1_10);
set_sys_clock_48mhz();
return mp_const_none;
case 1: // SLOW: 12 MHZ, 1.0V
sys_freq = 12 * MHZ;
break;
case 0: // VERY_SLOW: 4 MHZ, 1.0V
sys_freq = 4 * MHZ;
break;
}
// Set the configured clock speed, by dividing the USB PLL
clock_configure(clk_sys,
CLOCKS_CLK_SYS_CTRL_SRC_VALUE_CLKSRC_CLK_SYS_AUX,
CLOCKS_CLK_SYS_CTRL_AUXSRC_VALUE_CLKSRC_PLL_USB,
48 * MHZ,
sys_freq);
clock_configure(clk_peri,
0,
CLOCKS_CLK_PERI_CTRL_AUXSRC_VALUE_CLK_SYS,
sys_freq,
sys_freq);
clock_configure(clk_adc,
0,
CLOCKS_CLK_ADC_CTRL_AUXSRC_VALUE_CLKSRC_PLL_USB,
48 * MHZ,
sys_freq);
// No longer using the SYS PLL so disable it
pll_deinit(pll_sys);
// Not using USB so stop the clock
clock_stop(clk_usb);
// Drop the core voltage
vreg_set_voltage(VREG_VOLTAGE_1_00);
return mp_const_none;
}
} }

Wyświetl plik

@ -43,3 +43,5 @@ extern mp_obj_t Badger2040_command(mp_obj_t self_in, mp_obj_t reg, mp_obj_t data
extern mp_obj_t Badger2040_pressed_to_wake(mp_obj_t button); extern mp_obj_t Badger2040_pressed_to_wake(mp_obj_t button);
extern mp_obj_t Badger2040_woken_by_button(); extern mp_obj_t Badger2040_woken_by_button();
extern mp_obj_t Badger2040_system_speed(mp_obj_t speed);

Wyświetl plik

@ -20,4 +20,7 @@ target_compile_definitions(usermod_${MOD_NAME} INTERFACE
MODULE_BADGER2040_ENABLED=1 MODULE_BADGER2040_ENABLED=1
) )
target_link_libraries(usermod INTERFACE usermod_${MOD_NAME}) target_link_libraries(usermod INTERFACE usermod_${MOD_NAME}
hardware_vreg
hardware_pll
hardware_resets)