« Arduino-IDEでPicoを動かす | トップページ | platformioでpicoを動かす »

2021年4月17日 (土)

PimoroniボードをPicoで動かす

2021/2/17
初版

rpi Pico Pimoroni board

rpi Pico Pimoroni board

概要

以下のPimoroniボードをPicoで動かす
デモとしてC++のデモとmicropythonのデモを動かしてみる。
(ホストPCとしてはubuntuを想定している)

Pico Display Pack
Pico Unicorn Pack

C++デモのビルド

以下の手順でビルドする:

# Pico-SDKがインストールされている前提 export PICO_SDK_PATH=~/pico/pico-sdk cd ~/pico git clone https://github.com/pimoroni/pimoroni-pico.git cd pimoroni-pico mkdir build cd build cmake .. make # 以上でデモプログラムのuf2fが出来る

C++デモの書き込み

# pico_unicorn_plasma デモを書き込む(unicornボードの場合) cd ~/pico/pimoroni-pico/build/examples/pico_unicorn_plasma cp unicornplasma.uf2 /media/<USER>/RPI-RP2/ # pico_display デモを書き込む(displayボードの場合) cd ~/pico/pimoroni-pico/build/examples/pico_display cp display.uf2 /media/<USER>/RPI-RP2/

<USER>は、環境依存なので、自分の環境に合わせる。

C++デモ・ソース

以下、デモのソース:(特に修正していない)

pico_display/demo.cpp

#include <string.h> #include <math.h> #include <vector> #include <cstdlib> #include "pico_display.hpp" using namespace pimoroni; extern unsigned char image_tif[]; extern unsigned int image_tif_len; uint16_t buffer[PicoDisplay::WIDTH * PicoDisplay::HEIGHT]; PicoDisplay pico_display(buffer); /* void pixel(int x, int y, uint16_t c) { x *= 2; y *= 2; pico_display.frame_buffer[x + y * 240] = c; pico_display.frame_buffer[x + 1 + y * 240] = c; pico_display.frame_buffer[x + 1 + (y + 1) * 240] = c; pico_display.frame_buffer[x + (y + 1) * 240] = c; } void rect(int x, int y, int w, int h, uint16_t c) { for(int rx = x; rx < x + w; rx++) { for(int ry = y; ry < y + h; ry++) { pixel(rx, ry, c); } } }*/ uint8_t arrow[] = { 0b00010000, 0b00110000, 0b01110000, 0b11111111, 0b11111111, 0b01110000, 0b00110000, 0b00010000 }; uint8_t tick[] = { 0b00000000, 0b00000010, 0b00000111, 0b01001110, 0b11111100, 0b00111000, 0b00010000, 0b00000000, }; /* void sprite(uint8_t *p, int x, int y, bool flip, uint16_t c) { for(int ay = 0; ay < 8; ay++) { uint8_t sl = p[ay]; for(int ax = 0; ax < 8; ax++) { if(flip) { if((0b10000000 >> ax) & sl) { pixel(ax + x, ay + y, c); } }else{ if((0b1 << ax) & sl) { pixel(ax + x, ay + y, c); } } } } }*/ int main() { pico_display.init(); pico_display.set_backlight(100); // uint16_t white = pico_display.create_pen(255, 255, 255); // uint16_t black = pico_display.create_pen(0, 0, 0); // uint16_t red = pico_display.create_pen(255, 0, 0); // uint16_t green = pico_display.create_pen(0, 255, 0); // uint16_t dark_grey = pico_display.create_pen(20, 40, 60); // uint16_t dark_green = pico_display.create_pen(10, 100, 10); // uint16_t blue = pico_display.create_pen(0, 0, 255); bool a_pressed = false; bool b_pressed = false; bool x_pressed = false; bool y_pressed = false; 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 < 1000; i++) { pt shape; shape.x = rand() % 240; shape.y = rand() % 135; shape.r = (rand() % 10) + 3; shape.dx = float(rand() % 255) / 128.0f; shape.dy = float(rand() % 255) / 128.0f; shape.pen = pico_display.create_pen(rand() % 255, rand() % 255, rand() % 255); shapes.push_back(shape); } uint32_t i = 0; while(true) { 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 < 0) shape.dx *= -1; if(shape.x >= pico_display.bounds.w) shape.dx *= -1; if(shape.y < 0) shape.dy *= -1; if(shape.y >= pico_display.bounds.h) shape.dy *= -1; pico_display.set_pen(shape.pen); pico_display.circle(Point(shape.x, shape.y), shape.r); } float led_step = fmod(i / 20.0f, M_PI * 2.0f); int r = (sin(led_step) * 25.0f) + 25.0f; pico_display.set_led(r, r / 1.2f, r); std::vector<Point> poly; poly.push_back(Point(30, 30)); poly.push_back(Point(50, 35)); poly.push_back(Point(70, 25)); poly.push_back(Point(80, 65)); poly.push_back(Point(50, 85)); poly.push_back(Point(30, 45)); pico_display.set_pen(255, 255, 0); pico_display.polygon(poly); pico_display.set_pen(0, 255, 255); pico_display.triangle(Point(50, 50), Point(130, 80), Point(80, 110)); pico_display.set_pen(255, 255, 255); pico_display.line(Point(50, 50), Point(120, 80)); pico_display.line(Point(20, 20), Point(120, 20)); pico_display.line(Point(20, 20), Point(20, 120)); for(int r = 0; r < 30; r++) { for(int j = 0; j < 10; j++) { float rads = ((M_PI * 2) / 30.0f) * float(r); rads += (float(i) / 100.0f); rads += (float(j) / 100.0f); float cx = sin(rads) * 300.0f; float cy = cos(rads) * 300.0f; pico_display.line(Point(120, 67), Point(cx + 120, cy + 67)); } } /* if(pico_display.is_pressed(pico_display.A)) { pico_display.rectangle(0, 0, 18, 18); //sprite(tick, 5, 5, true, green); }else{ //sprite(arrow, 10 + bounce, 10, true, white); } if(pico_display.is_pressed(pico_display.B)) { pico_display.rectangle(0, 49, 18, 18); //sprite(tick, 5, 54, true, green); }else{ //sprite(arrow, 10 - bounce, 50, true, white); } if(pico_display.is_pressed(pico_display.X)) { pico_display.rectangle(102, 0, 18, 18); //sprite(tick, 107, 5, true, green); }else{ //sprite(arrow, 102 - bounce, 10, false, white); } if(pico_display.is_pressed(pico_display.Y)) { pico_display.rectangle(102, 49, 18, 18); //sprite(tick, 107, 54, true, green); }else{ //sprite(arrow, 102 + bounce, 50, false, white); } */ // update screen pico_display.update(); i++; } return 0; }

pico_display/image_data.cpp

unsigned char image_tif[] = { 0x49, 0x49, 0x2a, 0x00, 0x08, 0x00, 0x00, 0x00, 0x11, 0x00, 0xfe, 0x00, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x01, 0x01, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x87, 0x00, 0x00, 0x00, 0x02, 0x01, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0xda, 0x00, 0x00, 0x00, 0x03, 0x01, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x06, 0x01, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x11, 0x01, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, 0x24, 0x01, 0x00, 0x00, 0x12, 0x01, <> 0x08, 0x0a, 0x04, 0x08, 0x09, 0x04, 0x07, 0x08, 0x03, 0x07, 0x08, 0x03, 0x07, 0x08, 0x03, 0x07, 0x07, 0x02, 0x06, 0x07, 0x03, 0x06, 0x07, 0x02, 0x06, 0x07, 0x03, 0x06, 0x07, 0x02, 0x06, 0x07, 0x03, 0x06, 0x06, 0x02, 0x06, 0x07, 0x03, 0x06 }; unsigned int image_tif_len = 97492;

pico_unicorn_plasma/demo.cpp

/* Pico Unicorn Plasma Example Written by Tim Kerby https://github.com/tkerby Hardware: Raspberry Pi Pico with Pimoroni Unicorn Pico Display Printf over USB 9600 8N1 (see makefile) Based on Adafruit Arduino Example for 32x32 panel Originally written by Limor Fried/Ladyada & Phil Burgess/PaintYourDragon for Adafruit Industries. https://github.com/adafruit/RGB-matrix-Panel/blob/master/examples/plasma_32x32/plasma_32x32.ino BSD License */ #include <stdio.h> #include <stdlib.h> #include <math.h> #include "pico/stdlib.h" #include <time.h> #include "pico_unicorn.hpp" using namespace pimoroni; PicoUnicorn pico_unicorn; // Sine table to speed up execution static const int8_t sinetab[256] = { 0, 2, 5, 8, 11, 15, 18, 21, 24, 27, 30, 33, 36, 39, 42, 45, 48, 51, 54, 56, 59, 62, 65, 67, 70, 72, 75, 77, 80, 82, 85, 87, 89, 91, 93, 96, 98, 100, 101, 103, 105, 107, 108, 110, 111, 113, 114, 116, 117, 118, 119, 120, 121, 122, 123, 123, 124, 125, 125, 126, 126, 126, 126, 126, 127, 126, 126, 126, 126, 126, 125, 125, 124, 123, 123, 122, 121, 120, 119, 118, 117, 116, 114, 113, 111, 110, 108, 107, 105, 103, 101, 100, 98, 96, 93, 91, 89, 87, 85, 82, 80, 77, 75, 72, 70, 67, 65, 62, 59, 56, 54, 51, 48, 45, 42, 39, 36, 33, 30, 27, 24, 21, 18, 15, 11, 8, 5, 2, 0, -3, -6, -9, -12, -16, -19, -22, -25, -28, -31, -34, -37, -40, -43, -46, -49, -52, -55, -57, -60, -63, -66, -68, -71, -73, -76, -78, -81, -83, -86, -88, -90, -92, -94, -97, -99,-101,-102,-104, -106,-108,-109,-111,-112,-114,-115,-117, -118,-119,-120,-121,-122,-123,-124,-124, -125,-126,-126,-127,-127,-127,-127,-127, -128,-127,-127,-127,-127,-127,-126,-126, -125,-124,-124,-123,-122,-121,-120,-119, -118,-117,-115,-114,-112,-111,-109,-108, -106,-104,-102,-101, -99, -97, -94, -92, -90, -88, -86, -83, -81, -78, -76, -73, -71, -68, -66, -63, -60, -57, -55, -52, -49, -46, -43, -40, -37, -34, -31, -28, -25, -22, -19, -16, -12, -9, -6, -3 }; // We have four objects with radius and centre points as configured for the 16x7 display const float radius1 =8.2, radius2 =11.5, radius3 =20.4, radius4 =22.1, centerx1=8.0, centerx2=5.8, centerx3=12.7, centerx4= 2.0, centery1= 2.1, centery2= 1.5, centery3=3.2, centery4=-0.5; float angle1 = 0.0, angle2 = 0.0, angle3 = 0.0, angle4 = 0.0; long hueShift= 0; #define FPS 30 // Maximum frames-per-second // 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() { stdio_init_all(); pico_unicorn.init(); pico_unicorn.clear(); while(true) { int x1, x2, x3, x4, y1, y2, y3, y4, sx1, sx2, sx3, sx4; unsigned char x, y; int8_t value; uint8_t r, g, b,j,k,l,m; // Setup a delay to slow the framerate. // Would be better to read from a timer as some math operations take variable time sleep_ms(1000 / FPS); sx1 = (int)(cos(angle1) * radius1 + centerx1); sx2 = (int)(cos(angle2) * radius2 + centerx2); sx3 = (int)(cos(angle3) * radius3 + centerx3); sx4 = (int)(cos(angle4) * radius4 + centerx4); y1 = (int)(sin(angle1) * radius1 + centery1); y2 = (int)(sin(angle2) * radius2 + centery2); y3 = (int)(sin(angle3) * radius3 + centery3); y4 = (int)(sin(angle4) * radius4 + centery4); for(y=0; y<7; y++) { x1 = sx1; x2 = sx2; x3 = sx3; x4 = sx4; for(x=0; x<16; x++) { j = (x1 * x1 + y1 * y1) >> 2; k = (x2 * x2 + y2 * y2) >> 2; l = (x3 * x3 + y3 * y3) >> 3; m = (x4 * x4 + y4 * y4) >> 3; //printf("X: %i, Y: %i, \t%i, %i, %i, %i\n",x,y,j,k,l,m); value = (int8_t)(hueShift + (int8_t)*(sinetab + j) + (int8_t)*(sinetab + k) + (int8_t)*(sinetab + l) + (int8_t)*(sinetab + m)); //printf("X: %i, Y: %i, H: %i\n",x,y,value); from_hsv(((value+128.0f)/256.0f), 1, 1, r, g, b); pico_unicorn.set_pixel(x, y, r, g, b); x1--; x2--; x3--; x4--; } y1--; y2--; y3--; y4--; } angle1 += 0.03; angle2 -= 0.07; angle3 += 0.13; angle4 -= 0.15; hueShift += 2; } return 0; }

micorpythonの準備

pinoroni用モジュールを利用する都合上、
純正のmicropythonのファームウェアではなく
以下のpimoroni用のmicropythonのファームウェアを使用する:

cd ~/Downloads wget https://github.com/pimoroni/pimoroni-pico/releases/download/v0.1.1/pimoroni-pico-micropython.uf2 cp pimoroni-pico-micropython.uf2 /media/<USER>/RPI-RP2/

・<USER>は、環境依存なので、自分の環境に合わせる。

micropythonデモ・ソース

以下、デモのソース:(特に修正なし)

displayボード用:
display_demo.py

import time import random import picodisplay as display width = display.get_width() height = display.get_height() display_buffer = bytearray(width * height * 2) # 2-bytes per pixel (RGB565) display.init(display_buffer) display.set_backlight(1.0) class Ball: def __init__(self, x, y, r, dx, dy, pen): self.x = x self.y = y self.r = r self.dx = dx self.dy = dy self.pen = pen # initialise shapes balls = [] for i in range(0, 100): r = random.randint(0, 10) + 3 balls.append( Ball( random.randint(r, r + (width - 2 * r)), random.randint(r, r + (height - 2 * r)), r, (14 - r) / 2, (14 - r) / 2, display.create_pen(random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)), ) ) while True: display.set_pen(40, 40, 40) display.clear() for ball in balls: ball.x += ball.dx ball.y += ball.dy xmax = width - ball.r xmin = ball.r ymax = height - ball.r ymin = ball.r if ball.x < xmin or ball.x > xmax: ball.dx *= -1 if ball.y < ymin or ball.y > ymax: ball.dy *= -1 display.set_pen(ball.pen) display.circle(int(ball.x), int(ball.y), int(ball.r)) display.update() time.sleep(0.01)

unicornボード用:
unicorn_demo.py

import picounicorn picounicorn.init() # From CPython Lib/colorsys.py def hsv_to_rgb(h, s, v): if s == 0.0: return v, v, v i = int(h * 6.0) f = (h * 6.0) - i p = v * (1.0 - s) q = v * (1.0 - s * f) t = v * (1.0 - s * (1.0 - f)) i = i % 6 if i == 0: return v, t, p if i == 1: return q, v, p if i == 2: return p, v, t if i == 3: return p, q, v if i == 4: return t, p, v if i == 5: return v, p, q w = picounicorn.get_width() h = picounicorn.get_height() # Display a rainbow across Pico Unicorn for x in range(w): for y in range(h): r, g, b = [int(c * 255) for c in hsv_to_rgb(x / w, y / h, 1.0)] picounicorn.set_pixel(x, y, r, g, b) print("Press Button A") while not picounicorn.is_pressed(picounicorn.BUTTON_A): # Wait for Button A to be pressed pass # Clear the display for x in range(w): for y in range(h): picounicorn.set_pixel(x, y, 0, 0, 0) print("Button A pressed!")

参照情報

PicoボードにPico_SDKでC言語をビルドする
Pimoroni Pico Libraries and Examples

Pinout for Pico Display Pack
Pinout for Pico Unicorn Pack
Pinout for Pico Audio Pack

How to add a reset button to your Raspberry Pi Pico
All you need to do is to wire the GND and RUN pins together and add an extra momentary contact button to your breadboard. Pushing the button will reset the board.

Programmable I/O with Raspberry Pi Pico

Raspberry Pi Picoスタートガイド C/C++
Pico C/C++ SDK
Pico SDK docs

Raspberry Pi Pico Datasheet
RP2040 Datasheet

Pico Pinout

Ubuntu 18.04 に Cmake の Latest Release をインストールする

Ubuntu 20.04のPCでRaspberry Pi Picoを2台使ってOpenOCDによるデバッグ

以上

|

« Arduino-IDEでPicoを動かす | トップページ | platformioでpicoを動かす »

pimoroni」カテゴリの記事

コメント

コメントを書く



(ウェブ上には掲載しません)




« Arduino-IDEでPicoを動かす | トップページ | platformioでpicoを動かす »