Skip to content

Support neopixel primitives on Zephyr (rpi_pico) #305

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 41 additions & 1 deletion platforms/Zephyr/boards/rpi_pico.overlay
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
#include "../app.overlay"
#include <zephyr/dt-bindings/led/led.h>

/ {
aliases {
led-strip = &ws2812;
};

zephyr,user {
warduino-gpios =
<&gpio0 0 0>,
Expand Down Expand Up @@ -34,4 +39,39 @@
<&gpio0 28 0>,
<&gpio0 29 0>;
};
};
};

&pio1 {
status = "okay";

/*
* Need to put this on PIO1 as having this on PIO0 causes the GPIO hog to
* not work.
*/
pio-ws2812 {
compatible = "worldsemi,ws2812-rpi_pico-pio";
status = "okay";
pinctrl-0 = <&ws2812_pio1_default>;
pinctrl-names = "default";
bit-waveform = <3>, <3>, <4>;

ws2812: ws2812 {
status = "okay";
gpios = <&gpio0 12 GPIO_ACTIVE_HIGH>;
chain-length = <64>;
color-mapping = <LED_COLOR_ID_GREEN
LED_COLOR_ID_RED
LED_COLOR_ID_BLUE>;
reset-delay = <280>;
frequency = <800000>;
};
};
};

&pinctrl {
ws2812_pio1_default: ws2812_pio1_default {
ws2812 {
pinmux = <PIO1_P12>;
};
};
};
4 changes: 4 additions & 0 deletions platforms/Zephyr/prj.conf
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,7 @@ CONFIG_CONSOLE_PUTCHAR_BUFSIZE=4096

CONFIG_POSIX_API=y
CONFIG_MAIN_STACK_SIZE=8192

CONFIG_LOG=y
CONFIG_LED_STRIP=y
CONFIG_LED_STRIP_LOG_LEVEL_DBG=n
112 changes: 92 additions & 20 deletions src/Primitives/zephyr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include <zephyr/drivers/uart.h>
#include <zephyr/dt-bindings/gpio/gpio.h>
#include <zephyr/kernel.h>
#include <zephyr/drivers/led_strip.h>

#include <chrono>
#include <cmath>
Expand All @@ -32,7 +33,7 @@
#include "../Utils/util.h"
#include "primitives.h"

#define ALL_PRIMITIVES 5
#define ALL_PRIMITIVES 7

// Global index for installing primitives
int prim_index = 0;
Expand Down Expand Up @@ -262,6 +263,86 @@ def_prim(print_int, oneToNoneU32) {
return true;
}

static const device *const strip = DEVICE_DT_GET(DT_ALIAS(led_strip));
const size_t strip_length = 64;//led_strip_length(device);
led_rgb pixels[strip_length] = {0};
led_rgb pixels_shown[strip_length] = {0};

def_prim(show_pixels, NoneToNoneU32) {
memcpy(pixels_shown, pixels, strip_length * sizeof(led_rgb));
int rc = led_strip_update_rgb(strip, pixels_shown, strip_length);
if (rc) {
printf("couldn't update strip: %d", rc);
}
return true;
}

def_prim_serialize(show_pixels) {
for (int i = 0; i < strip_length; i++) {
auto *state = new IOStateElement();
state->key = "n" + std::to_string(i);
state->output = true;
state->value = pixels_shown[i].r << 16 | pixels_shown[i].g << 8 | pixels_shown[i].b;
external_state.push_back(state);
}
}

def_prim_reverse(show_pixels) {
for (IOStateElement state : external_state) {
if (!state.output) {
continue;
}

if (state.key[0] == 'n') {
int index = stoi(state.key.substr(1));
pixels_shown[index].r = ((uint32_t) state.value >> 16) & 0xff;
pixels_shown[index].g = ((uint32_t) state.value >> 8) & 0xff;
pixels_shown[index].b = state.value & 0xff;
int rc = led_strip_update_rgb(strip, pixels_shown, strip_length);
if (rc) {
printf("couldn't update strip: %d", rc);
}
}
}
}

def_prim(set_pixel_color, fourToOneU32) {
uint8_t blue = arg0.uint32;
uint8_t green = arg1.uint32;
uint8_t red = arg2.uint32;
uint8_t index = arg3.uint32;

led_rgb color = {.r = red, .g = green, .b= blue};
memcpy(&pixels[index], &color, sizeof(struct led_rgb));
pop_args(4);
return true;
}

def_prim_serialize(set_pixel_color) {
for (int i = 0; i < strip_length; i++) {
auto *state = new IOStateElement();
state->key = "b" + std::to_string(i);
state->output = true;
state->value = pixels[i].r << 16 | pixels[i].g << 8 | pixels[i].b;
external_state.push_back(state);
}
}

def_prim_reverse(set_pixel_color) {
for (IOStateElement state : external_state) {
if (!state.output) {
continue;
}

if (state.key[0] == 'b') {
int index = stoi(state.key.substr(1));
pixels[index].r = ((uint32_t) state.value >> 16) & 0xff;
pixels[index].g = ((uint32_t) state.value >> 8) & 0xff;
pixels[index].b = state.value & 0xff;
}
}
}

//------------------------------------------------------
// Installing all the primitives
//------------------------------------------------------
Expand All @@ -272,6 +353,10 @@ void install_primitives() {
install_primitive(chip_digital_write);
install_primitive(chip_digital_read);
install_primitive(print_int);
install_primitive(set_pixel_color);
install_primitive_reverse(set_pixel_color);
install_primitive(show_pixels);
install_primitive_reverse(show_pixels);
}

//------------------------------------------------------
Expand Down Expand Up @@ -317,25 +402,12 @@ bool resolve_external_memory(char *symbol, Memory **val) {
//------------------------------------------------------
void restore_external_state(Module *m,
const std::vector<IOStateElement> &external_state) {
uint8_t opcode = *m->pc_ptr;
// TODO: Maybe primitives can also be called using the other call
// instructions such as call_indirect
// maybe there should just be a function that checks if a certain function
// is being called that handles all these cases?
if (opcode == 0x10) { // call opcode
uint8_t *pc_copy = m->pc_ptr + 1;
uint32_t fidx = read_LEB_32(&pc_copy);
if (fidx < m->import_count) {
for (auto &primitive : primitives) {
if (!strcmp(primitive.name, m->functions[fidx].import_field)) {
if (primitive.f_reverse) {
debug("Reversing action for primitive %s\n",
primitive.name);
primitive.f_reverse(m, external_state);
}
return;
}
}
for (int i = 0; i < ALL_PRIMITIVES; i++) {
auto primitive = primitives[i];
if (primitive.f_reverse) {
debug("Reversing action for primitive %s\n",
primitive.name);
primitive.f_reverse(m, external_state);
}
}
}
Expand Down
Loading