Skip to content

Commit

Permalink
Make USB uart separate from hardware UART
Browse files Browse the repository at this point in the history
Also make hardware UART fully blocking for kput/kprintf
  • Loading branch information
veremenko-y committed Apr 3, 2024
1 parent 83151c8 commit bca9bc1
Show file tree
Hide file tree
Showing 13 changed files with 319 additions and 72 deletions.
5 changes: 2 additions & 3 deletions Kernel/platform/platform-rpipico/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ add_executable(fuzix
main.c
misc.c
rawflash.c
rawuart.c
swapper.c
tricks.S
core1.c
Expand Down Expand Up @@ -70,9 +71,7 @@ target_link_libraries(fuzix
pico_multicore
hardware_flash
hardware_spi
hardware_uart
tinyusb_device_unmarked
tinyusb_board
tinyusb_device
)

pico_set_float_implementation(fuzix none)
Expand Down
13 changes: 11 additions & 2 deletions Kernel/platform/platform-rpipico/config.h
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
#ifndef CONFIG_H
#define CONFIG_H
#include "tusb_config.h"
/*
* Set this according to your SD card pins (default
* is the David Given arrangement).
Expand Down Expand Up @@ -48,7 +51,7 @@
#define UDATA_SIZE (UDATA_BLKS << BLKSHIFT)
#define USERMEM (160*1024)
#define PROGSIZE (65536 - UDATA_SIZE)
extern uint8_t progbase[USERMEM];
extern char progbase[USERMEM];
#define udata (*(struct u_data*)progbase)

#define USERSTACK (4*1024) /* 4kB */
Expand All @@ -73,7 +76,12 @@ extern uint8_t progbase[USERMEM];
#define SWAPDEV (swap_dev) /* dynamic swap */

/* Device parameters */
#define NUM_DEV_TTY 1
#define NUM_DEV_TTY_UART 1
#define NUM_DEV_TTY_USB (CFG_TUD_CDC)
#define NUM_DEV_TTY (NUM_DEV_TTY_UART + NUM_DEV_TTY_USB)

#define USB_TO_TTY(x) (x + 1 + NUM_DEV_TTY_UART)
#define TTY_TO_USB(x) (x - 1 - NUM_DEV_TTY_UART)

#define TTYDEV BOOT_TTY /* Device used by kernel for messages, panics */
#define NBUFS 20 /* Number of block buffers */
Expand All @@ -91,5 +99,6 @@ extern uint8_t progbase[USERMEM];
#define MANGLED 1
#include "mangle.h"

#endif
// vim: sw=4 ts=4 et

178 changes: 133 additions & 45 deletions Kernel/platform/platform-rpipico/core1.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,90 +4,178 @@
* SPDX-License-Identifier: BSD-3-Clause
*/

#include <kernel.h>
#include "picosdk.h"
#include "config.h"
#include "core1.h"

#include <tusb.h>
#include <pico/stdlib.h>
#include <pico/time.h>
#include <pico/binary_info.h>
#include <pico/critical_section.h>
#include <pico/multicore.h>
#include <hardware/uart.h>
#include <hardware/irq.h>
#include "core1.h"

bool usbconsole_is_readable(void)
#define CONFIG_CONSOLE_BUF_LEN 16

#if CONFIG_CONSOLE_BUF_LEN > 255
#error "Invalid console buffer length"
#endif

struct console_buf_t
{
return multicore_fifo_rvalid();
uint8_t buffer[CONFIG_CONSOLE_BUF_LEN];
uint8_t rindex;
uint8_t windex;
uint8_t len;
};

struct console_t
{
struct console_buf_t rbuf;
struct console_buf_t wbuf;
bool sleeping;
};

static struct console_t console_table[NUM_DEV_TTY_USB];
critical_section_t critical_section;

static void console_buf_write(struct console_buf_t *buf, uint8_t b)
{
/*
can deadlock core1 thread
while(buf->len >= CONFIG_CONSOLE_BUF_LEN)
tight_loop_contents();
*/
critical_section_enter_blocking(&critical_section);
if(buf->len < CONFIG_CONSOLE_BUF_LEN)
{
buf->buffer[buf->windex] = b;
buf->windex = (buf->windex + 1) % CONFIG_CONSOLE_BUF_LEN;
buf->len++;
}
critical_section_exit(&critical_section);
}

bool usbconsole_is_writable(void)
static uint8_t console_buf_read(struct console_buf_t *buf)
{
return multicore_fifo_wready();
critical_section_enter_blocking(&critical_section);
if(buf->len == 0)
{
panic("rd undrf");
}
uint8_t b = buf->buffer[buf->rindex];
buf->rindex = (buf->rindex + 1) % CONFIG_CONSOLE_BUF_LEN;
buf->len--;
critical_section_exit(&critical_section);
return b;
}

uint8_t usbconsole_getc_blocking(void)
int usbconsole_read(uint8_t *buffer, int size)
{
return multicore_fifo_pop_blocking();
if(size & 0x01)
{
panic("buf size");
}
int written = 0;
for(int i = 0; i < NUM_DEV_TTY && written < size; i++)
{
struct console_buf_t *buf = &console_table[i].rbuf;
if (buf->len > 0)
{
buffer[0] = USB_TO_TTY(i);
buffer[1] = console_buf_read(buf);
buffer += 2;
written += 2;
}
}
return written;
}

void usbconsole_putc_blocking(uint8_t b)
extern bool usbconsole_is_writable(uint8_t minor)
{
multicore_fifo_push_blocking(b);
minor = TTY_TO_USB(minor);
return console_table[minor].wbuf.len < CONFIG_CONSOLE_BUF_LEN;
}

static void core1_main(void)
extern bool usbconsole_is_available(uint8_t minor)
{
uart_init(uart_default, PICO_DEFAULT_UART_BAUD_RATE);
gpio_set_function(PICO_DEFAULT_UART_TX_PIN, GPIO_FUNC_UART);
gpio_set_function(PICO_DEFAULT_UART_RX_PIN, GPIO_FUNC_UART);
uart_set_translate_crlf(uart_default, false);
uart_set_fifo_enabled(uart_default, true);
minor = TTY_TO_USB(minor);
return minor <= NUM_DEV_TTY_USB;
}

tusb_init();
extern void usbconsole_putc(uint8_t minor, uint8_t b)
{
minor = TTY_TO_USB(minor);
if (minor >= NUM_DEV_TTY_USB)
{
panic("ttydev");
}
struct console_buf_t *buf = &console_table[minor].wbuf;
if (buf->len >= CONFIG_CONSOLE_BUF_LEN)
{
panic("ovf");
}

console_buf_write(buf, b);
}

extern void usbconsole_setsleep(uint8_t minor, bool sleeping)
{
console_table[TTY_TO_USB(minor)].sleeping = sleeping;
}

extern bool usbconsole_is_sleeping(uint8_t minor)
{
return console_table[TTY_TO_USB(minor)].sleeping;
}

#if NUM_DEV_TTY_USB > 0
static void core1_main(void)
{
tusb_init();

for (;;)
{
tud_task();

if (multicore_fifo_rvalid()
&& (!tud_cdc_connected() || tud_cdc_write_available())
&& uart_is_writable(uart_default))
{
int b = multicore_fifo_pop_blocking();
/*
We ignore tud_cdc_n_connected because if DTR is not set by the host
all tty's will appear disconnected, which seems to be the case for pi pico
*/

if (tud_cdc_connected())
for(int i = 0; i < CFG_TUD_CDC; i++)
{
if (tud_cdc_n_write_available(i)
&& console_table[i].wbuf.len)
{
tud_cdc_write(&b, 1);
tud_cdc_write_flush();
uint8_t b = console_buf_read(&console_table[i].wbuf);
tud_cdc_n_write_char(i, b);
tud_cdc_n_write_flush(i);
}

uart_putc(uart_default, b);
}

if (multicore_fifo_wready()
&& ((tud_cdc_connected() && tud_cdc_available())
|| uart_is_readable(uart_default)))
for (int i = 0; i < CFG_TUD_CDC; i++)
{
/* Only service a byte from CDC *or* the UART, in case two show
* up at the same time and we end up blocking. No big loss, the
* next one will be read the next time around the loop. */

if (tud_cdc_available())
if (!tud_cdc_n_available(i))
{
uint8_t b;
int count = tud_cdc_read(&b, 1);
if (count)
multicore_fifo_push_blocking(b);
continue;
}
else if (uart_is_readable(uart_default))
struct console_buf_t *buf = &console_table[i].rbuf;
if (buf->len < CONFIG_CONSOLE_BUF_LEN)
{
uint8_t b = uart_get_hw(uart_default)->dr;
multicore_fifo_push_blocking(b);
uint8_t b = tud_cdc_n_read_char(i);
console_buf_write(buf, b);
}
}
}
}
#endif

void core1_init(void)
{
multicore_reset_core1();
critical_section_init(&critical_section);
#if NUM_DEV_TTY_USB > 0
multicore_launch_core1(core1_main);
#endif
}

11 changes: 7 additions & 4 deletions Kernel/platform/platform-rpipico/core1.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,13 @@

extern void core1_init(void);

extern bool usbconsole_is_readable(void);
extern bool usbconsole_is_writable(void);
extern uint8_t usbconsole_getc_blocking(void);
extern void usbconsole_putc_blocking(uint8_t b);
extern int usbconsole_read(uint8_t *buffer, int size);
extern bool usbconsole_is_writable(uint8_t minor);
extern bool usbconsole_is_available(uint8_t minor);
extern void usbconsole_putc(uint8_t minor, uint8_t b);
extern void usbconsole_setsleep(uint8_t minor, bool sleeping);
extern bool usbconsole_is_sleeping(uint8_t minor);


#endif

12 changes: 5 additions & 7 deletions Kernel/platform/platform-rpipico/devices.c
Original file line number Diff line number Diff line change
Expand Up @@ -52,14 +52,12 @@ static void timer_tick_cb(unsigned alarm)
update_us_since_boot(&next, time_us_64() + (1000000 / TICKSPERSEC));
hardware_alarm_set_target(0, next);
}

irqflags_t irq = di();
udata.u_ininterrupt = 1;
tty_interrupt();
timer_interrupt();

if (usbconsole_is_readable())
{
uint8_t c = usbconsole_getc_blocking();
tty_inproc(minor(BOOT_TTY), c);
}
udata.u_ininterrupt = 0;
irqrestore(irq);
}

void device_init(void)
Expand Down
Loading

0 comments on commit bca9bc1

Please sign in to comment.