kopia lustrzana https://github.com/pimoroni/pimoroni-pico
Merge pull request #325 from MichaelBell/improve-performance
Badger2040: system_speed call, plus performance improvementspull/328/head
commit
7c523f82df
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -208,6 +208,7 @@ namespace pimoroni {
|
|||
void off();
|
||||
|
||||
void pixel(int x, int y, int v);
|
||||
uint8_t* get_frame_buffer();
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
```
|
||||
|
||||
|
|
|
@ -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) },
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
Ładowanie…
Reference in New Issue