aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorLouis Burda <quent.burda@gmail.com>2022-11-20 01:35:41 +0100
committerLouis Burda <quent.burda@gmail.com>2022-11-20 01:35:53 +0100
commit5c2cb697aa8d03eed27b45f8dc67957c45a3d722 (patch)
tree056e08b0e4d4aa0d6f65f84043beb151d6c6245f /src
parent12a423434352af137bda357001ac824aa23fdf77 (diff)
downloadsxkbd-5c2cb697aa8d03eed27b45f8dc67957c45a3d722.tar.gz
sxkbd-5c2cb697aa8d03eed27b45f8dc67957c45a3d722.zip
Onboard neopixel led support
Diffstat (limited to 'src')
-rw-r--r--src/main.c37
-rw-r--r--src/neopix.c22
-rw-r--r--src/neopix.h22
-rw-r--r--src/ws2812.pio48
-rw-r--r--src/ws2812.pio.h58
5 files changed, 168 insertions, 19 deletions
diff --git a/src/main.c b/src/main.c
index 25f6204..d73c530 100644
--- 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
new file mode 100644
index 0000000..ddc78a3
--- /dev/null
+++ 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
new file mode 100644
index 0000000..8b01038
--- /dev/null
+++ 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
new file mode 100644
index 0000000..ae19a6b
--- /dev/null
+++ 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
new file mode 100644
index 0000000..e95f7ea
--- /dev/null
+++ 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