commit 5c2cb697aa8d03eed27b45f8dc67957c45a3d722
parent 12a423434352af137bda357001ac824aa23fdf77
Author: Louis Burda <quent.burda@gmail.com>
Date: Sun, 20 Nov 2022 01:35:41 +0100
Onboard neopixel led support
Diffstat:
9 files changed, 312 insertions(+), 29 deletions(-)
diff --git a/.gitignore b/.gitignore
@@ -1 +1,2 @@
.build
+.cache
diff --git a/CMakeLists.txt b/CMakeLists.txt
@@ -2,26 +2,31 @@ cmake_minimum_required(VERSION 3.5)
include(${CMAKE_CURRENT_SOURCE_DIR}/lib/tinyusb/hw/bsp/family_support.cmake)
-# gets PROJECT name for the example (e.g. <BOARD>-<DIR_NAME>)
family_get_project_name(PROJECT ${CMAKE_CURRENT_LIST_DIR})
project(${PROJECT})
-# Checks this example is valid for the family and initializes the project
family_initialize_project(${PROJECT} ${CMAKE_CURRENT_LIST_DIR})
add_executable(${PROJECT})
-# Example source
target_sources(${PROJECT} PUBLIC
- ${CMAKE_CURRENT_SOURCE_DIR}/src/main.c
- ${CMAKE_CURRENT_SOURCE_DIR}/src/usb_descriptors.c
- )
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/main.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/neopix.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/usb_descriptors.c
+)
-# Example include
target_include_directories(${PROJECT} PUBLIC
- ${CMAKE_CURRENT_SOURCE_DIR}/src
- )
+ ${CMAKE_CURRENT_SOURCE_DIR}/src
+ ${PICO_SDK_PATH}/src/rp2_common/hardware_gpio/include
+ ${PICO_SDK_PATH}/src/rp2_common/hardware_pio/include
+)
+
+target_link_libraries(${PROJECT} PRIVATE
+ pico_stdlib
+ hardware_pio
+ hardware_gpio
+)
# Configure compilation flags and libraries for the example... see the corresponding function
# in hw/bsp/FAMILY/family.cmake for details.
diff --git a/Makefile b/Makefile
@@ -16,7 +16,7 @@ lib/picosdk:
.build:
mkdir $@
-upload:
+flash:
picotool load .build/sxkbd.uf2
.PHONY: all clean cmake upload
diff --git a/compile_commands.json b/compile_commands.json
@@ -0,0 +1,128 @@
+[
+ {
+ "arguments": [
+ "/usr/bin/arm-none-eabi-gcc",
+ "-DCFG_TUSB_MCU=OPT_MCU_RP2040",
+ "-DCFG_TUSB_OS=OPT_OS_PICO",
+ "-DLIB_PICO_BIT_OPS=1",
+ "-DLIB_PICO_BIT_OPS_PICO=1",
+ "-DLIB_PICO_BOOTSEL_VIA_DOUBLE_RESET=1",
+ "-DLIB_PICO_DIVIDER=1",
+ "-DLIB_PICO_DIVIDER_HARDWARE=1",
+ "-DLIB_PICO_DOUBLE=1",
+ "-DLIB_PICO_DOUBLE_PICO=1",
+ "-DLIB_PICO_FIX_RP2040_USB_DEVICE_ENUMERATION=1",
+ "-DLIB_PICO_FLOAT=1",
+ "-DLIB_PICO_FLOAT_PICO=1",
+ "-DLIB_PICO_INT64_OPS=1",
+ "-DLIB_PICO_INT64_OPS_PICO=1",
+ "-DLIB_PICO_MALLOC=1",
+ "-DLIB_PICO_MEM_OPS=1",
+ "-DLIB_PICO_MEM_OPS_PICO=1",
+ "-DLIB_PICO_PLATFORM=1",
+ "-DLIB_PICO_PRINTF=1",
+ "-DLIB_PICO_PRINTF_PICO=1",
+ "-DLIB_PICO_RUNTIME=1",
+ "-DLIB_PICO_STANDARD_LINK=1",
+ "-DLIB_PICO_STDIO=1",
+ "-DLIB_PICO_STDIO_UART=1",
+ "-DLIB_PICO_STDLIB=1",
+ "-DLIB_PICO_SYNC=1",
+ "-DLIB_PICO_SYNC_CORE=1",
+ "-DLIB_PICO_SYNC_CRITICAL_SECTION=1",
+ "-DLIB_PICO_SYNC_MUTEX=1",
+ "-DLIB_PICO_SYNC_SEM=1",
+ "-DLIB_PICO_TIME=1",
+ "-DLIB_PICO_UTIL=1",
+ "-DLIB_TINYUSB_BOARD=1",
+ "-DLIB_TINYUSB_DEVICE=1",
+ "-DPICO_BOARD=\"pico\"",
+ "-DPICO_BUILD=1",
+ "-DPICO_CMAKE_BUILD_TYPE=\"Release\"",
+ "-DPICO_COPY_TO_RAM=0",
+ "-DPICO_CXX_ENABLE_EXCEPTIONS=0",
+ "-DPICO_NO_FLASH=0",
+ "-DPICO_NO_HARDWARE=0",
+ "-DPICO_ON_DEVICE=1",
+ "-DPICO_RP2040_USB_DEVICE_ENUMERATION_FIX=1",
+ "-DPICO_TARGET_NAME=\"sxkbd\"",
+ "-DPICO_USE_BLOCKED_RAM=0",
+ "-I/snx/dev/sxkbd/src",
+ "-I/usr/share/pico-sdk/src/common/pico_stdlib/include",
+ "-I/usr/share/pico-sdk/src/rp2_common/hardware_gpio/include",
+ "-I/usr/share/pico-sdk/src/common/pico_base/include",
+ "-I/snx/dev/sxkbd/.build/generated/pico_base",
+ "-I/usr/share/pico-sdk/src/boards/include",
+ "-I/usr/share/pico-sdk/src/rp2_common/pico_platform/include",
+ "-I/usr/share/pico-sdk/src/rp2040/hardware_regs/include",
+ "-I/usr/share/pico-sdk/src/rp2_common/hardware_base/include",
+ "-I/usr/share/pico-sdk/src/rp2040/hardware_structs/include",
+ "-I/usr/share/pico-sdk/src/rp2_common/hardware_claim/include",
+ "-I/usr/share/pico-sdk/src/rp2_common/hardware_sync/include",
+ "-I/usr/share/pico-sdk/src/rp2_common/hardware_irq/include",
+ "-I/usr/share/pico-sdk/src/common/pico_sync/include",
+ "-I/usr/share/pico-sdk/src/common/pico_time/include",
+ "-I/usr/share/pico-sdk/src/rp2_common/hardware_timer/include",
+ "-I/usr/share/pico-sdk/src/common/pico_util/include",
+ "-I/usr/share/pico-sdk/src/rp2_common/hardware_uart/include",
+ "-I/usr/share/pico-sdk/src/rp2_common/hardware_divider/include",
+ "-I/usr/share/pico-sdk/src/rp2_common/pico_runtime/include",
+ "-I/usr/share/pico-sdk/src/rp2_common/hardware_clocks/include",
+ "-I/usr/share/pico-sdk/src/rp2_common/hardware_resets/include",
+ "-I/usr/share/pico-sdk/src/rp2_common/hardware_pll/include",
+ "-I/usr/share/pico-sdk/src/rp2_common/hardware_vreg/include",
+ "-I/usr/share/pico-sdk/src/rp2_common/hardware_watchdog/include",
+ "-I/usr/share/pico-sdk/src/rp2_common/hardware_xosc/include",
+ "-I/usr/share/pico-sdk/src/rp2_common/pico_printf/include",
+ "-I/usr/share/pico-sdk/src/rp2_common/pico_bootrom/include",
+ "-I/usr/share/pico-sdk/src/common/pico_bit_ops/include",
+ "-I/usr/share/pico-sdk/src/common/pico_divider/include",
+ "-I/usr/share/pico-sdk/src/rp2_common/pico_double/include",
+ "-I/usr/share/pico-sdk/src/rp2_common/pico_int64_ops/include",
+ "-I/usr/share/pico-sdk/src/rp2_common/pico_float/include",
+ "-I/usr/share/pico-sdk/src/rp2_common/pico_malloc/include",
+ "-I/usr/share/pico-sdk/src/rp2_common/boot_stage2/include",
+ "-I/usr/share/pico-sdk/src/common/pico_binary_info/include",
+ "-I/usr/share/pico-sdk/src/rp2_common/pico_stdio/include",
+ "-I/usr/share/pico-sdk/src/rp2_common/pico_stdio_uart/include",
+ "-I/snx/dev/sxkbd/lib/tinyusb/src",
+ "-I/snx/dev/sxkbd/lib/tinyusb/src/common",
+ "-I/snx/dev/sxkbd/lib/tinyusb/hw",
+ "-I/usr/share/pico-sdk/src/rp2_common/pico_fix/rp2040_usb_device_enumeration/include",
+ "-mcpu=cortex-m0plus",
+ "-mthumb",
+ "-O3",
+ "-DNDEBUG",
+ "-Wall",
+ "-Wextra",
+ "-Werror",
+ "-Wfatal-errors",
+ "-Wdouble-promotion",
+ "-Wfloat-equal",
+ "-Wshadow",
+ "-Wwrite-strings",
+ "-Wsign-compare",
+ "-Wmissing-format-attribute",
+ "-Wunreachable-code",
+ "-Wcast-align",
+ "-Wcast-qual",
+ "-Wnull-dereference",
+ "-Wuninitialized",
+ "-Wunused",
+ "-Wredundant-decls",
+ "-Wconversion",
+ "-Wcast-function-type",
+ "-Wstrict-overflow",
+ "-Wno-strict-aliasing",
+ "-ffunction-sections",
+ "-fdata-sections",
+ "-c",
+ "-o",
+ "CMakeFiles/sxkbd.dir/src/main.c.obj",
+ "/snx/dev/sxkbd/src/main.c"
+ ],
+ "directory": "/snx/dev/sxkbd/.build",
+ "file": "/snx/dev/sxkbd/src/main.c",
+ "output": "/snx/dev/sxkbd/.build/CMakeFiles/sxkbd.dir/src/main.c.obj"
+ }
+]
diff --git a/src/main.c b/src/main.c
@@ -1,12 +1,14 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
+#include <sys/types.h>
#include "bsp/board.h"
#include "tusb.h"
+#include "neopix.h"
/* Blink pattern
- * - 250 ms : device not mounted
+ * - 250 ms : device not mounted
* - 1000 ms : device mounted
* - 2500 ms : device is suspended
*/
@@ -18,19 +20,20 @@ enum {
static uint32_t blink_interval_ms = BLINK_NOT_MOUNTED;
+static struct neopix onboard_led;
+
void led_blinking_task(void);
-/*------------- MAIN -------------*/
int main(void)
{
board_init();
- // init device stack on configured roothub port
+ neopix_init(&onboard_led, pio0, 0, 25);
+
tud_init(BOARD_TUD_RHPORT);
- while (1)
- {
- tud_task(); // tinyusb device task
+ while (1) {
+ tud_task();
led_blinking_task();
}
@@ -78,7 +81,6 @@ void tud_resume_cb(void)
uint16_t tud_hid_get_report_cb(uint8_t itf, uint8_t report_id,
hid_report_type_t report_type, uint8_t* buffer, uint16_t reqlen)
{
- // TODO not Implemented
(void) itf;
(void) report_id;
(void) report_type;
@@ -93,27 +95,24 @@ uint16_t tud_hid_get_report_cb(uint8_t itf, uint8_t report_id,
void tud_hid_set_report_cb(uint8_t itf, uint8_t report_id,
hid_report_type_t report_type, uint8_t const* buffer, uint16_t bufsize)
{
- // This example doesn't use multiple report and report ID
(void) itf;
(void) report_id;
(void) report_type;
- // echo back anything we received from host
tud_hid_report(0, buffer, bufsize);
}
-//--------------------------------------------------------------------+
-// BLINKING TASK
-//--------------------------------------------------------------------+
-void led_blinking_task(void)
+void
+led_blinking_task(void)
{
static uint32_t start_ms = 0;
- static bool led_state = false;
+ static bool state = false;
- // Blink every interval ms
- if ( board_millis() - start_ms < blink_interval_ms) return; // not enough time
- start_ms += blink_interval_ms;
+ if (board_millis() - start_ms < blink_interval_ms)
+ return;
+
+ neopix_put(&onboard_led, neopix_u32rgb(255 * state, 0, 0));
- board_led_write(led_state);
- led_state = 1 - led_state; // toggle
+ start_ms += blink_interval_ms;
+ state ^= true;
}
diff --git a/src/neopix.c b/src/neopix.c
@@ -0,0 +1,22 @@
+#include "hardware/pio.h"
+
+#include "neopix.h"
+#include "ws2812.pio.h"
+
+void
+neopix_init(struct neopix *pix, PIO pio, uint sm, uint pin)
+{
+ uint offset;
+
+ pix->sm = sm;
+ pix->pio = pio;
+ pix->pin = pin;
+ offset = pio_add_program(pix->pio, &ws2812_program);
+ ws2812_program_init(pix->pio, pix->sm, offset,
+ pix->pin, 800000, false);
+}
+
+void
+neopix_put(struct neopix *pix, uint32_t rgb) {
+ pio_sm_put_blocking(pix->pio, pix->sm, rgb << 8u);
+}
diff --git a/src/neopix.h b/src/neopix.h
@@ -0,0 +1,22 @@
+#include "hardware/pio.h"
+#include "hardware/gpio.h"
+
+struct neopix {
+ PIO pio;
+ uint sm;
+ uint pin;
+};
+
+void neopix_init(struct neopix *pix, PIO pio, uint sm, uint pin);
+void neopix_put(struct neopix *pix, uint32_t rgb);
+
+inline uint32_t
+neopix_u32rgb(uint8_t r, uint8_t g, uint8_t b) {
+ uint32_t rgb;
+
+ rgb = ((uint32_t) r) << 8;
+ rgb |= ((uint32_t) g) << 16;
+ rgb |= ((uint32_t) b) << 0;
+
+ return rgb;
+}
diff --git a/src/ws2812.pio b/src/ws2812.pio
@@ -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);
+}
+%}
diff --git a/src/ws2812.pio.h b/src/ws2812.pio.h
@@ -0,0 +1,58 @@
+// -------------------------------------------------- //
+// This file is autogenerated by pioasm; do not edit! //
+// -------------------------------------------------- //
+
+#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 = ((float) clock_get_hz(clk_sys)) / (freq * (float) cycles_per_bit);
+ sm_config_set_clkdiv(&c, div);
+ pio_sm_init(pio, sm, offset, &c);
+ pio_sm_set_enabled(pio, sm, true);
+}
+
+#endif