Merge pull request #5877 from c1728p9/kinetis_usb_stability_fixes

Kinetis USB improvements and fixes
pull/5898/head
Cruz Monrreal 2018-01-22 10:24:23 -06:00 committed by GitHub
commit ff08b10a90
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 85 additions and 42 deletions

View File

@ -187,27 +187,8 @@ bool USBDevice::controlOut(void)
/* Check we should be transferring data OUT */ /* Check we should be transferring data OUT */
if (transfer.direction != HOST_TO_DEVICE) if (transfer.direction != HOST_TO_DEVICE)
{ {
#if defined(TARGET_KL25Z) | defined(TARGET_KL43Z) | defined(TARGET_KL46Z) | defined(TARGET_K20D5M) | defined(TARGET_K64F) | defined(TARGET_K22F) | defined(TARGET_TEENSY3_1)
/*
* We seem to have a pending device-to-host transfer. The host must have
* sent a new control request without waiting for us to finish processing
* the previous one. This appears to happen when we're connected to certain
* USB 3.0 host chip set. Do a zeor-length send to tell the host we're not
* ready for the new request - that'll make it resend - and then just
* pretend we were successful here so that the pending transfer can finish.
*/
uint8_t buf[1] = { 0 };
EP0write(buf, 0);
/* execute our pending ttransfer */
controlIn();
/* indicate success */
return true;
#else
/* for other platforms, count on the HAL to handle this case */ /* for other platforms, count on the HAL to handle this case */
return false; return false;
#endif
} }
/* Read from endpoint */ /* Read from endpoint */

View File

@ -22,6 +22,7 @@
#include "fsl_common.h" #include "fsl_common.h"
#endif #endif
#include "USBHAL.h" #include "USBHAL.h"
#include "mbed_critical.h"
USBHAL * USBHAL::instance; USBHAL * USBHAL::instance;
@ -64,6 +65,13 @@ typedef struct BDT {
uint32_t address; // Addr uint32_t address; // Addr
} BDT; } BDT;
typedef enum {
CTRL_XFER_READY,
CTRL_XFER_IN,
CTRL_XFER_NONE,
CTRL_XFER_OUT
} ctrl_xfer_t;
// there are: // there are:
// * 4 bidirectionnal endpt -> 8 physical endpt // * 4 bidirectionnal endpt -> 8 physical endpt
// * as there are ODD and EVEN buffer -> 8*2 bdt // * as there are ODD and EVEN buffer -> 8*2 bdt
@ -73,6 +81,7 @@ uint8_t * endpoint_buffer[NUMBER_OF_PHYSICAL_ENDPOINTS * 2];
static uint8_t set_addr = 0; static uint8_t set_addr = 0;
static uint8_t addr = 0; static uint8_t addr = 0;
static ctrl_xfer_t ctrl_xfer = CTRL_XFER_READY;
static uint32_t Data1 = 0x55555555; static uint32_t Data1 = 0x55555555;
@ -223,11 +232,16 @@ bool USBHAL::realiseEndpoint(uint8_t endpoint, uint32_t maxPacket, uint32_t flag
USB_ENDPT_EPRXEN_MASK; // en RX (OUT) tran. USB_ENDPT_EPRXEN_MASK; // en RX (OUT) tran.
bdt[EP_BDT_IDX(log_endpoint, RX, ODD )].byte_count = maxPacket; bdt[EP_BDT_IDX(log_endpoint, RX, ODD )].byte_count = maxPacket;
bdt[EP_BDT_IDX(log_endpoint, RX, ODD )].address = (uint32_t) buf; bdt[EP_BDT_IDX(log_endpoint, RX, ODD )].address = (uint32_t) buf;
bdt[EP_BDT_IDX(log_endpoint, RX, ODD )].info = BD_OWN_MASK | BD_DTS_MASK; bdt[EP_BDT_IDX(log_endpoint, RX, ODD )].info = BD_DTS_MASK;
bdt[EP_BDT_IDX(log_endpoint, RX, EVEN)].info = 0; bdt[EP_BDT_IDX(log_endpoint, RX, EVEN)].info = 0;
if (log_endpoint == 0) {
// Prepare for setup packet
bdt[EP_BDT_IDX(log_endpoint, RX, ODD )].info |= BD_OWN_MASK;
}
} }
Data1 |= (1 << endpoint); // First transfer will be a DATA0 packet
Data1 &= ~(1 << endpoint);
return true; return true;
} }
@ -239,13 +253,35 @@ void USBHAL::EP0setup(uint8_t *buffer) {
} }
void USBHAL::EP0readStage(void) { void USBHAL::EP0readStage(void) {
Data1 &= ~1UL; // set DATA0 // Not needed
bdt[0].info = (BD_DTS_MASK | BD_OWN_MASK);
} }
void USBHAL::EP0read(void) { void USBHAL::EP0read(void) {
uint32_t idx = EP_BDT_IDX(PHY_TO_LOG(EP0OUT), RX, 0); if (ctrl_xfer == CTRL_XFER_READY) {
bdt[idx].byte_count = MAX_PACKET_SIZE_EP0; // Transfer is done so ignore call
return;
}
if (ctrl_xfer == CTRL_XFER_IN) {
ctrl_xfer = CTRL_XFER_READY;
// Control transfer with a data IN stage.
// The next packet received will be the status packet - an OUT packet using DATA1
//
// PROBLEM:
// If a Setup packet is received after status packet of
// a Control In transfer has been received in the RX buffer
// but before the processor has had a chance the prepare
// this buffer for the Setup packet, the Setup packet
// will be dropped.
//
// WORKAROUND:
// Set data toggle to DATA0 so if the status stage of a
// Control In transfer arrives it will be ACKed by hardware
// but will be discarded without filling the RX buffer.
// This allows a subsequent SETUP packet to be stored
// without any processor intervention.
Data1 &= ~1UL; // set DATA0
}
endpointRead(EP0OUT, MAX_PACKET_SIZE_EP0);
} }
uint32_t USBHAL::EP0getReadResult(uint8_t *buffer) { uint32_t USBHAL::EP0getReadResult(uint8_t *buffer) {
@ -255,6 +291,15 @@ uint32_t USBHAL::EP0getReadResult(uint8_t *buffer) {
} }
void USBHAL::EP0write(uint8_t *buffer, uint32_t size) { void USBHAL::EP0write(uint8_t *buffer, uint32_t size) {
if (ctrl_xfer == CTRL_XFER_READY) {
// Transfer is done so ignore call
return;
}
if ((ctrl_xfer == CTRL_XFER_NONE) || (ctrl_xfer == CTRL_XFER_OUT)) {
// Prepare for next setup packet
endpointRead(EP0OUT, MAX_PACKET_SIZE_EP0);
ctrl_xfer = CTRL_XFER_READY;
}
endpointWrite(EP0IN, buffer, size); endpointWrite(EP0IN, buffer, size);
} }
@ -262,13 +307,34 @@ void USBHAL::EP0getWriteResult(void) {
} }
void USBHAL::EP0stall(void) { void USBHAL::EP0stall(void) {
if (ctrl_xfer == CTRL_XFER_READY) {
// Transfer is done so ignore call
return;
}
ctrl_xfer = CTRL_XFER_READY;
core_util_critical_section_enter();
stallEndpoint(EP0OUT); stallEndpoint(EP0OUT);
// Prepare for next setup packet
// Note - time between stalling and setting up the endpoint
// must be kept to a minimum to prevent a dropped SETUP
// packet.
endpointRead(EP0OUT, MAX_PACKET_SIZE_EP0);
core_util_critical_section_exit();
} }
EP_STATUS USBHAL::endpointRead(uint8_t endpoint, uint32_t maximumSize) { EP_STATUS USBHAL::endpointRead(uint8_t endpoint, uint32_t maximumSize) {
endpoint = PHY_TO_LOG(endpoint); uint8_t log_endpoint = PHY_TO_LOG(endpoint);
uint32_t idx = EP_BDT_IDX(endpoint, RX, 0);
uint32_t idx = EP_BDT_IDX(log_endpoint, RX, 0);
bdt[idx].byte_count = maximumSize; bdt[idx].byte_count = maximumSize;
if ((Data1 >> endpoint) & 1) {
bdt[idx].info = BD_OWN_MASK | BD_DTS_MASK | BD_DATA01_MASK;
}
else {
bdt[idx].info = BD_OWN_MASK | BD_DTS_MASK;
}
Data1 ^= (1 << endpoint);
return EP_PENDING; return EP_PENDING;
} }
@ -307,18 +373,14 @@ EP_STATUS USBHAL::endpointReadResult(uint8_t endpoint, uint8_t * buffer, uint32_
buffer[n] = ep_buf[n]; buffer[n] = ep_buf[n];
} }
if (((Data1 >> endpoint) & 1) == ((bdt[idx].info >> 6) & 1)) { if (setup) {
if (setup && (buffer[6] == 0)) // if no setup data stage, // Record the setup type
Data1 &= ~1UL; // set DATA0 if (buffer[6] == 0) {
else ctrl_xfer = CTRL_XFER_NONE;
Data1 ^= (1 << endpoint); } else {
uint8_t in_xfer = (buffer[0] >> 7) & 1;
ctrl_xfer = in_xfer ? CTRL_XFER_IN : CTRL_XFER_OUT;
} }
if (((Data1 >> endpoint) & 1)) {
bdt[idx].info = BD_DTS_MASK | BD_DATA01_MASK | BD_OWN_MASK;
}
else {
bdt[idx].info = BD_DTS_MASK | BD_OWN_MASK;
} }
USB0->CTL &= ~USB_CTL_TXSUSPENDTOKENBUSY_MASK; USB0->CTL &= ~USB_CTL_TXSUSPENDTOKENBUSY_MASK;
@ -351,9 +413,9 @@ EP_STATUS USBHAL::endpointWrite(uint8_t endpoint, uint8_t *data, uint32_t size)
} }
if ((Data1 >> endpoint) & 1) { if ((Data1 >> endpoint) & 1) {
bdt[idx].info = BD_OWN_MASK | BD_DTS_MASK;
} else {
bdt[idx].info = BD_OWN_MASK | BD_DTS_MASK | BD_DATA01_MASK; bdt[idx].info = BD_OWN_MASK | BD_DTS_MASK | BD_DATA01_MASK;
} else {
bdt[idx].info = BD_OWN_MASK | BD_DTS_MASK;
} }
Data1 ^= (1 << endpoint); Data1 ^= (1 << endpoint);
@ -450,7 +512,7 @@ void USBHAL::usbisr(void) {
// setup packet // setup packet
if ((num == 0) && (TOK_PID((EP_BDT_IDX(num, dir, ev_odd))) == SETUP_TOKEN)) { if ((num == 0) && (TOK_PID((EP_BDT_IDX(num, dir, ev_odd))) == SETUP_TOKEN)) {
Data1 &= ~0x02; Data1 |= 0x02 | 0x01; // set DATA1 for TX and RX
bdt[EP_BDT_IDX(0, TX, EVEN)].info &= ~BD_OWN_MASK; bdt[EP_BDT_IDX(0, TX, EVEN)].info &= ~BD_OWN_MASK;
bdt[EP_BDT_IDX(0, TX, ODD)].info &= ~BD_OWN_MASK; bdt[EP_BDT_IDX(0, TX, ODD)].info &= ~BD_OWN_MASK;