sxkbd

Firmware for RP2040-based corne split keyboard
git clone https://git.sinitax.com/sinitax/sxkbd
Log | Files | Refs | Submodules | README | LICENSE | sfeed.txt

commit 0392766bc379448c907de2bce45d6b57621d95b5
parent 6defee37f9939991bbf3152e2cd4e18593baa541
Author: Louis Burda <quent.burda@gmail.com>
Date:   Fri,  2 Dec 2022 16:06:32 +0100

Added split uart support based on chibios impl

Diffstat:
M.gitignore | 1+
MCMakeLists.txt | 10+++++++++-
Aextra/tinyusb.diff | 31+++++++++++++++++++++++++++++++
Msrc/board.h | 6+-----
Asrc/led.c | 55+++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/led.h | 18++++++++++++++++++
Msrc/main.c | 58++++++++++++++++++----------------------------------------
Dsrc/neopix.c | 27---------------------------
Dsrc/neopix.h | 27---------------------------
Msrc/split.c | 299++++++++++++++++++++++++++++++++++++++++++-------------------------------------
Msrc/split.h | 1+
Asrc/uart_rx.pio | 22++++++++++++++++++++++
Asrc/uart_tx.pio | 10++++++++++
Msrc/util.c | 34++++++++++++----------------------
Msrc/util.h | 14+++++++++++---
Asrc/ws2812.c | 43+++++++++++++++++++++++++++++++++++++++++++
Asrc/ws2812.h | 20++++++++++++++++++++
Msrc/ws2812.pio | 32--------------------------------
Dsrc/ws2812.pio.h | 58----------------------------------------------------------
19 files changed, 410 insertions(+), 356 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -1,3 +1,4 @@ .build .cache compile_commands.json +src/*.pio.h diff --git a/CMakeLists.txt b/CMakeLists.txt @@ -10,12 +10,17 @@ family_initialize_project(${PROJECT} ${CMAKE_CURRENT_LIST_DIR}) add_executable(${PROJECT}) +pico_generate_pio_header(${PROJECT} ${CMAKE_CURRENT_SOURCE_DIR}/src/ws2812.pio) +pico_generate_pio_header(${PROJECT} ${CMAKE_CURRENT_SOURCE_DIR}/src/uart_tx.pio) +pico_generate_pio_header(${PROJECT} ${CMAKE_CURRENT_SOURCE_DIR}/src/uart_rx.pio) + target_sources(${PROJECT} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/src/main.c ${CMAKE_CURRENT_SOURCE_DIR}/src/util.c ${CMAKE_CURRENT_SOURCE_DIR}/src/hid.c ${CMAKE_CURRENT_SOURCE_DIR}/src/split.c - ${CMAKE_CURRENT_SOURCE_DIR}/src/neopix.c + ${CMAKE_CURRENT_SOURCE_DIR}/src/ws2812.c + ${CMAKE_CURRENT_SOURCE_DIR}/src/led.c ${CMAKE_CURRENT_SOURCE_DIR}/src/matrix.c ${CMAKE_CURRENT_SOURCE_DIR}/src/keymap.c ${CMAKE_CURRENT_SOURCE_DIR}/src/usb_stdio.c @@ -53,3 +58,6 @@ target_compile_options(${PROJECT} PRIVATE family_configure_target(${PROJECT}) family_add_default_example_warnings(${PROJECT}) suppress_tinyusb_warnings() + +#pico_enable_stdio_usb(${PROJECT} 1) +pico_enable_stdio_uart(${PROJECT} 0) diff --git a/extra/tinyusb.diff b/extra/tinyusb.diff @@ -0,0 +1,31 @@ +diff --git a/hw/bsp/rp2040/family.c b/hw/bsp/rp2040/family.c +index 90e2192c0..6a2735eaf 100644 +--- a/hw/bsp/rp2040/family.c ++++ b/hw/bsp/rp2040/family.c +@@ -118,7 +118,7 @@ void stdio_rtt_init(void) + + #endif + +-#ifdef UART_DEV ++#if defined(UART_DEV) && defined(LIB_PICO_STDIO_UART) + static uart_inst_t *uart_inst; + #endif + +@@ -188,7 +188,7 @@ uint32_t board_button_read(void) + + int board_uart_read(uint8_t* buf, int len) + { +-#ifdef UART_DEV ++#if defined(UART_DEV) && defined(LIB_PICO_STDIO_UART) + for(int i=0;i<len;i++) { + buf[i] = uart_getc(uart_inst); + } +@@ -201,7 +201,7 @@ int board_uart_read(uint8_t* buf, int len) + + int board_uart_write(void const * buf, int len) + { +-#ifdef UART_DEV ++#if defined(UART_DEV) && defined(LIB_PICO_STDIO_UART) + char const* bufch = (char const*) buf; + for(int i=0;i<len;i++) { + uart_putc(uart_inst, bufch[i]); diff --git a/src/board.h b/src/board.h @@ -1,8 +1,6 @@ #pragma once -#include "neopix.h" - -#define ONBOARD_LED_PIN 25 +#include <stdint.h> #define REPORT_ID_MIN REPORT_ID_KEYBOARD enum { @@ -12,7 +10,5 @@ enum { REPORT_ID_MAX }; -extern struct neopix onboard_led; - extern const uint32_t **keymap_layers; diff --git a/src/led.c b/src/led.c @@ -0,0 +1,55 @@ +#include "led.h" +#include "ws2812.h" +#include "util.h" + +#include "bsp/board.h" + +#define ONBOARD_LED_PIN 25 + +static struct ws2812 onboard_led; + +int led_mode; +bool led_reset; +uint32_t led_blink_ms; +uint32_t led_rgb; + +void +led_init(void) +{ + led_reset = true; + led_mode = LED_ON; + led_rgb = WS2812_U32RGB(100, 100, 100); + ws2812_init(&onboard_led, pio0, ONBOARD_LED_PIN); +} + +void +led_task(void) +{ + static uint32_t start_ms = 0; + static bool state = false; + + switch (led_mode) { + case LED_OFF: + if (led_reset) + ws2812_put(&onboard_led, 0); + break; + case LED_ON: + if (led_reset) + ws2812_put(&onboard_led, led_rgb); + break; + case LED_BLINK: + if (led_reset) + start_ms = board_millis(); + + if (board_millis() - start_ms < led_blink_ms) + return; + start_ms += led_blink_ms; + + state = !state; + ws2812_put(&onboard_led, state ? led_rgb : 0); + break; + } + + led_reset = false; +} + diff --git a/src/led.h b/src/led.h @@ -0,0 +1,18 @@ +#pragma once + +#include <stdint.h> +#include <stdbool.h> + +enum { + LED_OFF, + LED_ON, + LED_BLINK +}; + +extern int led_mode; +extern bool led_reset; +extern uint32_t led_blink_ms; +extern uint32_t led_rgb; + +void led_init(void); +void led_task(void); diff --git a/src/main.c b/src/main.c @@ -2,9 +2,10 @@ #include "usb_stdio.h" #include "matrix.h" #include "split.h" +#include "led.h" #include "hid.h" #include "keymap.h" -#include "neopix.h" +#include "ws2812.h" #include "util.h" #include "hardware/gpio.h" @@ -19,42 +20,26 @@ #include <stdlib.h> #include <stdio.h> #include <string.h> -#include <sys/types.h> - -enum { - BLINK_NOT_MOUNTED = 250, - BLINK_MOUNTED = 1000, - BLINK_SUSPENDED = 2500, -}; bool send_hid_report(int id, bool state); -void blink_task(void); - -static uint32_t blink_interval_ms = BLINK_NOT_MOUNTED; - static bool hit_state = false; - const uint32_t **keymap_layers = keymap_layers_de; -struct neopix onboard_led; - int main(void) { board_init(); tud_init(BOARD_TUD_RHPORT); usb_stdio_init(); - neopix_init(&onboard_led, ONBOARD_LED_PIN); + led_init(); matrix_init(); split_init(); //hid_init(); - ASSERT(1 == 0); - while (true) { tud_task(); - blink_task(); + led_task(); split_task(); //hid_task(); } @@ -65,25 +50,34 @@ main(void) void tud_mount_cb(void) { - blink_interval_ms = BLINK_MOUNTED; + led_rgb = WS2812_U32RGB(100, 0, 100); + led_mode = LED_ON; + led_reset = true; } void tud_umount_cb(void) { - blink_interval_ms = BLINK_NOT_MOUNTED; + led_blink_ms = 500; + led_rgb = WS2812_U32RGB(100, 100, 100); + led_mode = LED_BLINK; + led_reset = true; } void tud_suspend_cb(bool remote_wakeup_en) { - blink_interval_ms = BLINK_SUSPENDED; + led_rgb = WS2812_U32RGB(100, 100, 100); + led_mode = LED_ON; + led_reset = true; } void tud_resume_cb(void) { - blink_interval_ms = BLINK_MOUNTED; + led_rgb = WS2812_U32RGB(100, 0, 100); + led_mode = LED_ON; + led_reset = true; } void @@ -94,6 +88,7 @@ tud_cdc_line_state_cb(uint8_t itf, bool dtr, bool rts) void tud_cdc_rx_cb(uint8_t itf) { + printf("ALIVE\n\r"); } uint16_t @@ -201,20 +196,3 @@ send_hid_report_timed(void) send_hid_report(REPORT_ID_MIN, hit_state); } - -void -blink_task(void) -{ - static uint32_t start_ms = 0; - static bool state = false; - - if (board_millis() - start_ms < blink_interval_ms) - return; - start_ms += blink_interval_ms; - - DEBUG("blink"); - - state ^= true; - neopix_put(&onboard_led, neopix_u32rgb(255 * state, 0, 255 * state)); -} - diff --git a/src/neopix.c b/src/neopix.c @@ -1,27 +0,0 @@ -#include "neopix.h" -#include "ws2812.pio.h" -#include "util.h" - -#include "hardware/pio.h" - -void -neopix_init(struct neopix *pix, uint pin) -{ - uint offset; - int sm; - - pix->pio = pio0; - sm = pio_claim_unused_sm(pix->pio, true); - ASSERT(sm >= 0); - pix->sm = (uint) sm; - pix->pin = pin; - offset = pio_add_program(pix->pio, &ws2812_program); - ws2812_program_init(pix->pio, pix->sm, offset, - pix->pin, 800000, false); - pix->init = true; -} - -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 @@ -1,27 +0,0 @@ -#pragma once - -#include "hardware/pio.h" -#include "hardware/gpio.h" - -#include <stdbool.h> - -struct neopix { - PIO pio; - uint sm; - uint pin; - bool init; -}; - -void neopix_init(struct neopix *pix, 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/split.c b/src/split.c @@ -1,29 +1,34 @@ +#include "hardware/regs/io_bank0.h" +#include "hardware/structs/padsbank0.h" +#include "uart_rx.pio.h" +#include "uart_tx.pio.h" + #include "split.h" -#include "class/cdc/cdc_device.h" #include "util.h" #include "matrix.h" #include "hardware/pio.h" #include "hardware/irq.h" #include "hardware/gpio.h" +#include "hardware/address_mapped.h" #include "hardware/regs/intctrl.h" +#include "hardware/regs/pads_bank0.h" #include "hardware/uart.h" #include "hardware/timer.h" #include "hardware/clocks.h" #include "pico/time.h" #include "bsp/board.h" +#include "class/cdc/cdc_device.h" #include "tusb.h" + #include <stdint.h> #define UART_TIMEOUT 20 #define UART_BAUD 115200 - -/* same pin since half-duplex */ -#define UART_TX_PIN 0 -#define UART_RX_PIN 0 +#define UART_PIN 1 enum { - CMD_SCAN_MATRIX_REQ = 0x80, + CMD_SCAN_MATRIX_REQ = 0x0F, CMD_SCAN_MATRIX_RESP, CMD_STDIO_PUTS }; @@ -33,15 +38,16 @@ enum { LEFT, RIGHT }; static void uart_tx_init(void); static void uart_rx_init(void); +static void uart_full_init(void); -static void uart_enter_rx(void); static void uart_leave_rx(void); +static void uart_enter_rx(void); -static int uart_sync_rx(void); -static int uart_sync_tx(void); +static bool uart_await_rx(void); +static bool uart_await_tx(void); -static uint8_t uart_in_byte(void); -static void uart_out_byte(uint8_t c); +static uint8_t uart_rx_byte(void); +static void uart_tx_byte(uint8_t c); static uint uart_recv(uint8_t *data, uint len); static uint uart_send(const uint8_t *data, uint len); @@ -49,43 +55,11 @@ static uint uart_send(const uint8_t *data, uint len); static void irq_rx_cmd(uint8_t cmd); static void irq_rx(void); -static const uint16_t uart_tx_program_asm[] = { - // .wrap_target - 0x9fa0, // 0: pull block side 1 [7] - 0xf727, // 1: set x, 7 side 0 [7] - 0x6081, // 2: out pindirs, 1 - 0x0642, // 3: jmp x--, 2 [6] - // .wrap -}; - -static const uint16_t uart_rx_program_asm[] = { - // .wrap_target - 0x2020, // 0: wait 0 pin, 0 - 0xea27, // 1: set x, 7 [10] - 0x4001, // 2: in pins, 1 - 0x0642, // 3: jmp x--, 2 [6] - 0x00c8, // 4: jmp pin, 8 - 0xc020, // 5: irq wait 0 - 0x20a0, // 6: wait 1 pin, 0 - 0x0000, // 7: jmp 0 - 0x8020, // 8: push block - // .wrap -}; - -static const pio_program_t uart_tx_program = { - .instructions = uart_tx_program_asm, - .length = 4, - .origin = -1, -}; - -static const pio_program_t uart_rx_program = { - .instructions = uart_rx_program_asm, - .length = 9, - .origin = -1, -}; - static uint uart_tx_sm; +static uint uart_tx_sm_offset; + static uint uart_rx_sm; +static uint uart_rx_sm_offset; static bool scan_pending = false; @@ -93,93 +67,112 @@ void uart_tx_init(void) { pio_sm_config config; - uint offset; - int sm; - - sm = pio_claim_unused_sm(pio0, true); - ASSERT(sm >= 0); - uart_tx_sm = (uint) sm; - - offset = pio_add_program(pio0, &uart_tx_program); - pio_sm_set_pins_with_mask(pio0, uart_tx_sm, 0, 1 << UART_TX_PIN); - pio_sm_set_consecutive_pindirs(pio0, - uart_tx_sm, UART_TX_PIN, 1, true); - - config = pio_get_default_sm_config(); - sm_config_set_wrap(&config, offset, - offset + ARRLEN(uart_tx_program_asm) - 1); - sm_config_set_sideset(&config, 2, true, true); + + uart_tx_sm = CLAIM_UNUSED_SM(pio0); + uart_tx_sm_offset = pio_add_program(pio0, &uart_tx_program); + + config = uart_tx_program_get_default_config(uart_tx_sm_offset); sm_config_set_out_shift(&config, true, false, 32); - sm_config_set_out_pins(&config, UART_TX_PIN, 1); - sm_config_set_sideset_pins(&config, UART_TX_PIN); + sm_config_set_out_pins(&config, UART_PIN, 1); + sm_config_set_sideset_pins(&config, UART_PIN); sm_config_set_fifo_join(&config, PIO_FIFO_JOIN_TX); sm_config_set_clkdiv(&config, - (float) clock_get_hz(clk_sys) / (8 * UART_BAUD)); + ((float) clock_get_hz(clk_sys)) / (8 * UART_BAUD)); - pio_sm_init(pio0, uart_tx_sm, offset, &config); - pio_sm_set_enabled(pio0, uart_tx_sm, true); + pio_sm_init(pio0, uart_tx_sm, uart_tx_sm_offset, &config); + pio_sm_set_enabled(pio0, uart_tx_sm, false); } void uart_rx_init(void) { pio_sm_config config; - uint offset; - int sm; - - sm = pio_claim_unused_sm(pio0, true); - ASSERT(sm >= 0); - uart_rx_sm = (uint) sm; - offset = pio_add_program(pio0, &uart_rx_program); + uart_rx_sm = CLAIM_UNUSED_SM(pio0); + uart_rx_sm_offset = pio_add_program(pio0, &uart_rx_program); - config = pio_get_default_sm_config(); - sm_config_set_wrap(&config, offset, - offset + ARRLEN(uart_rx_program_asm) - 1); - sm_config_set_in_pins(&config, UART_RX_PIN); - sm_config_set_jmp_pin(&config, UART_RX_PIN); + config = uart_rx_program_get_default_config(uart_rx_sm_offset); + sm_config_set_in_pins(&config, UART_PIN); + sm_config_set_jmp_pin(&config, UART_PIN); sm_config_set_in_shift(&config, true, false, 32); sm_config_set_fifo_join(&config, PIO_FIFO_JOIN_RX); sm_config_set_clkdiv(&config, - (float) clock_get_hz(clk_sys) / (8 * UART_BAUD)); + ((float) clock_get_hz(clk_sys)) / (8 * UART_BAUD)); - pio_sm_init(pio0, uart_rx_sm, offset, &config); - pio_sm_set_enabled(pio0, uart_rx_sm, true); + pio_sm_init(pio0, uart_rx_sm, uart_rx_sm_offset, &config); + pio_sm_set_enabled(pio0, uart_rx_sm, false); } void -uart_enter_rx(void) +uart_full_init(void) { - while (!pio_sm_is_tx_fifo_empty(pio0, uart_tx_sm)); - /* even after fifo is empty, we still need to wait until last byte - * = max (1 start + 8 data + 1 stop + 1 par) is fully transmitted */ - sleep_us(1000000U * 11 / UART_BAUD); + pio_sm_set_pins_with_mask(pio0, uart_tx_sm, 0U, 1U << UART_PIN); + pio_sm_set_consecutive_pindirs(pio0, uart_tx_sm, UART_PIN, 1, true); - pio_sm_set_enabled(pio0, uart_tx_sm, false); - gpio_set_drive_strength(UART_TX_PIN, GPIO_DRIVE_STRENGTH_2MA); - pio_sm_set_pins_with_mask(pio0, - uart_tx_sm, 1U << UART_TX_PIN, 1U << UART_TX_PIN); - pio_sm_set_consecutive_pindirs(pio0, - uart_tx_sm, UART_TX_PIN, 1, false); - pio_sm_set_enabled(pio0, uart_rx_sm, true); + pio_gpio_init(pio0, UART_PIN); + gpio_pull_up(UART_PIN); + gpio_set_slew_rate(UART_PIN, GPIO_SLEW_RATE_FAST); + /* 1 => set INPUT and pull line HIGH from pullup + * 0 => set OUTPUT and pull line LOW from signal */ + gpio_set_oeover(UART_PIN, GPIO_OVERRIDE_INVERT); + + uart_rx_init(); + uart_tx_init(); + + pio_set_irq0_source_enabled(pio0, + pis_sm0_rx_fifo_not_empty + uart_rx_sm, false); + pio_set_irq0_source_enabled(pio0, + pis_sm0_tx_fifo_not_full + uart_tx_sm, false); + pio_set_irq0_source_enabled(pio0, pis_interrupt0, true); + pio_set_irq0_source_enabled(pio0, pis_interrupt1, true); + + irq_set_priority(PIO0_IRQ_0, PICO_HIGHEST_IRQ_PRIORITY); + irq_set_exclusive_handler(PIO0_IRQ_0, irq_rx); + irq_set_enabled(PIO0_IRQ_0, true); + + pio_sm_set_enabled(pio0, uart_tx_sm, true); + uart_enter_rx(); } void uart_leave_rx(void) { - /* disable rx to not receive when we send */ + irq_set_enabled(USBCTRL_IRQ, false); pio_sm_set_enabled(pio0, uart_rx_sm, false); - pio_sm_set_consecutive_pindirs(pio0, - uart_tx_sm, UART_TX_PIN, 1, true); - pio_sm_set_pins_with_mask(UART_TX_PIN, - uart_tx_sm, 0, 1U << UART_TX_PIN); - gpio_set_drive_strength(UART_TX_PIN, GPIO_DRIVE_STRENGTH_12MA); + + /* because of OE override pindir true = INPUT (!) */ + pio_sm_set_consecutive_pindirs(pio0, uart_tx_sm, UART_PIN, 1, true); + + /* drive LOW with high drive-current for steep falling edges */ + pio_sm_set_pins_with_mask(pio0, uart_tx_sm, 0U, 1 << UART_PIN); + gpio_set_drive_strength(UART_PIN, GPIO_DRIVE_STRENGTH_12MA); + pio_sm_restart(pio0, uart_tx_sm); pio_sm_set_enabled(pio0, uart_tx_sm, true); } -int -uart_sync_rx(void) +void +uart_enter_rx(void) +{ + /* wait for tx fifo to empty and final byte to transmit + * + extra max. 1 start + 8 data + 1 stop + 1 par bits */ + while (!pio_sm_is_tx_fifo_empty(pio0, uart_tx_sm)); + sleep_us(1000000U * 11 / UART_BAUD); + pio_sm_set_enabled(pio0, uart_tx_sm, false); + + /* pull HIGH with low drive-current for steeper rising edge */ + gpio_set_drive_strength(UART_PIN, GPIO_DRIVE_STRENGTH_2MA); + pio_sm_set_pins_with_mask(pio0, uart_tx_sm, ~0U, 1 << UART_PIN); + + /* because of OE override pindir false = OUTPUT (!) */ + pio_sm_set_consecutive_pindirs(pio0, uart_tx_sm, UART_PIN, 1, false); + + pio_sm_set_enabled(pio0, uart_rx_sm, true); + irq_set_enabled(USBCTRL_IRQ, true); +} + +bool +uart_await_rx(void) { uint32_t start_ms; bool empty; @@ -191,11 +184,11 @@ uart_sync_rx(void) tud_task(); } while (board_millis() < start_ms + UART_TIMEOUT); - return empty; + return !empty; } -int -uart_sync_tx(void) +bool +uart_await_tx(void) { uint32_t start_ms; bool full; @@ -207,17 +200,17 @@ uart_sync_tx(void) tud_task(); } while (board_millis() < start_ms + UART_TIMEOUT); - return full; + return !full; } uint8_t -uart_in_byte(void) +uart_rx_byte(void) { return *(uint8_t*)((uintptr_t)&pio0->rxf[uart_rx_sm] + 3); } void -uart_out_byte(uint8_t c) +uart_tx_byte(uint8_t c) { pio_sm_put(pio0, uart_tx_sm, c); } @@ -227,13 +220,11 @@ uart_recv(uint8_t *data, uint len) { uint recv; - recv = 0; - while (recv < len) { + for (recv = 0; recv < len; recv++) { if (pio_sm_is_rx_fifo_empty(pio0, uart_rx_sm)) { - if (uart_sync_rx()) break; + if (!uart_await_rx()) break; } - *data++ = uart_in_byte(); - recv++; + *data++ = uart_rx_byte(); } return recv; @@ -245,13 +236,11 @@ uart_send(const uint8_t *data, uint len) uint sent; uart_leave_rx(); - sent = 0; - while (sent < len) { + for (sent = 0; sent < len; sent++) { if (pio_sm_is_tx_fifo_full(pio0, uart_tx_sm)) { - if (uart_sync_tx()) break; + if (!uart_await_tx()) break; } - uart_out_byte(*data++); - sent++; + uart_tx_byte(*data++); } uart_enter_rx(); @@ -291,9 +280,21 @@ irq_rx(void) { uint8_t cmd; - DEBUG("UART IRQ\n"); + (void) cmd; + (void) irq_rx_cmd; + + if (pio_interrupt_get(pio0, 0)) { + DEBUG("RX ERR"); + pio_interrupt_clear(pio0, 0); + } + + //DEBUG("UART IRQ"); + // while (!pio_sm_is_rx_fifo_empty(pio0, uart_rx_sm)) + // uart_rx_byte(); + // ASSERT(1 == 0); + while (!pio_sm_is_rx_fifo_empty(pio0, uart_rx_sm)) { - cmd = uart_in_byte(); + cmd = uart_rx_byte(); DEBUG("UART RX CMD %i\n", cmd); irq_rx_cmd(cmd); } @@ -302,20 +303,22 @@ irq_rx(void) void split_init(void) { - uart_tx_init(); - uart_rx_init(); + uart_full_init(); +} - pio_set_irq0_source_enabled(pio0, - pis_sm0_rx_fifo_not_empty + uart_rx_sm, false); - pio_set_irq0_source_enabled(pio0, - pis_sm0_tx_fifo_not_full + uart_tx_sm, false); - pio_set_irq0_source_enabled(pio0, pis_interrupt0, false); +void +split_test(void) +{ + pio_sm_set_pins_with_mask(pio0, uart_tx_sm, 0U, 1U << UART_PIN); + pio_sm_set_consecutive_pindirs(pio0, uart_tx_sm, UART_PIN, 1, false); - irq_set_priority(PIO0_IRQ_0, PICO_HIGHEST_IRQ_PRIORITY); - irq_set_exclusive_handler(PIO0_IRQ_0, irq_rx); - irq_set_enabled(PIO0_IRQ_0, true); + pio_gpio_init(pio0, UART_PIN); + gpio_pull_up(UART_PIN); + gpio_set_slew_rate(UART_PIN, GPIO_SLEW_RATE_FAST); - uart_enter_rx(); + /* 1 => set INPUT and pull line HIGH from pullup + * 0 => set OUTPUT and pull line LOW from signal */ + gpio_set_oeover(UART_PIN, GPIO_OVERRIDE_INVERT); } void @@ -324,17 +327,20 @@ split_task(void) uint32_t start_ms; uint8_t cmd; - if (SPLIT_ROLE == SLAVE) { - if (scan_pending) { - scan_matrix(); - cmd = CMD_SCAN_MATRIX_RESP; - ASSERT(uart_send(&cmd, 1)); - scan_pending = false; - } - } else if (SPLIT_ROLE == MASTER) { + // if (!uart_await_tx()) + // return; + + // sleep_us(100); + // uart_leave_rx(); + // uart_tx_byte(0xAA); + // uart_enter_rx(); + + // return; + + if (SPLIT_ROLE == MASTER) { scan_pending = true; cmd = CMD_SCAN_MATRIX_REQ; - ASSERT(uart_send(&cmd, 1)); + ASSERT(uart_send(&cmd, 1) == 1); scan_matrix(); /* scan our side in parallel */ start_ms = board_millis(); while (scan_pending && board_millis() < start_ms + 50) @@ -342,5 +348,16 @@ split_task(void) if (scan_pending) WARN("Slave matrix scan timeout"); else DEBUG("Slave matrix scan success"); scan_pending = false; - } + } else { + if (!uart_await_rx()) + return; + cmd = uart_rx_byte(); + DEBUG("GOT RX: %i", cmd); + if (scan_pending) { + scan_matrix(); + cmd = CMD_SCAN_MATRIX_RESP; + ASSERT(uart_send(&cmd, 1) == 1); + scan_pending = false; + } + } } diff --git a/src/split.h b/src/split.h @@ -1,4 +1,5 @@ #pragma once void split_init(void); +void split_test(void); void split_task(void); diff --git a/src/uart_rx.pio b/src/uart_rx.pio @@ -0,0 +1,22 @@ +.program uart_rx + +.wrap_target +start: + wait 0 pin, 0 [6] ; wait for START bit + + set x, 7 [4] ; read 8 DATA bits and offset + ; clock for better readings +bitloop: + in pins, 1 + jmp x--, bitloop [6] + + jmp pin, outb ; got STOP bit, output byte + +error: + irq wait 0 ; no STOP bit, + wait 1 pin, 0 ; set err IRQ and await reset + jmp start + +outb: + push block +.wrap diff --git a/src/uart_tx.pio b/src/uart_tx.pio @@ -0,0 +1,10 @@ +.program uart_tx +.side_set 1 opt pindirs + +.wrap_target + pull block side 1 [7] ; IDLE / STOP bit + set x, 7 side 0 [7] ; START bit +bitloop: + out pindirs, 1 ; 8 DATA bits + jmp x--, bitloop [6] +.wrap diff --git a/src/util.c b/src/util.c @@ -1,7 +1,9 @@ #include "util.h" #include "board.h" -#include "neopix.h" +#include "led.h" +#include "ws2812.h" +#include "pico/stdio.h" #include "tusb.h" #include "bsp/board.h" #include "tusb_config.h" @@ -28,27 +30,11 @@ panic_task(const char *fmtstr, va_list ap, uint32_t sleep_ms) va_copy(cpy, ap); vprintf(fmtstr, cpy); printf("\n\r"); + stdio_flush(); start_ms += sleep_ms; } -static void -blink_task(struct neopix *pix, uint32_t blink_ms) -{ - static uint32_t start_ms = 0; - static bool led_state = false; - - if (!start_ms) start_ms = board_millis(); - - if (board_millis() < start_ms + blink_ms) - return; - - neopix_put(pix, neopix_u32rgb(255 * led_state, 0, 0)); - led_state ^= true; - - start_ms += blink_ms; -} - void __attribute__ ((format (printf, 2, 3))) stdio_log(int level, const char *fmtstr, ...) @@ -65,21 +51,25 @@ stdio_log(int level, const char *fmtstr, ...) vprintf(fmtstr, ap); va_end(ap); printf("\n\r"); + stdio_flush(); } void -__attribute__((format(printf, 1, 2))) -blink_panic(const char *fmtstr, ...) +__attribute__((format(printf, 3, 4))) +blink_panic(uint32_t blink_ms, uint32_t rgb, const char *fmtstr, ...) { va_list ap; va_start(ap, fmtstr); + led_blink_ms = blink_ms; + led_rgb = rgb; + led_mode = LED_BLINK; + while (1) { tud_task(); panic_task(fmtstr, ap, 1000); - if (onboard_led.init) - blink_task(&onboard_led, 200); + led_task(); } va_end(ap); diff --git a/src/util.h b/src/util.h @@ -1,6 +1,9 @@ #pragma once +#include "ws2812.h" + #include <stdbool.h> +#include <stdint.h> #include <stdarg.h> #define ARRLEN(x) (sizeof(x) / sizeof((x)[0])) @@ -10,12 +13,17 @@ #define INFO(...) stdio_log(LOG_INFO, "INFO : " __VA_ARGS__) #define DEBUG(...) stdio_log(LOG_DEBUG, "DEBUG: " __VA_ARGS__) -#define PANIC(...) blink_panic(__VA_ARGS__); +#define PANIC(...) blink_panic(200, WS2812_U32RGB(255, 0, 0), __VA_ARGS__); #define ASSERT(cond) do { \ - if (!(cond)) blink_panic("Assertion failed: (%s) in %s:%i", \ + if (!(cond)) PANIC("Assertion failed: (%s) in %s:%i", \ #cond, __FILE__, __LINE__); \ } while (0) +#define CLAIM_UNUSED_SM(pio) ({ \ + int tmp = pio_claim_unused_sm(pio, false); \ + ASSERT(tmp >= 0); \ + (uint) tmp; }) + enum { LOG_NONE, LOG_ERR, @@ -26,6 +34,6 @@ enum { void stdio_log(int loglevel, const char *fmtstr, ...); -void blink_panic(const char *fmtstr, ...); +void blink_panic(uint32_t blink_ms, uint32_t rgb, const char *fmtstr, ...); extern int loglevel; diff --git a/src/ws2812.c b/src/ws2812.c @@ -0,0 +1,43 @@ +#include "ws2812.h" +#include "ws2812.pio.h" +#include "util.h" + +#include "hardware/pio.h" +#include "hardware/clocks.h" + +#define CYCLES_PER_BIT (ws2812_T1 + ws2812_T2 + ws2812_T3) + +void +ws2812_init(struct ws2812 *pix, PIO pio, uint pin) +{ + pio_sm_config config; + uint offset; + uint sm; + + pix->pio = pio; + pix->pin = pin; + + sm = CLAIM_UNUSED_SM(pio); + pix->sm = sm; + + pio_gpio_init(pio, pin); + pio_sm_set_consecutive_pindirs(pio, sm, pin, 1, true); + + offset = pio_add_program(pix->pio, &ws2812_program); + config = ws2812_program_get_default_config(offset); + sm_config_set_sideset_pins(&config, pin); + sm_config_set_out_shift(&config, false, true, 24); + sm_config_set_fifo_join(&config, PIO_FIFO_JOIN_TX); + sm_config_set_clkdiv(&config, + (float) clock_get_hz(clk_sys) / (800000 * CYCLES_PER_BIT)); + + pio_sm_init(pio, sm, offset, &config); + pio_sm_set_enabled(pio, sm, true); + + pix->init = true; +} + +void +ws2812_put(struct ws2812 *pix, uint32_t rgb) { + pio_sm_put_blocking(pix->pio, pix->sm, rgb << 8u); +} diff --git a/src/ws2812.h b/src/ws2812.h @@ -0,0 +1,20 @@ +#pragma once + +#include "hardware/pio.h" +#include "hardware/gpio.h" + +#include <stdbool.h> + +#define _WS2812_U8(v, s) (((uint32_t) (v) & 0xFF) << s) +#define WS2812_U32RGB(r, g, b) \ + (_WS2812_U8(b, 0) | _WS2812_U8(r, 8) | _WS2812_U8(g, 16)) + +struct ws2812 { + PIO pio; + uint sm; + uint pin; + bool init; +}; + +void ws2812_init(struct ws2812 *pix, PIO pio, uint pin); +void ws2812_put(struct ws2812 *pix, uint32_t rgb); diff --git a/src/ws2812.pio b/src/ws2812.pio @@ -1,9 +1,3 @@ -; -; Copyright (c) 2020 Raspberry Pi (Trading) Ltd. -; -; SPDX-License-Identifier: BSD-3-Clause -; - .program ws2812 .side_set 1 @@ -11,10 +5,6 @@ .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 @@ -24,25 +14,3 @@ do_one: 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 @@ -1,58 +0,0 @@ -// -------------------------------------------------- // -// 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