Compare commits
33 Commits
Author | SHA1 | Date |
---|---|---|
Philip Howard | f3b53b6b5f | |
coadkins | 37c4d22527 | |
Philip Howard | 616b1cc8d6 | |
Phil Howard | 45a9925072 | |
Connor Linfoot | 32c10482d9 | |
Philip Howard | 4c44b77193 | |
Phil Howard | 5510c82564 | |
Philip Howard | 3a10b29f54 | |
Phil Howard | 8cf276b992 | |
Philip Howard | f1ea35fbbf | |
Philip Howard | c066325ca0 | |
Philip Howard | fd4eb165f8 | |
Phil Howard | 8fc8a8ee06 | |
Phil Howard | 3bfb548686 | |
Philip Howard | 9edcdcc126 | |
Philip Howard | e8e550b18b | |
thirdr | cdb7b4bf2c | |
Philip Howard | 4fc3095433 | |
Phil Howard | 9c5b529754 | |
ZodiusInfuser | a87d5581aa | |
ZodiusInfuser | 44d7875f7e | |
ZodiusInfuser | a90c31fb3b | |
ZodiusInfuser | 458b0ac209 | |
Phil Howard | a537672dd4 | |
Phil Howard | d34e692f51 | |
Phil Howard | 27b913124c | |
Phil Howard | c7b788cd1d | |
Philip Howard | c386b3e9cf | |
Philip Howard | a7a2e2bee0 | |
Phil Howard | 19fa8864cf | |
Phil Howard | 964cf5eedf | |
Phil Howard | eab1595352 | |
Phil Howard | 5dd76ed31b |
|
@ -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
|
||||
|
|
|
@ -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 }}
|
||||
|
@ -80,6 +81,13 @@ jobs:
|
|||
source $BUILD_TOOLS
|
||||
micropython_clone
|
||||
|
||||
- name: "Py_Decl: Checkout py_decl"
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: gadgetoid/py_decl
|
||||
ref: v0.0.1
|
||||
path: py_decl
|
||||
|
||||
- name: Build MPY Cross
|
||||
run: |
|
||||
source $BUILD_TOOLS
|
||||
|
@ -110,8 +118,13 @@ jobs:
|
|||
source $BUILD_TOOLS
|
||||
cmake_build
|
||||
|
||||
- name: "Py_Decl: Verify UF2"
|
||||
shell: bash
|
||||
run: |
|
||||
python3 py_decl/py_decl.py --to-json --verify build-${{ matrix.name }}/${{ env.RELEASE_FILE }}.uf2
|
||||
|
||||
- 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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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).
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -70,7 +70,7 @@ namespace pimoroni {
|
|||
// Methods
|
||||
//--------------------------------------------------
|
||||
public:
|
||||
void busy_wait();
|
||||
void busy_wait(uint timeout_ms=45000);
|
||||
void reset();
|
||||
void power_off();
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
|
@ -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()
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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)
|
|
@ -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
|
||||
|
|
|
@ -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,37 @@ 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 also included Bitbank's PNGdec - https://github.com/bitbank2/PNGdec - for PNG file support with Pico Graphics.
|
||||
|
||||
Like JPEG decoding, PNG decoding supports loading files from microSD, flash and RAM, but unlike JPEG decoding there are some new options for cropping, scaling and rotating you PNG images. (Note: the order is always crop, scale and rotate.)
|
||||
|
||||
A basic example looks something like this:
|
||||
|
||||
```python
|
||||
from pngdec import PNG
|
||||
png = PNG(display)
|
||||
png.open_file("fire.png")
|
||||
png.decode(0, 0)
|
||||
```
|
||||
The arguments for `decode` are as follows:
|
||||
1. Decode X - where to place the decoded PNG on screen
|
||||
2. Decode Y
|
||||
3. Source - The region, in pixels, that you want to show from the PNG. The argument is given as a tuple of four values which give the offset from the left and top of the images, plus the width and height of the selected region. The whole PNG is loaded and decoded no matter what you put here, but this it makes it easier to manage multiple images for things like icons.
|
||||
4. Scale - Lets you scale images up by a fixed multiplier along the X and Y axis. If you want to make an image 4x wider and 2x taller you'd use `scale=(4,2)'.
|
||||
5. Rotate - Lets you rotate your PNG graphic in 90 degree intervals.
|
||||
6. Mode - For indexed PNGs, you can supply a mode argument with one of `PNG COPY`, `PNG DITHER`, and `PNG_POSTERISE`. `PNG_COPY` will copy the palette indexes into a P4 or P8 graphics buffer rather than dithering or posterising (snapping to the nearest available colour).
|
||||
`PNG_DITHER` will use a simple ordered dither matrix to dither the image colours to the available display colours.
|
||||
`PNG_POSTERISE` will snap the colours in the PNG to their nearest display counterpart. Posterise is the default in all cases.
|
||||
|
||||
Lets say you have a spritesheet with 8x8 sprites and you want to display a 3x2 character from it at 4x scale, you might do something like this:
|
||||
|
||||
```python
|
||||
from pngdec import PNG
|
||||
png = PNG(display)
|
||||
png.open_file("/s4m_ur4i-pirate-characters.png")
|
||||
|
||||
png.decode(0, 0, source=(32, 48, 24, 16), scale=(4, 4), rotate=0)
|
||||
```
|
||||
|
|
|
@ -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) },
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue