FX3 DMA Buffer filling

Tip / Sign in to post questions, reply, level up, and achieve exciting badges. Know more

cross mob
jl46
Level 4
Level 4
50 replies posted 50 sign-ins 25 replies posted

Hello,

In configuring the DMA channels, the size and count parameters dictate the amount of data that can be stored within the DMA channel:

jl46_0-1631840965900.png

What I understood from this is that there would be CY_FX_BULKLP_DMA_BUF_COUNT buffers with size of size * 8 where data can be stored etc. in the DMA channel i.e. size = 8192, count = 2 means 2x8192 buffer size total.

Is there a way that I can fill up the two buffers consecutively before committing them for sending? What I currently tried is filling up one whole buffer and then committing it before filling up the next buffer for another commit. I would like to try filling up both or all available buffers first before committing to minimize the commit buffer call.

Thanks,
jl46

0 Likes
1 Solution
JayakrishnaT_76
Moderator
Moderator
Moderator
First question asked 1000 replies posted 750 replies posted

Hello,

Yes, SPI flash can be used to store the data. But, if you are using SPI flash for booting the firmware for FX3 device, then you should make sure that the data to be sent out through the USB endpoint will not corrupt the firmware image. You can make use of a sector that is not used for storing the firmware image for storing the data. This is because SPI flashes needs to be erased before storing new data. You can refer to the following project in the FX3 SDK as a reference for reading and writing data from/to SPI flash:

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

Best Regards,
Jayakrishna

View solution in original post

0 Likes
25 Replies
jl46
Level 4
Level 4
50 replies posted 50 sign-ins 25 replies posted

The firmware that I'm using is based on the bulkloopmanualinout example code.

Thanks,
jl46

0 Likes
JayakrishnaT_76
Moderator
Moderator
Moderator
First question asked 1000 replies posted 750 replies posted

Hello,

I believe that you are planning to use MANUAL OUT channel (from CPU socket to a USB EP socket). Please correct me if my understanding is wrong.

In this case the API CyU3PDmaChannelGetBuffer() can be used to obtain an empty buffer that can be filled by the firmware. After the buffer is obtained, you should fill it and commit it before calling the next CyU3PDmaChannelGetBuffer(). If you call CyU3PDmaChannelGetBuffer () multiple times before calling the API CyU3PDmaChannelCommitBuffer (), then only the last filled data will be committed i.e the buffer will be overwritten. 

So, it is not possible fill a second buffer before committing the first buffer. 

Best Regards,
Jayakrishna
0 Likes

Hello Jayakrishna,

Yes, I'm using the Manual OUT channel like in the ManualInOut example.

Is this only for the ManualInOut example or can this limitation be minimized or eliminated when using a different firmware example e.g. the one with DMA Callback?

Thanks,
jl46

0 Likes
JayakrishnaT_76
Moderator
Moderator
Moderator
First question asked 1000 replies posted 750 replies posted

Hello,

If you want to send a data from firmware (CPU) to host (USB IN endpoint), then you can make use of a MANUAL OUT channel. In this channel, the data transfer as mentioned in my previous response. So, it is not possible to realize your requirement with this channel.

Now, if the producer is some other block like an FPGA, then you can try the following approach:

1. Interface the FPGA with the GPIF II socket (P Port).

2. Make use of a manual channel with P Port as producer and Endpoint socket as consumer socket and register a callback function with appropriate notifications.

3. Inside the DMA  callback, for the producer event, just count the number of buffers received.

4. Inside the infinite for loop, you can call the API CyU3PDmaChannelGetBuffer() and commit the buffer by using CyU3PDmaChannelCommitBuffer (). 

If you are using this method, then you need to ensure that the host reads out data before the buffers are exhausted. 

Please let us know why you want to fill all the buffers first and then commit them later? 

Best Regards,
Jayakrishna
0 Likes

Hi Jayakrishna,

The data that I'm collecting is from the gpio registers. I extract the bits that correspond to specific GPIOs i.e. 23 - 27. In my current implementation, I'm storing the data in a DMA buffer and then committing the buffer before capturing data again. 

I was able to set the DMA size to 32768 and the buf count to 2 meaning that I can capture 2 x 32768 bytes but once I fill up the 32768 buffer, I commit it and then capture again. I think that the commit instance causes me to miss some bytes. This is why I was asking if there's a way to fill up the buffers first before performing a commit.

Thanks,
jl46

0 Likes
JayakrishnaT_76
Moderator
Moderator
Moderator
First question asked 1000 replies posted 750 replies posted

Hello,

You can try the following:

1. Use a larger DMA buffer to store the data

2. If you have enough size for allocating DMA buffers, then you can make use of the API CyU3PDmaBufferAlloc () to allocate required amount of buffer memory. You can allocate a buffer of 32KB using this API. After the buffer is allocated, you can store the data into this buffer. Later you can copy the data from this buffer into the buffer returned by the CyU3PDmaChannelGetBuffer () API and commit the same. But, this method will again add up the delay. Also, if you are planning to use CyU3PDmaBufferAlloc (), then make sure that the allocated buffers are freed by using the API CyU3PDmaBufferFree () after their use.

Best Regards,
Jayakrishna
0 Likes

Hi Jayakrishna,

Option 1 seems to be good but only to a certain extent because the buffer size set is limited and so the amount of data points that I could send in 1 commit would still be limited by the max buffer size.

Option 2 as you said would induce additional delay  which is also a limitation to what I'm trying to accomplish.

I have an onboard S25FL064LABMFB011 SPI Flash memory. It seems to be working because I am able to store firmware on the board thru SPI flash. I am looking at the datasheet but I can't seem to get the needed process to store data there. Based on my schematic, the memory is operating like a typical SPI device (send data on MOSI, receive from MISO). Is the SPI flash memory a possible approach to store the needed equivalent data I need before committing the saved data to the buffer for sending? If so, is there an easier reference I can look at to know the needed SPI sequence to write on the SPI flash memory?

Thanks,
jl46

0 Likes
jl46
Level 4
Level 4
50 replies posted 50 sign-ins 25 replies posted

I also thought of using a one-to-many approach where I would store the variables in the buffer of consumer1 and then to consumer2 up to consumer N and then commit them all afterwards. Is it possible to also use this approach where I store data on the buffer of multiple consumer channels and then commit them all once they are all filled up?

Thanks,
jl46

0 Likes
JayakrishnaT_76
Moderator
Moderator
Moderator
First question asked 1000 replies posted 750 replies posted

Hello,

CPU socket is not a valid producer socket for a MANUAL one to many channel. If CPU socket is used, then the API CyU3PDmaMultiChannelCreate () will fail with error code 0x40 (CY_U3P_ERROR_BAD_ARGUMENT).

Best Regards,
Jayakrishna
0 Likes
JayakrishnaT_76
Moderator
Moderator
Moderator
First question asked 1000 replies posted 750 replies posted

Hello,

Yes, SPI flash can be used to store the data. But, if you are using SPI flash for booting the firmware for FX3 device, then you should make sure that the data to be sent out through the USB endpoint will not corrupt the firmware image. You can make use of a sector that is not used for storing the firmware image for storing the data. This is because SPI flashes needs to be erased before storing new data. You can refer to the following project in the FX3 SDK as a reference for reading and writing data from/to SPI flash:

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

Best Regards,
Jayakrishna
0 Likes

Hi Jayakrishna,

How can I know / check which sector the firmware is stored in the SPI flash memory so that I know what not to access if ever?

Are the functions in the spidmamode example directly compatible with the SPI flash memory, hardware connection-wise? I checked the example and I saw the functions for reading etc. but in the main thread they aren't used. Also, does this mean that I need to setup another DMA channel for the SPI access?

Thanks,
jl46

0 Likes
JayakrishnaT_76
Moderator
Moderator
Moderator
First question asked 1000 replies posted 750 replies posted

Hello,

When control center is used for programming the SPI flash, the firmware is stored in the flash starting from address 0 of the flash. Suppose the sector size is 64KB and if the firmware size is 120KB, then we can understand that it takes 2 sectors of the SPI flash to store the firmware image. In this case, you can write the data into any sectors other than the first 2 sectors.

The following KBA documents the SPI flashes compatible with FX3 device:

https://community.cypress.com/t5/Knowledge-Base-Articles/Selection-of-SPI-Flash-Compatible-with-FX3-...

The same command set is used by the project that was shared in my previous response. In the example project, vendor commands are used to initiate the read/write from the flash device. As mentioned in my previous response, this is just a reference project and can be used to develop your own project based on your requirement. The functions for reading, writing and erasing are called inside the function CyFxUSBSetupCB () after parsing the vendor commands received from the host.

Also, does this mean that I need to setup another DMA channel for the SPI access?

>> Yes, you need to setup another DMA channel for SPI access as this example is based on SPI in DMA mode. There is another example using SPI in register mode. This can be found in the following location of FX3 SDK:

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

But, register mode is slow compared to DMA mode and might not fulfill your requirements.

Best Regards,
Jayakrishna
0 Likes

Hi Jayakrishna,

I see. I will look more into the dma mode of spi example to understand how the function is used. 

Just another thought, what if instead of using a one to many channel, I can just keep the manual In Out that I have right now and declare another output buffer variable i.e. outBuf_2p etc. and store the other data there? I can then just commit buffer to the output channel using the different outBuf variables declared that would be filled up. Is this possible? 

Thanks,
jl46

0 Likes
JayakrishnaT_76
Moderator
Moderator
Moderator
First question asked 1000 replies posted 750 replies posted

Hello,

This approach was already mentioned in my previous response. The same is written again below for your reference:

"If you have enough size for allocating DMA buffers, then you can make use of the API CyU3PDmaBufferAlloc () to allocate required amount of buffer memory. You can allocate a buffer of 32KB using this API. After the buffer is allocated, you can store the data into this buffer. Later you can copy the data from this buffer into the buffer returned by the CyU3PDmaChannelGetBuffer () API and commit the same. But, this method will again add up the delay. Also, if you are planning to use CyU3PDmaBufferAlloc (), then make sure that the allocated buffers are freed by using the API CyU3PDmaBufferFree () after their use."

Basically you need to allocate a buffer in the memory rather than just declaring it. This can be done by using the API  CyU3PDmaBufferAlloc (). But, this buffer cannot be committed until it is explicitly copied into a buffer associated with the DMA channel. For obtaining a free buffer associated with the MANUAL OUT channel, the API CyU3PDmaChannelGetBuffer () should be used. Then the buffer that was used for storing the data needs to be copied to the free buffer associated with the DMA channel. Only after this, the buffer can be committed to the consumer socket.

Best Regards,
Jayakrishna
0 Likes

Hi Jayakrishna,

I see. I will try to look more into the DMA SPI example as it is faster and can enable me to write or read to/from the SPI flash memory I have onboard. Hopefully I get this to work.

Thanks,
jl46

0 Likes
jl46
Level 4
Level 4
50 replies posted 50 sign-ins 25 replies posted

Hi Jayakrishna,

It seems that the SPI DMA mode performs transactions on the control end point and I am not familiar with this mode of transfer. Is there a reference / guide that I can look at to know what to put in the necessary fields so that I can try the vendor requests etc.

Thanks,
jl46

0 Likes
JayakrishnaT_76
Moderator
Moderator
Moderator
First question asked 1000 replies posted 750 replies posted

Hello,

You can refer to the readme file that comes along with the project. It can be found along with the project files in the following location:

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

Best Regards,
Jayakrishna
0 Likes
jl46
Level 4
Level 4
50 replies posted 50 sign-ins 25 replies posted

Hi Jayakrishna,

I was able to figure out the transfer using the control endpoint in control center. I tried using the SPI write and read functions to see if I was able to successfulyy write data but this is what I'm getting:

jl46_0-1632127667691.png

 

I wrote the string "testing" using the SPI write command and the readback value using SPI read command is "@A H". The SPI flash memory I'm using is the S25FL064LABMFB011, CYUSB3011 chip and set up to boot in USB mode. Is there a step I'm using to make sure that I'm doing everything correctly? 

Thanks,
jl46

 

0 Likes
JayakrishnaT_76
Moderator
Moderator
Moderator
First question asked 1000 replies posted 750 replies posted

Hello,

Please let me know if you erased the sector before writing data into the SPI flash. This is required to write data into the flash. If you have not used the vendor command for erasing the flash sectors, then please use it before writing data into the flash. Please share snapshots of control center application after each vendor command transfer for us to check.

Best Regards,
Jayakrishna
0 Likes

Hi Jayakrishna,

I was able to write and read properly by doing the erase sector. It seems that if I want to overwrite a data, i must first erase the contents of the existing address / location.

I will try to incorporate the functions to my modified firmware and see if this would help my requirements.  I was just wondering, how many bytes can i store in one address / sector of the SPI flash memory? 

 

Thanks,
jl46

0 Likes
JayakrishnaT_76
Moderator
Moderator
Moderator
First question asked 1000 replies posted 750 replies posted

Hello,

Yes, as I mentioned before, you need to erase the flash before writing data into it. The sector size of the flash should be available in the datasheet of the flash. 

Best Regards,
Jayakrishna
0 Likes
jl46
Level 4
Level 4
50 replies posted 50 sign-ins 25 replies posted

Hi Jayakrishna,

I checked with the manualInOut firmware and it seems that if I were to incorporate the SPI DMA functions, there would be conflict in the producer and consumer socket IDs. How can I resolve this? 

 

Thanks,
jl46

0 Likes
JayakrishnaT_76
Moderator
Moderator
Moderator
First question asked 1000 replies posted 750 replies posted

Hello,

Can you please elaborate the statement "there would be conflict in the producer and consumer socket IDs" so that we can understand it better? How are you planning to create the DMA channels for this application?

Best Regards,
Jayakrishna
0 Likes

Hi Jayakrishna,

In the SPI DMA code, the DMA channel is initialized as so:

jl46_0-1632140467406.png


In the ManualInOut firmware, the DMA channel is initialized as follows:

jl46_1-1632140531969.png

I noticed that the prodSckId and consSckId for both manual IN, OUT, SPI TX, and SPI RX channels which lead me to think that there might be some conflict in the DMA initialization. For example, both SPI RX and the Manual IN consSckId are both noted as CY_U3P_CPU_SOCKET_CONS.

 

Thanks,
jl46

0 Likes
JayakrishnaT_76
Moderator
Moderator
Moderator
First question asked 1000 replies posted 750 replies posted

Hello,

The DMA channels used in both the example projects will be different as both the projects are functionally different. In the SPI example, you can find that the DMA channels are created between SPI and CPU sockets. But, for the ManualInOut firmware, the DMA channels are created between CPU and endpoint sockets. You can modify the ManualInOut so that the channels between CPU and SPI sockets along with the additional code required to read data from the SPI flash is added to it. 

As mentioned before, in the SPI example, the data is sent as response to a vendor command. This is done by first reading data using the SPI to CPU channel and then sending it out through the control channel. For your use case, you need to have a DMA channel between SPI producer and CPU consumer socket. This channel will be used to read data from the SPI flash. Once the data is read, you can send it out through another channel that is created between CPU and the endpoint socket. For writing data into SPI flash, you would need another channel between CPU and endpoint socket. The remaining code/logic can be implemented based on your requirements by referring to the SPI example project that was shared earlier in this thread.

Best Regards,
Jayakrishna
0 Likes