Compare commits

...

42 Commits

Author SHA1 Message Date
thirdr 662df5a8b1 linting 2024-04-24 13:04:38 +01:00
thirdr eb841fbe53 correct layout on pico display 1 & 2 2024-04-24 13:04:38 +01:00
thirdr 14877b1793 adding pngdec 2024-04-24 13:04:38 +01:00
thirdr 233896ac81 fixed background colour 2024-04-24 13:04:38 +01:00
thirdr badc679c2b fixed background colour 2024-04-24 13:04:38 +01:00
thirdr fc67c0db86 offset palette example 2024-04-24 13:04:38 +01:00
thirdr 3b56bc1781 adjustment to scale and location 2024-04-24 13:04:38 +01:00
thirdr d74279dbdf png palette offset example 2024-04-24 13:04:38 +01:00
thirdr 4a7f552f8a Changed the png used 2024-04-24 13:04:38 +01:00
thirdr a4e8fda4d8 png decode example for tufty 2024-04-24 13:04:38 +01:00
thirdr 111e00de64 png decode example for display pack 2024-04-24 13:04:38 +01:00
thirdr 9cce6a7474 Error handling 2024-04-24 13:04:38 +01:00
thirdr dc63b215cd pngdec example for inky 2024-04-24 13:04:38 +01:00
Connor Linfoot 32c10482d9
Add support for 96x48 display to Interstate75 (#867)
* Add DISPLAY_INTERSTATE75_96X48
2024-04-17 13:41:02 +01:00
Philip Howard 4c44b77193
Merge pull request #912 from pimoroni/patch-picodisplay-180
PicoDisplay: Fix misalignment on rotated Pico Displays (fixes #562.)
2024-04-17 12:54:18 +01:00
Phil Howard 5510c82564 PicoDisplay: Fix rotation offset for #562.
Pico Display would have a pixel offset at 90 and 180 degree rotations.

Add a special case offset tweak for these, and demystify the rotate_180 variable.
2024-04-17 12:44:40 +01:00
Philip Howard 3a10b29f54
Merge pull request #920 from pimoroni/patch-inky7-update-timeout
inky73: Add busy wait timeout.
2024-04-17 12:42:53 +01:00
Phil Howard 8cf276b992 inky73: Add busy wait timeout.
Add a timeout to fix Inky 7.3" hanging on batteries.

Basically assumes the update has finished if it takes > 45s, and allows a subsequent attempt
rather than hanging indefinitely.

Raised, texted and fixed by w3stbam: https://github.com/pimoroni/pimoroni-pico/pull/900

Rewritten as mentioned in the PR.
2024-04-17 12:33:24 +01:00
Philip Howard f1ea35fbbf
Merge pull request #911 from pimoroni/patch-unicorn-brightness
G/S/C Unicorn: Fix get_brightness to use correct max value.
2024-04-11 17:45:48 +01:00
Philip Howard c066325ca0
Merge pull request #909 from pimoroni/patch-ltr559-interrupt
LTR559: Add interrupt.py demo from #169.
2024-04-11 17:41:58 +01:00
Philip Howard fd4eb165f8
Merge pull request #930 from pimoroni/patch-misc-ci-fixes
Slightly less frustrating MicroPython builds.
2024-04-11 17:08:44 +01:00
Phil Howard 8fc8a8ee06 CI: Rename tiny2040 to tiny2040_8mb.
It was not super obvious that this build is specific to the 8mb
version of Tiny 2040.
2024-04-11 17:01:21 +01:00
Phil Howard 3bfb548686 CI: Continue other MicroPython builds if one fails.
In almost all cases it's more useful to know if a given build
is likely to succeed rather than have *everything* fail. This
change adjusts the workflow to allow other builds to continue
if one fails.
2024-04-11 17:01:09 +01:00
Philip Howard 9edcdcc126
Merge pull request #919 from pimoroni/patch-pngdec-palette-offset
PNGdec: Add support for palette offsets and greyscale copy mode
2024-04-11 16:32:08 +01:00
Philip Howard e8e550b18b
Merge pull request #929 from pimoroni/patch/wordclock
Fixed arg order bug
2024-04-11 14:57:07 +01:00
thirdr cdb7b4bf2c fixed arg order bug 2024-04-11 14:02:26 +01:00
Philip Howard 4fc3095433
Merge pull request #925 from pimoroni/patch-actions-nodejs
CI: Update actions to fix nodejs deprecation warnings.
2024-04-08 12:58:00 +01:00
Phil Howard 9c5b529754 CI: Update actions to fix nodejs deprecation warnings. 2024-04-08 12:47:14 +01:00
ZodiusInfuser a87d5581aa
Merge pull request #923 from pimoroni/patch/inventor_encoders
Added example for reading speeds from Inventor 2040W's encoders
2024-04-03 14:57:41 +01:00
ZodiusInfuser 44d7875f7e Relocated example and updated readme 2024-04-03 14:37:26 +01:00
ZodiusInfuser a90c31fb3b More explanation of encoder capture 2024-04-03 14:29:17 +01:00
ZodiusInfuser 458b0ac209 Added a speed reading example for inventor 2024-04-03 14:29:01 +01:00
Phil Howard a537672dd4 PNGdec: Don't convert greys if mode=COPY. 2024-03-28 15:35:05 +00:00
Phil Howard d34e692f51 PNGdec: Don't add palette_offset twice. 2024-03-28 15:30:32 +00:00
Phil Howard 27b913124c PNGdec: Add copy support and offset to greyscale. 2024-03-28 15:04:06 +00:00
Phil Howard c7b788cd1d PNGdec: Add palette offset arg.
Allow index colour PNGs to be copied with a palette offset.

EG: a 4bit PNG could be offset 16 times for as many colour variations.
2024-03-28 15:04:02 +00:00
Philip Howard c386b3e9cf
Merge pull request #910 from pimoroni/patch-readme-stubs
README.md: Add link to pimoroni-pico-stubs.
2024-03-28 10:17:02 +00:00
Philip Howard a7a2e2bee0
Merge pull request #918 from pimoroni/patch-pngdec-1bit
PNGdec: Add greyscale support.
2024-03-27 12:59:25 +00:00
Phil Howard 19fa8864cf PNGdec: Add greyscale support.
Add an optional MODE_PEN to draw the PNG in the current pen colour.

Best used with, but not limited to, 1bit PNG images.
2024-03-27 12:49:09 +00:00
Phil Howard 964cf5eedf G/S/C Unicorn: Fix get_brightness to use correct max value.
Add a comment noting that 256 is the correct maximum brightness.
2024-03-11 21:14:43 +00:00
Phil Howard eab1595352 README.md: Add link to pimoroni-pico-stubs. 2024-03-11 15:04:18 +00:00
Phil Howard 5dd76ed31b LTR559: Add interrupt.py demo from #169. 2024-03-11 13:38:07 +00:00
34 changed files with 510 additions and 43 deletions

View File

@ -25,7 +25,7 @@ jobs:
steps:
- name: Compiler Cache
uses: actions/cache@v3
uses: actions/cache@v4
with:
path: /home/runner/.ccache
key: ccache-cmake-${{github.ref}}-${{matrix.board}}-${{github.sha}}
@ -34,13 +34,13 @@ jobs:
ccache-cmake-${{github.ref}}
ccache-cmake
- uses: actions/checkout@v3
- uses: actions/checkout@v4
with:
submodules: true
# Check out the Pico SDK
- name: Checkout Pico SDK
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
repository: raspberrypi/pico-sdk
path: pico-sdk
@ -48,7 +48,7 @@ jobs:
# Check out the Pico Extras
- name: Checkout Pico Extras
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
repository: raspberrypi/pico-extras
path: pico-extras

View File

@ -13,6 +13,7 @@ jobs:
build:
name: ${{ matrix.name }} (${{ matrix.board }})
runs-on: ubuntu-20.04
continue-on-error: true
strategy:
matrix:
include:
@ -20,7 +21,7 @@ jobs:
board: RPI_PICO
- name: picow
board: RPI_PICO_W
- name: tiny2040
- name: tiny2040_8mb
board: PIMORONI_TINY2040
- name: picolipo_4mb
board: PIMORONI_PICOLIPO_4MB
@ -52,7 +53,7 @@ jobs:
steps:
- name: Compiler Cache
uses: actions/cache@v3
uses: actions/cache@v4
with:
path: /home/runner/.ccache
key: ccache-micropython-${{ matrix.name }}-${{ github.ref }}-${{ github.sha }}
@ -111,7 +112,7 @@ jobs:
cmake_build
- name: Store .uf2 as artifact
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: ${{ env.RELEASE_FILE }}.uf2
path: build-${{ matrix.name }}/${{ env.RELEASE_FILE }}.uf2

View File

@ -9,7 +9,7 @@ jobs:
name: Python Linting
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Install Python Deps
run: python3 -m pip install flake8

View File

@ -44,6 +44,10 @@ You can find MicroPython examples for supported sensors, packs and bases in the
* [MicroPython Examples](micropython/examples)
You can also install MicroPython stubs into Visual Studio Code to give you auto-complete, see:
* [MicroPython Stubs](https://github.com/pimoroni/pimoroni-pico-stubs)
# C/C++
Advanced users that want to unleash the full power of Pico can use our C++ libraries. If you know what you're doing and want to build your own Pimoroni Pico project then start with the [Pimoroni Pico SDK Boilerplate](https://github.com/pimoroni/pico-boilerplate).

View File

@ -47,8 +47,9 @@ namespace pimoroni {
return !(sr.read() & 128);
}
void Inky73::busy_wait() {
while(is_busy()) {
void Inky73::busy_wait(uint timeout_ms) {
absolute_time_t timeout = make_timeout_time_ms(timeout_ms);
while(is_busy() && !time_reached(timeout)) {
tight_loop_contents();
}
}

View File

@ -70,7 +70,7 @@ namespace pimoroni {
// Methods
//--------------------------------------------------
public:
void busy_wait();
void busy_wait(uint timeout_ms=45000);
void reset();
void power_off();

View File

@ -133,8 +133,6 @@ namespace pimoroni {
void ST7789::configure_display(Rotation rotate) {
bool rotate180 = rotate == ROTATE_180 || rotate == ROTATE_90;
if(rotate == ROTATE_90 || rotate == ROTATE_270) {
std::swap(width, height);
}
@ -185,20 +183,30 @@ namespace pimoroni {
// Pico Display
if(width == 240 && height == 135) {
caset[0] = 40; // 240 cols
caset[1] = 279;
raset[0] = 53; // 135 rows
raset[1] = 187;
madctl = rotate180 ? MADCTL::ROW_ORDER : MADCTL::COL_ORDER;
caset[1] = 40 + width - 1;
raset[0] = 52; // 135 rows
raset[1] = 52 + height - 1;
if (rotate == ROTATE_0) {
raset[0] += 1;
raset[1] += 1;
}
madctl = rotate == ROTATE_180 ? MADCTL::ROW_ORDER : MADCTL::COL_ORDER;
madctl |= MADCTL::SWAP_XY | MADCTL::SCAN_ORDER;
}
// Pico Display at 90 degree rotation
if(width == 135 && height == 240) {
caset[0] = 52; // 135 cols
caset[1] = 186;
caset[1] = 52 + width - 1;
raset[0] = 40; // 240 rows
raset[1] = 279;
madctl = rotate180 ? (MADCTL::COL_ORDER | MADCTL::ROW_ORDER) : 0;
raset[1] = 40 + height - 1;
madctl = 0;
if (rotate == ROTATE_90) {
caset[0] += 1;
caset[1] += 1;
madctl = MADCTL::COL_ORDER | MADCTL::ROW_ORDER;
}
madctl = rotate == ROTATE_90 ? (MADCTL::COL_ORDER | MADCTL::ROW_ORDER) : 0;
}
// Pico Display 2.0
@ -207,7 +215,7 @@ namespace pimoroni {
caset[1] = 319;
raset[0] = 0;
raset[1] = 239;
madctl = rotate180 ? MADCTL::ROW_ORDER : MADCTL::COL_ORDER;
madctl = (rotate == ROTATE_180 || rotate == ROTATE_90) ? MADCTL::ROW_ORDER : MADCTL::COL_ORDER;
madctl |= MADCTL::SWAP_XY | MADCTL::SCAN_ORDER;
}
@ -217,7 +225,7 @@ namespace pimoroni {
caset[1] = 239;
raset[0] = 0;
raset[1] = 319;
madctl = rotate180 ? (MADCTL::COL_ORDER | MADCTL::ROW_ORDER) : 0;
madctl = (rotate == ROTATE_180 || rotate == ROTATE_90) ? (MADCTL::COL_ORDER | MADCTL::ROW_ORDER) : 0;
}
// Byte swap the 16bit rows/cols values

View File

@ -494,11 +494,14 @@ namespace pimoroni {
void CosmicUnicorn::set_brightness(float value) {
value = value < 0.0f ? 0.0f : value;
value = value > 1.0f ? 1.0f : value;
// Max brightness is - in fact - 256 since it's applied with:
// result = (channel * brightness) >> 8
// eg: (255 * 256) >> 8 == 255
this->brightness = floor(value * 256.0f);
}
float CosmicUnicorn::get_brightness() {
return this->brightness / 255.0f;
return this->brightness / 256.0f;
}
void CosmicUnicorn::adjust_brightness(float delta) {

View File

@ -488,11 +488,14 @@ namespace pimoroni {
void GalacticUnicorn::set_brightness(float value) {
value = value < 0.0f ? 0.0f : value;
value = value > 1.0f ? 1.0f : value;
// Max brightness is - in fact - 256 since it's applied with:
// result = (channel * brightness) >> 8
// eg: (255 * 256) >> 8 == 255
this->brightness = floor(value * 256.0f);
}
float GalacticUnicorn::get_brightness() {
return this->brightness / 255.0f;
return this->brightness / 256.0f;
}
void GalacticUnicorn::adjust_brightness(float delta) {

View File

@ -485,11 +485,14 @@ namespace pimoroni {
void StellarUnicorn::set_brightness(float value) {
value = value < 0.0f ? 0.0f : value;
value = value > 1.0f ? 1.0f : value;
// Max brightness is - in fact - 256 since it's applied with:
// result = (channel * brightness) >> 8
// eg: (255 * 256) >> 8 == 255
this->brightness = floor(value * 256.0f);
}
float StellarUnicorn::get_brightness() {
return this->brightness / 255.0f;
return this->brightness / 256.0f;
}
void StellarUnicorn::adjust_brightness(float delta) {

View File

@ -0,0 +1,30 @@
import time
from machine import Pin
from pimoroni_i2c import PimoroniI2C
from breakout_ltr559 import BreakoutLTR559
PINS_BREAKOUT_GARDEN = {"sda": 4, "scl": 5}
PINS_PICO_EXPLORER = {"sda": 20, "scl": 21}
PIN_INTERRUPT = 22 # 3 for Breakout Garden
i2c = PimoroniI2C(**PINS_PICO_EXPLORER)
ltr = BreakoutLTR559(i2c, interrupt=PIN_INTERRUPT)
interrupt = Pin(PIN_INTERRUPT, Pin.IN, Pin.PULL_DOWN)
ltr.light_threshold(0, 10) # COUNTS, NOT LUX!!!
ltr.proximity_threshold(0, 10)
def read(pin):
reading = ltr.get_reading()
if reading is not None:
print("T: ", time.ticks_ms(), " Lux: ", reading[BreakoutLTR559.LUX], " Prox: ", reading[BreakoutLTR559.PROXIMITY])
interrupt.irq(trigger=Pin.IRQ_RISING, handler=read)
part_id = ltr.part_id()
print("Found LTR559. Part ID: 0x", '{:02x}'.format(part_id), sep="")
while True:
pass

View File

@ -0,0 +1,36 @@
from picographics import PicoGraphics, DISPLAY_INKY_FRAME as DISPLAY # 5.7"
# from picographics import PicoGraphics, DISPLAY_INKY_FRAME_4 as DISPLAY # 4.0"
# from picographics import PicoGraphics, DISPLAY_INKY_FRAME_7 as DISPLAY # 7.3"
import pngdec
# Create a PicoGraphics instance
graphics = PicoGraphics(DISPLAY)
WIDTH, HEIGHT = graphics.get_bounds()
# Set the font
graphics.set_font("bitmap8")
# Create an instance of the PNG Decoder
png = pngdec.PNG(graphics)
# Clear the screen
graphics.set_pen(1)
graphics.clear()
graphics.set_pen(0)
# Few lines of text.
graphics.text("PNG Pencil", 70, 100, WIDTH, 3)
# Open our PNG File from flash. In this example we're using a cartoon pencil.
# You can use Thonny to transfer PNG Images to your Inky Frame.
try:
png.open_file("pencil_256x256.png")
# Decode our PNG file and set the X and Y
png.decode(200, 100)
except OSError:
graphics.text("Unable to find PNG file! Copy 'pencil_256x256.png' to your Inky Frame using Thonny :)", 10, 70, WIDTH, 3)
# Start the screen update
graphics.update()

View File

@ -95,7 +95,7 @@ def draw():
y += line_space
x = default_x
graphics.text(letter.upper(), x, y, 640, scale, spacing)
graphics.text(letter.upper(), x, y, 640, scale=scale, spacing=spacing)
x += letter_space
graphics.update()

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

View File

@ -4,6 +4,7 @@
- [Read ADCs](#read-adcs)
- [Read GPIOs](#read-gpios)
- [Read Encoders](#read-encoders)
- [Read Speeds](#read-speeds)
- [LED Rainbow](#led-rainbow)
- [Reset Inventor](#reset-inventor)
- [Motor Examples](#motor-examples)
@ -22,13 +23,14 @@
- [Velocity Tuning](#velocity-tuning)
- [Position on Velocity Tuning](#position-on-velocity-tuning)
- [Servo Examples](#servo-examples)
- [Single Servos](#single-servo)
- [Single Servo](#single-servo)
- [Multiple Servos](#multiple-servos)
- [Simple Easing](#simple-easing)
- [Servo Wave](#servo-wave)
- [Calibration](#calibration)
- [Audio Examples](#audio-examples)
- [Tone Song](#tone-song)
- [Motor Song](#motor-song)
## Function Examples
@ -50,6 +52,12 @@ Shows how to initialise and read the 6 GPIO headers of Inventor 2040 W.
Demonstrates how to read the angles of Inventor 2040 W's two encoders.
### Read Speeds
[read_speeds.py](read_speeds.py)
Demonstrates how to read the speeds of Inventor 2040 W's two encoders.
### LED Rainbow
[led_rainbow.py](led_rainbow.py)

View File

@ -0,0 +1,46 @@
import time
from inventor import Inventor2040W, NUM_MOTORS # , MOTOR_A, MOTOR_B
# from pimoroni import REVERSED_DIR
"""
Demonstrates how to read the speeds of Inventor 2040 W's two encoders.
Press "User" to exit the program.
"""
# Wheel friendly names
NAMES = ["LEFT", "RIGHT"]
# Constants
GEAR_RATIO = 50 # The gear ratio of the motor
SPEED = 1.0 # The speed to drive the motors at
SLEEP = 0.1 # The time to sleep between each capture
# Create a new Inventor2040W
board = Inventor2040W(motor_gear_ratio=GEAR_RATIO)
# Uncomment the below lines (and the top imports) to
# reverse the counting direction of an encoder
# encoders[MOTOR_A].direction(REVERSED_DIR)
# encoders[MOTOR_B].direction(REVERSED_DIR)
# Set both motors driving
for motor in board.motors:
motor.speed(SPEED)
# Variables for storing encoder captures
captures = [None] * NUM_MOTORS
# Read the encoders until the user button is pressed
while not board.switch_pressed():
# Capture the state of all the encoders since the last capture, SLEEP seconds ago
for i in range(NUM_MOTORS):
captures[i] = board.encoders[i].capture()
# Print out the speeds from each encoder
for i in range(NUM_MOTORS):
print(NAMES[i], "=", captures[i].revolutions_per_second, end=", ")
print()
time.sleep(SLEEP)

View File

@ -0,0 +1,40 @@
from picographics import PicoGraphics, DISPLAY_PICO_DISPLAY, PEN_RGB332
import pngdec
# Create a PicoGraphics instance
display = PicoGraphics(display=DISPLAY_PICO_DISPLAY, pen_type=PEN_RGB332)
# Set the backlight so we can see it!
display.set_backlight(1.0)
# Create an instance of the PNG Decoder
png = pngdec.PNG(display)
# Create some pens for use later.
BG = display.create_pen(200, 200, 200)
TEXT = display.create_pen(0, 0, 0)
# Clear the screen
display.set_pen(BG)
display.clear()
display.set_pen(TEXT)
display.text("PNG Pencil", 15, 80)
try:
# Open our PNG File from flash. In this example we're using an image of a cartoon pencil.
# You can use Thonny to transfer PNG Images to your Pico.
png.open_file("pencil.png")
# Decode our PNG file and set the X and Y
png.decode(20, 100, scale=3)
# Handle the error if the image doesn't exist on the flash.
except OSError:
print("Error: PNG File missing. Copy the PNG file from the example folder to your Pico using Thonny and run the example again.")
display.update()
# We're not doing anything else with the display now but we want to keep the program running!
while True:
pass

View File

@ -0,0 +1,66 @@
from picographics import PicoGraphics, DISPLAY_PICO_DISPLAY_2, PEN_P8
import pngdec
# Create a PicoGraphics instance
display = PicoGraphics(display=DISPLAY_PICO_DISPLAY_2, pen_type=PEN_P8, rotate=270)
# Get the display width/height so we can position the PNGs
width, height = display.get_bounds()
# Set the backlight so we can see it!
display.set_backlight(1.0)
# Create an instance of the PNG Decoder
png = pngdec.PNG(display)
# Create some pens for use later.
BG = display.create_pen(200, 200, 200)
# 16 Reds
for i in range(16):
display.create_pen(i * 16, 0, 0)
# 16 Greens
for i in range(16):
display.create_pen(0, i * 16, 0)
# 16 Blues
for i in range(16):
display.create_pen(0, 0, i * 16)
# Adding in an white background colour at the beginning of each offset.
for i in range(3):
display.update_pen(i * 16, 200, 200, 200)
# Clear the screen
display.set_pen(BG)
display.clear()
try:
# Open our PNG File from flash. In this example we're using an image of a cartoon pencil.
# You can use Thonny to transfer PNG Images to your Pico.
png.open_file("pencil_gray.png")
# Horizontally/vertically center the three PNG Images.
png_w = png.get_width()
png_h = png.get_height()
offset_x = (width - png_w * 2) // 2
height_y = (height // 3)
offset_y = (height_y - png_h * 2) // 2
# Decode our PNG file and set the X and Y
png.decode(offset_x, offset_y, scale=2, mode=pngdec.PNG_COPY, palette_offset=0)
png.decode(offset_x, offset_y + height_y, scale=2, mode=pngdec.PNG_COPY, palette_offset=16)
png.decode(offset_x, offset_y + (height_y * 2), scale=2, mode=pngdec.PNG_COPY, palette_offset=32)
# Handle the error if the image doesn't exist on the flash.
except OSError:
print("Error: PNG File missing. Copy the PNG file from the example folder to your Pico using Thonny and run the example again.")
display.update()
# We're not doing anything else with the display now but we want to keep the program running!
while True:
pass

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 497 B

View File

@ -0,0 +1,36 @@
from picographics import PicoGraphics, DISPLAY_TUFTY_2040
import pngdec
display = PicoGraphics(display=DISPLAY_TUFTY_2040)
# Create an instance of the PNG Decoder
png = pngdec.PNG(display)
# Create some pens for use later.
BG = display.create_pen(200, 200, 200)
TEXT = display.create_pen(0, 0, 0)
# Clear the screen
display.set_pen(BG)
display.clear()
display.set_pen(TEXT)
display.text("PNG Pencil", 105, 80)
try:
# Open our PNG File from flash. In this example we're using an image of a cartoon pencil.
# You can use Thonny to transfer PNG Images to your Pico.
png.open_file("pencil.png")
# Decode our PNG file and set the X and Y
png.decode(140, 100)
# Handle the error if the image doesn't exist on the flash.
except OSError:
print("Error: PNG File missing. Copy the PNG file from the example folder to your Pico using Thonny and run the example again.")
display.update()
# We're not doing anything else with the display now but we want to keep the program running!
while True:
pass

View File

@ -0,0 +1,54 @@
from picographics import PicoGraphics, DISPLAY_TUFTY_2040, PEN_P8
import pngdec
display = PicoGraphics(display=DISPLAY_TUFTY_2040, pen_type=PEN_P8)
# Create an instance of the PNG Decoder
png = pngdec.PNG(display)
# Create some pens for use later.
BG = display.create_pen(200, 200, 200)
TEXT = display.create_pen(0, 0, 0)
# 16 Reds
for i in range(15):
display.create_pen(i * 16, 0, 0)
# 16 Greens
for i in range(16):
display.create_pen(0, i * 16, 0)
# 16 Blues
for i in range(15):
display.create_pen(0, 0, i * 16)
# Adding in an white background colour at the beginning of each offset.
for i in range(3):
display.update_pen(i * 16, 200, 200, 200)
# Clear the screen
display.set_pen(BG)
display.clear()
display.set_pen(TEXT)
display.text("PNG Pencil \n& Offset Palette", 125, 115)
try:
# Open our PNG File from flash. In this example we're using an image of a cartoon pencil.
# You can use Thonny to transfer PNG Images to your Pico.
png.open_file("pencil_gray.png")
# Decode our PNG file and set the X and Y
png.decode(35, 10, scale=2, mode=pngdec.PNG_COPY, palette_offset=0)
png.decode(35, 90, scale=2, mode=pngdec.PNG_COPY, palette_offset=16)
png.decode(35, 170, scale=2, mode=pngdec.PNG_COPY, palette_offset=32)
# Handle the error if the image doesn't exist on the flash.
except OSError:
print("Error: PNG File missing. Copy the PNG file from the example folder to your Pico using Thonny and run the example again.")
display.update()
# We're not doing anything else with the display now but we want to keep the program running!
while True:
pass

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 497 B

View File

@ -6,6 +6,7 @@ This library offers an `Encoder` class that uses Programmable IO (PIO) hardware
## Table of Content
- [Table of Content](#table-of-content)
- [Encoder](#encoder)
- [Getting Started](#getting-started)
- [Count and Angle](#count-and-angle)
@ -102,7 +103,22 @@ degrees_per_second
radians_per_second
```
Internally `.capture()` does the same up-front reading of values but does so more optimally within the underlying C++ driver. As an added bonus, it calculates encoder speeds too, by using the captured `delta` along with timing information returned by the PIO, more accurately than estimating a speed from the `delta` alone.
Internally `.capture()` does the same up-front reading of values but does so more optimally within the underlying C++ driver. It calculates encoder speeds too, by using the difference between the current `count` and the **last capture's** `count` (aka the `delta`), along with timing information returned by the PIO. This produces speed readings that are more accurate than estimating a speed from the `delta` alone.
:information_source: **It is recommended to perform captures frequently and at a consistent rate.** If this is not possible for your project, consider performing a dummy capture at the start of the time window you actually wish to measure the encoder's speed over.
```python
# Perform a dummy capture to clear the encoder
enc.capture()
# Wait for the capture time to pass
time.sleep(CAPTURE_TIME)
# Perform a capture and read the measured speed
capture = enc.capture()
print("Speed =", capture.revolutions_per_second)
```
### State

View File

@ -84,6 +84,7 @@ The available display settings are listed here:
* 32 x 32 Matrix - `DISPLAY_INTERSTATE75_32X32`
* 64 x 32 Matrix - `DISPLAY_INTERSTATE75_64X32`
* 96 x 32 Matrix - `DISPLAY_INTERSTATE75_96X32`
* 96 x 48 Matrix - `DISPLAY_INTERSTATE75_96X48`
* 128 x 32 Matrix - `DISPLAY_INTERSTATE75_128X32`
* 64 x 64 Matrix - `DISPLAY_INTERSTATE75_64X64`
* 128 x 64 Matrix - `DISPLAY_INTERSTATE75_128X64`
@ -583,3 +584,42 @@ The arguments for `decode` are as follows:
2. Decode Y
3. Flags - one of `JPEG_SCALE_FULL`, `JPEG_SCALE_HALF`, `JPEG_SCALE_QUARTER` or `JPEG_SCALE_EIGHTH`
4. If you want to turn off dither altogether, try `dither=False`. This is useful if you want to [pre-dither your images](https://ditherit.com/) or for artsy posterization effects.
### PNG Files
We've included BitBank's PNGDEC - https://github.com/bitbank2/PNGDEC - so you can display PNG files on your LCDs.
Eg:
```python
import picographics
import pngdec
display = PicoGraphics(display=DISPLAY_PICO_DISPLAY, pen_type=PEN_RGB332)
# Create a new PNG decoder for our PicoGraphics
png = pngdec.PNG(display)
# Open the PNG file
png.open_file("filename.jpeg")
# Decode the PNG
png.decode(0, 0)
# Display the result
display.update()
```
PNG files must be small enough to load into RAM for decoding.
PNGDEC Supports the following PNG types:
1. True Colour
2. True Colour (with Alpha)
3. Indexed
4. Grayscale
The arguments for `decode` are as follows:
1. Decode X - where to place the decoded JPEG on screen
2. Decode Y

View File

@ -145,6 +145,7 @@ STATIC const mp_map_elem_t picographics_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR_DISPLAY_INTERSTATE75_32X32), MP_ROM_INT(DISPLAY_INTERSTATE75_32X32) },
{ MP_ROM_QSTR(MP_QSTR_DISPLAY_INTERSTATE75_64X32), MP_ROM_INT(DISPLAY_INTERSTATE75_64X32) },
{ MP_ROM_QSTR(MP_QSTR_DISPLAY_INTERSTATE75_96X32), MP_ROM_INT(DISPLAY_INTERSTATE75_96X32) },
{ MP_ROM_QSTR(MP_QSTR_DISPLAY_INTERSTATE75_96X48), MP_ROM_INT(DISPLAY_INTERSTATE75_96X48) },
{ MP_ROM_QSTR(MP_QSTR_DISPLAY_INTERSTATE75_128X32), MP_ROM_INT(DISPLAY_INTERSTATE75_128X32) },
{ MP_ROM_QSTR(MP_QSTR_DISPLAY_INTERSTATE75_64X64), MP_ROM_INT(DISPLAY_INTERSTATE75_64X64) },
{ MP_ROM_QSTR(MP_QSTR_DISPLAY_INTERSTATE75_128X64), MP_ROM_INT(DISPLAY_INTERSTATE75_128X64) },

View File

@ -155,6 +155,14 @@ bool get_display_settings(PicoGraphicsDisplay display, int &width, int &height,
if(rotate == -1) rotate = (int)Rotation::ROTATE_0;
if(pen_type == -1) pen_type = PEN_RGB888;
break;
case DISPLAY_INTERSTATE75_96X48:
width = 96;
height = 48;
bus_type = BUS_PIO;
// Portrait to match labelling
if(rotate == -1) rotate = (int)Rotation::ROTATE_0;
if(pen_type == -1) pen_type = PEN_RGB888;
break;
case DISPLAY_INTERSTATE75_128X32:
width = 128;
height = 32;

View File

@ -19,6 +19,7 @@ enum PicoGraphicsDisplay {
DISPLAY_INTERSTATE75_32X32,
DISPLAY_INTERSTATE75_64X32,
DISPLAY_INTERSTATE75_96X32,
DISPLAY_INTERSTATE75_96X48,
DISPLAY_INTERSTATE75_128X32,
DISPLAY_INTERSTATE75_64X64,
DISPLAY_INTERSTATE75_128X64,

View File

@ -49,6 +49,7 @@ STATIC const mp_map_elem_t PNG_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR_PNG_POSTERISE), MP_ROM_INT(0) },
{ MP_ROM_QSTR(MP_QSTR_PNG_DITHER), MP_ROM_INT(1) },
{ MP_ROM_QSTR(MP_QSTR_PNG_COPY), MP_ROM_INT(2) },
{ MP_ROM_QSTR(MP_QSTR_PNG_PEN), MP_ROM_INT(3) },
};
STATIC MP_DEFINE_CONST_DICT(mp_module_PNG_globals, PNG_globals_table);

View File

@ -25,6 +25,7 @@ typedef struct _PNG_decode_target {
Rect source = {0, 0, 0, 0};
Point scale = {1, 1};
int rotation = 0;
uint8_t palette_offset = 0;
} _PNG_decode_target;
typedef struct _PNG_obj_t {
@ -44,6 +45,7 @@ enum DECODE_MODE : uint8_t {
MODE_POSTERIZE = 0u,
MODE_DITHER = 1u,
MODE_COPY = 2u,
MODE_PEN = 3u,
};
void *pngdec_open_callback(const char *filename, int32_t *size) {
@ -125,6 +127,7 @@ mp_event_handle_nowait();
PicoGraphics *current_graphics = (PicoGraphics *)target->target;
Point current_position = target->position;
uint8_t current_mode = target->mode;
uint8_t current_palette_offset = target->palette_offset;
Point scale = target->scale;
int rotation = target->rotation;
Point step = {0, 0};
@ -158,29 +161,79 @@ mp_event_handle_nowait();
break;
}
//mp_printf(&mp_plat_print, "Drawing scanline at %d, %dbpp, type: %d, width: %d pitch: %d alpha: %d\n", y, pDraw->iBpp, pDraw->iPixelType, pDraw->iWidth, pDraw->iPitch, pDraw->iHasAlpha);
//mp_printf(&mp_plat_print, "Drawing scanline at %d, %dbpp, type: %d, width: %d pitch: %d alpha: %d\n", pDraw->y , pDraw->iBpp, pDraw->iPixelType, pDraw->iWidth, pDraw->iPitch, pDraw->iHasAlpha);
uint8_t *pixel = (uint8_t *)pDraw->pPixels;
if(pDraw->iPixelType == PNG_PIXEL_TRUECOLOR ) {
if(pDraw->iPixelType == PNG_PIXEL_TRUECOLOR || pDraw->iPixelType == PNG_PIXEL_TRUECOLOR_ALPHA) {
for(int x = 0; x < pDraw->iWidth; x++) {
uint8_t r = *pixel++;
uint8_t g = *pixel++;
uint8_t b = *pixel++;
if(x < target->source.x || x >= target->source.x + target->source.w) continue;
current_graphics->set_pen(r, g, b);
current_graphics->rectangle({current_position.x, current_position.y, scale.x, scale.y});
current_position += step;
}
} else if (pDraw->iPixelType == PNG_PIXEL_TRUECOLOR_ALPHA) {
for(int x = 0; x < pDraw->iWidth; x++) {
uint8_t r = *pixel++;
uint8_t g = *pixel++;
uint8_t b = *pixel++;
uint8_t a = *pixel++;
uint8_t a = 1;
if (pDraw->iHasAlpha) {
a = *pixel++;
}
if(x < target->source.x || x >= target->source.x + target->source.w) continue;
if (a) {
current_graphics->set_pen(r, g, b);
current_graphics->rectangle({current_position.x, current_position.y, scale.x, scale.y});
}
current_position += step;
}
} else if (pDraw->iPixelType == PNG_PIXEL_GRAYSCALE) {
for(int x = 0; x < pDraw->iWidth; x++) {
uint8_t i = 0;
if(pDraw->iBpp == 8) { // 8bpp
i = *pixel++; // Already 8bpc
} else if (pDraw->iBpp == 4) { // 4bpp
i = *pixel;
i >>= (x & 0b1) ? 0 : 4;
i &= 0xf;
if (x & 1) pixel++;
// Just copy the colour into the upper and lower nibble
if(current_mode != MODE_COPY) {
i = (i << 4) | i;
}
} else if (pDraw->iBpp == 2) { // 2bpp
i = *pixel;
i >>= 6 - ((x & 0b11) << 1);
i &= 0x3;
if ((x & 0b11) == 0b11) pixel++;
// Evenly spaced 4-colour palette
if(current_mode != MODE_COPY) {
i = (0xFFB86800 >> (i * 8)) & 0xFF;
}
} else { // 1bpp
i = *pixel;
i >>= 7 - (x & 0b111);
i &= 0b1;
if ((x & 0b111) == 0b111) pixel++;
if(current_mode != MODE_COPY) {
i = i ? 255 : 0;
}
}
if(x < target->source.x || x >= target->source.x + target->source.w) continue;
//mp_printf(&mp_plat_print, "Drawing pixel at %dx%d, %dbpp, value %d\n", current_position.x, current_position.y, pDraw->iBpp, i);
if (current_mode != MODE_PEN) {
// Allow greyscale PNGs to be copied just like an indexed PNG
// since we might want to offset and recolour them.
if(current_mode == MODE_COPY
&& (current_graphics->pen_type == PicoGraphics::PEN_P8
|| current_graphics->pen_type == PicoGraphics::PEN_P4
|| current_graphics->pen_type == PicoGraphics::PEN_3BIT
|| current_graphics->pen_type == PicoGraphics::PEN_INKY7)) {
if(current_palette_offset > 0) {
i = ((int16_t)(i) + current_palette_offset) & 0xff;
}
current_graphics->set_pen(i);
} else {
current_graphics->set_pen(i, i, i);
}
}
if (current_mode != MODE_PEN || i == 0) {
current_graphics->rectangle({current_position.x, current_position.y, scale.x, scale.y});
}
current_position += step;
}
} else if (pDraw->iPixelType == PNG_PIXEL_INDEXED) {
@ -231,6 +284,9 @@ mp_event_handle_nowait();
// Copy raw palette indexes over
if(current_mode == MODE_COPY) {
if(current_palette_offset > 0) {
i = ((int16_t)(i) + current_palette_offset) & 0xff;
}
current_graphics->set_pen(i);
current_graphics->rectangle({current_position.x, current_position.y, scale.x, scale.y});
// Posterized output to the available palete
@ -326,7 +382,7 @@ mp_obj_t _PNG_openRAM(mp_obj_t self_in, mp_obj_t buffer) {
// decode
mp_obj_t _PNG_decode(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_self, ARG_x, ARG_y, ARG_scale, ARG_mode, ARG_source, ARG_rotate };
enum { ARG_self, ARG_x, ARG_y, ARG_scale, ARG_mode, ARG_source, ARG_rotate, ARG_palette_offset };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_x, MP_ARG_INT, {.u_int = 0} },
@ -335,6 +391,7 @@ mp_obj_t _PNG_decode(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args)
{ MP_QSTR_mode, MP_ARG_INT, {.u_int = 0} },
{ MP_QSTR_source, MP_ARG_OBJ, {.u_obj = nullptr} },
{ MP_QSTR_rotate, MP_ARG_INT, {.u_int = 0} },
{ MP_QSTR_palette_offset, MP_ARG_INT, {.u_int = 0} },
};
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
@ -394,6 +451,8 @@ mp_obj_t _PNG_decode(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args)
self->decode_target->position = {args[ARG_x].u_int, args[ARG_y].u_int};
self->decode_target->palette_offset = args[ARG_palette_offset].u_int;
// Just-in-time open of the filename/buffer we stored in self->file via open_RAM or open_file
// Source is a filename

View File

@ -32,6 +32,7 @@ You can choose the HUB75 matrix display size that you wish to use by defining `d
DISPLAY_INTERSTATE75_32X32
DISPLAY_INTERSTATE75_64X32
DISPLAY_INTERSTATE75_96X32
DISPLAY_INTERSTATE75_96X48
DISPLAY_INTERSTATE75_128X32
DISPLAY_INTERSTATE75_64X64
DISPLAY_INTERSTATE75_128X64

View File

@ -1,5 +1,5 @@
from pimoroni import RGBLED, Button
from picographics import PicoGraphics, DISPLAY_INTERSTATE75_32X32, DISPLAY_INTERSTATE75_64X32, DISPLAY_INTERSTATE75_96X32, DISPLAY_INTERSTATE75_128X32, DISPLAY_INTERSTATE75_64X64, DISPLAY_INTERSTATE75_128X64, DISPLAY_INTERSTATE75_192X64, DISPLAY_INTERSTATE75_256X64
from picographics import PicoGraphics, DISPLAY_INTERSTATE75_32X32, DISPLAY_INTERSTATE75_64X32, DISPLAY_INTERSTATE75_96X32, DISPLAY_INTERSTATE75_96X48, DISPLAY_INTERSTATE75_128X32, DISPLAY_INTERSTATE75_64X64, DISPLAY_INTERSTATE75_128X64, DISPLAY_INTERSTATE75_192X64, DISPLAY_INTERSTATE75_256X64
from pimoroni_i2c import PimoroniI2C
import hub75
import sys
@ -23,6 +23,7 @@ class Interstate75:
DISPLAY_INTERSTATE75_32X32 = DISPLAY_INTERSTATE75_32X32
DISPLAY_INTERSTATE75_64X32 = DISPLAY_INTERSTATE75_64X32
DISPLAY_INTERSTATE75_96X32 = DISPLAY_INTERSTATE75_96X32
DISPLAY_INTERSTATE75_96X48 = DISPLAY_INTERSTATE75_96X48
DISPLAY_INTERSTATE75_128X32 = DISPLAY_INTERSTATE75_128X32
DISPLAY_INTERSTATE75_64X64 = DISPLAY_INTERSTATE75_64X64
DISPLAY_INTERSTATE75_128X64 = DISPLAY_INTERSTATE75_128X64