- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hello,
I'm trying to set up an endpoint, but when I write to the endpoint, I can't read the data from my app or the control center. I'm hoping if I post the code in question, some kind soul can help me figure out what I'm doing wrong.
I've included the function that configures the endpoints and the function that writes log messages to the host machine.
The endpoint in question is 10, and it's an IN endpoint, meaning it goes from the FX3 to the host. It's the last one listed in the descriptor, which means in my list of endpoints it's also the last one. When it isn't clear what value something is, I'll look it up in the debugger and put its value in a comment so you can follow along.
int8_t configureEndpoints()
{
// Wait until descriptor is parsed in another thread
CyU3PMutexGet (&descriptorMutex, CYU3P_WAIT_FOREVER);
CyU3PReturnStatus_t apiRetStatus = CY_U3P_SUCCESS;
CyU3PEpConfig_t epCfg;
CyU3PDmaChannelConfig_t dmaCfg;
CyU3PDmaType_t dmaType;
struct ConfigurationDescriptor *config = _getCurrentConfig();
for (uint8_t interfaceIndex = config->firstInterface;
interfaceIndex < config->firstInterface + config->numInterfaces;
++interfaceIndex){
struct InterfaceDescriptor *interface = gInterfaceDesc + interfaceIndex;
// for each interface in a configuration
for (uint8_t endpointIndex = interface->firstEndpoint;
endpointIndex < interface->firstEndpoint + interface->numEndpoints; ++endpointIndex){
struct EndpointDescriptor *endpoint = gEndpointDesc + endpointIndex;
// for each endpoint in an interface
// Configure the corresponding endpoint
CyU3PMemSet ((uint8_t *)&epCfg, 0, sizeof (epCfg));
epCfg.enable = CyTrue;
epCfg.epType = endpoint->type;// CY_U3P_USB_EP_INTR
epCfg.burstLen = 1;
epCfg.streams = 0;
epCfg.pcktSize = endpoint->packetSize; // 528
apiRetStatus = CyU3PSetEpConfig(endpoint->address, &epCfg); // 0x8a
switch(apiRetStatus){
case CY_U3P_ERROR_NOT_STARTED:
errorLoop();
break;
case CY_U3P_ERROR_NULL_POINTER:
// Should never happen
errorLoop();
break;
case CY_U3P_ERROR_BAD_ARGUMENT:
// We got a bad endpoint number from the descriptor
return USB_INVALID_ADDRESS;
case CY_U3P_ERROR_INVALID_CONFIGURATION:
// bursts of more than 1 are only supported on certain endpoints
// We're hardcoding this to false for now anyway, so this should never happen
errorLoop();
break;
}
// Set up the DMA buffer for the endpoint
uint8_t epLeadsToHost = endpoint->address & IN_Endpoint; // 0x80, but used as a boolean
uint8_t addressNum = endpoint->address & ~IN_Endpoint; // 10
dmaCfg.size = endpoint->packetSize; // 528
dmaCfg.count = DMA_CHANNEL_SIZE / endpoint->packetSize; // 16
if (epLeadsToHost && addressNum == 10){
// Debug endpoint
dmaCfg.notification = 0;
dmaCfg.prodSckId = CY_U3P_CPU_SOCKET_PROD;
dmaCfg.consSckId = CY_U3P_UIB_SOCKET_CONS_0 + addressNum;
dmaType = CY_U3P_DMA_TYPE_MANUAL_OUT;
}
else if (epLeadsToHost) {
// Data goes from the device to the host
// This block isn't used for the endpoint we're talking about
}
else {
//Data goes from the host to the device
// This block isn't used for the endpoint we're talking about either
}
dmaCfg.dmaMode = CY_U3P_DMA_MODE_BYTE;
dmaCfg.cb = CyFxDmaCallback; // Not used for this endpoint, but shouldn't be called because it has no notifications
dmaCfg.prodHeader = 0;
dmaCfg.prodFooter = 0;
dmaCfg.consHeader = 0;
dmaCfg.prodAvailCount = 0;
apiRetStatus = CyU3PDmaChannelCreate(&endpoint->dmaHandle, dmaType, &dmaCfg);
switch (apiRetStatus){
case CY_U3P_ERROR_BAD_ARGUMENT:
case CY_U3P_ERROR_NULL_POINTER:
// Shouldn't happen
errorLoop();
break;
case CY_U3P_ERROR_MEMORY_ERROR:
// Could not allocate buffers
errorLoop();
}
if (addressNum == 10){
debugChannel = &endpoint->dmaHandle;
}
// the 0 tells the DMA not to limit the transfers.
apiRetStatus = CyU3PDmaChannelSetXfer(&endpoint->dmaHandle, 0);
switch (apiRetStatus){
case CY_U3P_ERROR_NULL_POINTER:
case CY_U3P_ERROR_NOT_CONFIGURED:
case CY_U3P_ERROR_NOT_SUPPORTED:
// we passed a null pointer, which shouldn't happen
// our configuration was wrong, which shouldn't happen
// no buffer was allocated, which shouldn't happen
errorLoop();
}
if (!epLeadsToHost){
// Configure endpoint watermarks
endpoint->dmaThreadNum = USB_ADDRESS_TO_PIB(addressNum) % 4;
apiRetStatus = CyU3PGpifSocketConfigure(
endpoint->dmaThreadNum,
CY_U3P_PIB_SOCKET_0 + USB_ADDRESS_TO_PIB(addressNum),
0, // buffer contains data if watermark is higher than 0
CyTrue,
0);
if (apiRetStatus != CY_U3P_SUCCESS){
errorLoop();
}
}
// Flush the endpoint
CyU3PUsbFlushEp(endpoint->address);
//Configure the GPIF-II socket
}
}
CyU3PMutexPut (&descriptorMutex);
endpointsAreEnabled = CyTrue;
if (config->isHighSpeed){ // true
// The configuration must be high speed. Sending an interrupt without
// the ready pin asserted indicates that the enumeration was successful,
// but at the wrong speed
setReady(CyTrue);
}
else {
setReady(CyFalse);
}
// report when it's finished starting up
extern uint32_t interruptSentTicks;
interruptSentTicks = CyU3PGetTime();
interrupt8051(); // Does some GPIO stuff to ping another microcontroller
breaksAllowed = CyTrue; // First message has been received from host. Who cares if we time out our connection.
return 0;
}
// We have 16 bytes to work with because the smallest DMA buffer size increments are 16 bytes
#define DEBUG_HEADER_SIZE 15
#define DEBUG_FOOTER_SIZE 1
CyU3PDmaChannel *debugChannel;
void debugLog(int length, unsigned char *data, char endpoint){
#ifdef DEBUG_ENDPOINT10 // is defined
CyU3PReturnStatus_t error;
CyU3PDmaBuffer_t buffer;
// Get a buffer to pass in data
error = CyU3PDmaChannelGetBuffer (
debugChannel, /**< Handle to the DMA channel on which to wait. */
&buffer, /**< Output parameter that will be filled with data about the
buffer that was obtained. */
CYU3P_NO_WAIT /**< Duration to wait before returning a timeout status. */
);
if (error == CY_U3P_ERROR_TIMEOUT || error == CY_U3P_ERROR_MUTEX_FAILURE){ // Usually gets stuck here, failing to get the Mutex
return;
}
else if (error != CY_U3P_SUCCESS){
errorLoop();
}
// Copy data over
int transferLength = length; // should be 8 in this example
char wasClipped = 0;
if (length > buffer.size - (DEBUG_HEADER_SIZE + DEBUG_FOOTER_SIZE)){ // header is 15, footer is 1, buffer size is 528
// Shouldn't happen if my buffer sizes are right, but who knows? Better to be safe
transferLength = buffer.size - (DEBUG_HEADER_SIZE + DEBUG_FOOTER_SIZE);
wasClipped = 1;
}
// An easy pattern to recognize so we know we have the byte order right
buffer.buffer[0] = 0xDE;
buffer.buffer[1] = 0xAD;
buffer.buffer[2] = 0xBE;
buffer.buffer[3] = 0xEF;
// The endpoint this data is associated with, or 0xff is it's a generic log message
buffer.buffer[4] = endpoint; // 0 in this example
// 1 if the message has been clipped. 0 if it has not
buffer.buffer[5] = wasClipped;
// Reserved for more details later
buffer.buffer[6] = 0;
buffer.buffer[7] = 0;
buffer.buffer[8] = 0;
buffer.buffer[9] = 0;
buffer.buffer[10] = 0;
buffer.buffer[11] = 0;
buffer.buffer[12] = 0;
buffer.buffer[13] = 0;
buffer.buffer[14] = 0;
// the rest of the data
memcpy(buffer.buffer + DEBUG_HEADER_SIZE, data, transferLength);
buffer.count = transferLength + DEBUG_HEADER_SIZE + DEBUG_FOOTER_SIZE;
// checksum
unsigned char checksum = 0;
for (int i = 0; i < transferLength + DEBUG_HEADER_SIZE; ++i){
checksum += buffer.buffer[i];
}
buffer.buffer[transferLength + DEBUG_HEADER_SIZE] = checksum;
error = CyU3PDmaChannelCommitBuffer (
debugChannel, /**< Handle to the DMA channel to be modified. */
buffer.count, /**< Size of data in the buffer being committed. The buffer
address is implicit and is fetched from the active descriptor
for the channel. */
0 /**< Current status (end of transfer bit) of the buffer being
committed. The occupied bit will automatically be set by
the API. */
);
if (error != CY_U3P_SUCCESS){
errorLoop();
}
#endif
}
As I said in the comment, at the moment it's failing to get the mutex for some reason I don't understand, but earlier today it was getting farther than that and still nothing went through to the host machine. If you can help me understand what I'm doing wrong, or point out some other things I should check, I'd greatly appreciate it.
- Labels:
-
USB Superspeed Peripherals
- Tags:
- fx3
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi,
Could you remove all the Mutex related APIs from the firmware? This is because the getting and putting of Mutex for a particular API call is already taken care of in the library source file.
Also I can notice that, the first parameter of the getBuffer API is "debugChannel". Has
"&endpoint->dmaHandle" been assigned to "debugChannel", anywhere else in your source code?
AliAsgar
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
There's 4 references to debugChannel in the workspace. It's declared at the top of the file these functions come from, it's assigned in the configureEndpoints function when we go through endpoint 10, and it's used only in getBuffer and commitBuffer.
I've moved some calls around so the mutex isn't necessary anymore, but it wasn't protecting the API. My descriptor is a big byte array I copied from our old project, so I have to parse it out to feed the descriptor sections into CyU3PUsbSetDesc(), and while I do that, I copy useful information from it into the structs that we iterate over in the configureEndpoints function. The configureEndpoints function happens in the Event callback when we get a setconf event, so the mutex was making sure that those structs weren't half parsed when the callback happens.
Regardless, I'm still running into the same problem after removing the mutex.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi,
Have you confirmed if the issue is due to mutex failure itself and not timeout error?
How frequent is the error? Is it always due to the mutex failure/timeout error issue?
Could you share the firmware source code with us?
Best Regards,
AliAsgar
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
The only reason I know it's a mutex failure is that it returns CY_U3P_ERROR_MUTEX_FAILURE every time I've looked at it. If a timeout can cause that too, then maybe it's a timeout.
It happens every time as far as I can tell.
I've attached the firmware source. The debugLog function is defined in usb.c, it's supposed to communicate over endpoint 10, and it gets called every 10 seconds from a timer in main.c.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hello.
You cannot call CyU3PDmaChannelGetBuffer and CyU3PDmaChannelCommitBuffer in a timer callback. Do not call debug prints either in a timer callback.
You can either set a global variable in the timer callback and handle that global variable in your thread or alternatively set an event and have the thread waken on the event. In either case, the debugLog function should be called from the thread and not the callback. When that is done, you can read the 24 bytes of data over the IN endpoint 10.
Also note that you can call CyU3PDebugPreamble(CyFalse) after CyFxBulkLpApplnDebugInit() to remove the preamble that doesn't show as ascii characters in the debug terminal.
Frank
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Ok, I got it working and it turned out that calling the debug print during a timer callback was part of the problem like frank said.
I didn't end up needing to use it as a manual endpoint after all, so for the other part, my coworker and I walked through the usbDebug sample project line by line. Ultimately, we found that we had to call CyU3PUsbFlushEp on the endpoint right before calling CyU3PDebugInit. Flushing afterwards didn't work.
Edit: I found that the debug print function didn't work for me because the data I wanted to send has 0s in it, which would be interpreted as null characters.
I also found that I may have been configuring the debug out endpoint as if it were a GPIF endpoint like the others even though it was not. I may also have had the MANUAL_IN and MANUAL_OUT mixed up. In USB terms, IN and OUT are relative to the host, but since the DMA in the FX3 isn't just for USB, manual in and out are relative to it instead.