C class and MP bindings for PicoDisplay2

pull/170/head
ZodiusInfuser 2021-06-17 15:33:05 +01:00 zatwierdzone przez Phil Howard
rodzic 9ba3a6cfab
commit 9906fdec38
23 zmienionych plików z 1089 dodań i 4 usunięć

Wyświetl plik

@ -21,6 +21,7 @@ add_subdirectory(breakout_as7262)
add_subdirectory(breakout_bh1745)
add_subdirectory(pico_display)
add_subdirectory(pico_display_2)
add_subdirectory(pico_unicorn)
add_subdirectory(pico_unicorn_plasma)
add_subdirectory(pico_scroll)

Wyświetl plik

@ -0,0 +1,12 @@
set(OUTPUT_NAME display_2)
add_executable(
${OUTPUT_NAME}
demo.cpp
)
# Pull in pico libraries that we need
target_link_libraries( ${OUTPUT_NAME} pico_stdlib hardware_spi hardware_pwm hardware_dma pico_display_2)
# create map/bin/hex file etc.
pico_add_extra_outputs( ${OUTPUT_NAME})

Wyświetl plik

@ -0,0 +1,111 @@
#include <string.h>
#include <math.h>
#include <vector>
#include <cstdlib>
#include "pico_display_2.hpp"
using namespace pimoroni;
uint16_t buffer[PicoDisplay2::WIDTH * PicoDisplay2::HEIGHT];
PicoDisplay2 pico_display(buffer);
// HSV Conversion expects float inputs in the range of 0.00-1.00 for each channel
// Outputs are rgb in the range 0-255 for each channel
void from_hsv(float h, float s, float v, uint8_t &r, uint8_t &g, uint8_t &b) {
float i = floor(h * 6.0f);
float f = h * 6.0f - i;
v *= 255.0f;
uint8_t p = v * (1.0f - s);
uint8_t q = v * (1.0f - f * s);
uint8_t t = v * (1.0f - (1.0f - f) * s);
switch (int(i) % 6) {
case 0: r = v; g = t; b = p; break;
case 1: r = q; g = v; b = p; break;
case 2: r = p; g = v; b = t; break;
case 3: r = p; g = q; b = v; break;
case 4: r = t; g = p; b = v; break;
case 5: r = v; g = p; b = q; break;
}
}
int main() {
pico_display.init();
pico_display.set_backlight(255);
struct pt {
float x;
float y;
uint8_t r;
float dx;
float dy;
uint16_t pen;
};
std::vector<pt> shapes;
for(int i = 0; i < 100; i++) {
pt shape;
shape.x = rand() % pico_display.bounds.w;
shape.y = rand() % pico_display.bounds.h;
shape.r = (rand() % 10) + 3;
shape.dx = float(rand() % 255) / 64.0f;
shape.dy = float(rand() % 255) / 64.0f;
shape.pen = pico_display.create_pen(rand() % 255, rand() % 255, rand() % 255);
shapes.push_back(shape);
}
Point text_location(0, 0);
while(true) {
if(pico_display.is_pressed(pico_display.A)) text_location.x -= 1;
if(pico_display.is_pressed(pico_display.B)) text_location.x += 1;
if(pico_display.is_pressed(pico_display.X)) text_location.y -= 1;
if(pico_display.is_pressed(pico_display.Y)) text_location.y += 1;
pico_display.set_pen(120, 40, 60);
pico_display.clear();
for(auto &shape : shapes) {
shape.x += shape.dx;
shape.y += shape.dy;
if((shape.x - shape.r) < 0) {
shape.dx *= -1;
shape.x = shape.r;
}
if((shape.x + shape.r) >= pico_display.bounds.w) {
shape.dx *= -1;
shape.x = pico_display.bounds.w - shape.r;
}
if((shape.y - shape.r) < 0) {
shape.dy *= -1;
shape.y = shape.r;
}
if((shape.y + shape.r) >= pico_display.bounds.h) {
shape.dy *= -1;
shape.y = pico_display.bounds.h - shape.r;
}
pico_display.set_pen(shape.pen);
pico_display.circle(Point(shape.x, shape.y), shape.r);
}
// Since HSV takes a float from 0.0 to 1.0 indicating hue,
// then we can divide millis by the number of milliseconds
// we want a full colour cycle to take. 5000 = 5 sec.
uint8_t r = 0, g = 0, b = 0;
from_hsv((float)millis() / 5000.0f, 1.0f, 0.5f + sinf(millis() / 100.0f / 3.14159f) * 0.5f, r, g, b);
pico_display.set_led(r, g, b);
pico_display.set_pen(255, 255, 255);
pico_display.text("Hello World", text_location, 320);
// update screen
pico_display.update();
}
return 0;
}

Wyświetl plik

@ -18,6 +18,7 @@ add_subdirectory(breakout_msa301)
add_subdirectory(breakout_bh1745)
add_subdirectory(pico_graphics)
add_subdirectory(pico_display)
add_subdirectory(pico_display_2)
add_subdirectory(pico_unicorn)
add_subdirectory(pico_scroll)
add_subdirectory(pico_explorer)

Wyświetl plik

@ -0,0 +1,11 @@
set(LIB_NAME pico_display_2)
add_library(${LIB_NAME} INTERFACE)
target_sources(${LIB_NAME} INTERFACE
${CMAKE_CURRENT_LIST_DIR}/${LIB_NAME}.cpp
)
target_include_directories(${LIB_NAME} INTERFACE ${CMAKE_CURRENT_LIST_DIR})
# Pull in pico libraries that we need
target_link_libraries(${LIB_NAME} INTERFACE pico_stdlib hardware_spi hardware_pwm hardware_dma st7789 pico_graphics)

Wyświetl plik

@ -0,0 +1,123 @@
# Pico Display 2.0" Pack <!-- omit in toc -->
Our Pico Display Pack offers a vibrant 1.14" (240x135) IPS LCD screen for your Raspberry Pi Pico it also includes four switches and and an RGB LED!
We've included helper functions to handle every aspect of drawing to the screen and interfacing with the buttons and LED. See the [function reference](#function-reference) for details.
- [Example Program](#example-program)
- [Function Reference](#function-reference)
- [PicoGraphics](#picographics)
- [init](#init)
- [set_backlight](#set_backlight)
- [set_led](#set_led)
- [is_pressed](#is_pressed)
- [update](#update)
## Example Program
The following example sets up Pico Display, displays some basic demo text and graphics and will illuminate the RGB LED green if the A button is pressed.
```c++
#include "pico_display_2.hpp"
using namespace pimoroni;
uint16_t buffer[PicoDisplay2::WIDTH * PicoDisplay2::HEIGHT];
PicoDisplay2 pico_display(buffer);
int main() {
pico_display.init();
// set the backlight to a value between 0 and 255
// the backlight is driven via PWM and is gamma corrected by our
// library to give a gorgeous linear brightness range.
pico_display.set_backlight(100);
while(true) {
// detect if the A button is pressed (could be A, B, X, or Y)
if(pico_display.is_pressed(pico_display.A)) {
// make the led glow green
// parameters are red, green, blue all between 0 and 255
// these are also gamma corrected
pico_display.set_led(0, 255, 0);
}
// set the colour of the pen
// parameters are red, green, blue all between 0 and 255
pico_display.set_pen(30, 40, 50);
// fill the screen with the current pen colour
pico_display.clear();
// draw a box to put some text in
pico_display.set_pen(10, 20, 30);
Rect text_rect(10, 10, 150, 150);
pico_display.rectangle(text_rect);
// write some text inside the box with 10 pixels of margin
// automatically word wrapping
text_rect.deflate(10);
pico_display.set_pen(110, 120, 130);
pico_display.text("This is a message", Point(text_rect.x, text_rect.y), text_rect.w);
// now we've done our drawing let's update the screen
pico_display.update();
}
}
```
## Function Reference
### PicoGraphics
Pico Display uses our Pico Graphics library to draw graphics and text. For more information [read the Pico Graphics function reference.](../pico_graphics/README.md#function-reference).
### init
Sets up Pico Display. `init` must be called before any other functions since it configures the required PWM and GPIO:
```c++
pico_display.init();
```
### set_backlight
Set the display backlight from 0-255.
```c++
pico_display.set_backlight(brightness);
```
Uses hardware PWM to dim the display backlight, dimming values are gamma-corrected to provide smooth brightness transitions across the full range of intensity. This may result in some low values mapping as "off."
### set_led
Sets the RGB LED on Pico Display with an RGB triplet:
```c++
pico_display.set_led(r, g, b);
```
Uses hardware PWM to drive the LED. Values are automatically gamma-corrected to provide smooth brightness transitions and low values may map as "off."
### is_pressed
Reads the GPIO pin connected to one of Pico Display's buttons, returning a `bool` - `true` if it's pressed and `false` if it is released.
```c++
pico_display.is_pressed(button);
```
The button vaule should be a `uint8_t` denoting a pin, and constants `A`, `B`, `X` and `Y` are supplied to make it easier. e:
```c++
bool is_a_button_pressed = pico_display.is_pressed(PicoDisplay2::A)
```
### update
To display your changes on Pico Display's screen you need to call `update`:
```c++
pico_display.update();
```

Wyświetl plik

@ -0,0 +1,14 @@
include(${CMAKE_CURRENT_LIST_DIR}/../../drivers/st7789/st7789.cmake)
include(${CMAKE_CURRENT_LIST_DIR}/../pico_graphics/pico_graphics.cmake)
set(LIB_NAME pico_display_2)
add_library(${LIB_NAME} INTERFACE)
target_sources(${LIB_NAME} INTERFACE
${CMAKE_CURRENT_LIST_DIR}/${LIB_NAME}.cpp
)
target_include_directories(${LIB_NAME} INTERFACE ${CMAKE_CURRENT_LIST_DIR})
# Pull in pico libraries that we need
target_link_libraries(${LIB_NAME} INTERFACE pico_stdlib hardware_spi hardware_pwm hardware_dma st7789 pico_graphics)

Wyświetl plik

@ -0,0 +1,90 @@
#include <math.h>
#include <string.h>
#include "hardware/gpio.h" // Workaround SDK bug - https://github.com/raspberrypi/pico-sdk/issues/3
#include "hardware/pwm.h"
#include "pico_display_2.hpp"
const uint8_t LED_R = 6;
const uint8_t LED_G = 7;
const uint8_t LED_B = 8;
namespace pimoroni {
PicoDisplay2::PicoDisplay2(uint16_t *buf)
: PicoGraphics(WIDTH, HEIGHT, buf), screen(WIDTH, HEIGHT, buf, BG_SPI_FRONT) {
__fb = buf;
}
PicoDisplay2::PicoDisplay2(uint16_t *buf, int width, int height)
: PicoGraphics(width, height, buf), screen(width, height, buf, BG_SPI_FRONT) {
__fb = buf;
}
void PicoDisplay2::init() {
// setup the rgb led for pwm control
pwm_config cfg = pwm_get_default_config();
pwm_config_set_output_polarity(&cfg, true, true);
// red
pwm_set_wrap(pwm_gpio_to_slice_num(LED_R), 65535);
pwm_init(pwm_gpio_to_slice_num(LED_R), &cfg, true);
gpio_set_function(LED_R, GPIO_FUNC_PWM);
// green
pwm_set_wrap(pwm_gpio_to_slice_num(LED_G), 65535);
pwm_init(pwm_gpio_to_slice_num(LED_G), &cfg, true);
gpio_set_function(LED_G, GPIO_FUNC_PWM);
// blue
pwm_set_wrap(pwm_gpio_to_slice_num(LED_B), 65535);
pwm_init(pwm_gpio_to_slice_num(LED_B), &cfg, true);
gpio_set_function(LED_B, GPIO_FUNC_PWM);
// setup button inputs
gpio_set_function(A, GPIO_FUNC_SIO); gpio_set_dir(A, GPIO_IN); gpio_pull_up(A);
gpio_set_function(B, GPIO_FUNC_SIO); gpio_set_dir(B, GPIO_IN); gpio_pull_up(B);
gpio_set_function(X, GPIO_FUNC_SIO); gpio_set_dir(X, GPIO_IN); gpio_pull_up(X);
gpio_set_function(Y, GPIO_FUNC_SIO); gpio_set_dir(Y, GPIO_IN); gpio_pull_up(Y);
// initialise the screen
screen.init(true, false, 74 * 1000 * 1000);
}
void PicoDisplay2::update() {
screen.update();
}
void PicoDisplay2::set_backlight(uint8_t brightness) {
screen.set_backlight(brightness);
}
void PicoDisplay2::set_led(uint8_t r, uint8_t g, uint8_t b) {
// gamma correct the provided 0-255 brightness value onto a
// 0-65535 range for the pwm counter
static const float gamma = 2.8;
uint16_t value;
// red
value = (uint16_t)(pow((float)(r) / 255.0f, gamma) * 65535.0f + 0.5f);
pwm_set_gpio_level(LED_R, value);
// green
value = (uint16_t)(pow((float)(g) / 255.0f, gamma) * 65535.0f + 0.5f);
pwm_set_gpio_level(LED_G, value);
// blue
value = (uint16_t)(pow((float)(b) / 255.0f, gamma) * 65535.0f + 0.5f);
pwm_set_gpio_level(LED_B, value);
}
bool PicoDisplay2::is_pressed(uint8_t button) {
return !gpio_get(button);
}
void PicoDisplay2::flip() {
screen.flip();
}
}

Wyświetl plik

@ -0,0 +1,35 @@
#pragma once
#include "drivers/st7789/st7789.hpp"
#include "libraries/pico_graphics/pico_graphics.hpp"
namespace pimoroni {
class PicoDisplay2 : public PicoGraphics {
public:
static const int WIDTH = 320;
static const int HEIGHT = 240;
static const int PORTRAIT_WIDTH = 240;
static const int PORTRAIT_HEIGHT = 320;
static const uint8_t A = 12;
static const uint8_t B = 13;
static const uint8_t X = 14;
static const uint8_t Y = 15;
uint16_t *__fb;
private:
ST7789 screen;
public:
PicoDisplay2(uint16_t *buf);
PicoDisplay2(uint16_t *buf, int width, int height);
void init();
void update();
void set_backlight(uint8_t brightness);
void set_led(uint8_t r, uint8_t g, uint8_t b);
bool is_pressed(uint8_t button);
void flip();
};
}

Wyświetl plik

@ -1,6 +1,7 @@
# This example shows you a simple, non-interrupt way of reading Pico Display's buttons with a loop that checks to see if buttons are pressed.
import picodisplay as display
import picodisplay as display # Comment this line out to use PicoDisplay2
# import picodisplay2 as display # Uncomment this line to use PicoDisplay2
import utime
# Initialise display with a bytearray display buffer

Wyświetl plik

@ -1,6 +1,7 @@
import time
import random
import picodisplay as display
import picodisplay as display # Comment this line out to use PicoDisplay2
# import picodisplay2 as display # Uncomment this line to use PicoDisplay2
width = display.get_width()
height = display.get_height()

Wyświetl plik

@ -1,7 +1,8 @@
# This example borrows a CircuitPython hsv_to_rgb function to cycle through some rainbows on Pico Display's screen and RGB LED . If you're into rainbows, HSV (Hue, Saturation, Value) is very useful!
import utime
import picodisplay as display
import picodisplay as display # Comment this line out to use PicoDisplay2
# import picodisplay2 as display # Uncomment this line to use PicoDisplay2
# Set up and initialise Pico Display
buf = bytearray(display.get_width() * display.get_height() * 2)

Wyświetl plik

@ -6,7 +6,9 @@ import utime
import gc
# Pico Display boilerplate
import picodisplay as display
import picodisplay as display # Comment this line out to use PicoDisplay2
# import picodisplay2 as display # Uncomment this line to use PicoDisplay2
width = display.get_width()
height = display.get_height()
gc.collect()

Wyświetl plik

@ -30,6 +30,7 @@ include(pico_scroll/micropython)
include(pico_rgb_keypad/micropython)
include(pico_unicorn/micropython)
include(pico_display/micropython)
include(pico_display_2/micropython)
include(pico_explorer/micropython)
include(pico_wireless/micropython)
include(plasma/micropython)

Wyświetl plik

@ -0,0 +1,206 @@
# Pico Display Pack - MicroPython <!-- omit in toc -->
Pico Display 2.0" Pack is a vibrant 2.0", 320 x 240 pixel IPS LCD screen for your Raspberry Pi Pico, with four useful buttons and a RGB LED. [Click here](https://shop.pimoroni.com/products/pico-display-pack) to find out more!
We've included helper functions to handle every aspect of drawing to the screen and interfacing with the buttons and LED. See the [function reference](#function-reference) for details.
Check out [UnfinishedStuff's excellent Display Pack guide](https://github.com/UnfinishedStuff/Pimoroni_Pico_Display_Pack_documentation) for more detail on the functions and code examples, and [tonygo2's Display Pack Workout](https://www.instructables.com/Pimoroni-Pico-Display-Workout/) for a comprehensive demo!
- [Example Program](#example-program)
- [Function Reference](#function-reference)
- [init](#init)
- [set_backlight](#set_backlight)
- [set_led](#set_led)
- [is_pressed](#is_pressed)
- [update](#update)
- [set_pen](#set_pen)
- [create_pen](#create_pen)
- [clear](#clear)
- [pixel](#pixel)
- [pixel_span](#pixel_span)
- [rectangle](#rectangle)
- [circle](#circle)
- [character](#character)
- [text](#text)
- [set_clip](#set_clip)
- [remove_clip](#remove_clip)
## Example Program
The following example sets up Pico Display, displays some basic demo text and illuminates the RGB LED green when the A button is pressed.
```python
import utime
import picodisplay2 as picodisplay
# Initialise Picodisplay with a bytearray display buffer
buf = bytearray(picodisplay.get_width() * picodisplay.get_height() * 2)
picodisplay.init(buf)
picodisplay.set_backlight(1.0)
picodisplay.set_pen(255, 0, 0) # Set a red pen
picodisplay.clear() # Clear the display buffer
picodisplay.set_pen(255, 255, 255) # Set a white pen
picodisplay.text("pico display", 10, 10, 240, 6) # Add some text
picodisplay.update() # Update the display with our changes
picodisplay.set_led(255, 0, 0) # Set the RGB LED to red
utime.sleep(1) # Wait for a second
picodisplay.set_led(0, 255, 0) # Set the RGB LED to green
utime.sleep(1) # Wait for a second
picodisplay.set_led(0, 0, 255) # Set the RGB LED to blue
while picodisplay.is_pressed(picodisplay.BUTTON_A) == False:
pass
picodisplay.set_led(0, 255, 0) # Set the RGB LED to green
```
## Function Reference
### init
Sets up Pico Display. `init` must be called before any other functions since it configures the required PWM and GPIO. `init()` needs a bytearray type display buffer that MicroPython's garbage collection isn't going to eat, make sure you create one and pass it in like so:
```python
buf = bytearray(picodisplay.get_width() * picodisplay.get_height() * 2)
picodisplay.init(buf)
```
### set_backlight
Sets the display backlight from 0.0 to 1.0.
```python
picodisplay.set_backlight(brightness)
```
Uses hardware PWM to dim the display backlight, dimming values are gamma-corrected to provide smooth brightness transitions across the full range of intensity. This may result in some low values mapping as "off."
### set_led
Sets the RGB LED on Pico Display with an RGB triplet.
```python
picodisplay.set_led(r, g, b)
```
Uses hardware PWM to drive the LED. Values are automatically gamma-corrected to provide smooth brightness transitions and low values may map as "off."
### is_pressed
Reads the GPIO pin connected to one of Pico Display's buttons, returning `True` if it's pressed and `False` if it is released.
```python
picodisplay.is_pressed(button)
```
The button value should be a number denoting a pin, and constants `picodisplay.BUTTON_A`, `picodisplay.BUTTON_B`, `picodisplay.BUTTON_X` and `picodisplay.BUTTON_Y` are supplied to make it easier. e:
```python
is_a_button_pressed = picodisplay.is_pressed(picodisplay.BUTTON_A)
```
### update
To display your changes on Pico Display's screen you need to call `update`.
```python
picodisplay.update()
```
### set_pen
Sets the colour to be used by subsequent calls to drawing functions. The values for `r`, `g` and `b` should be from 0-255 inclusive.
```python
picodisplay.set_pen(r, g, b)
```
### create_pen
Creates a pen which can be stored as a variable for faster re-use of the same colour through calls to `set_pen`. The values for `r`, `g` and `b` should be from 0-255 inclusive.
```python
pen_colour = picodisplay.create_pen(r, g, b)
picodisplay.set_pen(penColour)
```
### clear
Fills the display buffer with the currently set pen colour.
```python
picodisplay.clear()
```
### pixel
Sets a single pixel in the display buffer to the current pen colour. The `x` and `y` parameters determine the X and Y coordinates of the drawn pixel in the buffer.
```python
picodisplay.pixel(x, y)
```
### pixel_span
Draws a horizontal line of pixels to the buffer. The `x` and `y` parameters specify the coordinates of the first pixel of the line. The `l` parameter describes the length of the line in pixels. This function will only extend the line towards the end of the screen, i.e. the `x` coordinate should specify the left hand extreme of the line.
```python
picodisplay.pixel_span(x, y, l)
```
### rectangle
Draws a rectangle filled with the current pen colour to the buffer. The `x` and `y` parameters specify the upper left corner of the rectangle, `w` specifies the width in pixels, and `h` the height.
```python
picodisplay.rectangle(x, y, w, h)
```
![Rectangle function explanation image](/micropython/modules/pico_display/images/rectangle.png)
### circle
Draws a circle filled with the current pen colour to the buffer. The `x` and `y` parameters specify the centre of the circle, `r` specifies the radius in pixels.
```python
picodisplay.circle(x, y, r)
```
![Circle function explanation image](/micropython/modules/pico_display/images/circle.png)
### character
Draws a single character to the display buffer in the current pen colour. The `c` parameter should be the ASCII numerical representation of the character to be printed, `x` and `y` describe the top-left corner of the character's drawing field. The `character` function can also be given an optional 4th parameter, `scale`, describing the scale of the character to be drawn. Default value is 2.
```python
char_a = ord('a')
picodisplay.character(char_a, x, y)
picodisplay.character(char_a, x, y, scale)
```
### text
Draws a string of text to the display buffer in the current pen colour. The `string` parameter is the string of text to be drawn, and `x` and `y` specify the upper left corner of the drawing field. The `wrap` parameter describes the width, in pixels, after which the next word in the string will be drawn on a new line underneath the current text. This will wrap the string over multiple lines if required. This function also has an optional parameter, `scale`, which describes the size of the characters to be drawn. The default `scale` is 2.
```python
picodisplay.text(string, x, y, wrap)
picodisplay.text(string, x, y, wrap, scale)
```
![Text scale explanation image](/micropython/modules/pico_display/images/text_scale.png)
### set_clip
This function defines a rectangular area outside which no drawing actions will take effect. If a drawing action crosses the boundary of the clip then only the pixels inside the clip will be drawn. Note that `clip` does not remove pixels which have already been drawn, it only prevents new pixels being drawn outside the described area. A more visual description of the function of clips can be found below. Only one clip can be active at a time, and defining a new clip replaces any previous clips. The `x` and `y` parameters describe the upper-left corner of the clip area, `w` and `h` describe the width and height in pixels.
```python
picodisplay.set_clip(x, y, w, h)
```
![Clip function explanation image](/micropython/modules/pico_display/images/clip.png)
### remove_clip
This function removes any currently implemented clip.

Plik binarny nie jest wyświetlany.

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 5.1 KiB

Plik binarny nie jest wyświetlany.

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 6.5 KiB

Plik binarny nie jest wyświetlany.

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 4.7 KiB

Plik binarny nie jest wyświetlany.

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 6.5 KiB

Wyświetl plik

@ -0,0 +1,28 @@
set(MOD_NAME pico_display_2)
string(TOUPPER ${MOD_NAME} MOD_NAME_UPPER)
add_library(usermod_${MOD_NAME} INTERFACE)
target_sources(usermod_${MOD_NAME} INTERFACE
${CMAKE_CURRENT_LIST_DIR}/${MOD_NAME}.c
${CMAKE_CURRENT_LIST_DIR}/${MOD_NAME}.cpp
${CMAKE_CURRENT_LIST_DIR}/../../../libraries/${MOD_NAME}/${MOD_NAME}.cpp
${CMAKE_CURRENT_LIST_DIR}/../../../drivers/st7789/st7789.cpp
${CMAKE_CURRENT_LIST_DIR}/../../../libraries/pico_graphics/pico_graphics.cpp
${CMAKE_CURRENT_LIST_DIR}/../../../libraries/pico_graphics/types.cpp
)
target_include_directories(usermod_${MOD_NAME} INTERFACE
${CMAKE_CURRENT_LIST_DIR}
)
target_compile_definitions(usermod_${MOD_NAME} INTERFACE
MODULE_${MOD_NAME_UPPER}_ENABLED=1
)
target_link_libraries(usermod INTERFACE usermod_${MOD_NAME})
set_source_files_properties(
${CMAKE_CURRENT_LIST_DIR}/${MOD_NAME}.c
PROPERTIES COMPILE_FLAGS
"-Wno-discarded-qualifiers -Wno-implicit-int"
)

Wyświetl plik

@ -0,0 +1,80 @@
#include "pico_display_2.h"
/***** Constants *****/
enum buttons
{
BUTTON_A = 0,
BUTTON_B,
BUTTON_X,
BUTTON_Y,
};
////////////////////////////////////////////////////////////////////////////////////////////////////
// picodisplay2 Module
////////////////////////////////////////////////////////////////////////////////////////////////////
/***** Module Functions *****/
STATIC MP_DEFINE_CONST_FUN_OBJ_1(picodisplay2_init_obj, picodisplay2_init);
STATIC MP_DEFINE_CONST_FUN_OBJ_0(picodisplay2_get_width_obj, picodisplay2_get_width);
STATIC MP_DEFINE_CONST_FUN_OBJ_0(picodisplay2_get_height_obj, picodisplay2_get_height);
STATIC MP_DEFINE_CONST_FUN_OBJ_0(picodisplay2_update_obj, picodisplay2_update);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(picodisplay2_set_backlight_obj, picodisplay2_set_backlight);
STATIC MP_DEFINE_CONST_FUN_OBJ_3(picodisplay2_set_led_obj, picodisplay2_set_led);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(picodisplay2_is_pressed_obj, picodisplay2_is_pressed);
STATIC MP_DEFINE_CONST_FUN_OBJ_0(picodisplay2_flip_obj, picodisplay2_flip);
//From PicoGraphics parent class
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(picodisplay2_set_pen_obj, 1, 3, picodisplay2_set_pen);
STATIC MP_DEFINE_CONST_FUN_OBJ_3(picodisplay2_create_pen_obj, picodisplay2_create_pen);
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(picodisplay2_set_clip_obj, 4, 4, picodisplay2_set_clip);
STATIC MP_DEFINE_CONST_FUN_OBJ_0(picodisplay2_remove_clip_obj, picodisplay2_remove_clip);
STATIC MP_DEFINE_CONST_FUN_OBJ_0(picodisplay2_clear_obj, picodisplay2_clear);
STATIC MP_DEFINE_CONST_FUN_OBJ_2(picodisplay2_pixel_obj, picodisplay2_pixel);
STATIC MP_DEFINE_CONST_FUN_OBJ_3(picodisplay2_pixel_span_obj, picodisplay2_pixel_span);
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(picodisplay2_rectangle_obj, 4, 4, picodisplay2_rectangle);
STATIC MP_DEFINE_CONST_FUN_OBJ_3(picodisplay2_circle_obj, picodisplay2_circle);
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(picodisplay2_character_obj, 3, 4, picodisplay2_character);
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(picodisplay2_text_obj, 4, 5, picodisplay2_text);
/***** Globals Table *****/
STATIC const mp_map_elem_t picodisplay2_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_picodisplay2) },
{ MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&picodisplay2_init_obj) },
{ MP_ROM_QSTR(MP_QSTR_get_width), MP_ROM_PTR(&picodisplay2_get_width_obj) },
{ MP_ROM_QSTR(MP_QSTR_get_height), MP_ROM_PTR(&picodisplay2_get_height_obj) },
{ MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&picodisplay2_update_obj) },
{ MP_ROM_QSTR(MP_QSTR_set_backlight), MP_ROM_PTR(&picodisplay2_set_backlight_obj) },
{ MP_ROM_QSTR(MP_QSTR_set_led), MP_ROM_PTR(&picodisplay2_set_led_obj) },
{ MP_ROM_QSTR(MP_QSTR_is_pressed), MP_ROM_PTR(&picodisplay2_is_pressed_obj) },
{ MP_ROM_QSTR(MP_QSTR_flip), MP_ROM_PTR(&picodisplay2_flip_obj) },
{ MP_ROM_QSTR(MP_QSTR_set_pen), MP_ROM_PTR(&picodisplay2_set_pen_obj) },
{ MP_ROM_QSTR(MP_QSTR_create_pen), MP_ROM_PTR(&picodisplay2_create_pen_obj) },
{ MP_ROM_QSTR(MP_QSTR_set_clip), MP_ROM_PTR(&picodisplay2_set_clip_obj) },
{ MP_ROM_QSTR(MP_QSTR_remove_clip), MP_ROM_PTR(&picodisplay2_remove_clip_obj) },
{ MP_ROM_QSTR(MP_QSTR_clear), MP_ROM_PTR(&picodisplay2_clear_obj) },
{ MP_ROM_QSTR(MP_QSTR_pixel), MP_ROM_PTR(&picodisplay2_pixel_obj) },
{ MP_ROM_QSTR(MP_QSTR_pixel_span), MP_ROM_PTR(&picodisplay2_pixel_span_obj) },
{ MP_ROM_QSTR(MP_QSTR_rectangle), MP_ROM_PTR(&picodisplay2_rectangle_obj) },
{ MP_ROM_QSTR(MP_QSTR_circle), MP_ROM_PTR(&picodisplay2_circle_obj) },
{ MP_ROM_QSTR(MP_QSTR_character), MP_ROM_PTR(&picodisplay2_character_obj) },
{ MP_ROM_QSTR(MP_QSTR_text), MP_ROM_PTR(&picodisplay2_text_obj) },
{ MP_ROM_QSTR(MP_QSTR_BUTTON_A), MP_ROM_INT(BUTTON_A) },
{ MP_ROM_QSTR(MP_QSTR_BUTTON_B), MP_ROM_INT(BUTTON_B) },
{ MP_ROM_QSTR(MP_QSTR_BUTTON_X), MP_ROM_INT(BUTTON_X) },
{ MP_ROM_QSTR(MP_QSTR_BUTTON_Y), MP_ROM_INT(BUTTON_Y) },
};
STATIC MP_DEFINE_CONST_DICT(mp_module_picodisplay2_globals, picodisplay2_globals_table);
/***** Module Definition *****/
const mp_obj_module_t picodisplay2_user_cmodule = {
.base = { &mp_type_module },
.globals = (mp_obj_dict_t*)&mp_module_picodisplay2_globals,
};
////////////////////////////////////////////////////////////////////////////////////////////////////
MP_REGISTER_MODULE(MP_QSTR_picodisplay2, picodisplay2_user_cmodule, MODULE_PICO_DISPLAY_2_ENABLED);
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////

Wyświetl plik

@ -0,0 +1,341 @@
#include "hardware/spi.h"
#include "hardware/sync.h"
#include "pico/binary_info.h"
#include "libraries/pico_display_2/pico_display_2.hpp"
using namespace pimoroni;
PicoDisplay2 *display2 = nullptr;
extern "C" {
#include "pico_display_2.h"
#define NOT_INITIALISED_MSG "Cannot call this function, as picodisplay2 is not initialised. Call picodisplay2.init(<bytearray>) first."
mp_obj_t picodisplay2_buf_obj;
mp_obj_t picodisplay2_init(mp_obj_t buf_obj) {
mp_buffer_info_t bufinfo;
mp_get_buffer_raise(buf_obj, &bufinfo, MP_BUFFER_RW);
picodisplay2_buf_obj = buf_obj;
if(display2 == nullptr)
display2 = new PicoDisplay2((uint16_t *)bufinfo.buf);
display2->init();
return mp_const_none;
}
mp_obj_t picodisplay2_get_width() {
return mp_obj_new_int(PicoDisplay2::WIDTH);
}
mp_obj_t picodisplay2_get_height() {
return mp_obj_new_int(PicoDisplay2::HEIGHT);
}
mp_obj_t picodisplay2_update() {
if(display2 != nullptr)
display2->update();
else
mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG);
return mp_const_none;
}
mp_obj_t picodisplay2_flip() {
if(display2 != nullptr)
display2->flip();
else
mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG);
return mp_const_none;
}
mp_obj_t picodisplay2_set_backlight(mp_obj_t brightness_obj) {
if(display2 != nullptr) {
float brightness = mp_obj_get_float(brightness_obj);
if(brightness < 0 || brightness > 1.0f)
mp_raise_ValueError("brightness out of range. Expected 0.0 to 1.0");
else
display2->set_backlight((uint8_t)(brightness * 255.0f));
}
else
mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG);
return mp_const_none;
}
mp_obj_t picodisplay2_set_led(mp_obj_t r_obj, mp_obj_t g_obj, mp_obj_t b_obj) {
if(display2 != nullptr) {
int r = mp_obj_get_int(r_obj);
int g = mp_obj_get_int(g_obj);
int b = mp_obj_get_int(b_obj);
if(r < 0 || r > 255)
mp_raise_ValueError("r out of range. Expected 0 to 255");
else if(g < 0 || g > 255)
mp_raise_ValueError("g out of range. Expected 0 to 255");
else if(b < 0 || b > 255)
mp_raise_ValueError("b out of range. Expected 0 to 255");
else
display2->set_led(r, g, b);
}
else
mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG);
return mp_const_none;
}
mp_obj_t picodisplay2_is_pressed(mp_obj_t button_obj) {
bool buttonPressed = false;
if(display2 != nullptr) {
int buttonID = mp_obj_get_int(button_obj);
switch(buttonID) {
case 0:
buttonPressed = display2->is_pressed(PicoDisplay2::A);
break;
case 1:
buttonPressed = display2->is_pressed(PicoDisplay2::B);
break;
case 2:
buttonPressed = display2->is_pressed(PicoDisplay2::X);
break;
case 3:
buttonPressed = display2->is_pressed(PicoDisplay2::Y);
break;
default:
mp_raise_ValueError("button not valid. Expected 0 to 3");
break;
}
}
else
mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG);
return buttonPressed ? mp_const_true : mp_const_false;
}
mp_obj_t picodisplay2_set_pen(mp_uint_t n_args, const mp_obj_t *args) {
if(display2 != nullptr) {
switch(n_args) {
case 1: {
int p = mp_obj_get_int(args[0]);
if(p < 0 || p > 0xffff)
mp_raise_ValueError("p is not a valid pen.");
else
display2->set_pen(p);
} break;
case 3: {
int r = mp_obj_get_int(args[0]);
int g = mp_obj_get_int(args[1]);
int b = mp_obj_get_int(args[2]);
if(r < 0 || r > 255)
mp_raise_ValueError("r out of range. Expected 0 to 255");
else if(g < 0 || g > 255)
mp_raise_ValueError("g out of range. Expected 0 to 255");
else if(b < 0 || b > 255)
mp_raise_ValueError("b out of range. Expected 0 to 255");
else
display2->set_pen(r, g, b);
} break;
default: {
char *buffer;
buffer = (char*)malloc(100);
sprintf(buffer, "function takes 1 or 3 (r,g,b) positional arguments but %d were given", n_args);
mp_raise_TypeError(buffer);
} break;
}
}
else
mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG);
return mp_const_none;
}
mp_obj_t picodisplay2_create_pen(mp_obj_t r_obj, mp_obj_t g_obj, mp_obj_t b_obj) {
int pen = 0;
if(display2 != nullptr) {
int r = mp_obj_get_int(r_obj);
int g = mp_obj_get_int(g_obj);
int b = mp_obj_get_int(b_obj);
if(r < 0 || r > 255)
mp_raise_ValueError("r out of range. Expected 0 to 255");
else if(g < 0 || g > 255)
mp_raise_ValueError("g out of range. Expected 0 to 255");
else if(b < 0 || b > 255)
mp_raise_ValueError("b out of range. Expected 0 to 255");
else
pen = display2->create_pen(r, g, b);
}
else
mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG);
return mp_obj_new_int(pen);
}
mp_obj_t picodisplay2_set_clip(mp_uint_t n_args, const mp_obj_t *args) {
(void)n_args; //Unused input parameter, we know it's 4
if(display2 != nullptr) {
int x = mp_obj_get_int(args[0]);
int y = mp_obj_get_int(args[1]);
int w = mp_obj_get_int(args[2]);
int h = mp_obj_get_int(args[3]);
Rect r(x, y, w, h);
display2->set_clip(r);
}
else
mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG);
return mp_const_none;
}
mp_obj_t picodisplay2_remove_clip() {
if(display2 != nullptr)
display2->remove_clip();
else
mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG);
return mp_const_none;
}
mp_obj_t picodisplay2_clear() {
if(display2 != nullptr)
display2->clear();
else
mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG);
return mp_const_none;
}
mp_obj_t picodisplay2_pixel(mp_obj_t x_obj, mp_obj_t y_obj) {
if(display2 != nullptr) {
int x = mp_obj_get_int(x_obj);
int y = mp_obj_get_int(y_obj);
Point p(x, y);
display2->pixel(p);
}
else
mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG);
return mp_const_none;
}
mp_obj_t picodisplay2_pixel_span(mp_obj_t x_obj, mp_obj_t y_obj, mp_obj_t l_obj) {
if(display2 != nullptr) {
int x = mp_obj_get_int(x_obj);
int y = mp_obj_get_int(y_obj);
int l = mp_obj_get_int(l_obj);
Point p(x, y);
display2->pixel_span(p, l);
}
else
mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG);
return mp_const_none;
}
mp_obj_t picodisplay2_rectangle(mp_uint_t n_args, const mp_obj_t *args) {
(void)n_args; //Unused input parameter, we know it's 4
if(display2 != nullptr) {
int x = mp_obj_get_int(args[0]);
int y = mp_obj_get_int(args[1]);
int w = mp_obj_get_int(args[2]);
int h = mp_obj_get_int(args[3]);
Rect r(x, y, w, h);
display2->rectangle(r);
}
else
mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG);
return mp_const_none;
}
mp_obj_t picodisplay2_circle(mp_obj_t x_obj, mp_obj_t y_obj, mp_obj_t r_obj) {
if(display2 != nullptr) {
int x = mp_obj_get_int(x_obj);
int y = mp_obj_get_int(y_obj);
int r = mp_obj_get_int(r_obj);
Point p(x, y);
display2->circle(p, r);
}
else
mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG);
return mp_const_none;
}
mp_obj_t picodisplay2_character(mp_uint_t n_args, const mp_obj_t *args) {
if(display2 != nullptr) {
int c = mp_obj_get_int(args[0]);
int x = mp_obj_get_int(args[1]);
int y = mp_obj_get_int(args[2]);
Point p(x, y);
if(n_args == 4) {
int scale = mp_obj_get_int(args[3]);
display2->character((char)c, p, scale);
}
else
display2->character((char)c, p);
}
return mp_const_none;
}
mp_obj_t picodisplay2_text(mp_uint_t n_args, const mp_obj_t *args) {
if(display2 != nullptr) {
if(mp_obj_is_str_or_bytes(args[0])) {
GET_STR_DATA_LEN(args[0], str, str_len);
std::string t((const char*)str);
int x = mp_obj_get_int(args[1]);
int y = mp_obj_get_int(args[2]);
int wrap = mp_obj_get_int(args[3]);
Point p(x, y);
if(n_args == 5) {
int scale = mp_obj_get_int(args[4]);
display2->text(t, p, wrap, scale);
}
else
display2->text(t, p, wrap);
}
else if(mp_obj_is_float(args[0])) {
mp_raise_TypeError("can't convert 'float' object to str implicitly");
}
else if(mp_obj_is_int(args[0])) {
mp_raise_TypeError("can't convert 'int' object to str implicitly");
}
else if(mp_obj_is_bool(args[0])) {
mp_raise_TypeError("can't convert 'bool' object to str implicitly");
}
else {
mp_raise_TypeError("can't convert object to str implicitly");
}
}
else
mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG);
return mp_const_none;
}
}

Wyświetl plik

@ -0,0 +1,26 @@
// Include MicroPython API.
#include "py/runtime.h"
#include "py/objstr.h"
// Declare the functions we'll make available in Python
extern mp_obj_t picodisplay2_init(mp_obj_t buf_obj);
extern mp_obj_t picodisplay2_get_width();
extern mp_obj_t picodisplay2_get_height();
extern mp_obj_t picodisplay2_set_backlight(mp_obj_t brightness_obj);
extern mp_obj_t picodisplay2_update();
extern mp_obj_t picodisplay2_set_led(mp_obj_t r_obj, mp_obj_t g_obj, mp_obj_t b_obj);
extern mp_obj_t picodisplay2_is_pressed(mp_obj_t button_obj);
extern mp_obj_t picodisplay2_flip();
// From PicoGraphics parent class
extern mp_obj_t picodisplay2_set_pen(mp_uint_t n_args, const mp_obj_t *args);
extern mp_obj_t picodisplay2_create_pen(mp_obj_t r_obj, mp_obj_t g_obj, mp_obj_t b_obj);
extern mp_obj_t picodisplay2_set_clip(mp_uint_t n_args, const mp_obj_t *args);
extern mp_obj_t picodisplay2_remove_clip();
extern mp_obj_t picodisplay2_clear();
extern mp_obj_t picodisplay2_pixel(mp_obj_t x_obj, mp_obj_t y_obj);
extern mp_obj_t picodisplay2_pixel_span(mp_obj_t x_obj, mp_obj_t y_obj, mp_obj_t l_obj);
extern mp_obj_t picodisplay2_rectangle(mp_uint_t n_args, const mp_obj_t *args);
extern mp_obj_t picodisplay2_circle(mp_obj_t x_obj, mp_obj_t y_obj, mp_obj_t r_obj);
extern mp_obj_t picodisplay2_character(mp_uint_t n_args, const mp_obj_t *args);
extern mp_obj_t picodisplay2_text(mp_uint_t n_args, const mp_obj_t *args);