- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hello,
On my FX3 project I created an EP discussing with a FPGA through UART link.
UART is configured on both sides to work with Byte mode DMA (dmaConfig.dmaMode = CY_U3P_DMA_MODE_BYTE)
All this works like a charm, except that I live with a limitation that I would like to fix : at reception (FPGA->FX3), DMA requires a minimal of 16 bytes to operate, which seems to be a limitation of FX3 (UART?) DMA engine.
This means if my FPGA sends less than 16 bytes of data they will not be forwarded to my USB endpoint.
I would like to keep it as simple as possible to avoid having FX3 firmware sniffing at UART events and processing packets. Is there a simple solution for that ?
Hereunder is my UART configuration :
CyU3PReturnStatus_t ConfigureUartDma(void) {
CyU3PReturnStatus_t Status = CY_U3P_SUCCESS;
CyU3PDmaChannelConfig_t dmaConfig;
// Create a AUTO channel for the USB to UART transfer
CyU3PMemSet((uint8_t *)&dmaConfig, 0, sizeof(dmaConfig));
dmaConfig.size = 128; // Maximal number of bytes allowed per DMA buffer.
// A larger message would stuck the EP
dmaConfig.count = 32; // Store up to 32 words in DMA buffers
dmaConfig.prodSckId = FPGA_CONFIG_ENDPOINT_SOCKET;
dmaConfig.consSckId = UART_CONSUMER_SOCKET;
dmaConfig.dmaMode = CY_U3P_DMA_MODE_BYTE;
Status = CyU3PDmaChannelCreate(&Usb2Uart_Handle, CY_U3P_DMA_TYPE_AUTO, &dmaConfig);
// Start the DMA Channel with transfer size to Infinite
Status = CyU3PDmaChannelSetXfer(&Usb2Uart_Handle, 0);
// Create a AUTO channel for the UART to USB transfer
CyU3PMemSet((uint8_t *)&dmaConfig, 0, sizeof(dmaConfig));
dmaConfig.size = 16; // Minimal value allowed by DMA.
// Any UART message longer than this will be split in 16 bytes "packets"
dmaConfig.count = 32; // Up to 32 words can be stored in DMA buffers
dmaConfig.prodSckId = UART_PRODUCER_SOCKET;
dmaConfig.consSckId = FPGA_STATUS_ENDPOINT_SOCKET;
dmaConfig.dmaMode = CY_U3P_DMA_MODE_BYTE;
Status = CyU3PDmaChannelCreate(&Uart2Usb_Handle, CY_U3P_DMA_TYPE_AUTO_SIGNAL, &dmaConfig);
// Start the DMA Channel with transfer size to Infinite
Status = CyU3PDmaChannelSetXfer(&Uart2Usb_Handle, 0);
return Status;
}
Thanks in advance
Solved! Go to Solution.
- Tags:
- fx3 uart
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hello Christophe,
I didn't get the question. Can you restate it?
From the previous post what i understood was that you want to commit the partial buffer.
As per your previous response, DMA channel from UART to USB is AUTO_SIGNAL. Still you can use CyU3PDmaChannelSetWrapUp API in the for{}. But you need to register a call back and handle the PROD_EVENT. In the PROD_EVENT the partial buffer can be committed. (Refer to the modified UsbUart example with DMA_TYPE_ AUTO_SIGNAL channel between uart and usb). You can check the working of the attached firmware and make changes to your firmware accordingly.
If you wan to use DMA Manual channel you need to commit the data manually to the consumer socket. This is done when the buffer is full or PROD_EVENT occurs and in DMA channel you commit that buffer.
But when the buffer is partially filled there will not be any PROD_EVENTS. So when you call CyU3PDmaChannelSetWrapUp there will be PROD_EVENT even when the buffer is partially filled. In the callback, this buffer will then be committed to the consumer socket.
We use this API in the for{} (as per usbuart example) to continuously check for partial buffer and commit it.
Regards,
Rashi
Rashi
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hello Christophe,
Please confirm if you referred to the USBUART example in the SDK.
In the USBUARTAppThread_Entry function CyU3PDmaChannelSetWrapUp (&glChHandleUarttoUsb); is called in the for{} loop to use the channel wrap-up feature to send any partial buffer to the USB host.
So you can use this API in you firmware as per your application.
Regards,
Rashi
Rashi
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hello Rashi,
Thanks for feedback.
No I am not using USBUART example from SDK. I did built my own application where UART is configured to use (AUTO ?) DMAs.
This is done in 2 steps :
- configure UART (see ConfigureUart() below)
- configure DMA (see code in initial thread message)
Doing so I don't have to have a thread running an infinite loop, but with this drawback I try to fix.
My remaining question is : "Is there a fix for that I do I have to go through Manual DMA + Callback + CyU3PDmaChannelSetWrapUp + infinite loop ? "
CyU3PReturnStatus_t ConfigureUart(void)
{
CyU3PReturnStatus_t Status = CY_U3P_SUCCESS;
CyU3PUartConfig_t uartConfig;
// Start the UART driver
Status = CyU3PUartInit();
// Configure my UART link, as fast as possible for interfacing with FPGA
CyU3PMemSet ((uint8_t *)&uartConfig, 0, sizeof (uartConfig));
uartConfig.baudRate = CY_U3P_UART_BAUDRATE_4M608K;
uartConfig.stopBit = CY_U3P_UART_ONE_STOP_BIT;
uartConfig.txEnable = CyTrue;
uartConfig.rxEnable = CyTrue;
uartConfig.isDma = CyTrue;
/* Set the UART configuration; no callback */
Status = CyU3PUartSetConfig(&uartConfig, NULL);
Status = CyU3PUartTxSetBlockXfer(0xFFFFFFFF); // Send as much data as I need to
Status = CyU3PUartRxSetBlockXfer(0xFFFFFFFF);
return Status;
}
I wrote this code a while back so excuse me if DMA modes of operations are not 100% clear in my mind.
Regards
Christophe
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hello Christophe,
I didn't get the question. Can you restate it?
From the previous post what i understood was that you want to commit the partial buffer.
As per your previous response, DMA channel from UART to USB is AUTO_SIGNAL. Still you can use CyU3PDmaChannelSetWrapUp API in the for{}. But you need to register a call back and handle the PROD_EVENT. In the PROD_EVENT the partial buffer can be committed. (Refer to the modified UsbUart example with DMA_TYPE_ AUTO_SIGNAL channel between uart and usb). You can check the working of the attached firmware and make changes to your firmware accordingly.
If you wan to use DMA Manual channel you need to commit the data manually to the consumer socket. This is done when the buffer is full or PROD_EVENT occurs and in DMA channel you commit that buffer.
But when the buffer is partially filled there will not be any PROD_EVENTS. So when you call CyU3PDmaChannelSetWrapUp there will be PROD_EVENT even when the buffer is partially filled. In the callback, this buffer will then be committed to the consumer socket.
We use this API in the for{} (as per usbuart example) to continuously check for partial buffer and commit it.
Regards,
Rashi
Rashi
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi Rashi,
You are right, I want to commit partially filled buffer.
Then from your example, it looks like this is correct approach.
I'll check if this works in my application and let you know.
Thanks a lot !
Christophe
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hello Rashi,
I applied proposed modifications to my code.
My UART to USB pipe is now failing.
I instrumented this section of code and I get an error within callback function after initialization :
UartRxDMACallback call
CyU3PDmaChannelCommitBuffer() failed, 71 = CY_U3P_ERROR_INVALID_SEQUENCE ?
Documentation mentions this happens when DMA is not configured. I checked how device is configured and I believe DMA should be configured.
C file handling UART function is attached for more details.
StartUart() function contained there is called by main program, which also have an infinite loop in a thread calling FlushUARTRxDMA() function every 100 ms.
Thanks for support
Christophe
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hello Christophe,
I went through the source code of the CyU3PDmaChannelCommitBuffer() API.
The error 71 (0x47) is when the socket is not in suspend mode.
Please confirm that this FlushUARTRxDMA function is not called before the channel is created i.e. before calling CyU3PDmaChannelCreate and CyU3PDmaChannelSetXfer
Regards,
Rashi
Rashi
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Rashi,
Here is code portion calling the function (within a specific thread) :
// Now run forever
while (1)
{
CyU3PThreadSleep(100);
// Check for UART data availabity (partially full DMA buffer)
if (glIsUartActive) {
Status = FlushUARTRxDMA();
CheckStatus("FlushUARTRxDMA()", Status);
}
}
glIsUartActive is set to true within StartUart() function after UART and associated DMAs are configured:
CyU3PReturnStatus_t StartUart(void)
{
CyU3PReturnStatus_t Status = CY_U3P_SUCCESS;
// Configure UART for interfacing with FPGA
Status = ConfigureUart();
CheckStatus("ConfigureUart()", Status);
// Configure USB endpoints linked to UART
Status = ConfigureUartEP();
CheckStatus("ConfigureUartEP()", Status);
// Create DMAs between EP and UART
Status = ConfigureUartDma();
CheckStatus("ConfigureUartDma()", Status);
// Mark USB <-> UART communication as active
glIsUartActive = CyTrue;
return Status;
}
So function should be called AFTER dma is configure within ConfigureUartDma() function.
Christophe
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hello Christophe,
Can you share your complete firmware as I am not able to reproduce the problem at my end.
The source code of CyU3PDmaChannelCommitBuffer() API checks the state of socket (suspend or not)
Also, share the debug logs.
Regards,
Rashi
Rashi
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hello Christophe,
From the firmware i found that you are using one Uart consumer socket for debugging and also you are creating a channel from USB to UART.
Uart block has only two sockets i.e. one consumer socket ans one producer socket. So you can use the consumer socket for one purpose only either it can be for USB > UART channel or for debugging purpose.
You can see in the UsbtoUart example doesn't have provision for debug prints due to this reason.
So can you please comment out the API's used for debugging
You can check whether the API is failing or not by calling the CYU3PDeviceRest(CyFalse) API in the condition checking for error
Regards,
Rashi
Rashi
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hello Rashi,
I think there is a lack of understanding here.
FX3 firmware operates as a bridge between UART module and EP2 (IN/OUT).
My Debug console is targeted towards EP4.
So UART and associated EP are not used to carry debug messages.
Also, note all this was working OK (except 16 bytes limitation we are discussing) before I tried using CyU3PDmaChannelSetWrapUp.
Regards
Christophe
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hello Christophe,
Please refer to this KBA Invalid Sequence Error in Multi-Channel Commit Buffer - KBA218830 . This is for multichannel commit buffer failure but similar conditions are checked in the source code of CyU3PDmaChannelCommitBuffer API. This KBA is for UVC applications but the cause of this error in your application is due to slow host. ( IN tokens)
As per this KBA CyU3PDmaChannelCommitBuffer() and CyU3PDmaChannelSetWrapUp() Returns INVALID_SEQUENCE Errors When Us... you have set the clock to 403.2 MHz
When do you get this failure after some transfers or as soon as you program the FX3 with the firmware. Can you share the debug prints when this error occurs. It would also help me to understand the flow of the code.
Regards,
Rashi
Rashi
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hello Rashi,
Sorry for late reply, but I had really little time to work on this till yesterday.
I looked at KBAs you mentionned. 1st one is the kind of issue I was suspecting.
Actually, at initialisation every "important" step is marked for debug (DebugPrint) and then pushed to a specific EP.
What happens is that it looks like this buffer tends to become full at initialisation and blocks execution of the code.
I then need to poll my EP to continue execution.
This is really close to KBA description.
For your information, here is the kind of log I get when all messages are printed :
Initialize USB Debug Console Successful
USBThread completed init. Monitoring USB events...
CyU3PUartInit Successful
CyU3PUartSetConfig Successful
CyU3PUartTxSetBlockXfer Successful
CyU3PUartRxSetBlockXfer Successful
ConfigureUart() Successful
Device ready, DebugThread waking up
Setup FPGA_CONFIG_ENDPOINT Successful
Flush FPGA_CONFIG_ENDPOINT Successful
Setup FPGA_STATUS_ENDPOINT Successful
Flush FPGA_STATUS_ENDPOINT Successful
ConfigureUartEP() Successful
Usb2Uart DmaChannelCreate Successful
Usb2Uart DmaChannelStart Successful
Uart2Usb DmaChannelCreate Successful
Uart2Usb DmaChannelStart Successful
ConfigureUartDma() Successful
StartUart() Successful
UartRxDMACallback call
CyU3PDmaChannelCommitBuffer() failed, 71 = CY_U3P_ERROR_INVALID_SEQUENCE
?
CyU3PDmaChannelSetWrapUp() Successful
FlushUARTRxDMA() Successful
I then tried a 1st fix that consists in suspending all DebugPrint until UART DMA callback is called.
I received same error log on Debug EP at CommitBuffer call:
USBThread completed init. Monitoring USB events...
UartRxDMACallback call
CyU3PDmaChannelCommitBuffer() failed, 71 = CY_U3P_ERROR_INVALID_SEQUENCE
?
CyU3PDmaChannelSetWrapUp() Successful
FlushUARTRxDMA() Successful
Device ready, DebugThread waking up?
KBA218830 solution proposal seems to bring other problem, since I cannot afford stopping GPIF state machine (will be used at the same time to transport data from FPGA to my host application). Or maybe could I apply this to UART and then acting only on UART config ?
It is still possible in my code modification to add this CyU3PDmaChannelCommitBuffer/CyU3PDmaChannelSetWrapUp there is something that went wrong...
Maybe UartRxDMACallback definition is incorrect ? Are arguments passed from OS to callback function ? What is chHandle parameters that is unused there ?
void UartRxDMACallback(
CyU3PDmaChannel *chHandle, /* Handle to the DMA channel. */
CyU3PDmaCbType_t type, /* Callback type. */
CyU3PDmaCBInput_t *input) /* Callback status. */
{
CyU3PReturnStatus_t Status = CY_U3P_SUCCESS;
if (type == CY_U3P_DMA_CB_PROD_EVENT)
{
glIsDebugActive = CyTrue;
DebugPrint(4, "\r\nUartRxDMACallback call");
Status = CyU3PDmaChannelCommitBuffer (&Uart2Usb_Handle, input->buffer_p.count, 0);
CheckStatus("CyU3PDmaChannelCommitBuffer()", Status);
glPktsPending++;
}
}
Regards
Christophe
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hello Christophe,
Can you comment out CyU3PDmaChannelCommitBuffer API in the PROD event.
Don't call any API inside the PROD event. For AUTO and AUTO_SIGNAL channel you don't need to call CyU3PDmaChannelCommitBuffer
The buffer will be committed without calling that API
Regards,
Rashi
Rashi
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Rashi,
This did not solve the issue. Actually, removing call to this function in DMA callback makes callback useless.
Nevertheless, I noticed some difference :
- without call to CyU3PDmaChannelCommitBuffer in DMA callback, there is no USB frame sent on my EP
- with call to CyU3PDmaChannelCommitBuffer in DMA callback, I get a USB frame, but it is empty.
Christophe
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hello Christophe,
Yes, i understand that there is no use of DMA callback , it is because the DMA channel is AUTO_SIGNAL / AUTO. The producer sockets directly signals the consumer socket that buffer is ready.CyU3PDmaChannelCommitBuffer is needed when it is Manual channel.
I tried commenting out the API in the DMA callback in the firmware i shared to you before. I an able to see the data i the teraterm which is sent from UART.
Try sending the data from UART and probe the USB lines. Please share the traces. You can use Wireshark for that.
Regards,
Rashi
Rashi
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Rashi,
I commented out call to CommitBuffer in callback function.
I kept the message indicating the callback function is called in my code
Here are logs I can see at initialisation :
Initialize USB Debug Console Successful
USBThread completed init. Monitoring USB events...
CyU3PUartInit Successful
CyU3PUartSetConfig Successful
CyU3PUartTxSetBlockXfer Successful
ConfigureUart() Successful
Setup FPGA_CONFIG_ENDPOINT Successful
Device ready, DebugThread waking up
Flush FPGA_CONFIG_ENDPOINT Successful
Setup FPGA_STATUS_ENDPOINT Successful
Flush FPGA_STATUS_ENDPOINT Successful
ConfigureUartEP() Successful
Usb2Uart DmaChannelCreate Successful
Usb2Uart DmaChannelStart Successful
Uart2Usb DmaChannelCreate Successful
Uart2Usb DmaChannelStart Successful
ConfigureUartDma() Successful
StartUart() Successful
UartRxDMACallback call
UartRxDMACallback call
UartRxDMACallback call
UartRxDMACallback call
UartRxDMACallback call
UartRxDMACallback call
UartRxDMACallback call
UartRxDMACallback call
0,
Timeout
You can see callback is called 8 times without any data being received on UART.
You can see in PCAP at 6s taht I end 6 bytes of data on UART (and I expect 8 bytes coming back from UART. I could saw bytes flowing on UART using oscilloscope).
I then try to read EP2 at t = 17s and I can see a bulk read with no data
Then I can see when polling debug frames that a new call to Callback is done (I actually noticed call to callback is done at each bulk in request)
Other bulk messages in PCAP are debug information sent by FX3 FW.
Regards
Christophe
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hello Christophe,
As the CyU3PDmaChannelSetWrapUp API is called in the for loop, it would start committing the buffer even when there is no data in the buffer(buffer.count = 0). When at 17s, there is BULK IN token from the host, the first buffer with no data will be consumed by the consumer socket. The data you sent would be ther in the buffer but in a queue after multiple IN tokens you may get the data you sent from UART
You need to synchronize this as per your application. If you want, that the data from Uart to USB should be should be transferred only after the data transfer from USB (OUT) to Uart is completed. Then you can call CyU3PDmaChannelSetWrapUp only when USB (OUT) to Uart transfer is completed.
In the default UsbUart example, CyU3PDmaChannelSetWrapUp API is called every 50 ms by setting CyU3PThreadSleep (50)
Regards,
Rashi
Rashi