aboutsummaryrefslogtreecommitdiffstats
path: root/src/split.c
diff options
context:
space:
mode:
authorLouis Burda <quent.burda@gmail.com>2022-12-02 16:06:32 +0100
committerLouis Burda <quent.burda@gmail.com>2022-12-02 17:18:16 +0100
commit0392766bc379448c907de2bce45d6b57621d95b5 (patch)
treeb87705bfb60a6569769b3c0125a910144c784436 /src/split.c
parent6defee37f9939991bbf3152e2cd4e18593baa541 (diff)
downloadsxkbd-0392766bc379448c907de2bce45d6b57621d95b5.tar.gz
sxkbd-0392766bc379448c907de2bce45d6b57621d95b5.zip
Added split uart support based on chibios impl
Diffstat (limited to 'src/split.c')
-rw-r--r--src/split.c299
1 files changed, 158 insertions, 141 deletions
diff --git a/src/split.c b/src/split.c
index 75505ff..7bc7e63 100644
--- 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;
+ }
+ }
}