Compare commits
5 commits
main
...
pio-txstal
| Author | SHA1 | Date | |
|---|---|---|---|
| 44208b33b4 | |||
|
|
6c6e4e0634 | ||
|
|
2678a4bdc9 | ||
|
|
92ea116eb7 | ||
|
|
9c8df3083b |
8 changed files with 221 additions and 104 deletions
236
src/pio_usb.c
236
src/pio_usb.c
|
|
@ -23,8 +23,6 @@
|
|||
#include "pio_usb_configuration.h"
|
||||
#include "pio_usb_ll.h"
|
||||
#include "usb_crc.h"
|
||||
#include "usb_tx.pio.h"
|
||||
#include "usb_rx.pio.h"
|
||||
|
||||
#define UNUSED_PARAMETER(x) (void)x
|
||||
|
||||
|
|
@ -37,29 +35,38 @@ static uint8_t ack_encoded[5];
|
|||
static uint8_t nak_encoded[5];
|
||||
static uint8_t stall_encoded[5];
|
||||
static uint8_t pre_encoded[5];
|
||||
static uint8_t wait_encoded[5];
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Bus functions
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
static void __no_inline_not_in_flash_func(send_pre)(const pio_port_t *pp) {
|
||||
static void __no_inline_not_in_flash_func(send_pre)(pio_port_t *pp) {
|
||||
// send PRE token in full-speed
|
||||
pp->low_speed = false;
|
||||
uint16_t instr = pp->fs_tx_pre_program->instructions[0];
|
||||
pp->pio_usb_tx->instr_mem[pp->offset_tx] = instr;
|
||||
|
||||
SM_SET_CLKDIV(pp->pio_usb_tx, pp->sm_tx, pp->clk_div_fs_tx);
|
||||
|
||||
pio_sm_exec(pp->pio_usb_tx, pp->sm_tx, pp->tx_start_instr);
|
||||
pp->pio_usb_tx->irq = IRQ_TX_ALL_MASK; // clear complete flag
|
||||
dma_channel_transfer_from_buffer_now(pp->tx_ch, pre_encoded,
|
||||
sizeof(pre_encoded));
|
||||
pp->pio_usb_tx->irq = IRQ_TX_ALL_MASK; // clear complete flag
|
||||
|
||||
while ((pp->pio_usb_tx->irq & IRQ_TX_EOP_MASK) == 0) {
|
||||
continue;
|
||||
}
|
||||
pio_sm_clear_fifos(pp->pio_usb_tx, pp->sm_tx);
|
||||
|
||||
// wait for complete transmission of the PRE packet
|
||||
uint32_t stall_mask = 1 << (PIO_FDEBUG_TXSTALL_LSB + pp->sm_tx);
|
||||
pp->pio_usb_tx->fdebug = stall_mask; // clear sticky stall mask bit
|
||||
while (!(pp->pio_usb_tx->fdebug & stall_mask)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// change bus speed to low-speed
|
||||
pp->low_speed = true;
|
||||
pio_sm_set_enabled(pp->pio_usb_tx, pp->sm_tx, false);
|
||||
instr = pp->fs_tx_program->instructions[0];
|
||||
pp->pio_usb_tx->instr_mem[pp->offset_tx] = instr;
|
||||
|
|
@ -75,7 +82,7 @@ static void __no_inline_not_in_flash_func(send_pre)(const pio_port_t *pp) {
|
|||
pio_sm_set_enabled(pp->pio_usb_rx, pp->sm_eop, true);
|
||||
}
|
||||
|
||||
void __not_in_flash_func(pio_usb_bus_usb_transfer)(const pio_port_t *pp,
|
||||
void __not_in_flash_func(pio_usb_bus_usb_transfer)(pio_port_t *pp,
|
||||
uint8_t *data, uint16_t len) {
|
||||
if (pp->need_pre) {
|
||||
send_pre(pp);
|
||||
|
|
@ -89,14 +96,14 @@ void __not_in_flash_func(pio_usb_bus_usb_transfer)(const pio_port_t *pp,
|
|||
while ((pp->pio_usb_tx->irq & IRQ_TX_ALL_MASK) == 0) {
|
||||
continue;
|
||||
}
|
||||
pio_sm_clear_fifos(pp->pio_usb_tx, pp->sm_tx);
|
||||
while (*pc < PIO_USB_TX_ENCODED_DATA_COMP) {
|
||||
pp->pio_usb_tx->irq = IRQ_TX_ALL_MASK; // clear complete flag
|
||||
while (*pc <= PIO_USB_TX_ENCODED_DATA_COMP) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
void __no_inline_not_in_flash_func(pio_usb_bus_send_handshake)(
|
||||
const pio_port_t *pp, uint8_t pid) {
|
||||
pio_port_t *pp, uint8_t pid) {
|
||||
switch (pid) {
|
||||
case USB_PID_ACK:
|
||||
pio_usb_bus_usb_transfer(pp, ack_encoded, 5);
|
||||
|
|
@ -113,7 +120,7 @@ void __no_inline_not_in_flash_func(pio_usb_bus_send_handshake)(
|
|||
}
|
||||
}
|
||||
|
||||
void __no_inline_not_in_flash_func(pio_usb_bus_send_token)(const pio_port_t *pp,
|
||||
void __no_inline_not_in_flash_func(pio_usb_bus_send_token)(pio_port_t *pp,
|
||||
uint8_t token,
|
||||
uint8_t addr,
|
||||
uint8_t ep_num) {
|
||||
|
|
@ -139,88 +146,127 @@ void __no_inline_not_in_flash_func(pio_usb_bus_prepare_receive)(const pio_port_t
|
|||
pio_sm_set_enabled(pp->pio_usb_rx, pp->sm_rx, true);
|
||||
}
|
||||
|
||||
void __no_inline_not_in_flash_func(pio_usb_bus_start_receive)(const pio_port_t *pp) {
|
||||
pp->pio_usb_rx->irq = IRQ_RX_ALL_MASK;
|
||||
static uint8_t __no_inline_not_in_flash_func(pio_usb_bus_wait_packet)(pio_port_t* pp) {
|
||||
uint16_t crc = 0xffff;
|
||||
uint16_t crc_prev = 0xffff;
|
||||
uint16_t crc_prev2 = 0xffff;
|
||||
uint16_t crc_receive = 0xffff;
|
||||
uint16_t crc_receive_inverse = 0;
|
||||
bool crc_match = false;
|
||||
|
||||
const uint16_t rx_buf_len = sizeof(pp->usb_rx_buffer) / sizeof(pp->usb_rx_buffer[0]);
|
||||
|
||||
if (pp->pio_usb_tx->dbg_padoe != 0) {
|
||||
gpio_put(8, 1);
|
||||
gpio_put(8, 0);
|
||||
}
|
||||
|
||||
// Wait for the handshake to start by "transmitting" a fake set of bits. They
|
||||
// aren't output to the pins. We just use it for timing.
|
||||
dma_channel_abort(pp->tx_ch);
|
||||
pio_sm_clear_fifos(pp->pio_usb_tx, pp->sm_tx);
|
||||
dma_channel_transfer_from_buffer_now(pp->tx_ch, wait_encoded,
|
||||
sizeof(wait_encoded));
|
||||
pp->pio_usb_tx->irq = IRQ_TX_ALL_MASK; // clear complete flag
|
||||
|
||||
gpio_put(7, 1);
|
||||
while ((pp->pio_usb_tx->irq & IRQ_TX_EOP_MASK) == 0) {
|
||||
if ((pp->pio_usb_rx->irq & IRQ_RX_START_MASK) != 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
dma_channel_abort(pp->tx_ch);
|
||||
while (dma_channel_is_busy(pp->tx_ch)) {
|
||||
continue;
|
||||
}
|
||||
pio_sm_clear_fifos(pp->pio_usb_tx, pp->sm_tx);
|
||||
// Wait for the OSR to drain. Otherwise we may set the irq accidentally
|
||||
// after clearing.
|
||||
while ((pp->pio_usb_tx->fdebug & PIO_FDEBUG_TXSTALL_BITS) == 0) {
|
||||
continue;
|
||||
}
|
||||
pp->pio_usb_tx->fdebug = PIO_FDEBUG_TXSTALL_BITS;
|
||||
gpio_put(7, 0);
|
||||
|
||||
// Timeout if we're not started.
|
||||
if ((pp->pio_usb_rx->irq & IRQ_RX_START_MASK) == 0) {
|
||||
gpio_put(8, 1);
|
||||
gpio_put(8, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int16_t idx = 0;
|
||||
// Timeout in seven microseconds. That is enough time to receive one byte at
|
||||
// low speed. This is to detect packets without an EOP because the device was
|
||||
// unplugged.
|
||||
uint32_t start = time_us_32();
|
||||
while (time_us_32() - start <= 7) {
|
||||
if (pio_sm_get_rx_fifo_level(pp->pio_usb_rx, pp->sm_rx)) {
|
||||
gpio_put(6, 1);
|
||||
uint8_t data = pio_sm_get(pp->pio_usb_rx, pp->sm_rx) >> 24;
|
||||
if (idx < rx_buf_len) {
|
||||
pp->usb_rx_buffer[idx] = data;
|
||||
}
|
||||
start = time_us_32();
|
||||
|
||||
if (idx >= 2) {
|
||||
crc_prev2 = crc_prev;
|
||||
crc_prev = crc;
|
||||
crc = update_usb_crc16(crc, data);
|
||||
crc_receive = (crc_receive >> 8) | (data << 8);
|
||||
crc_receive_inverse = crc_receive ^ 0xffff;
|
||||
crc_match = (crc_receive_inverse == crc_prev2);
|
||||
}
|
||||
idx++;
|
||||
gpio_put(6, 0);
|
||||
} else if ((pp->pio_usb_rx->irq & IRQ_RX_COMP_MASK) != 0) {
|
||||
// Exit early if we've gotten an EOP. There *might* be a race between EOP
|
||||
// detection and NRZI decoding but it is unlikely.
|
||||
gpio_put(7, 0);
|
||||
break;
|
||||
}
|
||||
if ((pp->pio_usb_rx->irq & IRQ_RX_COMP_MASK) != 0) {
|
||||
gpio_put(7, 1);
|
||||
}
|
||||
}
|
||||
if (time_us_32() - start > 7) {
|
||||
gpio_put(8, 1);
|
||||
gpio_put(8, 0);
|
||||
}
|
||||
|
||||
if (idx >= 4 && !crc_match) {
|
||||
gpio_put(8, 1);
|
||||
gpio_put(8, 0);
|
||||
// CRC failed, discard the packet.
|
||||
return 0;
|
||||
}
|
||||
return idx;
|
||||
}
|
||||
|
||||
uint8_t __no_inline_not_in_flash_func(pio_usb_bus_wait_handshake)(pio_port_t* pp) {
|
||||
int16_t t = 240;
|
||||
int16_t idx = 0;
|
||||
|
||||
while (t--) {
|
||||
if (pio_sm_get_rx_fifo_level(pp->pio_usb_rx, pp->sm_rx)) {
|
||||
uint8_t data = pio_sm_get(pp->pio_usb_rx, pp->sm_rx) >> 24;
|
||||
pp->usb_rx_buffer[idx++] = data;
|
||||
if (idx == 2) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
uint8_t len = pio_usb_bus_wait_packet(pp);
|
||||
if (len != 2) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (t > 0) {
|
||||
while ((pp->pio_usb_rx->irq & IRQ_RX_COMP_MASK) == 0) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// pio_sm_set_enabled(pp->pio_usb_rx, pp->sm_rx, true);
|
||||
|
||||
return pp->usb_rx_buffer[1];
|
||||
}
|
||||
|
||||
int __no_inline_not_in_flash_func(pio_usb_bus_receive_packet_and_handshake)(
|
||||
pio_port_t *pp, uint8_t handshake) {
|
||||
uint16_t crc = 0xffff;
|
||||
uint16_t crc_prev = 0xffff;
|
||||
uint16_t crc_prev2 = 0xffff;
|
||||
uint16_t crc_receive = 0xffff;
|
||||
uint16_t crc_receive_inverse;
|
||||
bool crc_match = false;
|
||||
int16_t t = 240;
|
||||
uint16_t idx = 0;
|
||||
uint16_t nak_timeout = 10000;
|
||||
const uint16_t rx_buf_len = sizeof(pp->usb_rx_buffer) / sizeof(pp->usb_rx_buffer[0]);
|
||||
|
||||
while (t--) {
|
||||
if (pio_sm_get_rx_fifo_level(pp->pio_usb_rx, pp->sm_rx)) {
|
||||
uint8_t data = pio_sm_get(pp->pio_usb_rx, pp->sm_rx) >> 24;
|
||||
pp->usb_rx_buffer[idx++] = data;
|
||||
if (idx == 2) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
uint8_t len = pio_usb_bus_wait_packet(pp);
|
||||
if (len == 0) {
|
||||
// Return and don't respond with a handshake.
|
||||
return -1;
|
||||
}
|
||||
// Only handshake if the other end gave data.
|
||||
if (len >= 4) {
|
||||
pio_usb_bus_send_handshake(pp, handshake);
|
||||
}
|
||||
|
||||
// timing critical start
|
||||
if (t > 0) {
|
||||
if (handshake == USB_PID_ACK) {
|
||||
while ((pp->pio_usb_rx->irq & IRQ_RX_COMP_MASK) == 0 && idx < rx_buf_len - 1) {
|
||||
if (pio_sm_get_rx_fifo_level(pp->pio_usb_rx, pp->sm_rx)) {
|
||||
uint8_t data = pio_sm_get(pp->pio_usb_rx, pp->sm_rx) >> 24;
|
||||
crc_prev2 = crc_prev;
|
||||
crc_prev = crc;
|
||||
crc = update_usb_crc16(crc, data);
|
||||
pp->usb_rx_buffer[idx++] = data;
|
||||
crc_receive = (crc_receive >> 8) | (data << 8);
|
||||
crc_receive_inverse = crc_receive ^ 0xffff;
|
||||
crc_match = (crc_receive_inverse == crc_prev2);
|
||||
}
|
||||
}
|
||||
|
||||
if (idx >= 4 && crc_match) {
|
||||
pio_usb_bus_send_handshake(pp, USB_PID_ACK);
|
||||
// timing critical end
|
||||
return idx - 4;
|
||||
}
|
||||
} else {
|
||||
// just discard received data since we NAK/STALL anyway
|
||||
while ((pp->pio_usb_rx->irq & IRQ_RX_COMP_MASK) == 0 && nak_timeout--) {
|
||||
continue;
|
||||
}
|
||||
pio_sm_clear_fifos(pp->pio_usb_rx, pp->sm_rx);
|
||||
|
||||
pio_usb_bus_send_handshake(pp, handshake);
|
||||
}
|
||||
if (handshake == USB_PID_ACK) {
|
||||
return len - 4;
|
||||
}
|
||||
|
||||
return -1;
|
||||
|
|
@ -244,8 +290,9 @@ static void __no_inline_not_in_flash_func(initialize_host_programs)(
|
|||
pp->offset_tx = 0;
|
||||
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);
|
||||
uint32_t sideset_fj_lk = pio_encode_sideset(2, usb_tx_dpdm_FJ_LK);
|
||||
pp->tx_start_instr = pio_encode_jmp(pp->offset_tx + 4) | sideset_fj_lk;
|
||||
pp->tx_reset_instr = pio_encode_jmp(pp->offset_tx + 2) | sideset_fj_lk;
|
||||
|
||||
add_pio_host_rx_program(pp->pio_usb_rx, &usb_nrzi_decoder_program,
|
||||
&usb_nrzi_decoder_debug_program, &pp->offset_rx,
|
||||
|
|
@ -346,6 +393,10 @@ void pio_usb_bus_init(pio_port_t *pp, const pio_usb_configuration_t *c,
|
|||
root->initialized = true;
|
||||
root->dev_addr = 0;
|
||||
|
||||
uint32_t core_clock_hz = clock_get_hz(clk_sys);
|
||||
pp->ticks_per_fs_bit = core_clock_hz / 12000000;
|
||||
pp->ticks_per_ls_bit = core_clock_hz / 1500000;
|
||||
|
||||
// pre-encode handshake packets
|
||||
uint8_t raw_packet[] = {USB_SYNC, USB_PID_ACK};
|
||||
pio_usb_ll_encode_tx_data(raw_packet, 2, ack_encoded);
|
||||
|
|
@ -355,6 +406,24 @@ 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);
|
||||
|
||||
// Encode wait for response
|
||||
|
||||
// Fill the buffer with Ks
|
||||
for (size_t i = 0; i < sizeof(wait_encoded); i++) {
|
||||
wait_encoded[i] = PIO_USB_TX_ENCODED_DATA_K << 6 |
|
||||
PIO_USB_TX_ENCODED_DATA_K << 4 |
|
||||
PIO_USB_TX_ENCODED_DATA_K << 2 |
|
||||
PIO_USB_TX_ENCODED_DATA_K;
|
||||
}
|
||||
// Replace our timeout with the interrupt (which is instruction 0)
|
||||
if (root->mode == PIO_USB_MODE_HOST) {
|
||||
// Hosts wait 18+ bit times. We do 20.
|
||||
wait_encoded[4] &= 0xfc;
|
||||
} else {
|
||||
// devices wait 17 bit times.
|
||||
wait_encoded[4] &= 0x3f;
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
|
|
@ -422,11 +491,11 @@ uint8_t __no_inline_not_in_flash_func(pio_usb_ll_encode_tx_data)(
|
|||
int current_state = 1;
|
||||
int bit_stuffing = 6;
|
||||
for (int idx = 0; idx < buffer_len; idx++) {
|
||||
uint8_t byte = buffer[idx];
|
||||
uint8_t data_byte = buffer[idx];
|
||||
for (int b = 0; b < 8; b++) {
|
||||
uint8_t byte_idx = bit_idx >> 2;
|
||||
encoded_data[byte_idx] <<= 2;
|
||||
if (byte & (1 << b)) {
|
||||
if (data_byte & (1 << b)) {
|
||||
if (current_state) {
|
||||
encoded_data[byte_idx] |= PIO_USB_TX_ENCODED_DATA_K;
|
||||
} else {
|
||||
|
|
@ -511,6 +580,7 @@ bool __no_inline_not_in_flash_func(pio_usb_ll_transfer_start)(endpoint_t *ep,
|
|||
ep->app_buf = buffer;
|
||||
ep->total_len = buflen;
|
||||
ep->actual_len = 0;
|
||||
ep->failed_count = 0;
|
||||
|
||||
if (ep->is_tx) {
|
||||
prepare_tx_data(ep);
|
||||
|
|
|
|||
|
|
@ -200,10 +200,10 @@ static void __no_inline_not_in_flash_func(usb_device_packet_handler)(void) {
|
|||
endpoint_t *ep = PIO_USB_ENDPOINT(ep_num << 1);
|
||||
|
||||
gpio_clr_mask(1<<4);
|
||||
uint8_t hanshake = ep->stalled
|
||||
uint8_t handshake = 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);
|
||||
int res = pio_usb_bus_receive_packet_and_handshake(pp, handshake);
|
||||
pio_sm_clear_fifos(pp->pio_usb_rx, pp->sm_rx);
|
||||
restart_usb_receiver(pp);
|
||||
pp->pio_usb_rx->irq = IRQ_RX_ALL_MASK;
|
||||
|
|
@ -257,6 +257,7 @@ usb_device_t *pio_usb_device_init(const pio_usb_configuration_t *c,
|
|||
pio_usb_bus_init(pp, c, rport);
|
||||
gpio_disable_pulls(rport->pin_dp); // needs external pull-up
|
||||
rport->mode = PIO_USB_MODE_DEVICE;
|
||||
pp->host = false;
|
||||
|
||||
memset(dev, 0, sizeof(*dev));
|
||||
for (int i = 0; i < PIO_USB_DEV_EP_CNT; i++) {
|
||||
|
|
|
|||
|
|
@ -21,6 +21,10 @@
|
|||
#include "usb_rx.pio.h"
|
||||
#include "usb_tx.pio.h"
|
||||
|
||||
enum {
|
||||
TRANSACTION_MAX_RETRY = 3, // Number of times to retry a failed transaction
|
||||
};
|
||||
|
||||
static alarm_pool_t *_alarm_pool = NULL;
|
||||
static repeating_timer_t sof_rt;
|
||||
// The sof_count may be incremented and then read on different cores.
|
||||
|
|
@ -64,6 +68,7 @@ usb_device_t *pio_usb_host_init(const pio_usb_configuration_t *c) {
|
|||
|
||||
pio_usb_bus_init(pp, c, root);
|
||||
root->mode = PIO_USB_MODE_HOST;
|
||||
pp->host = true;
|
||||
|
||||
float const cpu_freq = (float)clock_get_hz(clk_sys);
|
||||
pio_calculate_clkdiv_from_float(cpu_freq / 48000000,
|
||||
|
|
@ -148,6 +153,7 @@ __no_inline_not_in_flash_func(configure_tx_program)(pio_port_t *pp,
|
|||
|
||||
static void __no_inline_not_in_flash_func(configure_fullspeed_host)(
|
||||
pio_port_t *pp, root_port_t *port) {
|
||||
pp->low_speed = false;
|
||||
configure_tx_program(pp, port);
|
||||
pio_sm_clear_fifos(pp->pio_usb_tx, pp->sm_tx);
|
||||
override_pio_program(pp->pio_usb_tx, pp->fs_tx_program, pp->offset_tx);
|
||||
|
|
@ -165,6 +171,7 @@ static void __no_inline_not_in_flash_func(configure_fullspeed_host)(
|
|||
|
||||
static void __no_inline_not_in_flash_func(configure_lowspeed_host)(
|
||||
pio_port_t *pp, root_port_t *port) {
|
||||
pp->low_speed = true;
|
||||
configure_tx_program(pp, port);
|
||||
pio_sm_clear_fifos(pp->pio_usb_tx, pp->sm_tx);
|
||||
override_pio_program(pp->pio_usb_tx, pp->ls_tx_program, pp->offset_tx);
|
||||
|
|
@ -189,8 +196,9 @@ static void __no_inline_not_in_flash_func(configure_root_port)(
|
|||
}
|
||||
}
|
||||
|
||||
static void __no_inline_not_in_flash_func(restore_fs_bus)(const pio_port_t *pp) {
|
||||
static void __no_inline_not_in_flash_func(restore_fs_bus)(pio_port_t *pp) {
|
||||
// change bus speed to full-speed
|
||||
pp->low_speed = false;
|
||||
pio_sm_set_enabled(pp->pio_usb_tx, pp->sm_tx, false);
|
||||
SM_SET_CLKDIV(pp->pio_usb_tx, pp->sm_tx, pp->clk_div_fs_tx);
|
||||
pio_sm_set_enabled(pp->pio_usb_tx, pp->sm_tx, true);
|
||||
|
|
@ -206,8 +214,8 @@ static void __no_inline_not_in_flash_func(restore_fs_bus)(const pio_port_t *pp)
|
|||
|
||||
// Time about 1us ourselves so it lives in RAM.
|
||||
static void __not_in_flash_func(busy_wait_1_us)(void) {
|
||||
uint32_t start = timer_hw->timerawl;
|
||||
while (timer_hw->timerawl == start) {
|
||||
uint32_t start = time_us_32();
|
||||
while (time_us_32() == start) {
|
||||
tight_loop_contents();
|
||||
}
|
||||
}
|
||||
|
|
@ -535,7 +543,16 @@ static int __no_inline_not_in_flash_func(usb_in_transaction)(pio_port_t *pp,
|
|||
if ((pp->pio_usb_rx->irq & IRQ_RX_COMP_MASK) == 0) {
|
||||
res = -2;
|
||||
}
|
||||
pio_usb_ll_transfer_complete(ep, PIO_USB_INTS_ENDPOINT_ERROR_BITS);
|
||||
gpio_put(8, 1);
|
||||
gpio_put(8, 0);
|
||||
|
||||
if (++ep->failed_count > TRANSACTION_MAX_RETRY) {
|
||||
pio_usb_ll_transfer_complete(ep, PIO_USB_INTS_ENDPOINT_ERROR_BITS); // failed after 3 consecutive retries
|
||||
}
|
||||
}
|
||||
|
||||
if (res == 0) {
|
||||
ep->failed_count = 0; // reset failed count if we got a sound response
|
||||
}
|
||||
|
||||
pio_sm_set_enabled(pp->pio_usb_rx, pp->sm_rx, false);
|
||||
|
|
@ -569,7 +586,14 @@ static int __no_inline_not_in_flash_func(usb_out_transaction)(pio_port_t *pp,
|
|||
} else if (receive_token == USB_PID_STALL) {
|
||||
pio_usb_ll_transfer_complete(ep, PIO_USB_INTS_ENDPOINT_STALLED_BITS);
|
||||
} else {
|
||||
pio_usb_ll_transfer_complete(ep, PIO_USB_INTS_ENDPOINT_ERROR_BITS);
|
||||
res = -1;
|
||||
if (++ep->failed_count > TRANSACTION_MAX_RETRY) {
|
||||
pio_usb_ll_transfer_complete(ep, PIO_USB_INTS_ENDPOINT_ERROR_BITS);
|
||||
}
|
||||
}
|
||||
|
||||
if (res == 0) {
|
||||
ep->failed_count = 0;// reset failed count if we got a sound response
|
||||
}
|
||||
|
||||
pio_sm_set_enabled(pp->pio_usb_rx, pp->sm_rx, false);
|
||||
|
|
@ -581,7 +605,6 @@ static int __no_inline_not_in_flash_func(usb_out_transaction)(pio_port_t *pp,
|
|||
|
||||
static int __no_inline_not_in_flash_func(usb_setup_transaction)(
|
||||
pio_port_t *pp, endpoint_t *ep) {
|
||||
|
||||
int res = 0;
|
||||
|
||||
// Setup token
|
||||
|
|
@ -598,13 +621,19 @@ static int __no_inline_not_in_flash_func(usb_setup_transaction)(
|
|||
pio_usb_bus_wait_handshake(pp);
|
||||
pio_sm_set_enabled(pp->pio_usb_rx, pp->sm_rx, false);
|
||||
|
||||
ep->actual_len = 8;
|
||||
|
||||
if (pp->usb_rx_buffer[0] == USB_SYNC && pp->usb_rx_buffer[1] == USB_PID_ACK) {
|
||||
ep->actual_len = 8;
|
||||
pio_usb_ll_transfer_complete(ep, PIO_USB_INTS_ENDPOINT_COMPLETE_BITS);
|
||||
} else {
|
||||
res = -1;
|
||||
pio_usb_ll_transfer_complete(ep, PIO_USB_INTS_ENDPOINT_ERROR_BITS);
|
||||
ep->data_id = USB_PID_SETUP; // retry setup
|
||||
if (++ep->failed_count > TRANSACTION_MAX_RETRY) {
|
||||
pio_usb_ll_transfer_complete(ep, PIO_USB_INTS_ENDPOINT_ERROR_BITS);
|
||||
}
|
||||
}
|
||||
|
||||
if (res == 0) {
|
||||
ep->failed_count = 0;// reset failed count if we got a sound response
|
||||
}
|
||||
|
||||
pp->usb_rx_buffer[1] = 0; // reset buffer
|
||||
|
|
|
|||
|
|
@ -10,6 +10,9 @@
|
|||
#include "usb_definitions.h"
|
||||
#include <stdint.h>
|
||||
|
||||
#include "usb_tx.pio.h"
|
||||
#include "usb_rx.pio.h"
|
||||
|
||||
enum {
|
||||
PIO_USB_INTS_CONNECT_POS = 0,
|
||||
PIO_USB_INTS_DISCONNECT_POS,
|
||||
|
|
@ -80,6 +83,11 @@ typedef struct {
|
|||
pio_clk_div_t clk_div_ls_rx;
|
||||
|
||||
bool need_pre;
|
||||
bool low_speed;
|
||||
bool host;
|
||||
|
||||
uint ticks_per_ls_bit;
|
||||
uint ticks_per_fs_bit;
|
||||
|
||||
uint8_t usb_rx_buffer[128];
|
||||
} pio_port_t;
|
||||
|
|
@ -112,6 +120,7 @@ extern pio_port_t pio_port[1];
|
|||
#define IRQ_TX_EOP_MASK (1 << IRQ_TX_EOP)
|
||||
#define IRQ_TX_ALL_MASK (IRQ_TX_EOP_MASK)
|
||||
#define IRQ_RX_COMP_MASK (1 << IRQ_RX_EOP)
|
||||
#define IRQ_RX_START_MASK (1 << IRQ_RX_START)
|
||||
#define IRQ_RX_ALL_MASK \
|
||||
((1 << IRQ_RX_EOP) | (1 << IRQ_RX_BS_ERR) | (1 << IRQ_RX_START) | \
|
||||
(1 << DECODER_TRIGGER))
|
||||
|
|
@ -124,15 +133,14 @@ extern pio_port_t pio_port[1];
|
|||
void pio_usb_bus_init(pio_port_t *pp, const pio_usb_configuration_t *c,
|
||||
root_port_t *root);
|
||||
|
||||
void pio_usb_bus_start_receive(const pio_port_t *pp);
|
||||
void pio_usb_bus_prepare_receive(const pio_port_t *pp);
|
||||
int pio_usb_bus_receive_packet_and_handshake(pio_port_t *pp, uint8_t handshake);
|
||||
void pio_usb_bus_usb_transfer(const pio_port_t *pp, uint8_t *data,
|
||||
void pio_usb_bus_usb_transfer(pio_port_t *pp, uint8_t *data,
|
||||
uint16_t len);
|
||||
|
||||
uint8_t pio_usb_bus_wait_handshake(pio_port_t *pp);
|
||||
void pio_usb_bus_send_handshake(const pio_port_t *pp, uint8_t pid);
|
||||
void pio_usb_bus_send_token(const pio_port_t *pp, uint8_t token, uint8_t addr,
|
||||
void pio_usb_bus_send_handshake(pio_port_t *pp, uint8_t pid);
|
||||
void pio_usb_bus_send_token(pio_port_t *pp, uint8_t token, uint8_t addr,
|
||||
uint8_t ep_num);
|
||||
|
||||
static __always_inline port_pin_status_t
|
||||
|
|
@ -143,6 +151,12 @@ pio_usb_bus_get_line_state(root_port_t *root) {
|
|||
return (dm << 1) | dp;
|
||||
}
|
||||
|
||||
static __always_inline void pio_usb_bus_start_receive(const pio_port_t *pp) {
|
||||
gpio_put(6, 1);
|
||||
pp->pio_usb_rx->irq = IRQ_RX_ALL_MASK;
|
||||
gpio_put(6, 0);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Low Level functions
|
||||
//--------------------------------------------------------------------+
|
||||
|
|
|
|||
|
|
@ -75,6 +75,8 @@ typedef struct {
|
|||
|
||||
uint8_t buffer[(64 + 4) * 2 * 7 / 6 + 2];
|
||||
uint8_t encoded_data_len;
|
||||
uint8_t failed_count;
|
||||
|
||||
uint8_t *app_buf;
|
||||
uint16_t total_len;
|
||||
uint16_t actual_len;
|
||||
|
|
|
|||
|
|
@ -196,7 +196,7 @@ static inline void usb_rx_fs_program_init(PIO pio, uint sm, uint offset, uint pi
|
|||
}
|
||||
sm_config_set_in_pins(&c, pin_dp); // for WAIT, IN
|
||||
sm_config_set_jmp_pin(&c, pin_dp); // for JMP
|
||||
// Shift to right, autopull enabled, 8bit
|
||||
// Shift to right, autopush enabled, 8bit
|
||||
sm_config_set_in_shift(&c, true, true, 8);
|
||||
sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_RX);
|
||||
pio_sm_init(pio, sm, offset, &c);
|
||||
|
|
|
|||
|
|
@ -3,15 +3,15 @@
|
|||
.define public IRQ_TX_EOP 0 ; EOP start flag bit
|
||||
|
||||
; USB NRZI transmitter
|
||||
; Run at 48 MHz for full-spped (x4)
|
||||
; Run at 6 MHz for low-spped (x4)
|
||||
; Run at 48 MHz for full-speed (x4)
|
||||
; Run at 6 MHz for low-speed (x4)
|
||||
; autopull enabled
|
||||
; Should be placed at address 0
|
||||
.program usb_tx_dpdm
|
||||
.side_set 2
|
||||
|
||||
; J for fs, K for ls
|
||||
.define FJ_LK 0b01
|
||||
.define public FJ_LK 0b01
|
||||
; K for fs, J for ls
|
||||
.define FK_LJ 0b10
|
||||
.define SE0 0b00
|
||||
|
|
@ -49,8 +49,8 @@ set pindirs, 0b11 side FJ_LK
|
|||
.wrap
|
||||
|
||||
; USB NRZI transmitter
|
||||
; Run at 48 MHz for full-spped
|
||||
; Run at 6 MHz for low-spped
|
||||
; Run at 48 MHz for full-speed
|
||||
; Run at 6 MHz for low-speed
|
||||
; autopull enabled
|
||||
.program usb_tx_dmdp
|
||||
.side_set 2
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
#define usb_tx_dpdm_wrap_target 1
|
||||
#define usb_tx_dpdm_wrap 4
|
||||
#define usb_tx_dpdm_FJ_LK 1
|
||||
|
||||
static const uint16_t __not_in_flash("tx_program") usb_tx_dpdm_program_instructions[] = {
|
||||
0xc700, // 0: irq nowait 0 side 0 [7]
|
||||
|
|
|
|||
Loading…
Reference in a new issue