Skip to content

Commit 1173833

Browse files
committed
host: fix bus turnaround (inter-packet delay) when sending handshake after received data from device
host: send keep-alive packet instead of SOF on lowspeed bus
1 parent fdd723f commit 1173833

File tree

2 files changed

+27
-4
lines changed

2 files changed

+27
-4
lines changed

src/pio_usb.c

+18-3
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ void __not_in_flash_func(pio_usb_bus_usb_transfer)(pio_port_t *pp,
9797
continue;
9898
}
9999
pp->pio_usb_tx->irq = IRQ_TX_ALL_MASK; // clear complete flag
100-
while (*pc < PIO_USB_TX_ENCODED_DATA_COMP) {
100+
while (*pc <= PIO_USB_TX_ENCODED_DATA_COMP) {
101101
continue;
102102
}
103103
}
@@ -206,6 +206,19 @@ int __no_inline_not_in_flash_func(pio_usb_bus_receive_packet_and_handshake)(
206206
const uint16_t rx_buf_len = sizeof(pp->usb_rx_buffer) / sizeof(pp->usb_rx_buffer[0]);
207207
int16_t idx = 0;
208208

209+
// Per USB Specs 7.1.18 for turnaround: We must wait at least 2 bit times for inter-packet delay.
210+
// This is essential for working with LS device specially when we overlocked the mcu.
211+
// Pre-calculate number of cycle per bit time
212+
// - Lowspeed: 1 bit time = (cpufreq / 1.5 Mhz) = clk_div_ls_tx.div_int*6Mhz / 1.5 Mhz = 4 * clk_div_ls_tx.div_int
213+
// - Fullspeed 1 bit time = (cpufreq / 12 Mhz) = clk_div_fs_tx.div_int*48Mhz / 12 Mhz = 4 * clk_div_fs_tx.div_int
214+
// Since there is also overhead, we only wait 1.5 bit for LS and 1 bit for FS
215+
uint32_t turnaround_in_cycle;
216+
if (pp->low_speed) {
217+
turnaround_in_cycle = 6 * pp->clk_div_ls_tx.div_int; // 1.5 bit time
218+
} else {
219+
turnaround_in_cycle = 4 * pp->clk_div_fs_tx.div_int; // 1 bit time
220+
}
221+
209222
// Timeout in seven microseconds. That is enough time to receive one byte at low speed.
210223
// This is to detect packets without an EOP because the device was unplugged.
211224
uint32_t start = get_time_us_32();
@@ -227,8 +240,10 @@ int __no_inline_not_in_flash_func(pio_usb_bus_receive_packet_and_handshake)(
227240
}
228241
idx++;
229242
} else if ((pp->pio_usb_rx->irq & IRQ_RX_COMP_MASK) != 0) {
230-
// Exit early if we've gotten an EOP. There *might* be a race between EOP
231-
// detection and NRZI decoding but it is unlikely.
243+
// Exit since we've gotten an EOP.
244+
// Timing critical: pre specs handshake must be sent within 2-7 bit-time strictly
245+
busy_wait_at_least_cycles(turnaround_in_cycle); // wait for turnaround
246+
232247
if (handshake == USB_PID_ACK) {
233248
// Only ACK if crc matches
234249
if (idx >= 4 && crc_match) {

src/pio_usb_host.c

+9-1
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ static __unused uint32_t int_stat;
3535
static uint8_t sof_packet[4] = {USB_SYNC, USB_PID_SOF, 0x00, 0x10};
3636
static uint8_t sof_packet_encoded[4 * 2 * 7 / 6 + 2];
3737
static uint8_t sof_packet_encoded_len;
38+
static uint8_t keepalive_encoded[1];
3839

3940
static bool sof_timer(repeating_timer_t *_rt);
4041

@@ -84,6 +85,7 @@ usb_device_t *pio_usb_host_init(const pio_usb_configuration_t *c) {
8485

8586
sof_packet_encoded_len =
8687
pio_usb_ll_encode_tx_data(sof_packet, sizeof(sof_packet), sof_packet_encoded);
88+
pio_usb_ll_encode_tx_data(NULL, 0, keepalive_encoded);
8789

8890
if (!c->skip_alarm_pool) {
8991
_alarm_pool = c->alarm_pool;
@@ -266,7 +268,13 @@ void __not_in_flash_func(pio_usb_host_frame)(void) {
266268
continue;
267269
}
268270
configure_root_port(pp, root);
269-
pio_usb_bus_usb_transfer(pp, sof_packet_encoded, sof_packet_encoded_len);
271+
if (root->is_fullspeed) {
272+
// Send SOF for full speed
273+
pio_usb_bus_usb_transfer(pp, sof_packet_encoded, sof_packet_encoded_len);
274+
} else {
275+
// Send Keep alive for low speed
276+
pio_usb_bus_usb_transfer(pp, keepalive_encoded, 1);
277+
}
270278
}
271279

272280
// Carry out all queued endpoint transaction

0 commit comments

Comments
 (0)