diff --git a/.gitignore b/.gitignore index 5a8d6a8..e464c60 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,2 @@ /build - diff --git a/CMakeLists.txt b/CMakeLists.txt index 39b3bbe..570ca8d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,17 +4,23 @@ cmake_minimum_required(VERSION 3.13) # note: this must happen before project() include(libs/pico-sdk/pico_sdk_init.cmake) -project(my_project) +project(stofzuiger CXX C ASM) + +set(PICO_CXX_ENABLE_EXCEPTIONS 1) +set(PICO_CXX_ENABLE_RTTI 1) # initialize the Raspberry Pi Pico SDK pico_sdk_init() -add_executable(my_project - src/main.c -) +add_executable(stofzuiger src/main.c) -# Add pico_stdlib library which aggregates commonly used features -target_link_libraries(my_project pico_stdlib) +# pico_generate_pio_header(stofzuiger ${CMAKE_CURRENT_LIST_DIR}/src/ws2812.pio) +pico_generate_pio_header(stofzuiger ${CMAKE_CURRENT_LIST_DIR}/src/ws2812.pio OUTPUT_DIR ${CMAKE_CURRENT_LIST_DIR}/src/generated) + +target_link_libraries(stofzuiger pico_stdlib hardware_pio) + +pico_enable_stdio_uart(stofzuiger 0) +pico_enable_stdio_usb(stofzuiger 1) # create map/bin/hex/uf2 file in addition to ELF. -pico_add_extra_outputs(my_project) +pico_add_extra_outputs(stofzuiger) diff --git a/libs/pico-sdk b/libs/pico-sdk new file mode 160000 index 0000000..95ea6ac --- /dev/null +++ b/libs/pico-sdk @@ -0,0 +1 @@ +Subproject commit 95ea6acad131124694cda1c162c52cd30e0aece0 diff --git a/src/generated/.gitignore b/src/generated/.gitignore new file mode 100644 index 0000000..d6b7ef3 --- /dev/null +++ b/src/generated/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/src/main.c b/src/main.c index 411626b..bb695ba 100644 --- a/src/main.c +++ b/src/main.c @@ -1,36 +1,50 @@ #include -#include "pico/stdlib.h" +#include +#include +#include -// pin rgb led on Seeed XIAO RP2040 -#define PIN_RGB_R 17 -#define PIN_RGB_G 16 -#define PIN_RGB_B 25 +#include +#include +#include +#include "generated/ws2812.pio.h" -int main() { - setup_default_uart(); - printf("Hello, world!\n"); +#define IS_RGBW false +#define NUM_PIXELS 1 +#define WS2812_PIN 16 - gpio_init(PIN_RGB_R); - gpio_set_dir(PIN_RGB_R, GPIO_OUT); - gpio_init(PIN_RGB_G); - gpio_set_dir(PIN_RGB_G, GPIO_OUT); - gpio_init(PIN_RGB_B); - gpio_set_dir(PIN_RGB_B, GPIO_OUT); - while (true) - { - gpio_put(PIN_RGB_G, 1); - sleep_ms(250); - gpio_put(PIN_RGB_R, 0); - sleep_ms(250); - gpio_put(PIN_RGB_B, 1); - sleep_ms(250); - gpio_put(PIN_RGB_G, 0); - sleep_ms(250); - gpio_put(PIN_RGB_R, 1); - sleep_ms(250); - gpio_put(PIN_RGB_B, 0); - sleep_ms(250); - } - return 0; +static inline void put_pixel(PIO pio, uint sm, uint32_t pixel_grb) { + pio_sm_put_blocking(pio, sm, pixel_grb << 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); +} + +int main() { + //set_sys_clock_48(); + stdio_init_all(); + printf("WS2812 test %d\n", WS2812_PIN); + + // todo get free sm + PIO pio; + uint sm; + uint offset; + + // This will find a free pio and state machine for our program and load it for us + // We use pio_claim_free_sm_and_add_program_for_gpio_range (for_gpio_range variant) + // so we will get a PIO instance suitable for addressing gpios >= 32 if needed and supported by the hardware + bool success = pio_claim_free_sm_and_add_program_for_gpio_range(&ws2812_program, &pio, &sm, &offset, WS2812_PIN, 1, false); + if (success == false) + { + printf("Faild to claim PIO or SM"); + return -1; + } + ws2812_program_init(pio, sm, offset, WS2812_PIN, 800000, false); + + put_pixel(pio, sm, urgb_u32(50, 50, 50)); + + // This will free resources and unload our program + pio_remove_program_and_unclaim_sm(&ws2812_program, pio, sm, offset); + + return 0; +} \ No newline at end of file diff --git a/src/ws2812.pio b/src/ws2812.pio new file mode 100644 index 0000000..a294f37 --- /dev/null +++ b/src/ws2812.pio @@ -0,0 +1,53 @@ +; +; Copyright (c) 2020 Raspberry Pi (Trading) Ltd. +; +; SPDX-License-Identifier: BSD-3-Clause +; +.pio_version 0 // only requires PIO version 0 + +.program ws2812 +.side_set 1 + +; The following constants are selected for broad compatibility with WS2812, +; WS2812B, and SK6812 LEDs. Other constants may support higher bandwidths for +; specific LEDs, such as (7,10,8) for WS2812B LEDs. + +.define public T1 3 +.define public T2 3 +.define public T3 4 + +.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); +} +%}