Bladeren bron

Working with rainbow

Emil 3 jaren geleden
commit
d9b58a0a14
8 gewijzigde bestanden met toevoegingen van 499 en 0 verwijderingen
  1. 2 0
      .gitignore
  2. 9 0
      .idea/.gitignore
  3. 16 0
      CMakeLists.txt
  4. 114 0
      generated/ws2812.pio.h
  5. 46 0
      generated/ws2812.py
  6. 62 0
      pico_sdk_import.cmake
  7. 165 0
      ws2812.c
  8. 85 0
      ws2812.pio

+ 2 - 0
.gitignore

@@ -0,0 +1,2 @@
+/build/
+/cmake-build-debug/

+ 9 - 0
.idea/.gitignore

@@ -0,0 +1,9 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# Editor-based HTTP Client requests
+/httpRequests/
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml
+/SpotlightRGBW.iml

+ 16 - 0
CMakeLists.txt

@@ -0,0 +1,16 @@
+cmake_minimum_required(VERSION 3.12)
+
+include(pico_sdk_import.cmake)
+
+project(my_project)
+
+pico_sdk_init()
+
+add_executable(pio_ws2812)
+# generate the header file into the source tree as it is included in the RP2040 datasheet
+pico_generate_pio_header(pio_ws2812 ${CMAKE_CURRENT_LIST_DIR}/ws2812.pio OUTPUT_DIR ${CMAKE_CURRENT_LIST_DIR}/generated)
+
+target_sources(pio_ws2812 PRIVATE ws2812.c)
+
+target_link_libraries(pio_ws2812 PRIVATE pico_stdlib hardware_pio)
+pico_add_extra_outputs(pio_ws2812)

+ 114 - 0
generated/ws2812.pio.h

@@ -0,0 +1,114 @@
+// -------------------------------------------------- //
+// This file is autogenerated by pioasm; do not edit! //
+// -------------------------------------------------- //
+
+#pragma once
+
+#if !PICO_NO_HARDWARE
+#include "hardware/pio.h"
+#endif
+
+// ------ //
+// ws2812 //
+// ------ //
+
+#define ws2812_wrap_target 0
+#define ws2812_wrap 3
+
+#define ws2812_T1 2
+#define ws2812_T2 5
+#define ws2812_T3 3
+
+static const uint16_t ws2812_program_instructions[] = {
+            //     .wrap_target
+    0x6221, //  0: out    x, 1            side 0 [2] 
+    0x1123, //  1: jmp    !x, 3           side 1 [1] 
+    0x1400, //  2: jmp    0               side 1 [4] 
+    0xa442, //  3: nop                    side 0 [4] 
+            //     .wrap
+};
+
+#if !PICO_NO_HARDWARE
+static const struct pio_program ws2812_program = {
+    .instructions = ws2812_program_instructions,
+    .length = 4,
+    .origin = -1,
+};
+
+static inline pio_sm_config ws2812_program_get_default_config(uint offset) {
+    pio_sm_config c = pio_get_default_sm_config();
+    sm_config_set_wrap(&c, offset + ws2812_wrap_target, offset + ws2812_wrap);
+    sm_config_set_sideset(&c, 1, false, false);
+    return c;
+}
+
+#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);
+}
+
+#endif
+
+// --------------- //
+// ws2812_parallel //
+// --------------- //
+
+#define ws2812_parallel_wrap_target 0
+#define ws2812_parallel_wrap 3
+
+#define ws2812_parallel_T1 2
+#define ws2812_parallel_T2 5
+#define ws2812_parallel_T3 3
+
+static const uint16_t ws2812_parallel_program_instructions[] = {
+            //     .wrap_target
+    0x6020, //  0: out    x, 32                      
+    0xa10b, //  1: mov    pins, !null            [1] 
+    0xa401, //  2: mov    pins, x                [4] 
+    0xa103, //  3: mov    pins, null             [1] 
+            //     .wrap
+};
+
+#if !PICO_NO_HARDWARE
+static const struct pio_program ws2812_parallel_program = {
+    .instructions = ws2812_parallel_program_instructions,
+    .length = 4,
+    .origin = -1,
+};
+
+static inline pio_sm_config ws2812_parallel_program_get_default_config(uint offset) {
+    pio_sm_config c = pio_get_default_sm_config();
+    sm_config_set_wrap(&c, offset + ws2812_parallel_wrap_target, offset + ws2812_parallel_wrap);
+    return c;
+}
+
+#include "hardware/clocks.h"
+static inline void ws2812_parallel_program_init(PIO pio, uint sm, uint offset, uint pin_base, uint pin_count, float freq) {
+    for(uint i=pin_base; i<pin_base+pin_count; i++) {
+        pio_gpio_init(pio, i);
+    }
+    pio_sm_set_consecutive_pindirs(pio, sm, pin_base, pin_count, true);
+    pio_sm_config c = ws2812_parallel_program_get_default_config(offset);
+    sm_config_set_out_shift(&c, true, true, 32);
+    sm_config_set_out_pins(&c, pin_base, pin_count);
+    sm_config_set_set_pins(&c, pin_base, pin_count);
+    sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_TX);
+    int cycles_per_bit = ws2812_parallel_T1 + ws2812_parallel_T2 + ws2812_parallel_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);
+}
+
+#endif
+

+ 46 - 0
generated/ws2812.py

@@ -0,0 +1,46 @@
+# -------------------------------------------------- #
+# This file is autogenerated by pioasm; do not edit! #
+# -------------------------------------------------- #
+
+import rp2
+from machine import Pin
+# ------ #
+# ws2812 #
+# ------ #
+
+ws2812_T1 = 2
+ws2812_T2 = 5
+ws2812_T3 = 3
+
+@rp2.asm_pio(sideset_init=pico.PIO.OUT_HIGH, out_init=pico.PIO.OUT_HIGH, out_shiftdir=1)
+def ws2812():
+    wrap_target()
+    label("0")
+    out(x, 1)               .side(0) [2]  # 0
+    jmp(not_x, "3")         .side(1) [1]  # 1
+    jmp("0")                .side(1) [4]  # 2
+    label("3")
+    nop()                   .side(0) [4]  # 3
+    wrap()
+
+
+
+# --------------- #
+# ws2812_parallel #
+# --------------- #
+
+ws2812_parallel_T1 = 2
+ws2812_parallel_T2 = 5
+ws2812_parallel_T3 = 3
+
+@rp2.asm_pio()
+def ws2812_parallel():
+    wrap_target()
+    out(x, 32)                            # 0
+    mov(pins, invert(null))          [1]  # 1
+    mov(pins, x)                     [4]  # 2
+    mov(pins, null)                  [1]  # 3
+    wrap()
+
+
+

+ 62 - 0
pico_sdk_import.cmake

@@ -0,0 +1,62 @@
+# This is a copy of <PICO_SDK_PATH>/external/pico_sdk_import.cmake
+
+# This can be dropped into an external project to help locate this SDK
+# It should be include()ed prior to project()
+
+if (DEFINED ENV{PICO_SDK_PATH} AND (NOT PICO_SDK_PATH))
+    set(PICO_SDK_PATH $ENV{PICO_SDK_PATH})
+    message("Using PICO_SDK_PATH from environment ('${PICO_SDK_PATH}')")
+endif ()
+
+if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT} AND (NOT PICO_SDK_FETCH_FROM_GIT))
+    set(PICO_SDK_FETCH_FROM_GIT $ENV{PICO_SDK_FETCH_FROM_GIT})
+    message("Using PICO_SDK_FETCH_FROM_GIT from environment ('${PICO_SDK_FETCH_FROM_GIT}')")
+endif ()
+
+if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_PATH} AND (NOT PICO_SDK_FETCH_FROM_GIT_PATH))
+    set(PICO_SDK_FETCH_FROM_GIT_PATH $ENV{PICO_SDK_FETCH_FROM_GIT_PATH})
+    message("Using PICO_SDK_FETCH_FROM_GIT_PATH from environment ('${PICO_SDK_FETCH_FROM_GIT_PATH}')")
+endif ()
+
+set(PICO_SDK_PATH "${PICO_SDK_PATH}" CACHE PATH "Path to the PICO SDK")
+set(PICO_SDK_FETCH_FROM_GIT "${PICO_SDK_FETCH_FROM_GIT}" CACHE BOOL "Set to ON to fetch copy of PICO SDK from git if not otherwise locatable")
+set(PICO_SDK_FETCH_FROM_GIT_PATH "${PICO_SDK_FETCH_FROM_GIT_PATH}" CACHE FILEPATH "location to download SDK")
+
+if (NOT PICO_SDK_PATH)
+    if (PICO_SDK_FETCH_FROM_GIT)
+        include(FetchContent)
+        set(FETCHCONTENT_BASE_DIR_SAVE ${FETCHCONTENT_BASE_DIR})
+        if (PICO_SDK_FETCH_FROM_GIT_PATH)
+            get_filename_component(FETCHCONTENT_BASE_DIR "${PICO_SDK_FETCH_FROM_GIT_PATH}" REALPATH BASE_DIR "${CMAKE_SOURCE_DIR}")
+        endif ()
+        FetchContent_Declare(
+                pico_sdk
+                GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk
+                GIT_TAG master
+        )
+        if (NOT pico_sdk)
+            message("Downloading PICO SDK")
+            FetchContent_Populate(pico_sdk)
+            set(PICO_SDK_PATH ${pico_sdk_SOURCE_DIR})
+        endif ()
+        set(FETCHCONTENT_BASE_DIR ${FETCHCONTENT_BASE_DIR_SAVE})
+    else ()
+        message(FATAL_ERROR
+                "PICO SDK location was not specified. Please set PICO_SDK_PATH or set PICO_SDK_FETCH_FROM_GIT to on to fetch from git."
+                )
+    endif ()
+endif ()
+
+get_filename_component(PICO_SDK_PATH "${PICO_SDK_PATH}" REALPATH BASE_DIR "${CMAKE_BINARY_DIR}")
+if (NOT EXISTS ${PICO_SDK_PATH})
+    message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' not found")
+endif ()
+
+set(PICO_SDK_INIT_CMAKE_FILE ${PICO_SDK_PATH}/pico_sdk_init.cmake)
+if (NOT EXISTS ${PICO_SDK_INIT_CMAKE_FILE})
+    message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' does not appear to contain the PICO SDK")
+endif ()
+
+set(PICO_SDK_PATH ${PICO_SDK_PATH} CACHE PATH "Path to the PICO SDK" FORCE)
+
+include(${PICO_SDK_INIT_CMAKE_FILE})

+ 165 - 0
ws2812.c

@@ -0,0 +1,165 @@
+/**
+ * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+
+#include "pico/stdlib.h"
+#include "hardware/pio.h"
+#include "hardware/clocks.h"
+#include "ws2812.pio.h"
+
+#define IS_RGBW true
+#define NUM_PIXELS 1
+
+#ifdef PICO_DEFAULT_WS2812_PIN
+#define WS2812_PIN PICO_DEFAULT_WS2812_PIN
+#else
+// default to pin 2 if the board doesn't have a default WS2812 pin defined
+#define WS2812_PIN 6
+#endif
+
+typedef struct {
+    double r;       // a fraction between 0 and 1
+    double g;       // a fraction between 0 and 1
+    double b;       // a fraction between 0 and 1
+} rgb;
+
+static inline void put_pixel(uint32_t pixel_wgrb) {
+    pio_sm_put_blocking(pio0, 0, pixel_wgrb); //<< 8u);
+}
+
+static inline uint32_t urgb_u32(uint8_t r, uint8_t g, uint8_t b) {
+    return
+            ((uint32_t) (r) << 8) |
+            ((uint32_t) (g) << 16) |
+            (uint32_t) (b);
+}
+
+void pulse(uint8_t r, uint8_t g, uint8_t b, uint8_t w) {
+    for (int i = 0; i < 255; i++) {
+        uint32_t newR = (uint32_t) fmax(fmin(r * i / 255, 255), 0);
+        uint32_t newG = (uint32_t) fmax(fmin(g * i / 255, 255), 0);
+        uint32_t newB = (uint32_t) fmax(fmin(b * i / 255, 255), 0);
+        uint32_t newW = (uint32_t) fmax(fmin(w * i / 255, 255), 0);
+        uint32_t color = (newW << 24) | (newR << 16) | (newG << 8) | newB;
+        put_pixel(color);
+        sleep_ms(20);
+    };
+}
+
+rgb hsv2rgb(double h, double s, double v) {
+    double      hh, p, q, t, ff;
+    long        i;
+    rgb        out;
+
+    if(s <= 0.0) {       // < is bogus, just shuts up warnings
+        out.r = v;
+        out.g = v;
+        out.b = v;
+        return out;
+    }
+    hh = h;
+    if(hh >= 360.0) hh = 0.0;
+    hh /= 60.0;
+    i = (long)hh;
+    ff = hh - i;
+    p = v * (1.0 - s);
+    q = v * (1.0 - (s * ff));
+    t = v * (1.0 - (s * (1.0 - ff)));
+
+    switch(i) {
+        case 0:
+            out.r = v;
+            out.g = t;
+            out.b = p;
+            break;
+        case 1:
+            out.r = q;
+            out.g = v;
+            out.b = p;
+            break;
+        case 2:
+            out.r = p;
+            out.g = v;
+            out.b = t;
+            break;
+
+        case 3:
+            out.r = p;
+            out.g = q;
+            out.b = v;
+            break;
+        case 4:
+            out.r = t;
+            out.g = p;
+            out.b = v;
+            break;
+        case 5:
+        default:
+            out.r = v;
+            out.g = p;
+            out.b = q;
+            break;
+    }
+    return out;
+}
+
+int main() { //BGRW B: Lowest bits, W: Highest bits
+    stdio_init_all();
+
+    // todo get free sm
+    PIO pio = pio0;
+    int sm = 0;
+    uint offset = pio_add_program(pio, &ws2812_program);
+
+    ws2812_program_init(pio, sm, offset, WS2812_PIN, 800000, IS_RGBW);
+
+    put_pixel(0b11111111111111111111111111111111);
+    sleep_ms(1000);
+    put_pixel(0b00000000000000000000000000000000);
+    sleep_ms(1000);
+
+    while (1) {
+        /*uint32_t color = (255 << 24) | (255 << 16) | (255 << 8) | 255;
+        put_pixel(color);
+        sleep_ms(1000);
+        color = (0 << 24) | (0 << 16) | (0 << 8) | 255;
+        put_pixel(color);
+        sleep_ms(1000);
+        color = (0 << 24) | (0 << 16) | (255 << 8) | 255;
+        put_pixel(color);
+        sleep_ms(1000);
+        color = (0 << 24) | (255 << 16) | (255 << 8) | 255;
+        put_pixel(color);
+        sleep_ms(1000);*/
+        /*pulse(255, 0, 0, 0);
+        sleep_ms(10);
+        pulse(0, 255, 0, 0);
+        sleep_ms(10);
+        pulse(0, 0, 255, 0);
+        sleep_ms(10);
+        pulse(0, 0, 0, 255);
+        sleep_ms(10);
+        pulse(0, 0, 255, 255);
+        sleep_ms(10);
+        pulse(0, 255, 255, 255);
+        sleep_ms(10);
+        pulse(255, 255, 255, 255);
+        sleep_ms(10);*/
+        for (int i = 0; i < 360; i++) {
+            rgb newColor = hsv2rgb(i, 1, 1);
+            uint32_t color =
+                    ((uint32_t)(fmin(newColor.r * 255, 255)) << 16) | ((uint32_t)(fmin(newColor.g * 255, 255)) << 8) |
+                    (uint32_t)(fmin(newColor.b * 255, 255));
+            put_pixel(color);
+            sleep_ms(20);
+        }
+        /*put_pixel(0b11111111111111111111111111111111);
+        sleep_ms(1000);*/
+    }
+}

+ 85 - 0
ws2812.pio

@@ -0,0 +1,85 @@
+;
+; 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);
+}
+%}
+
+.program ws2812_parallel
+
+.define public T1 2
+.define public T2 5
+.define public T3 3
+
+.wrap_target
+    out x, 32
+    mov pins, !null [T1-1]
+    mov pins, x     [T2-1]
+    mov pins, null  [T3-2]
+.wrap
+
+% c-sdk {
+#include "hardware/clocks.h"
+
+static inline void ws2812_parallel_program_init(PIO pio, uint sm, uint offset, uint pin_base, uint pin_count, float freq) {
+    for(uint i=pin_base; i<pin_base+pin_count; i++) {
+        pio_gpio_init(pio, i);
+    }
+    pio_sm_set_consecutive_pindirs(pio, sm, pin_base, pin_count, true);
+
+    pio_sm_config c = ws2812_parallel_program_get_default_config(offset);
+    sm_config_set_out_shift(&c, true, true, 32);
+    sm_config_set_out_pins(&c, pin_base, pin_count);
+    sm_config_set_set_pins(&c, pin_base, pin_count);
+    sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_TX);
+
+    int cycles_per_bit = ws2812_parallel_T1 + ws2812_parallel_T2 + ws2812_parallel_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);
+}
+%}