Xilinx / embeddedsw

Xilinx Embedded Software (embeddedsw) Development
Other
944 stars 1.07k forks source link

PS SPI Polled transfer with manual SS and auto start does not properly work #42

Open mariobarbareschi opened 6 years ago

mariobarbareschi commented 6 years ago

The function XSpiPs_PolledTransfer checks the transfer completion by testing the flag XSPIPS_IXR_TXOW_MASK, which is reported to be the flag indicating the TX FIFO overwater, meant to be asserted whenever the content of TX FIFO crosses the configured watermark. This causes an issue when the master is configured with the manual SS mode. Indeed, checking the XSPIPS_IXR_TXOW_MASK causes the de assertion of SS before the transfer is completed; this is due to the fact that the TX FIFO is being dequeued until it is empty when the master is configured with the auto start mode.

To resolve the problem, a simply work around can be adopted: instead of checking the XSPIPS_IXR_TXOW_MASK (raw 576 of xspips.c), it should be enough to check the condition XSPIPS_IXR_RXNEMPTY_MASK once the RX Watermark is set equal to the amount of byte queued into the TX fifo. This will be eventually set since the counterpart device is going to sent backwards data during the master transfer, hence XSPIPS_IXR_RXNEMPTY_MASK will be asserted each time the TX fifo has been emptied.

So, probably there is the need to split up the XSpiPs_PolledTransfer into two versions: one with automatic SS and the other one with the manual SS; alternatively a branch over the SS mode can be adopted instead.

gcnugoud commented 6 years ago

We are looking in to issue reported in PS SPI driver and will incorporate changes suggested in driver if required .

gcnugoud commented 6 years ago

Cross checked the PS SPI programming sequence, there is known issue in PS SPI controller, The RX_NEMPTY flag in the SPI Controller is not updated for every change in the received FIFO's threshold value. https://www.xilinx.com/support/answers/65885.html Design team suggested to use TX FIFO overwater flag(XSPIPS_IXR_TXOW_MASK) as workaround

hagonzalezd commented 3 years ago

Hello, I am having a similar issue with the XSpiPS_PolledTransfer function called by the FlashReadID function while trying to run the xspips_flash_polled_example.c code in Vivado 2020.1 with a ZCU216 board. The configuration functions are working properly but the code hangs in the CheckTransfer loop forever as the (StatusReg & XSPIPS_IXR_TXOW_MASK) is always zero. Could you please let me know what is the workaround that you mention? What should I change on the code? Thanks for your kind help.

terbclancy commented 1 year ago

Anyone ever get resolution of this? I see this failure on and off with 2021.1 and zu19eg. tks

gcnugoud commented 1 year ago

@hagonzalezd xspips_flash_polled_example is for SPI flash device read/write test in polled mode. ZCU216 board doesn't have any SPI Flash device hence your seeing the hang issue Default ZCU216 HW design SPI will be disabled.

terbclancy commented 1 year ago

at least for me i am not using the zcu16 board so this is not my problem

gcnugoud commented 1 year ago

@terbclancy can you share your issue details,. For below HW issue we have implemented and tested workaround in both BareMetal/Linux driver, works consistently. https://www.xilinx.com/support/answers/65885.html

terbclancy commented 1 year ago

The failing function used is this one (generated by Vitis):

XSpiPs_PolledTransfer

and here is the while loop that fails to exit, note that i have put comment bars around the code that i added to work around this but it still does fails sometimes. My theory is the XSPIPS_CR_MANSTRT_MASK bit crosses clock domains and is not handled properly so the controller fails to start and then the code waits indefinitely for the xaction to finish (note that my theory is that it was never started so it will never finish). What I added repeatedly re asserts XSPIPS_CR_MANSTRT_MASK at least up to 2048 times before it gives up (note that I have still seen it fail but very seldom with this modification to the code).

        CheckTransfer = (u32)0U;
        u32 attempts=0;
        while (CheckTransfer == 0U){
        StatusReg = XSpiPs_ReadReg(
                        InstancePtr->Config.BaseAddress,
                            XSPIPS_SR_OFFSET);
            if ( (StatusReg & XSPIPS_IXR_MODF_MASK) != 0U) {
                /*
                 * Clear the mode fail bit
                 */
                XSpiPs_WriteReg(
                    InstancePtr->Config.BaseAddress,
                    XSPIPS_SR_OFFSET,
                    XSPIPS_IXR_MODF_MASK);
                Status_Polled = (s32)XST_SEND_ERROR;
                goto END;
            }
            CheckTransfer = (StatusReg &
                        XSPIPS_IXR_TXOW_MASK);

///////////////////////////////////////////////////////////////////////// if (CheckTransfer == 0) { attempts++; if ((attempts % 16) == 0) { xil_printf("Config Reg Data = 0x%08x\r\n",ConfigReg); } if (attempts == 2048) { xil_printf("%s::Xaction Failure\r\n", FUNCTION); exit(0); return 1; } XSpiPs_WriteReg(InstancePtr->Config.BaseAddress,XSPIPS_CR_OFFSET, ConfigReg); usleep(100);

            }

///////////////////////////////////////////////// }

Constantine3031 commented 1 year ago

The failing function used is this one (generated by Vitis):

XSpiPs_PolledTransfer

and here is the while loop that fails to exit, note that i have put comment bars around the code that i added to work around this but it still does fails sometimes. My theory is the XSPIPS_CR_MANSTRT_MASK bit crosses clock domains and is not handled properly so the controller fails to start and then the code waits indefinitely for the xaction to finish (note that my theory is that it was never started so it will never finish). What I added repeatedly re asserts XSPIPS_CR_MANSTRT_MASK at least up to 2048 times before it gives up (note that I have still seen it fail but very seldom with this modification to the code).

        CheckTransfer = (u32)0U;
        u32 attempts=0;
        while (CheckTransfer == 0U){
      StatusReg = XSpiPs_ReadReg(
                      InstancePtr->Config.BaseAddress,
                          XSPIPS_SR_OFFSET);
          if ( (StatusReg & XSPIPS_IXR_MODF_MASK) != 0U) {
              /*
               * Clear the mode fail bit
               */
              XSpiPs_WriteReg(
                  InstancePtr->Config.BaseAddress,
                  XSPIPS_SR_OFFSET,
                  XSPIPS_IXR_MODF_MASK);
              Status_Polled = (s32)XST_SEND_ERROR;
              goto END;
          }
          CheckTransfer = (StatusReg &
                      XSPIPS_IXR_TXOW_MASK);

///////////////////////////////////////////////////////////////////////// if (CheckTransfer == 0) { attempts++; if ((attempts % 16) == 0) { xil_printf("Config Reg Data = 0x%08x\r\n",ConfigReg); } if (attempts == 2048) { xil_printf("%s::Xaction Failure\r\n", FUNCTION); exit(0); return 1; } XSpiPs_WriteReg(InstancePtr->Config.BaseAddress,XSPIPS_CR_OFFSET, ConfigReg); usleep(100);

          }

///////////////////////////////////////////////// }

I have the same problem, and noticed a one thing. Infinite loop in this function begins only if I choosing the Slave which I need, if I don`t choose slave data transfers correctly.

Constantine3031 commented 1 year ago

The failing function used is this one (generated by Vitis): XSpiPs_PolledTransfer and here is the while loop that fails to exit, note that i have put comment bars around the code that i added to work around this but it still does fails sometimes. My theory is the XSPIPS_CR_MANSTRT_MASK bit crosses clock domains and is not handled properly so the controller fails to start and then the code waits indefinitely for the xaction to finish (note that my theory is that it was never started so it will never finish). What I added repeatedly re asserts XSPIPS_CR_MANSTRT_MASK at least up to 2048 times before it gives up (note that I have still seen it fail but very seldom with this modification to the code).

        CheckTransfer = (u32)0U;
        u32 attempts=0;
        while (CheckTransfer == 0U){
        StatusReg = XSpiPs_ReadReg(
                        InstancePtr->Config.BaseAddress,
                            XSPIPS_SR_OFFSET);
            if ( (StatusReg & XSPIPS_IXR_MODF_MASK) != 0U) {
                /*
                 * Clear the mode fail bit
                 */
                XSpiPs_WriteReg(
                    InstancePtr->Config.BaseAddress,
                    XSPIPS_SR_OFFSET,
                    XSPIPS_IXR_MODF_MASK);
                Status_Polled = (s32)XST_SEND_ERROR;
                goto END;
            }
            CheckTransfer = (StatusReg &
                        XSPIPS_IXR_TXOW_MASK);

///////////////////////////////////////////////////////////////////////// if (CheckTransfer == 0) { attempts++; if ((attempts % 16) == 0) { xil_printf("Config Reg Data = 0x%08x\r\n",ConfigReg); } if (attempts == 2048) { xil_printf("%s::Xaction Failure\r\n", FUNCTION); exit(0); return 1; } XSpiPs_WriteReg(InstancePtr->Config.BaseAddress,XSPIPS_CR_OFFSET, ConfigReg); usleep(100);

            }

///////////////////////////////////////////////// }

I have the same problem, and noticed a one thing. Infinite loop in this function begins only if I choosing the Slave which I need, if I don`t choose slave data transfers correctly.

I solved my problem after changing spi0 SS output from SPI0_SS1_O to SPI_SS_O on block diagram, I don`t know why but... It just works =) image