SPI clock pause and restart in Cypress FX3

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

cross mob
lock attach
Attachments are accessible only for community members.
RiBe_4514336
Level 1
Level 1
5 replies posted First reply posted First question asked

Hello,

I have a problem programming the Superspeed Explorer Kit.

I want to send 4 buffer of 200 Byte using spi. Sometimes happen that the clock 'pause' itself for ~20us and then restart whit the correct data.

I tried different frequencies, I disabled the CyU3PDebugPrint() function and I tried to build the project in Release mode but nothing changes.

I attach the code and also an oscilloscope screenshot whit the error.

CyFxSpiInit();

CyU3PSpiSetSsnLine(CyFalse);

CyU3PSpiTransmitWords(spi_cmd,1);

CyU3PSpiSetSsnLine(CyTrue);

CyU3PBusyWait(200);

CyU3PSpiSetSsnLine(CyFalse);

CyU3PSpiTransmitWords(mosi_buff_1,200);

CyU3PSpiSetSsnLine(CyTrue);

CyU3PBusyWait(200);

CyU3PSpiSetSsnLine(CyFalse);

CyU3PSpiTransmitWords(mosi_buff_2,200);

CyU3PSpiSetSsnLine(CyTrue);

CyU3PBusyWait(200);

CyU3PSpiSetSsnLine(CyFalse);

CyU3PSpiTransmitWords(mosi_buff_3,200);

CyU3PSpiSetSsnLine(CyTrue);

CyU3PBusyWait(200);

CyU3PSpiSetSsnLine(CyFalse);

CyU3PSpiTransmitWords(mosi_buff_4,200);

CyU3PSpiSetSsnLine(CyTrue);

Here the CyFxSpiInit() function:

CyU3PReturnStatus_t

CyFxSpiInit (void)

{

   CyU3PSpiConfig_t spiConfig;

    CyU3PReturnStatus_t status = CY_U3P_SUCCESS;

    /* Start the SPI module and configure the master. */

    status = CyU3PSpiInit();

    if (status != CY_U3P_SUCCESS)

    {

        return status;

    }

   CyU3PMemSet ((uint8_t *)&spiConfig, 0, sizeof(spiConfig));

    spiConfig.isLsbFirst = CyFalse;

    spiConfig.cpol       = CyFalse;//CyTrue;

    spiConfig.cpha       = CyFalse;//CyTrue;

    spiConfig.ssnPol     = CyFalse;

    spiConfig.leadTime   = CY_U3P_SPI_SSN_LAG_LEAD_ONE_HALF_CLK;

    spiConfig.lagTime    = CY_U3P_SPI_SSN_LAG_LEAD_ONE_HALF_CLK;

    spiConfig.ssnCtrl    = CY_U3P_SPI_SSN_CTRL_FW;

    spiConfig.clock      = 8000000 ;

    spiConfig.wordLen    = 8;

    status = CyU3PSpiSetConfig (&spiConfig, NULL);

    return status;

}

0 Likes
1 Solution
lock attach
Attachments are accessible only for community members.

Hello,

Please try using the attached library and let me know if you face the issue again. Please note that the SCK may still go to idle state, but the data loss should be avoided.

Best Regards,

Jayakrishna

Best Regards,
Jayakrishna

View solution in original post

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

Hello,

Please let me know the answers to my questions below in order to understand the issue better:

1. From the oscilloscope traces, I understand that the clock is paused for 20uS in between a transfer (in between a transfer of 200 bytes). Please confirm if my understanding is correct. Also, please let me know if this happens for all the 200 byte transfers or if it appears for only some or if it is random.

2. Is the ~20uS delay constant whenever this issue is seen?

3. According to my understanding, the data is received correctly by the slave without any bytes being missed. Please let me know if my understanding is correct and if the pause and restart of ~20uS is the thing of concern addressed here.

4. Please let me know which firmware is used for your testing. Is it a modification of an example project in SDK? If not, can you please share the complete project so that I can have a look at it. Also, please let me know the number of RTOS threads that you are using in your project.

5. Please let me know how are you filling the data into the buffers.

6. I understood that you tried to change the SPI interface frequency. Please let me know if this had an impact on the pause duration or not (did it increase or reduce the pause duration?).

7. Please confirm that you are using FX3 SDK version 1.3.4 which is the latest version of FX3 SDK.

Also, can you please let me know if this 200uS delay is essential for the slave? If not, can you please remove this delay and try sending all the 4x200 Bytes together? If it is possible, please try testing this and let me know if this test also shows the pause and restart of SPI clock.

Best Regards,

Jayakrishna

Best Regards,
Jayakrishna
0 Likes

Hello,

1. From the oscilloscope traces, I understand that the clock is paused for 20uS in between a transfer (in between a transfer of 200 bytes). Please confirm if my understanding is correct. Also, please let me know if this happens for all the 200 byte transfers or if it appears for only some or if it is random.

I made more test, here a table with 11 'lost packets' @8MHz

clock_paused.png

in the first column, there is the 'paused time', in the second column there is the number of the SPI transfer in which I found the stop and in the 3rd column, there is the byte lost during the pause.

The pause happens for one or more 200Bytes transfer randomly

3. According to my understanding, the data is received correctly by the slave without any bytes being missed. Please let me know if my understanding is correct and if the pause and restart of ~20uS is the thing of concern addressed here.

The data is received correctly by the slave with the last bytes missing, see column 3 of the table above, I send a ramp from 0 to 199 and I don't have any discontinuity on the data, I lost only the last packet (probably an interrupt that stops the transfer?).

eg. When I lost 3 Bytes I have the buffer filled correctly since the 'receive_buf[196]' and the remaining 'receive_buf[197]', 'receive_buf[198]', 'receive_buf[199]' are equal to 0;

4. Please let me know which firmware is used for your testing. Is it a modification of an example project in SDK? If not, can you please share the complete project so that I can have a look at it. Also, please let me know the number of RTOS threads that you are using in your project.

The starting firmware was the GpifToUsb example, I use one thread, here the initialization:

/* Application define function which creates the threads. */

void

CyFxApplicationDefine (

        void)

{

    void *ptr = NULL;

    uint32_t ret = CY_U3P_SUCCESS;

    /* Allocate the memory for the threads */

    ptr = CyU3PMemAlloc (CY_FX_GPIFTOUSB_THREAD_STACK);

    /* Create the thread for the application */

    ret = CyU3PThreadCreate (&glAppThread,                      /* App thread structure */

    "1:Gpit_to_USB",  //"21:Gpit_to_USB",                    /* Thread ID and thread name */

                          CyFxAppThread_Entry,                  /* App thread entry function */

                          0,                                    /* No input parameter to thread */

                          ptr,                                  /* Pointer to the allocated thread stack */

                          CY_FX_GPIFTOUSB_THREAD_STACK,        /* App thread stack size */

                          CY_FX_GPIFTOUSB_THREAD_PRIORITY,      /* App thread priority */ (8)

                          CY_FX_GPIFTOUSB_THREAD_PRIORITY,      /* App thread priority */

                          CYU3P_NO_TIME_SLICE,                  /* No time slice for the application thread */

                          CYU3P_AUTO_START                      /* Start the thread immediately */

                          );

    /* Check the return code */

    if (ret != 0)

    {

        /* Thread Creation failed with the error code retThrdCreate */

        /* Add custom recovery or debug actions here */

        /* Application cannot continue */

        /* Loop indefinitely */

        while(1);

    }

}

I tried to change the Thread's priority but nothing changes

5. Please let me know how are you filling the data into the buffers.

I fill the buffer with a ramp from 0 to 199 to test the firmware, in the real application I take the values from the USB (I have the same issue).

6. I understood that you tried to change the SPI interface frequency. Please let me know if this had an impact on the pause duration or not (did it increase or reduce the pause duration?).

Yes, I tried 8MHz and the mean pause time is 13.5uS, with some stop of 680 ns, 4 MHz -> ~10us, 2MHz -> ~3us.

Honestly, I've never seen a 20us again.

7. Please confirm that you are using FX3 SDK version 1.3.4 which is the latest version of FX3 SDK.

Yes

Also, can you please let me know if this 200uS delay is essential for the slave? If not, can you please remove this delay and try sending all the 4x200 Bytes together? If it is possible, please try testing this and let me know if this test also shows the pause and restart of SPI clock.

I tried different delays but nothing changes, also whit 15us I have the same issue. I cant send 800 Bytes together because the slave has a limitation of 255 Byte for each transfer.

I also tried to control the ssn pin using CY_U3P_SPI_SSN_CTRL_HW_END_OF_XFER and I found that also the ssn line goes high for the same period of time.

Thanks

Riccardo

0 Likes

Hello,

Thank you for sharing the results after detailed tests.

I understand that the data loss is seen at the end of the transfer and not when the SCK goes idle. I also understood that finally, the data needs to be sent from the host to FX3. In this case, can you please refer to the SDK example cyfxusbspidmamode. The example project can be found in the following location:

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

This example enumerates the  device as a vendor specific USB device with only the control endpoint and provides a set of vendor commands to read/write the data on SPI flash devices. The example is used for reading/writing data from/to SPI flash devices. You can modify this example for your SPI slave device.

Please refer to the readme file present along with this example project. From this, it can be understood that the vendor command 0xC2 is used for writing into the SPI flash. If you refer to the handling of vendor command 0xC2 (Macro: CY_FX_RQT_SPI_FLASH_WRITE), it can be understood that the function CyFxSpiTransfer() is invoked. As this example is used for communicating with SPI flash device, the address bytes and command is sent out to the SPI flash initially using the API CyU3PSpiTransmitWords() (prior to the data transfer). In your case, my understanding is that before writing the data, only a command needs to be send to the flash device. Note that only the command is sent out using the API CyU3PSpiTransmitWords() which makes use of SPI transfer in register mode. The data is transferred using DMA mode. This is done by the following piece of code:

            CyU3PSpiSetBlockXfer (glSpiPageSize, 0);

            status = CyU3PDmaChannelSetupSendBuffer (&glSpiTxHandle,

                    &buf_p);

            if (status != CY_U3P_SUCCESS)

            {

                CyU3PSpiSetSsnLine (CyTrue);

                return status;

            }

            status = CyU3PDmaChannelWaitForCompletion(&glSpiTxHandle,

                    CY_FX_USB_SPI_TIMEOUT);

            if (status != CY_U3P_SUCCESS)

            {

                CyU3PSpiSetSsnLine (CyTrue);

                return status;

            }

            CyU3PSpiSetSsnLine (CyTrue);

            CyU3PSpiDisableBlockXfer (CyTrue, CyFalse);

Please note that the SS line should be set to 0 (by using CyU3PSpiSetSsnLine (CyFalse);) before the above code. While sending the vendor command, you can provide the data that is to be sent to the device using Control Center application. You can customize this example project by adding more vendor commands (one for sending the command to SPI slave device, second for sending first 200 bytes, next for sending second 200 bytes and so on). But, before sending each data packet of 200 bytes to the slave device, the sequence of code mentioned above should be followed.

Please let me know if you need any clarifications on this. Please try this and let me know if you find any issue again.

Best Regards,

Jayakrishna

Best Regards,
Jayakrishna
0 Likes

Hello,

is it possible to use spi dma transfer using a bulk type endpoint?

thanks

0 Likes

Hello,

It is possible to use SPI DMA transfer using a bulk type endpoint. But we do not have a reference example project for this. You can try to modify the SDK example SPI dma mode to serve your requirement by referring to the SDK example USBBulkSrcSink  as follows:

1. The descriptors should support 2 endpoints (1 IN and 1 OUT) if you plan to write and read from the spi slave device. However if you plan to either write or read to/from the device, then only one endpoint is required. Please refer to the SDK example project USBBulkSrcSink to understand how the descriptors are to be changed.

2. The endpoints added needs to be configured. Please refer to the function CyFxBulkSrcSinkApplnStart() inside cyfxbulksrcsink.c source file of the example project USBBulkSrcSink to understand how to configure the endpoints.

3. The DMA channel in the default cyfxusbspidmamode project is between CPU and SPI sockets. These are to be changed between the corresponding Endpoint sockets and the SPI sockets. Also, in the default cyfxusbspidmamode project, the DMA buffer count is 0. This can be changed to a non zero value based on your requirement. Also, there should be a callback function registered and the notification should be set to (CY_U3P_DMA_CB_PROD_EVENT | CY_U3P_DMA_CB_CONS_EVENT). The example project USBBulkSrcSink can be used as a reference for these changes. Please note that the API CyU3PDmaChannelSetXfer() should not be called immediately after creating the channel.

4. Use a vendor command at the start to send the command to the SPI slave device (the command of one byte). After this is done, switch the SPI block to DMA mode and set the DMA channel transfer size. You can use the following lines of code to handle the vendor command:

  1. CyU3PSpiSetSsnLine(CyFalse); 
  2. CyU3PSpiTransmitWords(spi_cmd,1); //for sending the command in reg mode
  3. CyU3PSpiSetSsnLine(CyTrue); 
  4. CyU3PDmaChannelSetXfer(&chhandle, 200); //for setting the DMA transfer size
  5. CyU3PSpiSetBlockXfer(200,0); //for sending data in DMA mode.

5. Now, send the data through the bulk endpoint. The callback function will be triggered. Check if the type is CY_U3P_DMA_CB_PROD_EVENT. If the type is CY_U3P_DMA_CB_PROD_EVENT, then use the following lines of code to send the data to the SPI block:

  1. CyU3PSpiSetSsnLine(CyFalse);
  2. CyU3PDmaChannelCommitBuffer(chHandle, buf_p.size, 0); //for sending the data in DMA mode

6. Now, wait for the slave to receive the data that was sent. When the slave receives the data completely, the callback function will be triggered again. Check if the type is CY_U3P_DMA_CB_CONS_EVENT. If the type is CY_U3P_DMA_CB_CONS_EVENT, then do the following:

                 a. CyU3PSpiSetSsnLine(CyTrue);

                 b. Set a global boolean variable (initialized as CyFalse) to CyTrue.

                 c. CyU3PSpiDisableBlockXfer (CyTrue, CyFalse);

7. Use another vendor command to check if the global variable is set to CyTrue or not. If it is set to CyTrue, then it indicates that the data sent was consumed by the slave. Inside the handling of the vendor command, do the following:

                 a. Check if the global boolean variable is set to CyTrue. If it is set to CyTrue, then do the following:

                   i. CyU3PDmaChannelSetXfer(&chhandle, 200); //for setting the DMA transfer size

                    ii.CyU3PSpiSetBlockXfer(200,0); //for sending data in DMA mode.

                    iii. Return one byte of data to host to indicate that it can send more data through the bulk endpoint.

                    

                   b. If the global boolean variable is not set to CyTrue, then send one byte of data to the host to indicate that it cannot send more data through the bulk endpoint because the previous data is not yet consumed.

The data can be send to the host by using the API CyU3PUsbSendEP0Data().

8. On the host side, check if the data returned by the vendor command allows to send more data to the bulk endpoint. If yes, then send the data. Otherwise, keep on sending the vendor command to check when the data can be send through the bulk endpoint.

As mentioned above, this is a suggestion which you can try at your end. We have not tested this approach. We recommend that you follow the approach mentioned in my previous response as it is easy to implement. You are welcome to provide a better solution also.

Best Regards,

Jayakrishna

Best Regards,
Jayakrishna
0 Likes

Hello Jayakrishna,

I didn't try your solution yet, I noticed that the clock pauses with some regularity.

I try to send a transfer of 20 KBytes and the results are different depending on the word length.

Using 4-bit length the interference is periodic and it happens every 974 us, with 8-bit length the interference happens randomly but with a periodicity of 974 us or multiple.

D2 is chip select, D3 is clock

SDS00002.BMP

When I set chip select in CY_U3P_SPI_SSN_CTRL_HW_END_OF_XFER also the cs line stops as the clock, but if I set chip select as CY_U3P_SPI_SSN_CTRL_FW the problem on ssn line disappears but remains in the clock line.

There are any limitations on using spi in reg mode?

Thanks

0 Likes

Hello,

Please find the link below to a thread in which a similar issue was reported while using SPI in reg mode:

CyU3PSpiTransmitWords bug (SDK library 1.34)

The issue mentioned in this thread seems to occur due to the same reason as mentioned in the thread link above. This conclusion was made on the basis of the following understandings from your tests:

1. SCK goes idle. From section 8.3.4 of FX3 SDK, the SCK goes idle when the TX fifo is empty.

2. A data loss is seen at the end of the transfer

Can you please try using the library attached in response 11 of the following thread and let us know if you are seeing the data loss again?

commit error and back flow error in UVC AN75779

As mentioned in response 11 of the thread above, this library is only a test library and not an official release version.

Note that even with this library, the SCK may still go to idle state due to the reason mentioned before in this response. Also, for large data transfers, it is recommended to use DMA mode. So, please try my suggestion and implement SPI transfers in DMA mode.

Best Regards,

Jayakrishna

Best Regards,
Jayakrishna
0 Likes

Hello,

I tried to change the library found in commit error and back flow error in UVC AN75779 but nothing change.

0 Likes
lock attach
Attachments are accessible only for community members.

Hello,

Please try using the attached library and let me know if you face the issue again. Please note that the SCK may still go to idle state, but the data loss should be avoided.

Best Regards,

Jayakrishna

Best Regards,
Jayakrishna
0 Likes

Hello,

I changed the library in C:\Program Files (x86)\Cypress\EZ-USB FX3 SDK\1.3\fw_lib\1_3_4\fx3_debug, it seems to work properly now, the clock still goes idle but the data are correct.

Thanks

0 Likes

Hello,

As mentioned before, this issue happening here is described in the following thread:

CyU3PSpiTransmitWords bug (SDK library 1.34)

From section 8.3.4 of FX3 SDK, the SCK goes idle when the TX fifo is empty. The TX fifo can get empty due to the reason mentioned in the above thread. This is the reason why SCK goes idle. But the data loss should be avoided. Again, for large data transfers we recommend that you use DMA mode.

Best Regards,

Jayakrishna

Best Regards,
Jayakrishna
0 Likes

Hello,

I have the same problem。Do you solve it,can you tell me what I should do? Thank you very much!

0 Likes

Hello,

Please refer to my response 7 to understand the cause for this problem. Please try the suggestions listed in the same response and let us know if it helps.

Best Regards,

Jayakrishna

Best Regards,
Jayakrishna
0 Likes