Skip to content
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

pico: add "neopixel" led support (WS2812) #841

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
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
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ bld/
build/
build.stm32/
build.mingw/
cmake-build-debug/
cmake-build-*/
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not a comment on the actual change, but I've just noticed that the previous three lines are duplicated with line 340/341... (except that one has a wildcard)

[Bb]in/
[Oo]bj/
[Ll]og/
Expand Down
1 change: 1 addition & 0 deletions 32blit-pico/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ pico_sdk_init()
# generate PIO headers (has to be after SDK init)
pico_generate_pio_header(BlitHalPico ${CMAKE_CURRENT_LIST_DIR}/st7789.pio)
pico_generate_pio_header(BlitHalPico ${CMAKE_CURRENT_LIST_DIR}/spi.pio)
pico_generate_pio_header(BlitHalPico ${CMAKE_CURRENT_LIST_DIR}/ws2812.pio)

# include picovision drivers
if(BLIT_DISPLAY_DRIVER STREQUAL "picovision")
Expand Down
32 changes: 32 additions & 0 deletions 32blit-pico/led.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,24 @@
#if defined(LED_R_PIN) && defined(LED_G_PIN) && defined(LED_B_PIN)
static const int led_pins[]{LED_R_PIN, LED_G_PIN, LED_B_PIN};
#define HAVE_LED
#elif defined(LED_WS2812_PIN)
#include "hardware/pio.h"
#include "ws2812.pio.h"

static uint32_t last_color = 0;
static int pio_sm = -1;

static void put_pixel(uint8_t r, uint8_t g, uint8_t b, uint8_t a) {
if(pio_sm < 0) return;
uint32_t color =
(((uint32_t)((r * a) >> 8) << 8)
| ((uint32_t)((g * a) >> 8) << 16)
| (uint32_t)((b * a) >> 8)) << 8u;
Cpasjuste marked this conversation as resolved.
Show resolved Hide resolved
if(color != last_color) {
pio_sm_put_blocking(pio0, 0, color);
last_color = color;
}
}
#endif

void init_led() {
Expand All @@ -31,6 +49,18 @@ void init_led() {
bi_decl(bi_1pin_with_name(led_pins[0], "Red LED"));
bi_decl(bi_1pin_with_name(led_pins[1], "Green LED"));
bi_decl(bi_1pin_with_name(led_pins[2], "Blue LED"));
#elif defined(LED_WS2812_PIN)
PIO pio = pio0;
uint pio_offset = pio_add_program(pio, &ws2812_program);
pio_sm = pio_claim_unused_sm(pio, false);
if(pio_sm > -1) {
ws2812_program_init(pio, pio_sm, pio_offset, LED_WS2812_PIN, 800000, true);
pio_sm_put_blocking(pio, 0, 0);
} else {
printf("LED_WS2812: could not find a free pio sm\r\n");
}

bi_decl(bi_1pin_with_name(LED_WS2812_PIN, "NeoPixel RGB LED (WS2812)"));
#endif
}

Expand All @@ -45,5 +75,7 @@ void update_led() {
pwm_set_gpio_level(led_pins[1], value);
value = (uint16_t)(std::pow((float)(api.LED.b) / 255.0f, gamma) * 65535.0f + 0.5f);
pwm_set_gpio_level(led_pins[2], value);
#elif defined(LED_WS2812_PIN)
put_pixel(api.LED.r, api.LED.g, api.LED.b, api.LED.a);
#endif
}
48 changes: 48 additions & 0 deletions 32blit-pico/ws2812.pio
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
;
; Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
;
; SPDX-License-Identifier: BSD-3-Clause
;

.program ws2812
.side_set 1

.define public T1 2
.define public T2 5
.define public T3 3

.lang_opt python sideset_init = pico.PIO.OUT_HIGH
.lang_opt python out_init = pico.PIO.OUT_HIGH
.lang_opt python out_shiftdir = 1

.wrap_target
bitloop:
out x, 1 side 0 [T3 - 1] ; Side-set still takes place when instruction stalls
jmp !x do_zero side 1 [T1 - 1] ; Branch on the bit we shifted out. Positive pulse
do_one:
jmp bitloop side 1 [T2 - 1] ; Continue driving high, for a long pulse
do_zero:
nop side 0 [T2 - 1] ; Or drive low, for a short pulse
.wrap

% c-sdk {
#include "hardware/clocks.h"

static inline void ws2812_program_init(PIO pio, uint sm, uint offset, uint pin, float freq, bool rgbw) {

pio_gpio_init(pio, pin);
pio_sm_set_consecutive_pindirs(pio, sm, pin, 1, true);

pio_sm_config c = ws2812_program_get_default_config(offset);
sm_config_set_sideset_pins(&c, pin);
sm_config_set_out_shift(&c, false, true, rgbw ? 32 : 24);
sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_TX);

int cycles_per_bit = ws2812_T1 + ws2812_T2 + ws2812_T3;
float div = clock_get_hz(clk_sys) / (freq * cycles_per_bit);
sm_config_set_clkdiv(&c, div);

pio_sm_init(pio, sm, offset, &c);
pio_sm_set_enabled(pio, sm, true);
}
%}
Loading