Compare commits

...

5 commits

Author SHA1 Message Date
44208b33b4 Wait for complete transmission of PRE
Some checks failed
Build / build (1.5.1) (push) Has been cancelled
Build / build (2.0.0) (push) Has been cancelled
Build / build (2.1.0) (push) Has been cancelled
Build Arduino / build (rpipico) (push) Has been cancelled
.. by looking for the related state machine to enter txstall

h/t @tannewt for doing a protocol trace and noticing that there was
no LS packet transmitted after the PRE. I don't know what those words
mean but it led to me conjecturing a fix.

I also moved the clear of the IRQ complete flag above the start of the
transfer, just in case the transfer could complete before the flag was
cleared. But, I don't think this was a cause of the problem.

it may be worth looking at the other sites where IRQ_TX_EOP_MASK is used
to see whether similar treatment is necessary.

With this, a LS keyboard & LS gamepad will enumerate on my FruitJam
at 240MHz (via tools menu) & at 268MHz with HDMI display (dvhstx hard-coded
overclock)
2025-02-27 08:48:07 -06:00
Scott Shawcroft
6c6e4e0634
Switch to tx pio timing + us timer 2025-02-25 16:29:46 -08:00
Scott Shawcroft
2678a4bdc9
Use systick for better timeout tracking
Also, sideset the USB pins when starting and resetting TX. The
output may be active.
2025-02-25 10:44:29 -08:00
hathach
92ea116eb7
correctly retry setup packet 2025-02-25 15:54:06 +07:00
hathach
9c8df3083b
retry transaction up to 3 times for usb host 2025-02-19 23:47:57 +07:00
8 changed files with 221 additions and 104 deletions

View file

@ -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);

View file

@ -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++) {

View file

@ -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

View file

@ -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
//--------------------------------------------------------------------+

View file

@ -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;

View file

@ -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);

View file

@ -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

View file

@ -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]