Update pio_usb_device

This commit is contained in:
sekigon-gonnoc 2024-06-09 22:26:01 +09:00
parent 30283a92c8
commit ef9d780504
5 changed files with 110 additions and 40 deletions

View file

@ -163,7 +163,7 @@ uint8_t __no_inline_not_in_flash_func(pio_usb_bus_wait_handshake)(pio_port_t* pp
}
}
pio_sm_set_enabled(pp->pio_usb_rx, pp->sm_rx, false);
// pio_sm_set_enabled(pp->pio_usb_rx, pp->sm_rx, true);
return pp->usb_rx_buffer[1];
}

View file

@ -20,6 +20,8 @@
#include "hardware/dma.h"
#include "hardware/irq.h"
#include "hardware/gpio.h"
#include "hardware/pio.h"
static uint8_t new_devaddr = 0;
static uint8_t ep0_crc5_lut[16];
@ -39,19 +41,42 @@ static void __no_inline_not_in_flash_func(update_ep0_crc5_lut)(uint8_t addr) {
}
}
static __always_inline void restart_usb_reveiver(pio_port_t *pp) {
pio_sm_exec(pp->pio_usb_rx, pp->sm_rx, pp->rx_reset_instr);
static __always_inline void restart_usb_receiver(pio_port_t *pp) {
pio_sm_exec(pp->pio_usb_rx, pp->sm_rx, pp->rx_reset_instr2);
pio_sm_restart(pp->pio_usb_rx, pp->sm_rx);
pp->pio_usb_rx->irq = IRQ_RX_ALL_MASK;
}
static __always_inline int8_t device_receive_token(uint8_t *buffer,
uint8_t dev_addr) {
static __always_inline uint8_t device_receive_token(void) {
pio_port_t *pp = PIO_USB_PIO_PORT(0);
uint8_t idx = 0;
uint8_t buffer[2];
if ((pp->pio_usb_rx->irq & IRQ_RX_COMP_MASK) == 0) {
while ((pp->pio_usb_rx->irq & IRQ_RX_COMP_MASK) == 0) {
if (pio_sm_get_rx_fifo_level(pp->pio_usb_rx, pp->sm_rx)) {
buffer[idx++] = pio_sm_get(pp->pio_usb_rx, pp->sm_rx) >> 24;
if (idx == 2) {
return buffer[1];
}
}
}
} else {
// host is probably timeout. Ignore this packets.
pio_sm_clear_fifos(pp->pio_usb_rx, pp->sm_rx);
}
return 0;
}
static __always_inline int8_t device_receive_ep_address(uint8_t token,
uint8_t dev_addr) {
pio_port_t *pp = PIO_USB_PIO_PORT(0);
uint8_t idx = 0;
uint8_t addr;
uint8_t ep;
uint8_t ep_num = 0;
uint8_t buffer[3];
bool match = false;
static uint8_t eplut[2][8] = {{0, 2, 4, 6, 8, 10, 12, 14},
@ -62,10 +87,13 @@ static __always_inline int8_t device_receive_token(uint8_t *buffer,
while ((pp->pio_usb_rx->irq & IRQ_RX_COMP_MASK) == 0) {
if (pio_sm_get_rx_fifo_level(pp->pio_usb_rx, pp->sm_rx)) {
buffer[idx++] = pio_sm_get(pp->pio_usb_rx, pp->sm_rx) >> 24;
if ((idx == 3) && (buffer[1] != USB_PID_SOF)) {
addr = buffer[2] & 0x7f;
current_lut = &eplut[buffer[2] >> 7][0];
if ((idx == 1) && (token != USB_PID_SOF)) {
addr = buffer[0] & 0x7f;
current_lut = &eplut[buffer[0] >> 7][0];
match = dev_addr == addr ? true : false;
} else if (idx == 2) {
ep_num = buffer[1];
break;
}
}
}
@ -74,11 +102,9 @@ static __always_inline int8_t device_receive_token(uint8_t *buffer,
pio_sm_clear_fifos(pp->pio_usb_rx, pp->sm_rx);
}
restart_usb_reveiver(pp);
if (match) {
ep = current_lut[buffer[3] & 0x07];
if (ep0_crc5_lut[ep] == buffer[3]) {
ep = current_lut[ep_num & 0x07];
if (ep0_crc5_lut[ep] == ep_num) {
return ep;
} else {
return -1;
@ -88,34 +114,42 @@ static __always_inline int8_t device_receive_token(uint8_t *buffer,
return -1;
}
static __always_inline void wait_receive_complete(pio_port_t *pp) {
while ((pp->pio_usb_rx->irq & IRQ_RX_COMP_MASK) == 0) {
continue;
}
pio_sm_clear_fifos(pp->pio_usb_rx, pp->sm_rx);
}
static void __no_inline_not_in_flash_func(usb_device_packet_handler)(void) {
static uint8_t token_buf[64];
pio_port_t *pp = PIO_USB_PIO_PORT(0);
root_port_t *rport = PIO_USB_ROOT_PORT(0);
gpio_clr_mask(1<<3);
//
// time critical start
//
int8_t ep_num = device_receive_token(token_buf, rport->dev_addr);
uint8_t addr = rport->dev_addr;
uint8_t token = device_receive_token();
if (token_buf[1] == USB_PID_IN) {
if (token == USB_PID_IN) {
int8_t ep_num = device_receive_ep_address(token, addr);
if (ep_num < 0) {
gpio_set_mask(1 << 3);
return;
}
endpoint_t *ep = PIO_USB_ENDPOINT((ep_num << 1) | 0x01);
uint16_t const xact_len = pio_usb_ll_get_transaction_len(ep);
pio_sm_set_enabled(pp->pio_usb_rx, pp->sm_rx, false);
pio_sm_exec(pp->pio_usb_tx, pp->sm_tx, pp->tx_start_instr);
volatile bool has_transfer = ep->has_transfer;
if (has_transfer) {
dma_channel_transfer_from_buffer_now(pp->tx_ch, ep->buffer, ep->encoded_data_len);
} else if (ep->stalled) {
dma_channel_transfer_from_buffer_now(pp->tx_ch, stall_encoded, 5);
dma_channel_transfer_from_buffer_now(pp->tx_ch, stall_encoded, sizeof(stall_encoded));
} else {
dma_channel_transfer_from_buffer_now(pp->tx_ch, nak_encoded, 5);
dma_channel_transfer_from_buffer_now(pp->tx_ch, nak_encoded, sizeof(nak_encoded));
}
pp->pio_usb_tx->irq = IRQ_TX_ALL_MASK; // clear complete flag
@ -144,28 +178,35 @@ static void __no_inline_not_in_flash_func(usb_device_packet_handler)(void) {
update_ep0_crc5_lut(rport->dev_addr);
}
pio_usb_ll_transfer_continue(ep, xact_len);
rport->ints |= PIO_USB_INTS_ENDPOINT_CONTINUE_BITS;
rport->ep_continue |= (1 << ep_num);
} else {
pp->pio_usb_rx->irq = IRQ_RX_ALL_MASK;
irq_clear(pp->device_rx_irq_num);
restart_usb_receiver(pp);
pio_usb_bus_start_receive(pp);
//
// time critical end
//
}
} else if (token_buf[1] == USB_PID_OUT) {
} else if (token == USB_PID_OUT) {
int8_t ep_num = device_receive_ep_address(token, addr);
wait_receive_complete(pp);
restart_usb_receiver(pp);
if (ep_num < 0) {
return;
}
endpoint_t *ep = PIO_USB_ENDPOINT(ep_num << 1);
gpio_clr_mask(1<<4);
uint8_t hanshake = ep->stalled
? USB_PID_STALL
: (ep->has_transfer ? USB_PID_ACK : USB_PID_NAK);
int res = pio_usb_bus_receive_packet_and_handshake(pp, hanshake);
pio_sm_clear_fifos(pp->pio_usb_rx, pp->sm_rx);
restart_usb_reveiver(pp);
restart_usb_receiver(pp);
pp->pio_usb_rx->irq = IRQ_RX_ALL_MASK;
irq_clear(pp->device_rx_irq_num);
if (ep->has_transfer) {
@ -174,13 +215,16 @@ static void __no_inline_not_in_flash_func(usb_device_packet_handler)(void) {
pio_usb_ll_transfer_continue(ep, res);
}
}
} else if (token_buf[1] == USB_PID_SETUP) {
} else if (token == USB_PID_SETUP) {
int8_t ep_num = device_receive_ep_address(token, addr);
restart_usb_receiver(pp);
if (ep_num < 0) {
return;
}
int res = pio_usb_bus_receive_packet_and_handshake(pp, USB_PID_ACK);
pio_sm_clear_fifos(pp->pio_usb_rx, pp->sm_rx);
restart_usb_reveiver(pp);
restart_usb_receiver(pp);
pp->pio_usb_rx->irq = IRQ_RX_ALL_MASK;
irq_clear(pp->device_rx_irq_num);
if (res >= 0) {
@ -192,16 +236,15 @@ static void __no_inline_not_in_flash_func(usb_device_packet_handler)(void) {
PIO_USB_ENDPOINT(0)->data_id = PIO_USB_ENDPOINT(1)->data_id = 1;
PIO_USB_ENDPOINT(0)->stalled = PIO_USB_ENDPOINT(1)->stalled = false;
}
} else if (token_buf[1] == USB_PID_SOF) {
} else if (token == USB_PID_SOF) {
// SOF interrupt
}
token_buf[0] = 0; // clear received token
token_buf[1] = 0;
if (rport->ints) {
pio_usb_device_irq_handler(0);
device_receive_ep_address(token, addr);
wait_receive_complete(pp);
restart_usb_receiver(pp);
} else {
device_receive_ep_address(token, addr);
wait_receive_complete(pp);
restart_usb_receiver(pp);
}
}
@ -212,6 +255,7 @@ usb_device_t *pio_usb_device_init(const pio_usb_configuration_t *c,
usb_device_t *dev = &pio_usb_device[0];
pio_usb_bus_init(pp, c, rport);
gpio_disable_pulls(rport->pin_dp); // needs external pull-up
rport->mode = PIO_USB_MODE_DEVICE;
memset(dev, 0, sizeof(*dev));
@ -231,18 +275,18 @@ usb_device_t *pio_usb_device_init(const pio_usb_configuration_t *c,
&pp->clk_div_fs_rx.div_frac);
pio_sm_set_jmp_pin(pp->pio_usb_rx, pp->sm_rx, rport->pin_dp);
pio_sm_set_enabled(pp->pio_usb_rx, pp->sm_rx, false);
SM_SET_CLKDIV_MAXSPEED(pp->pio_usb_rx, pp->sm_rx);
pio_sm_set_enabled(pp->pio_usb_rx, pp->sm_rx, true);
pio_sm_set_jmp_pin(pp->pio_usb_rx, pp->sm_eop, rport->pin_dm);
pio_sm_set_in_pins(pp->pio_usb_rx, pp->sm_eop, rport->pin_dp);
pio_sm_set_enabled(pp->pio_usb_rx, pp->sm_eop, false);
SM_SET_CLKDIV(pp->pio_usb_rx, pp->sm_eop, pp->clk_div_fs_rx);
descriptor_buffers = *buffers;
pio_sm_set_enabled(pp->pio_usb_tx, pp->sm_tx, true);
pio_usb_bus_prepare_receive(pp);
pp->pio_usb_rx->ctrl |= (1 << pp->sm_rx);
pp->pio_usb_rx->irq |= IRQ_RX_ALL_MASK;
// configure PIOx_IRQ_0 to detect packet receive start
pio_set_irqn_source_enabled(pp->pio_usb_rx, 0, pis_interrupt0 + IRQ_RX_START,
@ -323,6 +367,12 @@ static void __no_inline_not_in_flash_func(prepare_ep0_rx)(uint8_t *data,
}
void pio_usb_device_task(void) {
root_port_t *rport = PIO_USB_ROOT_PORT(0);
pio_port_t *pp = PIO_USB_PIO_PORT(0);
if (rport->ints) {
pio_usb_device_irq_handler(0);
}
switch (ep0_desc_request_type) {
case DESC_TYPE_CONFIG: {
uint16_t req_len = ep0_desc_request_len;
@ -348,8 +398,8 @@ void pio_usb_device_task(void) {
break;
}
root_port_t *rport = PIO_USB_ROOT_PORT(0);
uint32_t se0_time_us =0;
bool reset = false;
while (pio_usb_bus_get_line_state(rport) == PORT_PIN_SE0) {
busy_wait_us_32(1);
se0_time_us++;
@ -371,11 +421,14 @@ void pio_usb_device_task(void) {
// TODO should be reset end, this is reset start only
rport->ep_complete = rport->ep_stalled = rport->ep_error = 0;
rport->ints |= PIO_USB_INTS_RESET_END_BITS;
pio_port_t *pp = PIO_USB_PIO_PORT(0);
restart_usb_reveiver(pp);
reset = true;
}
}
if (reset) {
restart_usb_receiver(pp);
pio_sm_set_enabled(pp->pio_usb_rx, pp->sm_eop, true);
pp->pio_usb_rx->irq = IRQ_RX_ALL_MASK;
}
}
static void __no_inline_not_in_flash_func(configure_all_endpoints)(uint8_t const *desc) {
@ -496,6 +549,17 @@ static void __no_inline_not_in_flash_func(__pio_usb_device_irq_handler)(uint8_t
root->ep_complete &= ~ep_all;
}
if (ints & PIO_USB_INTS_ENDPOINT_CONTINUE_BITS) {
for (int b = 0; b < 16; b++) {
if (root->ep_continue & (1 << b)) {
endpoint_t *ep = PIO_USB_ENDPOINT((b << 1) | 0x01);
uint16_t const xact_len = pio_usb_ll_get_transaction_len(ep);
pio_usb_ll_transfer_continue(ep, xact_len);
root->ep_continue &= ~(1 << b);
}
}
}
// clear all
root->ints &= ~ints;
}

View file

@ -558,6 +558,7 @@ static int __no_inline_not_in_flash_func(usb_out_transaction)(pio_port_t *pp,
pio_usb_bus_start_receive(pp);
pio_usb_bus_wait_handshake(pp);
pio_sm_set_enabled(pp->pio_usb_rx, pp->sm_rx, false);
uint8_t const receive_token = pp->usb_rx_buffer[1];
@ -595,6 +596,7 @@ static int __no_inline_not_in_flash_func(usb_setup_transaction)(
// Handshake
pio_usb_bus_start_receive(pp);
pio_usb_bus_wait_handshake(pp);
pio_sm_set_enabled(pp->pio_usb_rx, pp->sm_rx, false);
ep->actual_len = 8;

View file

@ -20,6 +20,7 @@ enum {
PIO_USB_INTS_ENDPOINT_COMPLETE_POS,
PIO_USB_INTS_ENDPOINT_ERROR_POS,
PIO_USB_INTS_ENDPOINT_STALLED_POS,
PIO_USB_INTS_ENDPOINT_CONTINUE_POS,
};
#define PIO_USB_INTS_CONNECT_BITS (1u << PIO_USB_INTS_CONNECT_POS)
@ -34,6 +35,8 @@ enum {
#define PIO_USB_INTS_ENDPOINT_ERROR_BITS (1u << PIO_USB_INTS_ENDPOINT_ERROR_POS)
#define PIO_USB_INTS_ENDPOINT_STALLED_BITS \
(1u << PIO_USB_INTS_ENDPOINT_STALLED_POS)
#define PIO_USB_INTS_ENDPOINT_CONTINUE_BITS \
(1u << PIO_USB_INTS_ENDPOINT_CONTINUE_POS)
typedef enum {
PORT_PIN_SE0 = 0b00,

View file

@ -107,6 +107,7 @@ typedef struct struct_root_port_t {
volatile uint32_t ep_complete;
volatile uint32_t ep_error;
volatile uint32_t ep_stalled;
volatile uint32_t ep_continue;
// device only
uint8_t dev_addr;