Skip to main content
Visitor II
July 1, 2024
Question

STM32H7A3ZITQ_LQFP144 QSPI Timeout Issue

  • July 1, 2024
  • 2 replies
  • 1399 views
 

Hello,

I am using the STM32H7A3ZITQ and have encountered an issue while controlling the MT25QL128ABA1ESESF0IT flash memory during the flash read process. I am operating in QSPI mode. During extended aging evaluations, a 5-second timeout (a busy flag is not cleared) intermittently occurs in the LL_OSPI_Receive() function.

Since this issue occurs randomly, I tried to force the conditions to analyze the problem. I discovered that in debug mode, if I set a breakpoint and step over the function, the problem occurs 100% of the time.

Interestingly, if I add a variable inside the read function, the issue that occurs 100% of the time disappears. When examining the assembly code, I found that adding a volatile variable generates two additional assembly instructions, leading to a delay that seems to resolve the issue. However, attempting to induce a similar delay using asm("nop") did not resolve the issue.

I confirmed that adding a variable resolves the problem. Adding one, two, up to four variables resolves the issue, but adding five variables causes the issue to reappear. This leads me to believe that the problem might be due to something other than a timing issue.

I would appreciate any assistance you can provide regarding this phenomenon.

Thank you.

 

khkim_0-1719807496263.png

 

khkim_1-1719807509696.png
 
khkim_2-1719807523399.png

 

    This topic has been closed for replies.

    2 replies

    Technical Moderator
    July 1, 2024

    Hello @khkim 

     

    Please try to use the feature "Insert/Edit code sample" to share your code.

     

    Saket_Om_0-1719828777130.png

     

     Concerning your issue, did you set the correct dummy cycle according to the device specification?

    khkimAuthor
    Visitor II
    July 2, 2024

    Thanks for your answer,

     

    Here is my initialization code for OctoSPI1. I evaluated the number of dummy cycles from 1 to 15. It only works correctly with 10 dummy cycles. based on this, I estimate that we are operating at a clock frequency of 125MHz(Flash to read only under the condition that the dummy cycle is 10.). I am currently reading only 4 bytes.


    void OCTOSPI1_Init(void)
    {
    /* USER CODE BEGIN OCTOSPI1_Init 0 */
    LL_OSPI_DeInit(OCTOSPI1);

    /* USER CODE END OCTOSPI1_Init 0 */

    OSPI_InitTypeDef OSPI_InitStruct = {0};

    OSPIM_CfgTypeDef sOspiManagerCfg = {0};

    LL_GPIO_InitTypeDef GPIO_InitStruct = {0};

    /*Set clock source*/
    __LL_RCC_PLLCLKOUT_ENABLE(RCC_PLLCFGR_DIVQ1EN);
    LL_RCC_SetOSPIClockSource(LL_RCC_OSPI_CLKSOURCE_PLL2R);
    //LL_RCC_SetOSPIClockSource(LL_RCC_OSPI_CLKSOURCE_PLL1Q);

    /* OCTOSPI1 clock enable */
    __LL_RCC_OCTOSPIM_CLK_ENABLE();
    __LL_RCC_OSPI1_CLK_ENABLE();

    /* Peripheral clock enable */
    LL_AHB4_GRP1_EnableClock(LL_AHB4_GRP1_PERIPH_GPIOF);
    LL_AHB4_GRP1_EnableClock(LL_AHB4_GRP1_PERIPH_GPIOG);
    /**OCTOSPI1 GPIO Configuration
    PF6 ------> OCTOSPIM_P1_IO3
    PF7 ------> OCTOSPIM_P1_IO2
    PF8 ------> OCTOSPIM_P1_IO0
    PF9 ------> OCTOSPIM_P1_IO1
    PF10 ------> OCTOSPIM_P1_CLK
    PG6 ------> OCTOSPIM_P1_NCS
    */
    GPIO_InitStruct.Pin = LL_GPIO_PIN_6|LL_GPIO_PIN_7|LL_GPIO_PIN_8|LL_GPIO_PIN_9;
    GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
    GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
    GPIO_InitStruct.Pull = LL_GPIO_PULL_UP;
    GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = LL_GPIO_AF_10;
    LL_GPIO_Init(GPIOF, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = LL_GPIO_PIN_10;
    GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
    GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
    GPIO_InitStruct.Pull = LL_GPIO_PULL_UP;
    GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = LL_GPIO_AF_9;
    LL_GPIO_Init(GPIOF, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = LL_GPIO_PIN_6;
    GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
    GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
    GPIO_InitStruct.Pull = LL_GPIO_PULL_UP;
    GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = LL_GPIO_AF_10;
    LL_GPIO_Init(GPIOG, &GPIO_InitStruct);

    /* USER CODE BEGIN OCTOSPI1_Init 1 */

    /* USER CODE END OCTOSPI1_Init 1 */
    OSPI_InitStruct.FifoThreshold = 4;
    OSPI_InitStruct.DualQuad = LL_OSPI_DUALQUAD_DISABLE;
    OSPI_InitStruct.MemoryType = LL_OSPI_MEMTYPE_MICRON;
    OSPI_InitStruct.DeviceSize = 24;
    OSPI_InitStruct.ChipSelectHighTime = 6;
    OSPI_InitStruct.FreeRunningClock = LL_OSPI_FREERUNCLK_DISABLE;
    OSPI_InitStruct.ClockMode = LL_OSPI_CLOCK_MODE_0;
    OSPI_InitStruct.WrapSize = LL_OSPI_WRAP_NOT_SUPPORTED;
    OSPI_InitStruct.ClockPrescaler = 1;
    OSPI_InitStruct.SampleShifting = LL_OSPI_SAMPLE_SHIFTING_HALFCYCLE;
    OSPI_InitStruct.DelayHoldQuarterCycle = LL_OSPI_DHQC_DISABLE;
    OSPI_InitStruct.ChipSelectBoundary = 0;
    OSPI_InitStruct.DelayBlockBypass = LL_OSPI_DELAY_BLOCK_BYPASSED;
    OSPI_InitStruct.MaxTran = 0;
    OSPI_InitStruct.Refresh = 0;
    LL_mDelay(1);
    if (LL_OSPI_Init(OCTOSPI1, &OSPI_InitStruct) != SUCCESS)
    {
    Error_Handler();
    }

     

    ErrorStatus LL_OSPI_Receive(OCTOSPI_TypeDef *OSPIx, uint8_t *pData, uint32_t Timeout)
    {
    ErrorStatus status;
    uint32_t tickstart = GetTick();
    __IO uint32_t *data_reg = &OSPIx->DR;
    uint32_t addr_reg =OSPIx->AR;
    uint32_t ir_reg = OSPIx->IR;
    uint8_t *pBuffPtr;
    __IO uint32_t XferSize;
    __IO uint32_t XferCount;

    /* Check the data pointer allocation */
    if (pData == NULL)
    {
    status = ERROR;
    }
    else
    {

    /* Configure counters and size */
    XferCount = READ_REG(OSPIx->DLR) + 1U;
    XferSize = XferCount;
    pBuffPtr = pData;

    /* Configure CR register with functional mode as indirect read */
    MODIFY_REG(OSPIx->CR, OCTOSPI_CR_FMODE, OSPI_FUNCTIONAL_MODE_INDIRECT_READ);

    /* Trig the transfer by re-writing address or instruction register */
    if ((READ_REG(OSPIx->DCR1) >> OCTOSPI_DCR1_MTYP_Pos) == 1UL)
    {
    WRITE_REG(OSPIx->AR, addr_reg);
    }
    else
    {
    if (READ_BIT(OSPIx->CCR, OCTOSPI_CCR_ADMODE) != LL_OSPI_ADDRESS_NONE)
    {
    WRITE_REG(OSPIx->AR, addr_reg);
    }
    else
    {
    WRITE_REG(OSPIx->IR, ir_reg);
    }
    }

    do
    {
    /* Wait till fifo threshold or transfer complete flags are set to read received data */
    status = OSPI_WaitFlagStateUntilTimeout(OSPIx, (LL_OSPI_FLAG_FT | LL_OSPI_FLAG_TC), SET, tickstart, Timeout);

    if (status != SUCCESS)
    {
    break;
    }

    *pBuffPtr = *((__IO uint8_t *)data_reg);
    pBuffPtr++;
    XferCount--;
    } while(XferCount > 0U);

    if (status == SUCCESS)
    {
    /* Wait till transfer complete flag is set to go back in idle state */
    status = OSPI_WaitFlagStateUntilTimeout(OSPIx, LL_OSPI_FLAG_TC, SET, tickstart, Timeout);
    //while((__LL_OSPI_GET_FLAG(OSPIx, LL_OSPI_FLAG_TC)) != SET){}
    //if ((__LL_OSPI_GET_FLAG(OSPIx, LL_OSPI_FLAG_TC)) == SET)
    //{
    // status = SUCCESS;
    //}

    if (status == SUCCESS)
    {
    /* Clear transfer complete flag */
    __LL_OSPI_CLEAR_FLAG(OSPIx, LL_OSPI_FLAG_TC);

    }
    }

    }

    /* Return function status */
    return status;
    }


    sOspiManagerCfg.ClkPort = 1;
    sOspiManagerCfg.NCSPort = 1;
    sOspiManagerCfg.IOLowPort = LL_OSPIM_IOPORT_1_LOW;
    if (LL_OSPIM_Config(OCTOSPI1, &sOspiManagerCfg) != SUCCESS)
    {
    Error_Handler();
    }

    /* USER CODE BEGIN OCTOSPI1_Init 2 */
    //__LL_OSPI_ENABLE(OCTOSPI1);


    /* USER CODE END OCTOSPI1_Init 2 */
    }

     

     

    khkim_0-1719894995303.png

    khkim_1-1719895019437.png

    khkim_0-1719909507577.png

     

    khkim_3-1719895390576.png

     

     

    khkimAuthor
    Visitor II
    July 3, 2024

    khkim_1-1719996492674.png

    In the conditions where the issue occurs, the clock continuously generates without interruption, and the data line remains consistently high and CS line low.

    Graduate II
    July 1, 2024

    You're pacing this transfer, how much data are you moving, what kind of clock speed do you have on the bus vs prescaler?

    What do the registers show?

    Don't break-point or put a peripheral view over the top of the QSPI/OSPI, the former at user response rates is problematic, the latter will break FIFO, etc. as invasive.

    khkimAuthor
    Visitor II
    July 4, 2024

    Hi, 
    Could you please provide some advice to help identify the root cause?