Lots of features added

pull/537/head
jon 2022-07-25 11:24:00 +01:00 zatwierdzone przez Phil Howard
rodzic e50827c412
commit 63183d28be
19 zmienionych plików z 9231 dodań i 394 usunięć

Wyświetl plik

@ -4,7 +4,8 @@ add_executable(
)
# Pull in pico libraries that we need
target_link_libraries(galactic_unicorn_demo pico_stdlib hardware_pio hardware_dma pico_graphics galactic_unicorn)
target_link_libraries(galactic_unicorn_demo pico_stdlib hardware_pio hardware_adc hardware_dma pico_graphics galactic_unicorn)
pico_enable_stdio_usb(galactic_unicorn_demo 1)
# create map/bin/hex file etc.
pico_add_extra_outputs(galactic_unicorn_demo)
@ -17,7 +18,108 @@ add_executable(
)
# Pull in pico libraries that we need
target_link_libraries(galactic_unicorn_demo2 pico_stdlib hardware_pio hardware_dma pico_graphics galactic_unicorn)
target_link_libraries(galactic_unicorn_demo2 pico_stdlib hardware_pio hardware_adc hardware_dma pico_graphics galactic_unicorn)
pico_enable_stdio_usb(galactic_unicorn_demo2 1)
# create map/bin/hex file etc.
pico_add_extra_outputs(galactic_unicorn_demo2)
add_executable(
nostalgia_prompt
nostalgia_prompt.cpp
)
# Pull in pico libraries that we need
target_link_libraries(nostalgia_prompt pico_stdlib hardware_pio hardware_adc hardware_dma pico_graphics galactic_unicorn)
pico_enable_stdio_usb(nostalgia_prompt 1)
# create map/bin/hex file etc.
pico_add_extra_outputs(nostalgia_prompt)
add_executable(
eighties_super_computer
eighties_super_computer.cpp
)
# Pull in pico libraries that we need
target_link_libraries(eighties_super_computer pico_stdlib hardware_pio hardware_adc hardware_dma pico_graphics galactic_unicorn)
pico_enable_stdio_usb(eighties_super_computer 1)
# create map/bin/hex file etc.
pico_add_extra_outputs(eighties_super_computer)
add_executable(
fire_effect
fire_effect.cpp
)
# Pull in pico libraries that we need
target_link_libraries(fire_effect pico_stdlib hardware_pio hardware_adc hardware_dma pico_graphics galactic_unicorn)
pico_enable_stdio_usb(fire_effect 1)
# create map/bin/hex file etc.
pico_add_extra_outputs(fire_effect)
add_executable(
scroll_text
scroll_text.cpp
)
# Pull in pico libraries that we need
target_link_libraries(scroll_text pico_stdlib hardware_pio hardware_adc hardware_dma pico_graphics galactic_unicorn)
pico_enable_stdio_usb(scroll_text 1)
# create map/bin/hex file etc.
pico_add_extra_outputs(scroll_text)
add_executable(
balls
balls.cpp
)
# Pull in pico libraries that we need
target_link_libraries(balls pico_stdlib hardware_pio hardware_adc hardware_dma pico_graphics galactic_unicorn)
pico_enable_stdio_usb(balls 1)
# create map/bin/hex file etc.
pico_add_extra_outputs(balls)
add_executable(
lava_lamp
lava_lamp.cpp
)
# Pull in pico libraries that we need
target_link_libraries(lava_lamp pico_stdlib hardware_pio hardware_adc hardware_dma pico_graphics galactic_unicorn)
pico_enable_stdio_usb(lava_lamp 1)
# create map/bin/hex file etc.
pico_add_extra_outputs(lava_lamp)
add_executable(
feature_test
feature_test.cpp
audio_samples.cpp
)
# Pull in pico libraries that we need
target_link_libraries(feature_test pico_stdlib hardware_pio hardware_adc hardware_dma pico_graphics galactic_unicorn)
pico_enable_stdio_usb(feature_test 1)
# create map/bin/hex file etc.
pico_add_extra_outputs(feature_test)

Wyświetl plik

@ -0,0 +1,88 @@
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "pico/stdlib.h"
#include "libraries/pico_graphics/pico_graphics.hpp"
#include "galactic_unicorn.hpp"
#include "okcolor.hpp"
using namespace pimoroni;
PicoGraphics_PenRGB565 graphics(53, 11, nullptr);
GalacticUnicorn galactic_unicorn;
// extra row of pixels for sourcing flames and averaging
float heat[53][13] = {0.0f};
int main() {
stdio_init_all();
galactic_unicorn.init();
while(true) {
if(galactic_unicorn.is_pressed(galactic_unicorn.SWITCH_BRIGHTNESS_UP)) {
galactic_unicorn.adjust_brightness(+0.01);
}
if(galactic_unicorn.is_pressed(galactic_unicorn.SWITCH_BRIGHTNESS_DOWN)) {
galactic_unicorn.adjust_brightness(-0.01);
}
graphics.set_pen(0, 0, 0);
graphics.clear();
for(int y = 0; y < 12; y++) {
for(int x = 0; x < 53; x++) {
if(heat[x][y] > 0.5f) {
graphics.set_pen(255, 255, 180);
graphics.pixel(Point(x, y));
}else if(heat[x][y] > 0.4f) {
graphics.set_pen(220, 160, 0);
graphics.pixel(Point(x, y));
}else if(heat[x][y] > 0.3f) {
graphics.set_pen(180, 50, 0);
graphics.pixel(Point(x, y));
}else if(heat[x][y] > 0.2f) {
graphics.set_pen(40, 40, 40);
graphics.pixel(Point(x, y));
}
// update this pixel by averaging the below pixels
if(x == 0) {
heat[x][y] = (heat[x][y] + heat[x][y + 2] + heat[x][y + 1] + heat[x + 1][y + 1]) / 4.0f;
} else if(x == 52) {
heat[x][y] = (heat[x][y] + heat[x][y + 2] + heat[x][y + 1] + heat[x - 1][y + 1]) / 4.0f;
} else {
heat[x][y] = (heat[x][y] + heat[x][y + 2] + heat[x][y + 1] + heat[x - 1][y + 1] + heat[x + 1][y + 1]) / 5.0f;
}
heat[x][y] -= 0.01f;
heat[x][y] = heat[x][y] < 0.0f ? 0.0f: heat[x][y];
}
}
galactic_unicorn.update(graphics);
// clear the bottom row and then add a new fire seed to it
for(int x = 0; x < 53; x++) {
heat[x][11] = 0.0f;
}
// add a new random heat source
for(int c = 0; c < 5; c++) {
int px = (rand() % 51) + 1;
heat[px][11] = 1.0f;
heat[px + 1][11] = 1.0f;
heat[px - 1][11] = 1.0f;
heat[px][12] = 1.0f;
heat[px + 1][12] = 1.0f;
heat[px - 1][12] = 1.0f;
}
sleep_ms(50);
}
return 0;
}

Wyświetl plik

@ -114,6 +114,9 @@ gpio_set_function(28, GPIO_FUNC_SIO);
float brightness = 0.5f;
float curve = 4.0f;
int x = 10;
int y = 5;
while(true) {
if(galactic_unicorn.is_pressed(galactic_unicorn.SWITCH_VOLUME_UP)) {
hue_offset += 0.05;
@ -143,6 +146,27 @@ gpio_set_function(28, GPIO_FUNC_SIO);
if(curve < 0.5) curve = 0.5;
}
if(galactic_unicorn.is_pressed(galactic_unicorn.SWITCH_A)) {
x -= 1;
sleep_ms(250);
}
if(galactic_unicorn.is_pressed(galactic_unicorn.SWITCH_B)) {
x += 1;
sleep_ms(250);
}
if(galactic_unicorn.is_pressed(galactic_unicorn.SWITCH_C)) {
y -= 1;
sleep_ms(250);
}
if(galactic_unicorn.is_pressed(galactic_unicorn.SWITCH_D)) {
y += 1;
sleep_ms(250);
}
/*
for(int y = 0; y < 11; y++) {
for(int x = 0; x < 53; x++) {
float fx = x / 53.0f;
@ -150,27 +174,18 @@ gpio_set_function(28, GPIO_FUNC_SIO);
float twopi = M_PI * 2;
float hue = fy + (sin(fx * twopi / curve));
float fade = 1.0f;
/* if(hue < 0.0f) {
fade += (hue * 10.0f);
if(fade < 0.0f) fade = 0.0f;
}
if(hue > 1.0f) {
fade -= ((hue - 1.0f) * 10.0f);
if(fade < 0.0f) fade = 0.0f;
}*/
hue += hue_offset;
while(hue < 0.0f) {hue += 1.0f;}
while(hue > 1.0f) {hue -= 1.0f;}
hue = 1.0f - hue;
/*
uint8_t r = 0, g = 0, b = 0;
from_hsv(hue, 1.0f, brightness * fade, r, g, b);*/
ok_color::HSL hsl{.h = hue, .s = 1.0f, .l = brightness * fade};
ok_color::RGB rgb = ok_color::okhsl_to_srgb(hsl);
galactic_unicorn.set_pixel(x, y, rgb.r * 255.0f, rgb.g * 255.0f, rgb.b * 255.0f);
}
}
}*/
galactic_unicorn.set_pixel(x, y, 255, 255, 255);
/*i++;
graphics.set_pen(0, 0, 0);

Wyświetl plik

@ -37,9 +37,9 @@ void text(std::string t, Point p, float s = 1.0f, float a = 1.0f) {
p.x += (53 / 2) - (w / 2);
p.y += (11 / 2);
graphics.text(t, Point(p.x, p.y), -1, s, a);
graphics.text(t, Point(p.x + 1, p.y), -1, s, a);
graphics.text(t, Point(p.x + 1, p.y + 1), -1, s, a);
graphics.text(t, Point(p.x, p.y + 1), -1, s, a);
//graphics.text(t, Point(p.x + 1, p.y), -1, s, a);
//graphics.text(t, Point(p.x + 1, p.y + 1), -1, s, a);
//graphics.text(t, Point(p.x, p.y + 1), -1, s, a);
}
struct star_t {
@ -73,6 +73,8 @@ void step_star(star_t &s) {
int main() {
stdio_init_all();
uint8_t hue_map[53][3];
for(int i = 0; i < 53; i++) {
from_hsv(i / 53.0f, 1.0f, 1.0f, hue_map[i][0], hue_map[i][1], hue_map[i][2]);
@ -103,18 +105,17 @@ gpio_set_function(28, GPIO_FUNC_SIO);
bool x_pressed = false;
bool y_pressed = false;
*/
graphics.set_font("sans");
graphics.set_font("bitmap8");
uint i = 0;
int v = 255;
float hue_offset = 0.0f;
float brightness = 0.5f;
float curve = 4.0f;
while(true) {
i++;
if(galactic_unicorn.is_pressed(galactic_unicorn.SWITCH_VOLUME_UP)) {
hue_offset += 0.05;
if(hue_offset > 1.0f) hue_offset = 1.0f;
@ -125,69 +126,37 @@ gpio_set_function(28, GPIO_FUNC_SIO);
}
if(galactic_unicorn.is_pressed(galactic_unicorn.SWITCH_BRIGHTNESS_UP)) {
brightness += 0.05;
if(brightness > 1.0f) brightness = 1.0f;
galactic_unicorn.adjust_brightness(+0.01);
}
if(galactic_unicorn.is_pressed(galactic_unicorn.SWITCH_BRIGHTNESS_DOWN)) {
brightness -= 0.05;
if(brightness < 0.0f) brightness = 0.0f;
galactic_unicorn.adjust_brightness(-0.01);
}
if(galactic_unicorn.is_pressed(galactic_unicorn.SWITCH_A)) {
curve += 0.5;
if(curve > 100.0f) curve = 100.0f;
}
if(galactic_unicorn.is_pressed(galactic_unicorn.SWITCH_B)) {
curve -= 0.5;
if(curve < 0.5) curve = 0.5;
}
i++;
graphics.set_pen(0, 0, 0);
if(galactic_unicorn.is_pressed(galactic_unicorn.SWITCH_A)) {graphics.set_pen(255, 0, 0);}
graphics.clear();
if(galactic_unicorn.is_pressed(galactic_unicorn.SWITCH_BRIGHTNESS_DOWN)) {v = v == 0 ? 0 : v - 1;}
for(int i = 0; i < 100; i++) {
star_t &star = stars[i];
step_star(star);
uint b = star.brightness();
graphics.set_pen(b, b, b);
//graphics.pixel(Point(star.x + (53 / 2), star.y + (11 / 2)));
}
graphics.set_pen(255, 255, 255);
float s = 0.8f;//0.65f + (sin(i / 25.0f) * 0.15f);
/*
graphics.set_pen(255, 255, 255);
float s = 0.65f;//0.65f + (sin(i / 25.0f) * 0.15f);
float a = 1.0f;// (sin(i / 25.0f) * 100.0f);
float x = (sin(i / 25.0f) * 40.0f) * s;
float y = (cos(i / 15.0f) * 10.0f) * s;
text("Galactic", Point(x, y), s, a);
uint16_t *p = (uint16_t *)graphics.frame_buffer;
for(size_t i = 0; i < 53 * 11; i++) {
int x = i % 53;
int y = i / 53;
uint r = ((*p & 0b1111100000000000) >> 11) << 3;
uint g = ((*p & 0b0000011111100000) >> 5) << 2;
uint b = ((*p & 0b0000000000011111) >> 0) << 3;
p++;
float x = (sin(i / 74.0f) * 80.0f) * s;
float y = (cos(i / 43.0f) * 6.0f) * s;
text("Chester smells!", Point(x, y - 3), s, a);
*/
if(r > 200 && g > 200 && b > 200) {
r = hue_map[x][0];
g = hue_map[x][1];
b = hue_map[x][2];
for(int x = 0; x < 53; x++) {
for(int y = 0; y < 11; y++) {
int v = ((sin((x + y) / 3.0f + i / 15.0f) + 1.5f) / 2.5f) * 255.0f;
graphics.set_pen(v, v, v);
graphics.pixel(Point(x, y));
}
galactic_unicorn.set_pixel(x, y, r, g, b);
}
galactic_unicorn.update(graphics);
sleep_ms(10);
printf("%d\n", galactic_unicorn.light());
sleep_ms(20);
}

Wyświetl plik

@ -0,0 +1,69 @@
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "pico/stdlib.h"
#include "libraries/pico_graphics/pico_graphics.hpp"
#include "galactic_unicorn.hpp"
#include "okcolor.hpp"
using namespace pimoroni;
PicoGraphics_PenRGB565 graphics(53, 11, nullptr);
GalacticUnicorn galactic_unicorn;
float lifetime[53][11];
float age[53][11];
int main() {
stdio_init_all();
for(int y = 0; y < 11; y++) {
for(int x = 0; x < 53; x++) {
lifetime[x][y] = 1.0f + ((rand() % 10) / 100.0f);
age[x][y] = ((rand() % 100) / 100.0f) * lifetime[x][y];
}
}
galactic_unicorn.init();
while(true) {
if(galactic_unicorn.is_pressed(galactic_unicorn.SWITCH_BRIGHTNESS_UP)) {
galactic_unicorn.adjust_brightness(+0.01);
}
if(galactic_unicorn.is_pressed(galactic_unicorn.SWITCH_BRIGHTNESS_DOWN)) {
galactic_unicorn.adjust_brightness(-0.01);
}
graphics.set_pen(0, 0, 0);
graphics.clear();
for(int y = 0; y < 11; y++) {
for(int x = 0; x < 53; x++) {
if(age[x][y] < lifetime[x][y] * 0.3f) {
graphics.set_pen(230, 150, 0);
graphics.pixel(Point(x, y));
}else if(age[x][y] < lifetime[x][y] * 0.5f) {
float decay = (lifetime[x][y] * 0.5f - age[x][y]) * 5.0f;
graphics.set_pen(decay * 230, decay * 150, 0);
graphics.pixel(Point(x, y));
}
if(age[x][y] >= lifetime[x][y]) {
age[x][y] = 0.0f;
lifetime[x][y] = 1.0f + ((rand() % 10) / 100.0f);
}
age[x][y] += 0.01f;
}
}
galactic_unicorn.update(graphics);
sleep_ms(10);
}
return 0;
}

Wyświetl plik

@ -0,0 +1,155 @@
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "pico/stdlib.h"
#include "libraries/pico_graphics/pico_graphics.hpp"
#include "galactic_unicorn.hpp"
#include "okcolor.hpp"
using namespace pimoroni;
PicoGraphics_PenRGB565 graphics(53, 11, nullptr);
GalacticUnicorn galactic_unicorn;
// left_channel_bin and right_channel_bin are in audio_samples.cpp
extern uint8_t left_channel_bin[];
extern uint32_t left_channel_bin_len;
extern uint8_t right_channel_bin[];
extern uint32_t right_channel_bin_len;
void gradient(uint8_t r, uint8_t g, uint8_t b) {
for(int y = 0; y < 12; y++) {
for(int x = 0; x < 53; x++) {
graphics.set_pen((r * x) / 52, (g * x) / 52, (b * x) / 52);
graphics.pixel(Point(x, y));
}
}
}
typedef void (*shader_func_t)(int ms, int x, int y);
void grid(int ms, int x, int y) {
int v = (x + y + (ms / 1000)) % 2 == 0 ? 255 : 0;
graphics.set_pen(v, v, v);
graphics.pixel(Point(x, y));
}
void shader_fill(int ms, shader_func_t f) {
for(int y = 0; y < 12; y++) {
for(int x = 0; x < 53; x++) {
f(ms, x, y);
}
}
}
void outline_text(std::string text) {
uint ms = to_ms_since_boot(get_absolute_time());
graphics.set_font("bitmap8");
uint8_t v = (sin(ms / 100.0f) + 1.0f) * 127.0f;
uint w = graphics.measure_text(text, 1);
int x = 53 / 2 - w / 2 + 1, y = 2;
graphics.set_pen(0, 0, 0);
graphics.text(text, Point(x - 1, y - 1), -1, 1);
graphics.text(text, Point(x , y - 1), -1, 1);
graphics.text(text, Point(x + 1, y - 1), -1, 1);
graphics.text(text, Point(x - 1, y ), -1, 1);
graphics.text(text, Point(x + 1, y ), -1, 1);
graphics.text(text, Point(x - 1, y + 1), -1, 1);
graphics.text(text, Point(x , y + 1), -1, 1);
graphics.text(text, Point(x + 1, y + 1), -1, 1);
graphics.set_pen(v, v, v);
graphics.text(text, Point(x, y), -1, 1);
}
int main() {
stdio_init_all();
galactic_unicorn.init();
// galactic_unicorn.play_sample(left_channel_bin, left_channel_bin_len);
while(true) {
if(galactic_unicorn.is_pressed(galactic_unicorn.SWITCH_BRIGHTNESS_UP)) {
galactic_unicorn.adjust_brightness(+0.01);
}
if(galactic_unicorn.is_pressed(galactic_unicorn.SWITCH_BRIGHTNESS_DOWN)) {
galactic_unicorn.adjust_brightness(-0.01);
}
uint ms = to_ms_since_boot(get_absolute_time());
uint8_t test = (ms / 5000) % 4;
graphics.set_pen(0, 0, 0);
graphics.clear();
switch(test) {
case 0: {
printf("grid pattern");
shader_fill(ms, grid);
}break;
case 1: {
printf("green gradient");
gradient(0, 255, 0);
}break;
case 2: {
printf("blue gradient");
gradient(0, 0, 255);
}break;
case 3: {
printf("white gradient");
gradient(255, 255, 255);
}break;
}
printf("%d\n", galactic_unicorn.light());
std::string text = "";
if(galactic_unicorn.is_pressed(GalacticUnicorn::SWITCH_A)) {
text = "Button A";
}
if(galactic_unicorn.is_pressed(GalacticUnicorn::SWITCH_B)) {
text = "Button B";
}
if(galactic_unicorn.is_pressed(GalacticUnicorn::SWITCH_C)) {
text = "Button C";
}
if(galactic_unicorn.is_pressed(GalacticUnicorn::SWITCH_D)) {
text = "Button D";
}
if(galactic_unicorn.is_pressed(GalacticUnicorn::SWITCH_VOLUME_UP)) {
text = "Louder!";
}
if(galactic_unicorn.is_pressed(GalacticUnicorn::SWITCH_VOLUME_DOWN)) {
text = "quieter";
}
if(galactic_unicorn.is_pressed(GalacticUnicorn::SWITCH_BRIGHTNESS_UP)) {
text = "Brighter!";
}
if(galactic_unicorn.is_pressed(GalacticUnicorn::SWITCH_BRIGHTNESS_DOWN)) {
text = "Darker";
}
if(galactic_unicorn.is_pressed(GalacticUnicorn::SWITCH_SLEEP)) {
text = "Zzz... zzz...";
}
outline_text(text);
graphics.set_pen(255, 255, 255);
graphics.clear();
galactic_unicorn.update(graphics);
sleep_ms(50);
}
return 0;
}

Wyświetl plik

@ -0,0 +1,88 @@
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "pico/stdlib.h"
#include "libraries/pico_graphics/pico_graphics.hpp"
#include "galactic_unicorn.hpp"
#include "okcolor.hpp"
using namespace pimoroni;
PicoGraphics_PenRGB565 graphics(53, 11, nullptr);
GalacticUnicorn galactic_unicorn;
// extra row of pixels for sourcing flames and averaging
float heat[53][15] = {0.0f};
int main() {
stdio_init_all();
galactic_unicorn.init();
while(true) {
if(galactic_unicorn.is_pressed(galactic_unicorn.SWITCH_BRIGHTNESS_UP)) {
galactic_unicorn.adjust_brightness(+0.01);
}
if(galactic_unicorn.is_pressed(galactic_unicorn.SWITCH_BRIGHTNESS_DOWN)) {
galactic_unicorn.adjust_brightness(-0.01);
}
graphics.set_pen(0, 0, 0);
graphics.clear();
for(int y = 0; y < 14; y++) {
for(int x = 0; x < 53; x++) {
if(heat[x][y] > 0.5f) {
graphics.set_pen(255, 255, 180);
graphics.pixel(Point(x, y));
}else if(heat[x][y] > 0.4f) {
graphics.set_pen(220, 160, 0);
graphics.pixel(Point(x, y));
}else if(heat[x][y] > 0.3f) {
graphics.set_pen(180, 50, 0);
graphics.pixel(Point(x, y));
}else if(heat[x][y] > 0.2f) {
graphics.set_pen(40, 40, 40);
graphics.pixel(Point(x, y));
}
// update this pixel by averaging the below pixels
if(x == 0) {
heat[x][y] = (heat[x][y] + heat[x][y + 2] + heat[x][y + 1] + heat[x + 1][y + 1]) / 4.0f;
} else if(x == 52) {
heat[x][y] = (heat[x][y] + heat[x][y + 2] + heat[x][y + 1] + heat[x - 1][y + 1]) / 4.0f;
} else {
heat[x][y] = (heat[x][y] + heat[x][y + 2] + heat[x][y + 1] + heat[x - 1][y + 1] + heat[x + 1][y + 1]) / 5.0f;
}
heat[x][y] -= 0.01f;
heat[x][y] = heat[x][y] < 0.0f ? 0.0f: heat[x][y];
}
}
galactic_unicorn.update(graphics);
// clear the bottom row and then add a new fire seed to it
for(int x = 0; x < 53; x++) {
heat[x][14] = 0.0f;
}
// add a new random heat source
for(int c = 0; c < 5; c++) {
int px = (rand() % 51) + 1;
heat[px][13] = 1.0f;
heat[px + 1][13] = 1.0f;
heat[px - 1][13] = 1.0f;
heat[px][14] = 1.0f;
heat[px + 1][14] = 1.0f;
heat[px - 1][14] = 1.0f;
}
sleep_ms(50);
}
return 0;
}

Wyświetl plik

@ -0,0 +1,148 @@
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "pico/stdlib.h"
#include "libraries/pico_graphics/pico_graphics.hpp"
#include "galactic_unicorn.hpp"
#include "okcolor.hpp"
using namespace pimoroni;
PicoGraphics_PenRGB565 graphics(53, 11, nullptr);
GalacticUnicorn galactic_unicorn;
// 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;
}
}
struct blob_t {
float x, y;
float r;
float dx, dy;
};
constexpr int blob_count = 20;
int main() {
stdio_init_all();
galactic_unicorn.init();
// randomise blob start positions, directions, and size
std::array<blob_t, blob_count> blobs;
for(auto &blob : blobs) {
blob.x = rand() % 11;
blob.y = rand() % 53;
blob.r = ((rand() % 40) / 10.0f) + 5.0f;
blob.dx = ((rand() % 2) / 10.0f) - 0.05f;
blob.dy = ((rand() % 3) / 10.0f) - 0.1f;
}
float hue = 0.0f;
while(true) {
// allow user to adjust brightness
if(galactic_unicorn.is_pressed(galactic_unicorn.SWITCH_BRIGHTNESS_UP)) {
galactic_unicorn.adjust_brightness(+0.01);
}
if(galactic_unicorn.is_pressed(galactic_unicorn.SWITCH_BRIGHTNESS_DOWN)) {
galactic_unicorn.adjust_brightness(-0.01);
}
uint start_ms = to_ms_since_boot(get_absolute_time());
// calculate the influence of each blob on the liquid based
// on their distance to each pixel. this causes blobs to
// "merge" into each other when we use fixed thresholds to
// determine which colour to draw with
float liquid[11][53] = {0.0f};
for(auto &blob : blobs) {
float r_sq = blob.r * blob.r;
for(int y = 0; y < 53; y++) {
for(int x = 0; x < 11; x++) {
float d_sq = (x - blob.x) * (x - blob.x) + (y - blob.y) * (y - blob.y);
if(d_sq <= r_sq) {
// add this blobs influence to this pixel
liquid[x][y] += 1.0f - (d_sq / r_sq);
}
}
}
}
// update the blob positions
for(auto &blob : blobs) {
blob.x += blob.dx;
blob.y += blob.dy;
// if we hit the edge then bounce!
if(blob.x < 0.0f || blob.x >= 11.0f) {
blob.dx *= -1.0f;
}
if(blob.y < 0.0f || blob.y >= 53.0f) {
blob.dy *= -1.0f;
}
}
// rotate the hue
hue += 0.001f;
// calculate dark, medium, and bright shades for rendering the
// lava
uint8_t dark_r, dark_g, dark_b;
from_hsv(hue, 1.0f, 0.3f, dark_r, dark_g, dark_b);
uint8_t mid_r, mid_g, mid_b;
from_hsv(hue, 1.0f, 0.6f, mid_r, mid_g, mid_b);
uint8_t bright_r, bright_g, bright_b;
from_hsv(hue, 1.0f, 1.0f, bright_r, bright_g, bright_b);
// clear the canvas
graphics.set_pen(0, 0, 0);
graphics.clear();
// render the lava
for(int y = 0; y < 53; y++) {
for(int x = 0; x < 11; x++) {
float v = liquid[x][y];
// select a colour for this pixel based on how much
// "blobfluence" there is at this position in the liquid
if(v >= 1.5f) {
graphics.set_pen(bright_r, bright_g, bright_b);
graphics.pixel(Point(y, x));
}else if(v >= 1.25f) {
graphics.set_pen(mid_r, mid_g, mid_b);
graphics.pixel(Point(y, x));
}else if(v >= 1.0f) {
graphics.set_pen(dark_r, dark_g, dark_b);
graphics.pixel(Point(y, x));
}
}
}
uint end_ms = to_ms_since_boot(get_absolute_time());
printf("rendering took %dms\n", end_ms - start_ms);
galactic_unicorn.update(graphics);
}
return 0;
}

Wyświetl plik

@ -0,0 +1,122 @@
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "pico/stdlib.h"
#include "libraries/pico_graphics/pico_graphics.hpp"
#include "galactic_unicorn.hpp"
#include "okcolor.hpp"
using namespace pimoroni;
PicoGraphics_PenRGB565 graphics(53, 11, nullptr);
GalacticUnicorn galactic_unicorn;
std::array<std::string, 11> c64 = {
"",
" OOOOO OOOOOO OO OOOO OO OO XXXXXXX",
" OO OO OO OOOO OO OO OO OO XXXXXXX",
" OO OO OO OO OO OO OO OO OO XXXXXXX",
" OOOOO OOOO OOOOOO OO OO OOOO XXXXXXX",
" OOOO OO OO OO OO OO OO XXXXXXX",
" OO OO OO OO OO OO OO OO OO XXXXXXX",
" OO OO OOOOOO OO OO OOOO OO OO XXXXXXX",
" XXXXXXX"
};
std::array<std::string, 11> spectrum = {
"",
" O OOOO OOOO OOOOO O O O O XXXXXXXX",
" O O O O O O O O O O O X XXXXXX",
" O O O O O O O X XXXXXX",
" O O O OOOOOO O O X XXXXXX",
" O O O O O O O X XXXXXX",
" OOOOOO OOOO O O OOOOO X XXXXXX",
" X X",
" XXXXXXXX"
};
std::array<std::string, 11> bbc_micro = {
"",
" OOOOO OO OOOO OOO OOOO O ",
" O O O O O O O O O O ",
" O O O O O O O O ",
" OOOOO O O OOOO O O O ",
" O O OOOOOO O O O O ",
" O O O O O O O O O O ",
" OOOOO O O OOOO OOO OOOO O ",
" XXXXXXX"
};
constexpr uint PROMPT_C64 = 0;
constexpr uint PROMPT_SPECTRUM = 1;
constexpr uint PROMPT_BBC_MICRO = 2;
uint prompt = 0;
int main() {
stdio_init_all();
galactic_unicorn.init();
while(true) {
uint time_ms = to_ms_since_boot(get_absolute_time());
prompt = (time_ms / 3000) % 3;
if(galactic_unicorn.is_pressed(galactic_unicorn.SWITCH_BRIGHTNESS_UP)) {
galactic_unicorn.adjust_brightness(+0.01);
}
if(galactic_unicorn.is_pressed(galactic_unicorn.SWITCH_BRIGHTNESS_DOWN)) {
galactic_unicorn.adjust_brightness(-0.01);
}
std::array<std::string, 11> image = c64;
if(prompt == PROMPT_C64) {
image = c64;
}else if(prompt == PROMPT_SPECTRUM) {
image = spectrum;
}else if(prompt == PROMPT_BBC_MICRO) {
image = bbc_micro;
}
if(prompt == PROMPT_C64) {
graphics.set_pen(20, 20, 120);
}else if(prompt == PROMPT_SPECTRUM){
graphics.set_pen(180, 150, 150);
}else if(prompt == PROMPT_BBC_MICRO){
graphics.set_pen(0, 0, 0);
}
graphics.clear();
if(prompt == PROMPT_C64) {
graphics.set_pen(230, 210, 250);
}else if(prompt == PROMPT_SPECTRUM){
graphics.set_pen(0, 0, 0);
}else if(prompt == PROMPT_BBC_MICRO){
graphics.set_pen(255, 255, 255);
}
for(size_t y = 0; y < image.size(); y++) {
for(size_t x = 0; x < image[y].length(); x++) {
// draw the prompt text
if(image[y][x] == 'O') {
graphics.pixel(Point(x, y + 1));
}
// draw the caret blinking
if(image[y][x] == 'X' && (time_ms / 300) % 2) {
graphics.pixel(Point(x, y + 1));
}
}
}
galactic_unicorn.update(graphics);
sleep_ms(10);
}
return 0;
}

Wyświetl plik

@ -0,0 +1,68 @@
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "pico/stdlib.h"
#include "libraries/pico_graphics/pico_graphics.hpp"
#include "galactic_unicorn.hpp"
#include "okcolor.hpp"
using namespace pimoroni;
PicoGraphics_PenRGB565 graphics(53, 11, nullptr);
GalacticUnicorn galactic_unicorn;
std::string message = "Pirate. Monkey. Robot. Ninja.";
int main() {
stdio_init_all();
galactic_unicorn.init();
float scroll = -53.0f;
while(true) {
//uint time_ms = to_ms_since_boot(get_absolute_time());
if(galactic_unicorn.is_pressed(galactic_unicorn.SWITCH_BRIGHTNESS_UP)) {
galactic_unicorn.adjust_brightness(+0.01);
}
if(galactic_unicorn.is_pressed(galactic_unicorn.SWITCH_BRIGHTNESS_DOWN)) {
galactic_unicorn.adjust_brightness(-0.01);
}
int width = graphics.measure_text(message, 1);
scroll += 0.25f;
if(scroll > width) {
scroll = -53.0f;
}
graphics.set_pen(0, 0, 0);
graphics.clear();
ok_color::HSL hsl{scroll / 100.0f, 1.0f, 0.5f};
ok_color::RGB rgb = ok_color::okhsl_to_srgb(hsl);
graphics.set_pen(rgb.r * 255, rgb.g * 255, rgb.b * 255);
graphics.text(message, Point(0 - scroll, 5), -1, 0.55);
/*graphics.text(message, Point(0 - scroll + 1, 5), -1, 0.5);
graphics.text(message, Point(0 - scroll, 5 + 1), -1, 0.5);
graphics.text(message, Point(0 - scroll + 1, 5 + 1), -1, 0.5);*/
/*
for(int x = 0; x < 53; x++) {
for(int y = 0; y < 2; y++) {
float b = sin((x - y * 3 + int(scroll) + 100) / 3.0f);
graphics.set_pen(180 * b, 150 * b, 0);
graphics.pixel(Point(52 - x, y));
graphics.pixel(Point(52 - x, y + 9));
}
}*/
galactic_unicorn.update(graphics);
sleep_ms(10);
}
return 0;
}

Wyświetl plik

@ -1,12 +1 @@
add_library(galactic_unicorn INTERFACE)
pico_generate_pio_header(galactic_unicorn ${CMAKE_CURRENT_LIST_DIR}/galactic_unicorn.pio)
target_sources(galactic_unicorn INTERFACE
${CMAKE_CURRENT_LIST_DIR}/galactic_unicorn.cpp
)
target_include_directories(galactic_unicorn INTERFACE ${CMAKE_CURRENT_LIST_DIR})
# Pull in pico libraries that we need
target_link_libraries(galactic_unicorn INTERFACE pico_stdlib hardware_pio hardware_dma)
include(galactic_unicorn.cmake)

Wyświetl plik

@ -17,6 +17,7 @@ We've included helper functions to handle every aspect of drawing to the display
- [init](#init)
- [set_pixel](#set_pixel)
- [is_pressed](#is_pressed)
- [Examples](#examples)
## Example Program
@ -98,4 +99,16 @@ The button vaule should be a `uint8_t` denoting a pin, and constants `A`, `B`, `
```c++
bool is_a_button_pressed = pico_unicorn.is_pressed(PicoUnicorn::A)
```
```
# Examples
## Game of Life
## Retro Super-computer
Random LEDs blink on and off mimicing the look of a movie super computer doing it's work in the eighties.
## Nostalgia Terminal
A collection of copies of classic terminal styles including C64, MS-DOS, Spectrum, and more.

Wyświetl plik

@ -0,0 +1,63 @@
;
; Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
;
; SPDX-License-Identifier: BSD-3-Clause
;
; Transmit a mono or stereo I2S audio stream as stereo
; This is 16 bits per sample; can be altered by modifying the "set" params,
; or made programmable by replacing "set x" with "mov x, y" and using Y as a config register.
;
; Autopull must be enabled, with threshold set to 32.
; Since I2S is MSB-first, shift direction should be to left.
; Hence the format of the FIFO word is:
;
; | 31 : 16 | 15 : 0 |
; | sample ws=0 | sample ws=1 |
;
; Data is output at 1 bit per clock. Use clock divider to adjust frequency.
; Fractional divider will probably be needed to get correct bit clock period,
; but for common syslck freqs this should still give a constant word select period.
;
; One output pin is used for the data output.
; Two side-set pins are used. Bit 0 is clock, bit 1 is word select.
; Send 16 bit words to the PIO for mono, 32 bit words for stereo
.program audio_i2s
.side_set 2
; /--- LRCLK
; |/-- BCLK
bitloop1: ; ||
out pins, 1 side 0b10
jmp x-- bitloop1 side 0b11
out pins, 1 side 0b00
set x, 14 side 0b01
bitloop0:
out pins, 1 side 0b00
jmp x-- bitloop0 side 0b01
out pins, 1 side 0b10
public entry_point:
set x, 14 side 0b11
% c-sdk {
static inline void audio_i2s_program_init(PIO pio, uint sm, uint offset, uint data_pin, uint clock_pin_base) {
pio_sm_config sm_config = audio_i2s_program_get_default_config(offset);
sm_config_set_out_pins(&sm_config, data_pin, 1);
sm_config_set_sideset_pins(&sm_config, clock_pin_base);
sm_config_set_out_shift(&sm_config, false, true, 32);
pio_sm_init(pio, sm, offset, &sm_config);
uint pin_mask = (1u << data_pin) | (3u << clock_pin_base);
pio_sm_set_pindirs_with_mask(pio, sm, pin_mask, pin_mask);
pio_sm_set_pins(pio, sm, 0); // clear pins
pio_sm_exec(pio, sm, pio_encode_jmp(offset + audio_i2s_offset_entry_point));
}
%}

Wyświetl plik

@ -1,12 +1,14 @@
add_library(pico_unicorn INTERFACE)
add_library(galactic_unicorn INTERFACE)
pico_generate_pio_header(pico_unicorn ${CMAKE_CURRENT_LIST_DIR}/pico_unicorn.pio)
pico_generate_pio_header(galactic_unicorn ${CMAKE_CURRENT_LIST_DIR}/galactic_unicorn.pio)
pico_generate_pio_header(galactic_unicorn ${CMAKE_CURRENT_LIST_DIR}/audio_i2s.pio)
target_sources(pico_unicorn INTERFACE
${CMAKE_CURRENT_LIST_DIR}/pico_unicorn.cpp
target_sources(galactic_unicorn INTERFACE
${CMAKE_CURRENT_LIST_DIR}/galactic_unicorn.cpp
)
target_include_directories(pico_unicorn INTERFACE ${CMAKE_CURRENT_LIST_DIR})
target_include_directories(galactic_unicorn INTERFACE ${CMAKE_CURRENT_LIST_DIR})
# Pull in pico libraries that we need
target_link_libraries(pico_unicorn INTERFACE pico_stdlib hardware_pio hardware_dma)
target_link_libraries(galactic_unicorn INTERFACE pico_stdlib pico_graphics hardware_adc hardware_pio hardware_dma)

Wyświetl plik

@ -2,88 +2,47 @@
#include "hardware/dma.h"
#include "hardware/irq.h"
#include "hardware/adc.h"
#include "hardware/clocks.h"
#include "galactic_unicorn.pio.h"
#include "audio_i2s.pio.h"
#include "galactic_unicorn.hpp"
// pixel data is stored as a stream of bits delivered in the
// order the PIO needs to manage the shift registers, row
// selects, delays, and latching/blanking
//
// the data consists of 11 rows each of which has 14 frames of
// bcd timing data
// the pins used are:
//
// bits are output in order:
// - 13: column clock (sideset)
// - 14: column data (out base)
// - 15: column latch
// - 16: column blank
// - 17: row select bit 0
// - 18: row select bit 1
// - 19: row select bit 2
// - 20: row select bit 3
//
// ROW_CLEAR, ROW_DATA1, ROW_DATA0, LED_BLANK, LED_LATCH, LED_CLOCK, LED_DATA0, LED_DATA1
// the framebuffer data is structured like this:
//
// the data is structured like this:
//
// loop through the eleven rows of the display...
//
// 1rr00000 // set row select bit on rows 0 and 8 (side set the clock)
// 00000000 00000000 00000000 // dummy bytes to align to dwords
//
// within this row we loop through the 14 bcd frames for this row...
//
// 0 - 161: 100100rr, 100101rr, 100100gg, 100101gg, 100100bb, 100101bb, ... x 27 # left+right half rgb pixel data doubled for clock pulses, keep BLANK high
// 162: 10011000 // LATCH pixel data
// 163: 10000000 // turn off BLANK to output pixel data - now at 164 bytes (41 dwords)
// 164 - 165: 00001111, 11111111, # bcd tick count (0-65536)
// 166: 10010000 // turn BLANK back on
// 167: 00000000 // dummy byte to ensure dword aligned
// for each row:
// for each bcd frame:
// 0: 00110110 // row pixel count (minus one)
// 1 - 53: xxxxxbgr, xxxxxbgr, xxxxxbgr, ... // pixel data
// 54 - 55: xxxxxxxx, xxxxxxxx // dummy bytes to dword align
// 56: xxxxrrrr // row select bits
// 57 - 59: tttttttt, tttttttt, tttttttt // bcd tick count (0-65536)
//
// .. and back to the start
/*
enum pin {
LED_DATA = 8,
LED_CLOCK = 9,
LED_LATCH = 10,
LED_BLANK = 11,
ROW_0 = 22,
ROW_1 = 21,
ROW_2 = 20,
ROW_3 = 19,
ROW_4 = 18,
ROW_5 = 17,
ROW_6 = 16,
A = 12,
B = 13,
X = 14,
Y = 15,
};*/
enum pin {
LED_DATA1 = 12,
LED_DATA0 = 13,
LED_CLOCK = 14,
LED_LATCH = 15,
LED_BLANK = 16,
ROW_DATA0 = 17,
ROW_DATA1 = 18,
ROW_CLEAR = 19,
ROW_CLOCK = 20,
SWITCH_A = 0,
SWITCH_B = 1,
SWITCH_C = 3,
SWITCH_D = 6,
SWITCH_E = 2,
SWITCH_VOLUME_UP = 21,
SWITCH_VOLUME_DOWN = 26,
SWITCH_BRIGHTNESS_UP = 7,
SWITCH_BRIGHTNESS_DOWN = 8
};
constexpr uint32_t ROW_COUNT = 11;
constexpr uint32_t ROW_BYTES = 4;
constexpr uint32_t ROW_FRAME_BYTES = 168;
constexpr uint32_t BCD_FRAMES = 15; // includes fet discharge frame
constexpr uint32_t BITSTREAM_LENGTH = (ROW_COUNT * ROW_BYTES + ROW_COUNT * ROW_FRAME_BYTES * BCD_FRAMES);
constexpr uint32_t BCD_FRAME_COUNT = 14;
constexpr uint32_t BCD_FRAME_BYTES = 60;
constexpr uint32_t ROW_BYTES = BCD_FRAME_COUNT * BCD_FRAME_BYTES;
constexpr uint32_t BITSTREAM_LENGTH = (ROW_COUNT * ROW_BYTES);
// must be aligned for 32bit dma transfer
alignas(4) static uint8_t bitstream[BITSTREAM_LENGTH] = {0};
@ -93,38 +52,7 @@ static uint16_t g_gamma_lut[256] = {0};
static uint16_t b_gamma_lut[256] = {0};
static uint32_t dma_channel;
static inline void unicorn_jetpack_program_init(PIO pio, uint sm, uint offset) {
pio_gpio_init(pio, pin::LED_DATA1);
pio_gpio_init(pio, pin::LED_DATA0);
pio_gpio_init(pio, pin::LED_CLOCK);
pio_gpio_init(pio, pin::LED_LATCH);
pio_gpio_init(pio, pin::LED_BLANK);
pio_gpio_init(pio, pin::ROW_DATA0);
pio_gpio_init(pio, pin::ROW_DATA1);
pio_gpio_init(pio, pin::ROW_CLEAR);
pio_gpio_init(pio, pin::ROW_CLOCK);
pio_sm_set_consecutive_pindirs(pio, sm, pin::LED_DATA1, 5, true);
pio_sm_set_consecutive_pindirs(pio, sm, pin::ROW_DATA0, 4, true);
pio_sm_config c = galactic_unicorn_program_get_default_config(offset);
// osr shifts right, autopull on, autopull threshold 8
sm_config_set_out_shift(&c, true, false, 32);
// configure out, set, and sideset pins
sm_config_set_out_pins(&c, pin::LED_DATA1, 8);
sm_config_set_sideset_pins(&c, pin::ROW_CLOCK);
// join fifos as only tx needed (gives 8 deep fifo instead of 4)
sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_TX);
pio_sm_init(pio, sm, offset, &c);
pio_sm_set_enabled(pio, sm, true);
///pio_sm_set_clkdiv(pio, sm, 4.0f);
}
static uint32_t audio_dma_channel;
namespace pimoroni {
@ -154,118 +82,124 @@ namespace pimoroni {
pio_sm_restart(bitstream_pio, bitstream_sm);
}
uint16_t GalacticUnicorn::light() {
adc_select_input(2);
return adc_read();
}
void GalacticUnicorn::init() {
// todo: shouldn't need to do this if things were cleaned up properly but without
// this any attempt to run a micropython script twice will fail
static bool already_init = false;
// setup pins
gpio_init(pin::LED_DATA0); gpio_set_dir(pin::LED_DATA0, GPIO_OUT);
gpio_init(pin::LED_DATA1); gpio_set_dir(pin::LED_DATA1, GPIO_OUT);
gpio_init(pin::LED_CLOCK); gpio_set_dir(pin::LED_CLOCK, GPIO_OUT);
gpio_init(pin::LED_LATCH); gpio_set_dir(pin::LED_LATCH, GPIO_OUT);
gpio_init(pin::LED_BLANK); gpio_set_dir(pin::LED_BLANK, GPIO_OUT);
gpio_init(pin::ROW_DATA0); gpio_set_dir(pin::ROW_DATA0, GPIO_OUT);
gpio_init(pin::ROW_DATA1); gpio_set_dir(pin::ROW_DATA1, GPIO_OUT);
gpio_init(pin::ROW_CLEAR); gpio_set_dir(pin::ROW_CLEAR, GPIO_OUT);
gpio_init(pin::ROW_CLOCK); gpio_set_dir(pin::ROW_CLOCK, GPIO_OUT);
// create 14-bit gamma luts
for(uint16_t v = 0; v < 256; v++) {
// gamma correct the provided 0-255 brightness value onto a
// 0-65535 range for the pwm counter
float r_gamma = 2.8f;
r_gamma_lut[v] = (uint16_t)(powf((float)(v) / 255.0f, r_gamma) * 16383.0f + 0.5f);
float g_gamma = 2.8f;
g_gamma_lut[v] = (uint16_t)(powf((float)(v) / 255.0f, g_gamma) * 16383.0f + 0.5f);
float b_gamma = 2.8f;
b_gamma_lut[v] = (uint16_t)(powf((float)(v) / 255.0f, b_gamma) * 16383.0f + 0.5f);
float r_gamma = 1.8f;
r_gamma_lut[v] = (uint16_t)(powf((float)(v) / 255.0f, r_gamma) * (float(1U << (BCD_FRAME_COUNT)) - 1.0f) + 0.5f);
float g_gamma = 2.0f;
g_gamma_lut[v] = (uint16_t)(powf((float)(v) / 255.0f, g_gamma) * (float(1U << (BCD_FRAME_COUNT)) - 1.0f) + 0.5f);
float b_gamma = 1.8f;
b_gamma_lut[v] = (uint16_t)(powf((float)(v) / 255.0f, b_gamma) * (float(1U << (BCD_FRAME_COUNT)) - 1.0f) + 0.5f);
}
// for each row:
// for each bcd frame:
// 0: 00110110 // row pixel count (minus one)
// 1 - 53: xxxxxbgr, xxxxxbgr, xxxxxbgr, ... // pixel data
// 54 - 55: xxxxxxxx, xxxxxxxx // dummy bytes to dword align
// 56: xxxxrrrr // row select bits
// 57 - 59: tttttttt, tttttttt, tttttttt // bcd tick count (0-65536)
//
// .. and back to the start
// the data is structured like this:
//
// loop through the eleven rows of the display...
//
// 1rr00000 // set row select bit on rows 0 and 8 (side set the clock)
// 00000000 00000000 00000000 // dummy bytes to align to dwords
//
// within this row we loop through the 14 bcd frames for this row...
//
// 0 - 161: 100100rr, 100101rr, 100100gg, 100101gg, 100100bb, 100101bb, ... x 27 # left+right half rgb pixel data doubled for clock pulses, keep BLANK high
// 162: 10011000 // LATCH pixel data
// 163: 10000000 // turn off BLANK to output pixel data - now at 164 bytes (41 dwords)
// 164 - 165: 00001111, 11111111, # bcd tick count (0-65536)
// 166: 10010000 // turn BLANK back on
// 167: 00000000 // dummy byte to ensure dword aligned
//
// .. and back to the start
// initialise the bcd timing values and row selects in the bitstream
for(uint8_t row = 0; row < HEIGHT; row++) {
uint16_t row_offset = row * (ROW_BYTES + ROW_FRAME_BYTES * BCD_FRAMES);
for(uint8_t frame = 0; frame < BCD_FRAME_COUNT; frame++) {
// find the offset of this row and frame in the bitstream
uint8_t *p = &bitstream[row * ROW_BYTES + (BCD_FRAME_BYTES * frame)];
// setup row select on rows 0 and 8
uint8_t row_select = row == 0 ? 0b10111000 : (row == 8 ? 0b11011000 : 0b10011000);
bitstream[row_offset + 0] = row_select;
for(uint8_t frame = 0; frame < BCD_FRAMES; frame++) {
uint16_t frame_offset = row_offset + ROW_BYTES + (ROW_FRAME_BYTES * frame);
bitstream[frame_offset + 162] = 0b10011000; // LATCH pixel data
bitstream[frame_offset + 163] = 0b10001000; // BLANK low to enable column outputs
p[ 0] = WIDTH - 1; // row pixel count
p[56] = row; // row select
// set the number of bcd ticks for this frame
uint16_t bcd_ticks = frame == BCD_FRAMES - 1 ? 1 : 1 << frame;
bitstream[frame_offset + 164] = (bcd_ticks & 0xff);
bitstream[frame_offset + 165] = (bcd_ticks & 0xff00) >> 8;
bitstream[frame_offset + 166] = 0b10010000; // BLANK high again to disable outputs
// setup empty pixels with BLANK high and a clock pulse
for(uint8_t col = 0; col < 162; col += 2) {
bitstream[frame_offset + col + 0] = 0b10010000;
bitstream[frame_offset + col + 1] = 0b10010100;
}
/*
uint16_t row_select_offset = offset + 164;
uint16_t bcd_offset = offset + 165;
// the last bcd frame is used to allow the fets to discharge to avoid ghosting
if(frame == BCD_FRAMES - 1) {
uint16_t bcd_ticks = 65535;
bitstream[bcd_offset + 1] = (bcd_ticks & 0xff00) >> 8;
bitstream[bcd_offset] = (bcd_ticks & 0xff);
}else{
uint8_t row_select = row == 0 ? 0b01000000 : (row == 8 ? 0b00100000 : 0b00000000);
bitstream[row_select_offset] = row_select;
uint16_t bcd_ticks = 1 << frame;
bitstream[bcd_offset + 1] = (bcd_ticks & 0xff00) >> 8;
bitstream[bcd_offset] = (bcd_ticks & 0xff);
}*/
uint32_t bcd_ticks = (1 << frame);
p[57] = (bcd_ticks & 0xff) >> 0;
p[58] = (bcd_ticks & 0xff00) >> 8;
p[59] = (bcd_ticks & 0xff0000) >> 16;
}
/*
for(size_t i = 0; i < sizeof(bitstream); i++) {
bitstream[i] = 0b11100000;
}*/
}
// setup light sensor adc
adc_init();
adc_gpio_init(LIGHT_SENSOR);
pio_gpio_init(bitstream_pio, COLUMN_CLOCK);
pio_gpio_init(bitstream_pio, COLUMN_DATA);
pio_gpio_init(bitstream_pio, COLUMN_LATCH);
gpio_init(COLUMN_CLOCK); gpio_set_dir(COLUMN_CLOCK, GPIO_OUT); gpio_put(COLUMN_CLOCK, false);
gpio_init(COLUMN_DATA); gpio_set_dir(COLUMN_DATA, GPIO_OUT); gpio_put(COLUMN_DATA, false);
gpio_init(COLUMN_LATCH); gpio_set_dir(COLUMN_LATCH, GPIO_OUT); gpio_put(COLUMN_LATCH, false);
sleep_ms(100);
// configure full output current in register 2
uint16_t reg1 = 0b1111111111001110;
// clock the register value to the first 9 driver chips
for(int j = 0; j < 9; j++) {
for(int i = 0; i < 16; i++) {
if(reg1 & (1U << (15 - i))) {
gpio_put(COLUMN_DATA, true);
}else{
gpio_put(COLUMN_DATA, false);
}
sleep_us(10);
gpio_put(COLUMN_CLOCK, true);
sleep_us(10);
gpio_put(COLUMN_CLOCK, false);
}
}
// clock the last chip and latch the value
for(int i = 0; i < 16; i++) {
if(reg1 & (1U << (15 - i))) {
gpio_put(COLUMN_DATA, true);
}else{
gpio_put(COLUMN_DATA, false);
}
sleep_us(10);
gpio_put(COLUMN_CLOCK, true);
sleep_us(10);
gpio_put(COLUMN_CLOCK, false);
if(i == 4) {
gpio_put(COLUMN_LATCH, true);
}
}
gpio_put(COLUMN_LATCH, false);
gpio_init(MUTE); gpio_set_dir(MUTE, GPIO_OUT); gpio_put(MUTE, true);
// setup button inputs
gpio_set_function(pin::SWITCH_A, GPIO_FUNC_SIO); gpio_set_dir(pin::SWITCH_A, GPIO_IN); gpio_pull_up(pin::SWITCH_A);
gpio_set_function(pin::SWITCH_B, GPIO_FUNC_SIO); gpio_set_dir(pin::SWITCH_B, GPIO_IN); gpio_pull_up(pin::SWITCH_B);
gpio_set_function(pin::SWITCH_C, GPIO_FUNC_SIO); gpio_set_dir(pin::SWITCH_C, GPIO_IN); gpio_pull_up(pin::SWITCH_C);
gpio_set_function(pin::SWITCH_D, GPIO_FUNC_SIO); gpio_set_dir(pin::SWITCH_D, GPIO_IN); gpio_pull_up(pin::SWITCH_D);
gpio_set_function(pin::SWITCH_E, GPIO_FUNC_SIO); gpio_set_dir(pin::SWITCH_E, GPIO_IN); gpio_pull_up(pin::SWITCH_E);
gpio_init(SWITCH_A); gpio_pull_up(SWITCH_A);
gpio_init(SWITCH_B); gpio_pull_up(SWITCH_B);
gpio_init(SWITCH_C); gpio_pull_up(SWITCH_C);
gpio_init(SWITCH_D); gpio_pull_up(SWITCH_D);
gpio_set_function(pin::SWITCH_BRIGHTNESS_UP, GPIO_FUNC_SIO); gpio_set_dir(pin::SWITCH_BRIGHTNESS_UP, GPIO_IN); gpio_pull_up(pin::SWITCH_BRIGHTNESS_UP);
gpio_set_function(pin::SWITCH_BRIGHTNESS_DOWN, GPIO_FUNC_SIO); gpio_set_dir(pin::SWITCH_BRIGHTNESS_DOWN, GPIO_IN); gpio_pull_up(pin::SWITCH_BRIGHTNESS_DOWN);
gpio_init(SWITCH_SLEEP); gpio_pull_up(SWITCH_SLEEP);
gpio_set_function(pin::SWITCH_VOLUME_UP, GPIO_FUNC_SIO); gpio_set_dir(pin::SWITCH_VOLUME_UP, GPIO_IN); gpio_pull_up(pin::SWITCH_VOLUME_UP);
gpio_set_function(pin::SWITCH_VOLUME_DOWN, GPIO_FUNC_SIO); gpio_set_dir(pin::SWITCH_VOLUME_DOWN, GPIO_IN); gpio_pull_up(pin::SWITCH_VOLUME_DOWN);
gpio_init(SWITCH_BRIGHTNESS_UP); gpio_pull_up(SWITCH_BRIGHTNESS_UP);
gpio_init(SWITCH_BRIGHTNESS_DOWN); gpio_pull_up(SWITCH_BRIGHTNESS_DOWN);
gpio_init(SWITCH_VOLUME_UP); gpio_pull_up(SWITCH_VOLUME_UP);
gpio_init(SWITCH_VOLUME_DOWN); gpio_pull_up(SWITCH_VOLUME_DOWN);
if(already_init) {
// stop and release the dma channel
@ -288,9 +222,38 @@ namespace pimoroni {
// setup the pio
bitstream_pio = pio0;
bitstream_sm = pio_claim_unused_sm(pio0, true);
sm_offset = pio_add_program(bitstream_pio, &galactic_unicorn_program);
unicorn_jetpack_program_init(bitstream_pio, bitstream_sm, sm_offset);
bitstream_sm = pio_claim_unused_sm(bitstream_pio, true);
bitstream_sm_offset = pio_add_program(bitstream_pio, &galactic_unicorn_program);
pio_gpio_init(bitstream_pio, COLUMN_CLOCK);
pio_gpio_init(bitstream_pio, COLUMN_DATA);
pio_gpio_init(bitstream_pio, COLUMN_LATCH);
pio_gpio_init(bitstream_pio, COLUMN_BLANK);
pio_gpio_init(bitstream_pio, ROW_BIT_0);
pio_gpio_init(bitstream_pio, ROW_BIT_1);
pio_gpio_init(bitstream_pio, ROW_BIT_2);
pio_gpio_init(bitstream_pio, ROW_BIT_3);
// set all led driving pins as outputs
pio_sm_set_consecutive_pindirs(bitstream_pio, bitstream_sm, COLUMN_CLOCK, 8, true);
pio_sm_config c = galactic_unicorn_program_get_default_config(bitstream_sm_offset);
// osr shifts right, autopull on, autopull threshold 8
sm_config_set_out_shift(&c, true, true, 32);
// configure out, set, and sideset pins
sm_config_set_out_pins(&c, ROW_BIT_0, 4);
sm_config_set_set_pins(&c, COLUMN_DATA, 3);
sm_config_set_sideset_pins(&c, COLUMN_CLOCK);
// join fifos as only tx needed (gives 8 deep fifo instead of 4)
sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_TX);
pio_sm_init(bitstream_pio, bitstream_sm, bitstream_sm_offset, &c);
pio_sm_set_enabled(bitstream_pio, bitstream_sm, true);
// setup dma transfer for pixel data to the pio
dma_channel = dma_claim_unused_channel(true);
@ -308,6 +271,52 @@ namespace pimoroni {
dma_channel_set_read_addr(dma_channel, bitstream, true);
already_init = true;
// setup audio pio program
/*
audio_pio = pio0;
audio_sm = pio_claim_unused_sm(audio_pio, true);
audio_sm_offset = pio_add_program(audio_pio, &audio_i2s_program);
audio_i2s_program_init(audio_pio, audio_sm, audio_sm_offset, I2S_DATA, I2S_BCLK);
//pio_sm_set_enabled(audio_pio, audio_sm, true);
uint32_t system_clock_frequency = clock_get_hz(clk_sys);
uint32_t divider = system_clock_frequency * 4 / 22050; // avoid arithmetic overflow
pio_sm_set_clkdiv_int_frac(audio_pio, audio_sm, divider >> 8u, divider & 0xffu);
audio_dma_channel = dma_claim_unused_channel(true);
dma_channel_config audio_config = dma_channel_get_default_config(audio_dma_channel);
channel_config_set_transfer_data_size(&audio_config, DMA_SIZE_32);
channel_config_set_bswap(&audio_config, false); // byte swap to reverse little endian
channel_config_set_dreq(&audio_config, pio_get_dreq(audio_pio, audio_sm, true));
dma_channel_configure(audio_dma_channel, &audio_config, &audio_pio->txf[audio_sm], NULL, 0, false);
dma_channel_set_irq0_enabled(audio_dma_channel, true);
irq_set_enabled(pio_get_dreq(audio_pio, audio_sm, true), true);*/
//irq_set_exclusive_handler(DMA_IRQ_0, dma_complete);
//irq_set_enabled(DMA_IRQ_0, true);
/* dma_channel_set_trans_count(audio_dma_channel, BITSTREAM_LENGTH / 4, false);
dma_channel_set_read_addr(audio_dma_channel, bitstream, true);*/
//pio_sm_config audio_i2s_config = audio_i2s_program_get_default_config(audio_sm_offset);
// osr shifts right, autopull on, autopull threshold 8
//sm_config_set_out_shift(&audio_i2s_config, true, true, 32);
// // configure out, set, and sideset pins
// sm_config_set_out_pins(&audio_i2s_config, ROW_BIT_0, 4);
// sm_config_set_set_pins(&audio_i2s_config, COLUMN_DATA, 3);
// sm_config_set_sideset_pins(&audio_i2s_config, COLUMN_CLOCK);
// // join fifos as only tx needed (gives 8 deep fifo instead of 4)
// sm_config_set_fifo_join(&audio_i2s_config, PIO_FIFO_JOIN_TX);
//pio_sm_init(audio_pio, audio_sm, audio_sm_offset, &audio_i2s_config);
//pio_sm_set_enabled(audio_pio, audio_sm, true);
}
void GalacticUnicorn::clear() {
@ -318,65 +327,44 @@ namespace pimoroni {
}
}
void GalacticUnicorn::set_pixel(int x, int y, uint8_t r, uint8_t g, uint8_t b) {
void GalacticUnicorn::play_sample(uint8_t *data, uint32_t length) {
dma_channel_transfer_from_buffer_now(audio_dma_channel, data, length / 4);
}
void GalacticUnicorn::set_pixel(int x, int y, uint8_t r, uint8_t g, uint8_t b) {
if(x < 0 || x >= WIDTH || y < 0 || y >= HEIGHT) return;
// make those coordinates sane
x = (WIDTH - 1) - x;
y = (HEIGHT - 1) - y;
// determine offset in the buffer for this row
uint16_t row_offset = y * (ROW_BYTES + ROW_FRAME_BYTES * BCD_FRAMES);
uint16_t gamma_r = r_gamma_lut[r];
uint16_t gamma_g = g_gamma_lut[g];
uint16_t gamma_b = b_gamma_lut[b];
uint16_t bits[3] = {r_gamma_lut[b], g_gamma_lut[g], b_gamma_lut[r]};
//uint16_t gr = r_gamma_lut[r];
//uint16_t gg = g_gamma_lut[g];
//uint16_t gb = b_gamma_lut[b];
// for each row:
// for each bcd frame:
// 0: 00110110 // row pixel count (minus one)
// 1 - 53: xxxxxbgr, xxxxxbgr, xxxxxbgr, ... // pixel data
// 54 - 55: xxxxxxxx, xxxxxxxx // dummy bytes to dword align
// 56: xxxxrrrr // row select bits
// 57 - 59: tttttttt, tttttttt, tttttttt // bcd tick count (0-65536)
//
// .. and back to the start
// set the appropriate bits in the separate bcd frames
for(uint8_t frame = 0; frame < BCD_FRAMES; frame++) {
uint16_t frame_offset = (ROW_FRAME_BYTES * frame) + 4;
uint16_t offset = row_offset + frame_offset;// + byte_offset;
for(uint8_t frame = 0; frame < BCD_FRAME_COUNT; frame++) {
uint8_t *p = &bitstream[y * ROW_BYTES + (BCD_FRAME_BYTES * frame) + 1 + x];
// loop through the eleven rows of the display...
//
// 1rr00000 // set row select bit on rows 0 and 8 (side set the clock)
// 00000000 00000000 00000000 // dummy bytes to align to dwords
//
// within this row we loop through the 14 bcd frames for this row...
//
// 0 - 161: 100100rr, 100101rr, 100100gg, 100101gg, 100100bb, 100101bb, ... x 27 # left+right half rgb pixel data doubled for clock pulses, keep BLANK high
// 162: 10011000 // LATCH pixel data
// 163: 10000000 // turn off BLANK to output pixel data - now at 164 bytes (41 dwords)
// 164 - 165: 00001111, 11111111, # bcd tick count (0-65536)
// 166: 10010000 // turn BLANK back on
// 167: 00000000 // dummy byte to ensure dword aligned
//
// .. and back to the start
uint8_t red_bit = gamma_r & 0b1;
uint8_t green_bit = gamma_g & 0b1;
uint8_t blue_bit = gamma_b & 0b1;
// work out the byte offset of this pixel
/*if(bit_offset >= 160) {
bit_offset -= 160;
}*/
*p = (blue_bit << 2) | (green_bit << 1) | (red_bit << 0);
for(int bit = 0; bit < 3; bit++) {
int16_t bit_offset = x * 6 + 4 + (bit * 2);
uint8_t bit_position = bit_offset >= 160 ? 1 : 0;
uint8_t mask = 0b1 << bit_position;
uint8_t value = (bits[bit] & 0b1) << bit_position;
bitstream[offset + (bit_offset % 160) + 0] &= ~mask;
bitstream[offset + (bit_offset % 160) + 0] |= value;
bitstream[offset + (bit_offset % 160) + 1] &= ~mask;
bitstream[offset + (bit_offset % 160) + 1] |= value;
//bit_offset += 2;
bits[bit] >>= 1;
}
gamma_r >>= 1;
gamma_g >>= 1;
gamma_b >>= 1;
}
}
@ -384,6 +372,55 @@ namespace pimoroni {
set_pixel(x, y, v, v, v);
}
void GalacticUnicorn::set_brightness(float value) {
value = value < 0.0f ? 0.0f : value;
value = value > 1.0f ? 1.0f : value;
this->brightness = floor(value * 255.0f);
}
float GalacticUnicorn::get_brightness() {
return this->brightness / 255.0f;
}
void GalacticUnicorn::adjust_brightness(float delta) {
this->set_brightness(this->get_brightness() + delta);
}
void GalacticUnicorn::set_volume(float value) {
value = value < 0.0f ? 0.0f : value;
value = value > 1.0f ? 1.0f : value;
this->volume = floor(value * 255.0f);
}
float GalacticUnicorn::get_volume() {
return this->volume / 255.0f;
}
void GalacticUnicorn::adjust_volume(float delta) {
this->set_volume(this->get_volume() + delta);
}
void GalacticUnicorn::update(PicoGraphics_PenRGB565 &graphics) {
uint16_t *p = (uint16_t *)graphics.frame_buffer;
for(size_t j = 0; j < 53 * 11; j++) {
int x = j % 53;
int y = j / 53;
uint16_t col = __builtin_bswap16(*p);
uint8_t r = ((col & 0b1111100000000000) >> 11) << 3;
uint8_t g = ((col & 0b0000011111100000) >> 5) << 2;
uint8_t b = ((col & 0b0000000000011111) >> 0) << 3;
p++;
r = (r * this->brightness) >> 8;
g = (g * this->brightness) >> 8;
b = (b * this->brightness) >> 8;
set_pixel(x, y, b, g, r);
}
}
bool GalacticUnicorn::is_pressed(uint8_t button) {
return !gpio_get(button);
}

Wyświetl plik

@ -1,6 +1,7 @@
#pragma once
#include "hardware/pio.h"
#include "pico_graphics.hpp"
namespace pimoroni {
@ -8,30 +9,81 @@ namespace pimoroni {
public:
static const int WIDTH = 53;
static const int HEIGHT = 11;
static const uint8_t SWITCH_A = 0;
static const uint8_t SWITCH_B = 1;
static const uint8_t SWITCH_C = 3;
static const uint8_t SWITCH_D = 6;
static const uint8_t SWITCH_E = 2;
static const uint8_t SWITCH_VOLUME_UP = 21;
static const uint8_t SWITCH_VOLUME_DOWN = 26;
static const uint8_t SWITCH_BRIGHTNESS_UP = 7;
static const uint8_t SWITCH_BRIGHTNESS_DOWN = 8;
// pin assignments
static const uint8_t COLUMN_CLOCK = 13;
static const uint8_t COLUMN_DATA = 14;
static const uint8_t COLUMN_LATCH = 15;
static const uint8_t COLUMN_BLANK = 16;
static const uint8_t ROW_BIT_0 = 17;
static const uint8_t ROW_BIT_1 = 18;
static const uint8_t ROW_BIT_2 = 19;
static const uint8_t ROW_BIT_3 = 20;
static const uint8_t LIGHT_SENSOR = 28;
static const uint8_t MUTE = 22;
static const uint8_t I2S_DATA = 9;
static const uint8_t I2S_BCLK = 10;
static const uint8_t I2S_LRCLK = 11;
static const uint8_t I2C_SDA = 4;
static const uint8_t I2C_SCL = 5;
static const uint8_t SWITCH_A = 0;
static const uint8_t SWITCH_B = 1;
static const uint8_t SWITCH_C = 3;
static const uint8_t SWITCH_D = 6;
static const uint8_t SWITCH_SLEEP = 27;
static const uint8_t SWITCH_VOLUME_UP = 7;
static const uint8_t SWITCH_VOLUME_DOWN = 8;
static const uint8_t SWITCH_BRIGHTNESS_UP = 21;
static const uint8_t SWITCH_BRIGHTNESS_DOWN = 26;
private:
PIO bitstream_pio = pio0;
uint bitstream_sm = 0;
uint sm_offset = 0;
uint bitstream_sm_offset = 0;
PIO audio_pio = pio0;
uint audio_sm = 0;
uint audio_sm_offset = 0;
uint8_t brightness = 255;
uint8_t volume = 127;
public:
~GalacticUnicorn();
void init();
static inline void pio_program_init(PIO pio, uint sm, uint offset);
void clear();
void update(PicoGraphics_PenRGB565 &graphics);
void set_brightness(float value);
float get_brightness();
void adjust_brightness(float delta);
void set_volume(float value);
float get_volume();
void adjust_volume(float delta);
void set_pixel(int x, int y, uint8_t r, uint8_t g, uint8_t b);
void set_pixel(int x, int y, uint8_t v);
uint16_t light();
bool is_pressed(uint8_t button);
void play_sample(uint8_t *data, uint32_t length);
};
}

Wyświetl plik

@ -2,65 +2,79 @@
.side_set 1 opt
; out pins:
; 0: data1 (base)
; 1: data0
; 2: clock
; 3: latch
; 4: blank
; 5: row1
; 6: row2
; 7: row_clear
;
; - 3: row select bit 0
; - 4: row select bit 1
; - 5: row select bit 2
; - 6: row select bit 3
; set pins:
;
; - 0: column data (base)
; - 1: column latch
; - 2: column blank
; sideset pin:
;
; - 0: column clock
; for each row:
; for each bcd frame:
; 0: 00110110 // row pixel count (minus one)
; 1 - 53: xxxxxbgr, xxxxxbgr, xxxxxbgr, ... // pixel data
; 54 - 55: xxxxxxxx, xxxxxxxx // dummy bytes to dword align
; 56: xxxxrrrr // row select bits
; 57 - 59: tttttttt, tttttttt, tttttttt, // bcd tick count (0-65536)
;
; .. and back to the start
; sideset pin: row_clock
.wrap_target
; set row select pins
pull
out pins, 8 side 0 [4]
nop side 1 [4] ; pulse row select clock
out null, 24 ; discard dummy data
; loop for bcd frames
set x, 14
bcd_frame:
; clock out 53 pixels worth of data - two pixels at a time, so 27 (actually 26.5) bits of data
set y, 26 ; 26 because `jmp` test is pre decrement
; loop over row pixels
out y, 8 ; get row pixel count (minus 1 because test is pre decrement)
pixels:
pull ifempty
out pins, 8 [1] ; two red bits..
out pins, 8 [1] ; ..with clock pulse
pull ifempty
out pins, 8 [1] ; two green bits..
out pins, 8 [1] ; ..with green pulse
pull ifempty
out pins, 8 [1] ; two blue bits..
out pins, 8 [1] ; ..with blue pulse
jmp y-- pixels
out pins, 8 ; LATCH pixel data
out pins, 8 ; turn off BLANK signal
; red bit
out x, 1 side 0 [1] ; pull in blue bit from OSR into register x, clear clock
set pins, 0b100 ; clear data bit, blank high
jmp !x endb ; if bit was zero jump
set pins, 0b101 ; set data bit, blank high
endb:
nop side 1 [2] ; clock in bit
pull
; green bit
out x, 1 side 0 [1] ; pull in green bit from OSR into register X, clear clock
set pins, 0b100 ; clear data bit, blank high
jmp !x endg ; if bit was zero jump
set pins, 0b101 ; set data bit, blank high
endg:
nop side 1 [2] ; clock in bit
; pull bcd tick count into x register
out y, 16
; blue bit
out x, 1 side 0 [1] ; pull in red bit from OSR into register X, clear clock
set pins, 0b100 ; clear data bit, blank high
jmp !x endr ; if bit was zero jump
set pins, 0b101 ; set data bit, blank high
endr:
out null, 5 side 1 [2] ; clock in bit
bcd_count:
jmp y-- bcd_count ; loop until bcd delay complete
;out null, 5 side 0 ; discard the five dummy bits for this pixel
; disable led output (blank) and clear latch pin
out pins, 8 ; turn off BLANK signal and clear row output
out null, 8 ; discard dummy data
jmp y-- pixels
jmp x-- bcd_frame ; loop to next bcd frame
out null, 16 ; discard dummy bytes
out pins, 8 ; output row select
set pins, 0b110 [5] ; latch high, blank high
set pins, 0b000 ; blank low (enable output)
; loop over bcd delay period
out y, 24 ; get bcd delay counter value
bcd_delay:
jmp y-- bcd_delay
set pins 0b100 ; blank high (disable output)
.wrap

Wyświetl plik

@ -276,8 +276,6 @@ namespace pimoroni {
void PicoGraphics::line(Point p1, Point p2) {
// fast horizontal line
if(p1.y == p2.y) {
p1 = p1.clamp(clip);
p2 = p2.clamp(clip);
int32_t start = std::min(p1.x, p2.x);
int32_t end = std::max(p1.x, p2.x);
pixel_span(Point(start, p1.y), end - start);
@ -286,13 +284,11 @@ namespace pimoroni {
// fast vertical line
if(p1.x == p2.x) {
p1 = p1.clamp(clip);
p2 = p2.clamp(clip);
int32_t start = std::min(p1.y, p2.y);
int32_t length = std::max(p1.y, p2.y) - start;
Point dest(p1.x, start);
while(length--) {
set_pixel(dest);
pixel(dest);
dest.y++;
}
return;
@ -314,7 +310,7 @@ namespace pimoroni {
int32_t y = p1.y << 16;
while(s--) {
Point p(x, y >> 16);
if(clip.contains(p)) set_pixel(p);
pixel(p);
y += sy;
x += sx;
}
@ -327,7 +323,7 @@ namespace pimoroni {
int32_t x = p1.x << 16;
while(s--) {
Point p(x >> 16, y);
if(clip.contains(p)) set_pixel(p);
pixel(p);
y += sy;
x += sx;
}