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
}
uint8_t* UC8151::get_frame_buffer() {
return frame_buffer;
}
void UC8151::invert(bool inv) {
inverted = inv;
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() {
switch(_update_speed) {
case 0:
return 5500;
return 4500;
case 1:
return 2600;
return 2000;
case 2:
return 1000;
return 800;
case 3:
return 300;
return 250;
default:
return 5500;
return 4500;
}
}

Wyświetl plik

@ -208,6 +208,7 @@ namespace pimoroni {
void off();
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?
}
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() {
gpio_put(ENABLE_3V3, 0);
@ -100,15 +92,54 @@ namespace pimoroni {
15, 7, 13, 5
};
if (p == 0) {
return 1;
}
if (p == 15) {
return 0;
}
// calculate dither matrix offset
uint32_t dmo = (x & 0b11) | ((y & 0b11) << 2);
if(p == 0) {
return 1;
}else if(p == 15) {
return p <= _odm[dmo] ? 1 : 0;
}
// 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;
}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);
}
// 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) {
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
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) {
@ -156,9 +211,44 @@ namespace pimoroni {
}
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++) {
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 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()
display = badger2040.Badger2040()

Wyświetl plik

@ -6,6 +6,9 @@ import machine
import badger2040
# Overclock the RP2040 to run the sim faster
badger2040.system_speed(badger2040.SYSTEM_TURBO)
# ------------------------------
# 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
screen = badger2040.Badger2040()
screen.led(128)
screen.update_speed(badger2040.UPDATE_TURBO)
restart = False # should sim be restarted

Wyświetl plik

@ -1,14 +1,13 @@
import gc
import time
import math
import machine
import badger2040
from badger2040 import WIDTH
import launchericons
import badger_os
# Reduce clock speed to 48MHz, that's fast enough!
machine.freq(48000000)
# Reduce clock speed to 48MHz
badger2040.system_speed(badger2040.SYSTEM_NORMAL)
changed = 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_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
@ -95,7 +107,6 @@ icon(data, icon_index, sheet_size, icon_size)
clear()
update()
partial_update(x, y, w, h)
update_speed(speed)
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_halt_obj, Badger2040_halt);
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 *****/
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_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_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_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_HEIGHT), MP_ROM_INT(128) },

Wyświetl plik

@ -139,7 +139,7 @@ MICROPY_EVENT_POLL_HOOK
// Ensure blocking for the minimum amount of time
// 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
MICROPY_EVENT_POLL_HOOK
#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));
}
#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_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
)
target_link_libraries(usermod INTERFACE usermod_${MOD_NAME})
target_link_libraries(usermod INTERFACE usermod_${MOD_NAME}
hardware_vreg
hardware_pll
hardware_resets)