Skip to main content
AShel.1
Associate III
June 21, 2023
Question

STM32H753XI MCU with W25Q512 in dual flash mode

  • June 21, 2023
  • 3 replies
  • 2946 views

Hello,

I'm using STM32H753XI MCU with two W25Q512JV(its 64Mb) in dual mode, the nCS and data lines are separate, Clock line is same. I've configured the QUAD SPI in dual flash mode as mentioned in AN4760. I'm trying to read the sectors from first flash then I see that the alternate bytes are not read correctly.

 hqspi.Instance = QUADSPI;
 hqspi.Init.ClockPrescaler = 2;
 hqspi.Init.FifoThreshold = 4;
 hqspi.Init.SampleShifting = QSPI_SAMPLE_SHIFTING_HALFCYCLE;
 hqspi.Init.FlashSize = 31;
 hqspi.Init.ChipSelectHighTime = QSPI_CS_HIGH_TIME_1_CYCLE;
 hqspi.Init.ClockMode = QSPI_CLOCK_MODE_0;
 hqspi.Init.FlashID = QSPI_FLASH_ID_1;
 hqspi.Init.DualFlash = QSPI_DUALFLASH_ENABLE;
 if (HAL_QSPI_Init(&hqspi) != HAL_OK)
 {
 Error_Handler();
 }

Next, I've tried using single flash at a time with FSEL bit, I'm able to read the data from one flash only. second flash write/ read operation is not happening. 

Am I missing some configuration part?

Thanks,

 

    This topic has been closed for replies.

    3 replies

    KDJEM.1
    ST Technical Moderator
    June 21, 2023

    Hello @AShel.1 ,

    When the Dual-flash mode enabled  (DFM = 1), the FSEL bit is ignored. 

     

    Could you please check the  ChipSelectHighTime in the datasheet memory .

    Thank you.

    Kaouthar

     

     

     

    To give better visibility on the answered topics, please click on "Best answer" on the reply which solved your issue or answered your question.
    AShel.1
    AShel.1Author
    Associate III
    July 4, 2023

    Hello,

    yes, when I've enabled DFM mode then I'm not using FSEL bit. 

    on ChipSelectHighTime, I've referred the settings from this example, also I've tried different combinations of chip select.

     

    https://github.com/Crazy-Geeks/STM32-W25Q-QSPI/tree/main 

    I'm trying dual bank memory mapped sample code from STM32Cube repository, 

     QSPIHandle.Instance = QUADSPI;
    
     /* QSPI initialization */
     /* ClockPrescaler set to 1, so QSPI clock = 200MHz / (1+1) = 100MHz */
     QSPIHandle.Init.ClockPrescaler = 1;
     QSPIHandle.Init.FifoThreshold = 1;
     QSPIHandle.Init.SampleShifting = QSPI_SAMPLE_SHIFTING_HALFCYCLE;
     QSPIHandle.Init.FlashSize = QSPI_FLASH_SIZE;
     QSPIHandle.Init.ChipSelectHighTime = QSPI_CS_HIGH_TIME_3_CYCLE;
     QSPIHandle.Init.ClockMode = QSPI_CLOCK_MODE_0;
     QSPIHandle.Init.DualFlash = QSPI_DUALFLASH_ENABLE;
    
     sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE;
     sCommand.AddressSize = QSPI_ADDRESS_32_BITS;
     sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
     sCommand.DdrMode = QSPI_DDR_MODE_DISABLE;
     sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
     sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
    
     while(1)
     {
     switch(step)
     {
     case 0:
     CmdCplt = 0;
    
     /* Initialize QuadSPI ------------------------------------------------ */
     HAL_QSPI_DeInit(&QSPIHandle);
     if (HAL_QSPI_Init(&QSPIHandle) != HAL_OK)
     {
     Error_Handler();
     }
     
     /* Enable 4 bytes Address mode */
     QSPI_EnterFourBytesAddress(&QSPIHandle);
     
     HAL_Delay(10);
     /* Enable write operations ------------------------------------------- */
     QSPI_WriteEnable(&QSPIHandle);
    
     /* Erasing Sequence -------------------------------------------------- */
     sCommand.Instruction = SECTOR_ERASE_CMD;
     sCommand.AddressMode = QSPI_ADDRESS_1_LINE;
     sCommand.Address = address;
     sCommand.DataMode = QSPI_DATA_NONE;
     sCommand.DummyCycles = 0;
    
     if (HAL_QSPI_Command_IT(&QSPIHandle, &sCommand) != HAL_OK)
     {
     Error_Handler();
     }
     
     step++;
     break;
    
     case 1:
     if(CmdCplt != 0)
     {
     CmdCplt = 0;
     StatusMatch = 0;
    
     /* Configure automatic polling mode to wait for end of erase ------- */ 
     QSPI_AutoPollingMemReady(&QSPIHandle);
    
     step++;
     }
     break;
     
     case 2:
     if(StatusMatch != 0)
     {
     StatusMatch = 0;
     TxCplt = 0;
     
     /* Enable write operations ----------------------------------------- */
     QSPI_WriteEnable(&QSPIHandle);
    
     /* Writing Sequence ------------------------------------------------ */
     sCommand.Instruction = QUAD_IN_FAST_PROG_CMD;
     sCommand.AddressMode = QSPI_ADDRESS_1_LINE;
     sCommand.DataMode = QSPI_DATA_4_LINES;
     sCommand.NbData = BUFFERSIZE;
    
     if (HAL_QSPI_Command(&QSPIHandle, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
     {
     Error_Handler();
     }
    
     if (HAL_QSPI_Transmit_IT(&QSPIHandle, aTxBuffer) != HAL_OK)
     {
     Error_Handler();
     }
    
     step++;
     }
     break;
    
     case 3:
     if(TxCplt != 0)
     {
     TxCplt = 0;
     StatusMatch = 0;
    
     /* Configure automatic polling mode to wait for end of program ----- */ 
     QSPI_AutoPollingMemReady(&QSPIHandle);
     
     step++;
     }
     break;
     
     case 4:
     if(StatusMatch != 0)
     {
     StatusMatch = 0;
     RxCplt = 0;
    
     /* Configure Volatile Configuration register (with new dummy cycles) */
     QSPI_DummyCyclesCfg(&QSPIHandle);
     
     /* Reading Sequence ------------------------------------------------ */
     sCommand.Instruction = QUAD_OUT_FAST_READ_CMD;
     sCommand.DummyCycles = DUMMY_CLOCK_CYCLES_READ_QUAD;
    
     sMemMappedCfg.TimeOutActivation = QSPI_TIMEOUT_COUNTER_DISABLE;
    
     if (HAL_QSPI_MemoryMapped(&QSPIHandle, &sCommand, &sMemMappedCfg) != HAL_OK)
     {
     Error_Handler();
     }
    
     for (index = 0; index < BUFFERSIZE; index++)
     {
     if (*qspi_addr != aTxBuffer[index])
     {
     BSP_LED_On(LED3);
     }
     qspi_addr++;
     }
     BSP_LED_Toggle(LED1);
    
     address += QSPI_PAGE_SIZE;
     if(address >= QSPI_END_ADDR)
     {
     address = 0;
     }
     qspi_addr = (__IO uint8_t *)(0x90000000 + address);
    
     step = 0;
     }
     break;
     
     default :
     Error_Handler();
     }
     }

    this example works fine for dual bank, it performs QSPI_Init->Erase->Write->Read operation, I'm not sure why it needs to re-initialize QSPI every time, if I take the QSPI init function out of the while loop, only one cycle of Erase->Write->Read operation is performed and it goes into ErrorHandler state in second cycle Erase function because the HAL is busy in HAL_QSPI_STATE_BUSY_MEM_MAPPED. 

    I've tried to force the hqspi->state to HAL_QSPI_STATE_READY but it still gives error.

    Tesla DeLorean
    Guru
    July 4, 2023

    In Dual Mode the thing to consider is that everything doubles in size. The erase blocks which were 4KB will be effectively be 8KB. You'll need to be conscious of this as the step distance for the addressing expands along with the expectations for writes and erases.

    The status read will also need to be double-wide and both devices will need to report ready/not-busy. The devices are not synchronized, so the erases and writes on each device might complete at different times, and may be content specific/related.

    Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
    AShel.1
    AShel.1Author
    Associate III
    July 4, 2023

    Thanks for the quick response, would you please provide me some example to handle this kind of case.

    Tesla DeLorean
    Guru
    July 4, 2023

    If you're deblocking at 4KB, 32KB or 64KB then you'll need to expand those to 8KB, 64KB and 128KB

    Perhaps look at the QSPI examples for the DISCO and EVAL boards, and where the polling operations operate on two bytes wide rather than one.

    Remember you're talking to TWO chips, and the content is being interleaved at a byte level.

    Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
    AShel.1
    AShel.1Author
    Associate III
    July 31, 2023

    This solution is working for STM32H753 Eval board but on my target board we've Winbond ICs wherein the same configuration did not work, I see right data read from first flash but the second flash reads 0x99 value.