cancel
Showing results for 
Search instead for 
Did you mean: 

USB Superspeed Peripherals

New Contributor II

Hi Cypress forum,

I want to test the UsbUart code example provided in the FX3 examples (EZ-USB FX3 SDK/1.3/firmware/serialif_examples/cyfxusbuart).

I've read on some other forum discussions, that in order to send under 16 bytes, I need to use the CyU3PDmaChannelSetWrapUp() function (which the code-example does in the USBUARTAppThread_Entry() function).

I have several questions regarding this issue:

  1. The default input parameter is CyU3PDmaChannelSetWrapUp (&glChHandleUarttoUsb), specifying the AUTO_SIG channel. If I wanted to send some binary data, for example "0xD5", how would I do that? How would I send a stream of data, for example "{0x01, 0x02, 0x03, 0x04}"?
  2. How do I receive data from the USB? Which function checks data coming from the USB, and how do I verify this? For example if I sent 0x01 from USB --> through UART --> FX3, how do I check that I received the correct input?
  3. How do I emulate USB data to send through to the FX3? I want to implement modbus, but since it's not readily implemented, I want to send some data with an emulator (or some other way, if you have suggestions?).
  4. Can I use the debug print UART configuration in my program while using the USB to UART example? If not, can I use it if I run the program on seperate threads? Or should I comment out all cases of my CyU3PDebugPrint (2, "debug print"), as well as my configuration of it?

Hope these questions are straight forward. If you need more information, let me know.

Best regards,

Søren

0 Likes
Reply
1 Solution
Moderator
Moderator

Hello Søren,

Please find my comments for your questions below:

1. The default UsbUart example project implements DMA channels between USB and UART sockegts. If you want to send hard coded data, then the DMA channel should be created as CPU socket being the producer socket and UART socket as consumer socket (MANUAL OUT channel). Then, you can call the API CyU3PDmaChannelGetBuffer() which returns an empty buffer for a MANUAL OUT channel. This buffer can be filled in the firmware and then sent out by using CyU3PDmaChannelCommitBuffer() API. Please refer to the FX3 API guide for more information on these APIs. This document comes along with FX3 SDK and can be found in the following path by default:

C:\Program Files (x86)\Cypress\EZ-USB FX3 SDK\1.3\doc\firmware

However, if you want to send data from the USB socket itself, then it can be done by using the Application Tera Term on Windows. 

2. According to my understanding, you are sending data from a PC to FX3 using a USB Serial chip. FX3 accepts the serial data through the UART interface and sends it to the USB socket. FX3 will either wait for a buffer of 32 bytes to be filled by the producer (UART producer socket) or it wraps up the DMA buffer every 50ms and sends it to the USB socket. The data sent out can be viewed by using Tera term application. 

3. As mentioned before, Tera Term can be used for demonstrating this example. This application can be used for sending data from the host to the producer endpoint (endpoint associated with producer socket) on FX3 and also to display the data obtained from the consumer endpoint (endpoint associated with consumer socket) on FX3.

4. It is not recommended to use debug prints in applications that make use of UART block for a different purpose. This is because the API CyU3PDebugPrint() sends the debug messages via UART interface and this can cause unwanted data to be received at the receiver side.

Please let me know if you have any queries on this.

Best Regards,
Jayakrishna

View solution in original post

0 Likes
Reply
15 Replies
Moderator
Moderator

Hello Søren,

Please find my comments for your questions below:

1. The default UsbUart example project implements DMA channels between USB and UART sockegts. If you want to send hard coded data, then the DMA channel should be created as CPU socket being the producer socket and UART socket as consumer socket (MANUAL OUT channel). Then, you can call the API CyU3PDmaChannelGetBuffer() which returns an empty buffer for a MANUAL OUT channel. This buffer can be filled in the firmware and then sent out by using CyU3PDmaChannelCommitBuffer() API. Please refer to the FX3 API guide for more information on these APIs. This document comes along with FX3 SDK and can be found in the following path by default:

C:\Program Files (x86)\Cypress\EZ-USB FX3 SDK\1.3\doc\firmware

However, if you want to send data from the USB socket itself, then it can be done by using the Application Tera Term on Windows. 

2. According to my understanding, you are sending data from a PC to FX3 using a USB Serial chip. FX3 accepts the serial data through the UART interface and sends it to the USB socket. FX3 will either wait for a buffer of 32 bytes to be filled by the producer (UART producer socket) or it wraps up the DMA buffer every 50ms and sends it to the USB socket. The data sent out can be viewed by using Tera term application. 

3. As mentioned before, Tera Term can be used for demonstrating this example. This application can be used for sending data from the host to the producer endpoint (endpoint associated with producer socket) on FX3 and also to display the data obtained from the consumer endpoint (endpoint associated with consumer socket) on FX3.

4. It is not recommended to use debug prints in applications that make use of UART block for a different purpose. This is because the API CyU3PDebugPrint() sends the debug messages via UART interface and this can cause unwanted data to be received at the receiver side.

Please let me know if you have any queries on this.

Best Regards,
Jayakrishna

View solution in original post

0 Likes
Reply
New Contributor II

Hi again,

Thank you for your reply, it does make sense, and I've taken a look at the FX3 API Guide PDF.

 

I've figured I've been looking at the wrong example code, since UsbUart is trying to use the USB 3.0... sorry about that. My intentions were simply to connect transfer and recieve data through UART to a USB port on my PC. I've taken a look at the UartLpRegMode code example, which is register mode and relatively straight forward. I can get this to work by using the CyU3PUartTransmitBytes and CyU3PUartReceiveBytes API.

My question is how to transmit and receive bytes via DMA mode (which might be similar to your previous answer). Unfortunately, the  UartLpDmaMode code example doesn't actually transfer any data in the UartLpAppThread_Entry function.

So after following the UartLpDmaMode code example we;

  1. Initialize the UART module
  2. Configure the UART and set it
  3. Configure a DNA Manual channel between UART producer socket and UART consumer socket and create it
  4. Set the UART Tx and Rx transfer size to infinite

From this point, we've configured everything so we (hopefully) simply need to call the transfer and receive APIs which are done a bit differently in DMA mode. Is it correct to do the following:

  1. Initiate a DMA buffer. How do we do this?
  2. Call CyU3PDmaChannelGetBuffer(&glUartLpChHandle, DMA_bubffer, waitOption)
    • What is the default waitOption parameter? From the code examples, they set it to 0.
  3. Call CyU3PDmaChannelCommitBuffer(&glUartLpChHandle, size_of_data, status) continously as we want to send data.

I assume this is how we send data in DMA mode. Do we have to disable UART receiver block before sending, and do we have to configure this (as you do in the UsbUart code example on ~line 590)? Moreover, if I want to send data without filling the buffer, do we simply just call CyU3PDmaChannelSetWrapUp(&glUartLpChHandle)?

Finally, how do we receive data? All of the above are transmitting data. This means, receiving data from the PC through UART (no USB). 

 

Regards,

Søren

0 Likes
Reply
Moderator
Moderator

Hello Søren,

The example UartLpDmaMode implements a simple UART loopback application. That is, when the producer socket (associated with UART receiver) fills a DMA buffer associated with the channel whose handle is glUartLpChHandle, it is committed to the consumer socket (associated with UART transmitter). 

As per my understanding, this is not exactly the application that you need. According to my understanding, you would like to implement the following data paths:

1. Uart Rx to PC (through IN endpoint).

2. PC  (through OUT endpoint) to UART Tx.

Please correct me if my understanding is wrong. 

If this is your application, then the example project UsbUart is the correct reference for you. 

For your remaining questions, please find my comments below:

1. The DMA buffers are generally filled by the producer sockets. If you are planning to use a MANUAL_OUT channel (i.e from CPU to a consumer socket), then it can be filled in the firmware after obtaining an empty buffer. To obtain an empty buffer for a MANUAL_OUT channel, you can make use of the API CyU3PDmaChannelGetBuffer() as mentioned before.

2. The default waitOption parameter is 0.

3. After filling a DMA buffer with the required amount of bytes, you can call the API CyU3PDmaChannelCommitBuffer() for transferring the data to the consumer socket. Note that the API CyU3PDmaChannelCommitBuffer() should be called once for every buffer filled. You should not repeatedly call this API as it can trigger errors.

The API CyU3PDmaChannelSetWrapUp() is used for wrapping up the current active buffer for the channel from the producer side. In the example UsbUart, the DMA buffer size for the channel between UART Rx and In endpoint is 32 bytes. When the UART Rx block of FX3 receives 32 bytes of data (a full buffer is obtained), a PROD_EVENT will be raised. This is handled in the firmware by committing the buffer to the consumer socket. Now, suppose the UART Rx  receive less than 32 bytes of data only. In this case, the data will not be forwarded to the consumer socket as PROD_EVENT is not raised. To workaround this problem, we wrap up the current active buffer for the channel every 50ms. While doing so, care should be taken that the UART receiver is disabled to prevent it from filling more data into the current active buffer. For this, we disable the Rx block before wrap up and re-enable the block after wrap up.  This section of code needs to be used only if it is required for your application.

Regarding your question on receiving the data, for the example UsbUart as mentioned before, the DMA channel is created between UART Producer (associated with UART Rx of FX3) and USB consumer socket (associated with USB IN endpoint of FX3). Whenever, the UART Rx block of FX3 receives data, the DMA buffers associated with this channel are filled forwarded by the firmware to the consumer socket when the DMA buffer is full. If the DMA buffer is not full, we wrap up the current active DMA buffer every 50ms to avoid any data loss.

Please let me know if you have any queries on this.

Best Regards,
Jayakrishna
0 Likes
Reply
New Contributor II

I still think the example UartLpDmaMode is correct. You can see my setup from the picture below:

137511438_2744895932416234_7460787388640804424_n (1).jpg

There is more to it (accelerometer connected via SPI), but I unplugged those components since they are irrelevant for my question here.

I've successfully managed to figure out the example UartLpDmaMode, and it works for me (I can send and receive data with help of the implemented buffer in your APIs). I've also included the CyU3PDmaChannelSetWrapUp() API since it is relevant for my end application. Now my question is how to access this buffer and read it in my firmware. Moreover, how do I fill the buffer by other means than the APIs automatically filling it up from the received data? In other words: I want to parse the incoming data information from the PC to the microcontroller and do actions in my firmware depending on the data input. Basically, I want to make an if-statement(s) that checks the buffer data at certain points in the code, and do actions based upon those.

After I've done the action according to the data in the buffer, I want to insert data into the buffer manually. How do I do this? I've attached my code, and it is specifically on line 41 and 44 where I want to be able to access the buffer manually (if that makes it easier for you to help me).

0 Likes
Reply
Moderator
Moderator

Hello,

Once the data is received at the UART producer socket, PROD_EVENT will be raised for the channel. Inside the PROD_EVENT, you can parse and check the data in the buffer as shown below:

JayakrishnaT_76_0-1610505987175.png

This snapshot also shows how you can insert data manually into the buffer. Please let me know what exactly is the action that you are planning to implement in the firmware once the data is received? We recommend not to add any blocking calls in DMA callback functions as this can delay other operations performed by the driver thread. 

Best Regards,
Jayakrishna
0 Likes
Reply
New Contributor II

Hi again,

Thanks, that was exactly what I was looking for. What I'm planning to do is fill the buffer with data from a SPI connection I have. So eventually I will probably use this buffer (written by the SPI connection) to send through from the CyU3PDmaChannelCommitBuffer() API. But at the same time I need to check the incoming data (in your code snippet example, the temp_buf) to see exactly which and how much SPI data to send back.

If this is a bad practice or a wrong way to go about it (perhaps because of blocking calls in DMA callback functions), then please suggest a different approach.

If I'm going about it the correct way, I consider this thread resolved. Thank you for the help!

Regards,

Søren

0 Likes
Reply
Moderator
Moderator

Hello Søren,

Based on my understanding, the data from the SPI interface will be obtained before the reception of data on the UART interface. Once the data is received on the UART Rx, on the corresponding DMA callback function, the data is parsed and some checks are done on it. Then the data in the buffer (associated with the DMA channel between UART producer and UART consumer socket) is modified with the data received previously from the SPI interface. This modified buffer is sent out using UART Tx. Please confirm if my understanding is correct.

If this is the use case, then it should be okay to proceed with your current approach. If this is not your use case, then please let us know the exact requirement so that we can guide you with the best possible method for implementing your end application.

Best Regards,
Jayakrishna
0 Likes
Reply
New Contributor II

Yes, your understand is correct - this is what I want to do with my end application.

Thank you for the support. I will accept your answer as a solution.

Best regards,

Søren

0 Likes
Reply
New Contributor II

Hi again,

I've run into a problem when trying to manipulate the buffer (and manually insert data). The way you show in the picture in your second-to-latest reply works fine, but if I want to resize the buffer, I get issues. To resize the buffer I say (for example):

input.buffer_p.size = input.buffer_p.size + 2;

input.buffer_p.buffer[8] = 0x01;

input.buffer_p.buffer[9] = 0x02;

Where the initial buffer had a size of 8.

Now the buffer is bigger, and the values are written, but when I commit the buffer with the API CyU3PDmaChannelCommitBuffer(), it returns the correct value (including the extra two), but then doesn't reset the buffer to being empty, but instead resets everything except the extra values I added (in this case two). This means, that because in the for-loop where it wraps up the buffer every 50ms if anything has been stored with the API CyU3PDmaChannelSetWrapUp(), it will always do this and send it every 50ms, since it will always store the first values of the inital array after resizing! How do I avoid this? I can send some pictures of my oscilloscope readings when I arrive at work tomorrow if the situation is not completely clear.

The example in question could be the UartLpDmaMode code example, where when a PROD event occurs, then before you commit the buffer you resize the buffer so it becomes larger and add the new values to those places manually (as I did above). Then this problem will occur.

Hope you still follow the thread even though I've marked your answer as a solution!

Best regards,

Søren

0 Likes
Reply
Moderator
Moderator

Hello Søren,

It is not recommended to change the DMA buffer size inside the DMA callback function. Please use a larger DMA size while you create the channel if required. Also, the DMA buffer size needs to a multiple of 16 bytes.  

Please let me know if you are adding the additional data to the end of the buffer or to the beginning of the buffer? It would be great if you can share the code for us to check.

Best Regards,
Jayakrishna
0 Likes
Reply
New Contributor II

Hi,

I've provided the code where you can explicitly see what I want to do. I've added comments in the code to show my thought process for the different ideas. The exact location in the code you need to look at lines 45-84.

Just for clarity, I've provided the oscilloscope outputs in the original and my changed version for you to see the difference (I will provide it in 5-10 mins after running the tests).

0 Likes
Reply
Moderator
Moderator

Hello Søren,

In the code share, I see that entry_func is used to get the handle to the buffer you want over UART. And the additional data is overwritten to the first few bytes (equal to response_buffer_dma.response_size ) DMA buffer. so the additional data is to written at the starting (beginning) of the DMA buffer. Is my understanding correct?

If yes, please let me know the maximum size of response_buffer_dma.response_size so that we can make the modifications accordingly. Also share the source of entry_func

 

Regards,
Rashi
0 Likes
Reply
New Contributor II

entry_func is used to retrieve a new array (and its size) (which can be completely different to the input buffer), and is what I want to send out. Essentially, I don't need the input buffer anymore after I've gotten the entry_func buffer. It returns the array and size (a struct), that is stored in response_buffer_dma. I'm not sure this answers your question - if not let me know. So the data in response_buffer_dma needs to be written to a dma buffer (in the channel used), such that it can be sent out.

The maximum size of the response array (buffer) will be around 250 bytes. The least amount will be 8 bytes.

I've provided the source of entry_func. Please note that it returns 10 bytes by default for testing purposes now, but this is not the end application (the end application is without the beginning of the entry_func). I've also modified the entry_func names to entry_func_dmamode both in the source of it and the uart.c source file, just so you know and avoid confusion.

Also, as the modbus_self_implemented.c might indicate, I have gotten this to work for the register mode, but I want it to work for DMA mode to parse different inputs from modbus masters (including ASCII  inputs which are longer than RTU inputs (the case of it now)).

I've also attached the behaviour of the program (pictures) when I modify the buffers size and data, and when its running normally and how that is the desired outcome. As you can see in the incorrect_behaviour picture, it keeps sending the same data since it keeps being stored in the buffer and thus invokes the prod event every 50ms because of the API CyU3PDmaChannelSetWrapUp(), where I want it to be erased, such that nothing is wrapped up until a new input is recieved.

 

0 Likes
Reply
Moderator
Moderator

Hello,

This is an expected behaviour. Whenever, the API CyU3PDmaChannelSetWrapUp() is called, a PROD_EVENT will be signalled for that channel. Inside the PROD_EVENT, you are manually filling the data and the filled data is sent out. Ifthe UART PROD socket is not sending any data to FX3 and still the PROD_EVENT is triggered, then it should be due to the API CyU3PDmaChannelSetWrapUp(). In this case, you can check the amount of meaningful data in the DMA buffer by looking into the following:

input->buffer_p.count //this gives the amount of meaningful data in the buffer

Now, if the value above is 0, you can discard the buffer by using the API CyU3PDmaChannelDiscardBuffer(). In this case, you need not fill any data into the buffer manually. However, if the wrapup was triggered with atleast one byte of data, the filling of buffer will take place and it will be sent out. 

Please try this and let me know the result.

Best Regards,
Jayakrishna
New Contributor II

This is exactly what I was looking for. If I do the (input->buffer_p.count != 0) check before handling anything, I send a buffer that I manually choose 🙂 Thank you for the support!

Best regards,

Søren

0 Likes
Reply