Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
199 changes: 166 additions & 33 deletions src/pio_usb.c
Original file line number Diff line number Diff line change
Expand Up @@ -226,39 +226,107 @@ int __no_inline_not_in_flash_func(pio_usb_bus_receive_packet_and_handshake)(
return -1;
}

static __always_inline void add_pio_host_rx_program(PIO pio,
static __always_inline int try_add_pio_host_rx_program(PIO pio,
const pio_program_t *program,
const pio_program_t *debug_program,
uint *offset, int debug_pin) {
if (debug_pin < 0) {
*offset = pio_add_program(pio, program);
} else {
*offset = pio_add_program(pio, debug_program);
int *offset, int debug_pin) {
const pio_program_t *prog;

if (debug_pin < 0)
prog = program;
else
prog = debug_program;

if (pio_can_add_program(pio, prog)) {
*offset = pio_add_program(pio, prog);
return prog->length;
}

return -1;
}

static void __no_inline_not_in_flash_func(initialize_host_programs)(
pio_port_t *pp, const pio_usb_configuration_t *c, root_port_t *port) {
static __always_inline void remove_pio_host_rx_program(PIO pio,
const pio_program_t *program,
const pio_program_t *debug_program,
int offset, int debug_pin) {
if (debug_pin < 0) {
pio_remove_program(pio, program, offset);
} else {
pio_remove_program(pio, debug_program, offset);
}
}

static bool __no_inline_not_in_flash_func(try_initialize_host_programs)(
pio_port_t *pp, const pio_usb_configuration_t *c, root_port_t *port,
uint *tx_inst_count, uint *rx_inst_count) {
int offset_tx = -1, offset_rx = -1, offset_eop = -1;
int sm_tx = -1, sm_rx = -1, sm_eop = -1;
int ret;

// TX program should be placed at address 0
pio_add_program_at_offset(pp->pio_usb_tx, pp->fs_tx_program, 0);
pp->offset_tx = 0;
if (pio_can_add_program_at_offset(pp->pio_usb_tx, pp->fs_tx_program, 0)) {
offset_tx = pio_add_program_at_offset(pp->pio_usb_tx, pp->fs_tx_program, 0);
if (tx_inst_count)
*tx_inst_count = pp->fs_tx_program->length;
} else {
goto err_out;
}
ret = try_add_pio_host_rx_program(pp->pio_usb_rx, &usb_nrzi_decoder_program,
&usb_nrzi_decoder_debug_program, &offset_rx, c->debug_pin_rx);
if (ret <= 0)
goto err_out;
if (rx_inst_count)
*rx_inst_count = ret;
ret = try_add_pio_host_rx_program(pp->pio_usb_rx, &usb_edge_detector_program,
&usb_edge_detector_debug_program, &offset_eop, c->debug_pin_eop);
if (ret <= 0)
goto err_out;
if (rx_inst_count)
*rx_inst_count += ret;
if (c->sm_tx < 0) {
sm_tx = pio_claim_unused_sm(pp->pio_usb_tx, false);
if (sm_tx < 0)
goto err_out;
} else {
pp->sm_tx = c->sm_tx;
pio_sm_claim(pp->pio_usb_tx, pp->sm_tx);
}
if (c->sm_rx < 0) {
sm_rx = pio_claim_unused_sm(pp->pio_usb_rx, false);
if (sm_rx < 0)
goto err_out;
} else {
pp->sm_rx = c->sm_rx;
pio_sm_claim(pp->pio_usb_rx, pp->sm_rx);
}
if (c->sm_eop < 0) {
sm_eop = pio_claim_unused_sm(pp->pio_usb_rx, false);
if (sm_eop < 0)
goto err_out;
} else {
pp->sm_eop = c->sm_eop;
pio_sm_claim(pp->pio_usb_rx, pp->sm_eop);
}
pp->offset_tx = offset_tx;
pp->offset_rx = offset_rx;
pp->offset_eop = offset_eop;
if (c->sm_rx < 0)
pp->sm_rx = sm_rx;
if (c->sm_tx < 0)
pp->sm_tx = sm_tx;
if (c->sm_eop < 0)
pp->sm_eop = sm_eop;
usb_tx_fs_program_init(pp->pio_usb_tx, pp->sm_tx, pp->offset_tx, port->pin_dp,
port->pin_dm);
pp->tx_start_instr = pio_encode_jmp(pp->offset_tx + 4);
pp->tx_reset_instr = pio_encode_jmp(pp->offset_tx + 2);

add_pio_host_rx_program(pp->pio_usb_rx, &usb_nrzi_decoder_program,
&usb_nrzi_decoder_debug_program, &pp->offset_rx,
c->debug_pin_rx);
usb_rx_fs_program_init(pp->pio_usb_rx, pp->sm_rx, pp->offset_rx, port->pin_dp,
port->pin_dm, c->debug_pin_rx);
pp->rx_reset_instr = pio_encode_jmp(pp->offset_rx);
pp->rx_reset_instr2 = pio_encode_set(pio_x, 0);

add_pio_host_rx_program(pp->pio_usb_rx, &usb_edge_detector_program,
&usb_edge_detector_debug_program, &pp->offset_eop,
c->debug_pin_eop);
eop_detect_fs_program_init(pp->pio_usb_rx, c->sm_eop, pp->offset_eop,
eop_detect_fs_program_init(pp->pio_usb_rx, pp->sm_eop, pp->offset_eop,
port->pin_dp, port->pin_dm, true,
c->debug_pin_eop);

Expand All @@ -267,6 +335,25 @@ static void __no_inline_not_in_flash_func(initialize_host_programs)(
pio_sm_set_jmp_pin(pp->pio_usb_rx, pp->sm_rx, port->pin_dp);
pio_sm_set_jmp_pin(pp->pio_usb_rx, pp->sm_eop, port->pin_dm);
pio_sm_set_in_pins(pp->pio_usb_rx, pp->sm_eop, port->pin_dp);

return true;

err_out:
if (offset_tx >= 0)
pio_remove_program(pp->pio_usb_tx, pp->fs_tx_program, offset_tx);
if (offset_rx >= 0)
remove_pio_host_rx_program(pp->pio_usb_rx, &usb_nrzi_decoder_program,
&usb_nrzi_decoder_debug_program, offset_rx, c->debug_pin_rx);
if (offset_eop >= 0)
remove_pio_host_rx_program(pp->pio_usb_rx, &usb_edge_detector_program,
&usb_edge_detector_debug_program, offset_eop, c->debug_pin_eop);
if (sm_tx >= 0)
pio_sm_unclaim(pp->pio_usb_tx, sm_tx);
if (sm_rx >= 0)
pio_sm_unclaim(pp->pio_usb_rx, sm_rx);
if (sm_eop >= 0)
pio_sm_unclaim(pp->pio_usb_rx, sm_eop);
return false;
}

static void configure_tx_channel(uint8_t ch, PIO pio, uint sm) {
Expand All @@ -281,15 +368,43 @@ static void configure_tx_channel(uint8_t ch, PIO pio, uint sm) {
dma_channel_set_write_addr(ch, &pio->txf[sm], false);
}

static bool init_host_programs(
pio_port_t *pp, const pio_usb_configuration_t *c, root_port_t *port,
uint *tx_inst_count, uint *rx_inst_count) {
bool pio_rx_auto = false, pio_tx_auto = false;

if (!pp->pio_usb_tx) {
pio_tx_auto = true;
pp->pio_usb_tx = pio0;
}
if (!pp->pio_usb_rx) {
pio_rx_auto = true;
pp->pio_usb_rx = pio1;
}
if (try_initialize_host_programs(pp, c, port, tx_inst_count, rx_inst_count))
return true;
if (!pio_tx_auto && !pio_rx_auto)
return false;
if (pio_tx_auto)
pp->pio_usb_tx = pio1;
if (pio_rx_auto)
pp->pio_usb_rx = pio0;
return try_initialize_host_programs(pp, c, port, tx_inst_count, rx_inst_count);
}

static void apply_config(pio_port_t *pp, const pio_usb_configuration_t *c,
root_port_t *port) {
pp->pio_usb_tx = pio_get_instance(c->pio_tx_num);
pp->sm_tx = c->sm_tx;
pp->tx_ch = c->tx_ch;
pp->pio_usb_rx = pio_get_instance(c->pio_rx_num);
pp->sm_rx = c->sm_rx;
pp->sm_eop = c->sm_eop;
port->pin_dp = c->pin_dp;
if (c->pio_tx_num >= 0)
pp->pio_usb_tx = pio_get_instance(c->pio_tx_num);
else
pp->pio_usb_tx = NULL;

if (c->pio_rx_num >=-0)
pp->pio_usb_rx = pio_get_instance(c->pio_rx_num);
else
pp->pio_usb_tx = NULL;

port->pin_dp = c->pin_dp;

uint highest_pin;
if (c->pinout == PIO_USB_PINOUT_DPDM) {
Expand Down Expand Up @@ -319,10 +434,6 @@ static void apply_config(pio_port_t *pp, const pio_usb_configuration_t *c,

pp->debug_pin_rx = c->debug_pin_rx;
pp->debug_pin_eop = c->debug_pin_eop;

pio_sm_claim(pp->pio_usb_tx, pp->sm_tx);
pio_sm_claim(pp->pio_usb_rx, pp->sm_rx);
pio_sm_claim(pp->pio_usb_rx, pp->sm_eop);
}

static void port_pin_drive_setting(const root_port_t *port) {
Expand All @@ -332,16 +443,36 @@ static void port_pin_drive_setting(const root_port_t *port) {
gpio_set_drive_strength(port->pin_dm, GPIO_DRIVE_STRENGTH_12MA);
}

static void get_dma_channel(pio_port_t *pp, const pio_usb_configuration_t *c) {
if (c->tx_ch < 0) {
pp->tx_ch = dma_claim_unused_channel(true);
} else {
pp->tx_ch = c->tx_ch;
dma_channel_claim(pp->tx_ch + 1);
}
}

static void dump_allocated_hw_resources(
const pio_port_t *pp, uint tx_inst_count, uint rx_inst_count) {
printf("pio-usb is using:\n");
printf("\tUSB transmitter: %d instructions @ PIO %d, State Machine %d, DMA %d\n",
tx_inst_count, pp->pio_usb_tx == pio1 ? 1 : 0, pp->sm_tx, pp->tx_ch);
printf("\tUSB receiver: %d instructions @ PIO %d, State Machines %d and %d\n",
rx_inst_count, pp->pio_usb_rx == pio1 ? 1 : 0, pp->sm_rx, pp->sm_eop);
}

void pio_usb_bus_init(pio_port_t *pp, const pio_usb_configuration_t *c,
root_port_t *root) {
memset(root, 0, sizeof(root_port_t));
uint tx_inst_count = 0, rx_inst_count = 0;

pp->pio_usb_tx = pio_get_instance(c->pio_tx_num);
dma_claim_mask(1<<c->tx_ch);
configure_tx_channel(c->tx_ch, pp->pio_usb_tx, c->sm_tx);
memset(root, 0, sizeof(root_port_t));
get_dma_channel(pp, c);

apply_config(pp, c, root);
initialize_host_programs(pp, c, root);
if (!init_host_programs(pp, c, root, &tx_inst_count, &rx_inst_count))
panic("pio-usb: Not enough hardware resources - State Machines and instructions");
configure_tx_channel(pp->tx_ch, pp->pio_usb_tx, pp->sm_tx);

port_pin_drive_setting(root);
root->initialized = true;
root->dev_addr = 0;
Expand All @@ -355,6 +486,8 @@ void pio_usb_bus_init(pio_port_t *pp, const pio_usb_configuration_t *c,
pio_usb_ll_encode_tx_data(raw_packet, 2, stall_encoded);
raw_packet[1] = USB_PID_PRE;
pio_usb_ll_encode_tx_data(raw_packet, 2, pre_encoded);

dump_allocated_hw_resources(pp, tx_inst_count, rx_inst_count);
}

//--------------------------------------------------------------------+
Expand Down
24 changes: 12 additions & 12 deletions src/pio_usb_configuration.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ typedef enum {

typedef struct {
uint8_t pin_dp;
uint8_t pio_tx_num;
uint8_t sm_tx;
uint8_t tx_ch;
uint8_t pio_rx_num;
uint8_t sm_rx;
uint8_t sm_eop;
int8_t pio_tx_num;
int8_t sm_tx;
int8_t tx_ch;
int8_t pio_rx_num;
int8_t sm_rx;
int8_t sm_eop;
void* alarm_pool;
int8_t debug_pin_rx;
int8_t debug_pin_eop;
Expand All @@ -25,13 +25,13 @@ typedef struct {
#define PIO_USB_DP_PIN_DEFAULT 0
#endif

#define PIO_USB_TX_DEFAULT 0
#define PIO_SM_USB_TX_DEFAULT 0
#define PIO_USB_DMA_TX_DEFAULT 0
#define PIO_USB_TX_DEFAULT (-1)
#define PIO_SM_USB_TX_DEFAULT (-1)
#define PIO_USB_DMA_TX_DEFAULT (-1)

#define PIO_USB_RX_DEFAULT 0
#define PIO_SM_USB_RX_DEFAULT 1
#define PIO_SM_USB_EOP_DEFAULT 2
#define PIO_USB_RX_DEFAULT (-1)
#define PIO_SM_USB_RX_DEFAULT (-1)
#define PIO_SM_USB_EOP_DEFAULT (-1)

#define PIO_USB_DEBUG_PIN_NONE (-1)

Expand Down