2024-06-30 09:20 PM - edited 2024-07-01 12:30 AM
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.
2024-07-01 03:20 AM - edited 2024-07-01 03:34 AM
Hello @khkim
Please try to use the feature "Insert/Edit code sample" to share your code.
Concerning your issue, did you set the correct dummy cycle according to the device specification?
2024-07-01 06:02 AM
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.
2024-07-01 09:45 PM - edited 2024-07-02 01:38 AM
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 */
}
2024-07-03 01:49 AM
In the conditions where the issue occurs, the clock continuously generates without interruption, and the data line remains consistently high and CS line low.
2024-07-03 10:43 PM
Hi,
Could you please provide some advice to help identify the root cause?