cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F7 QSPI Fast Read Quad Problems

PUrsu.1
Associate II

I am here again to ask for your help :)

I am using a STM32F767ZI Nucleo Board and connected a Winbond W25Q64JV using the QSPI interface of the MCU. Everything is working fine so far - I can read data in every mode described in the data sheet (even Fast Read Dual I/O), and write data even in the Quad Input Page Program mode.

The only thing not working at the moment is reading data in Fast Read Quad Out or Fast Read Quad Input mode. The data returned by the Winbond memory chip is not correct.

The only thing I do is checking in the registers that the QE bit is set correctly - which it is.

QSPI Init method:

static void MX_QUADSPI_Init(void) {
    /* QUADSPI parameter configuration*/
    hqspi.Instance = QUADSPI;
    // CPU freq: 216
    hqspi.Init.ClockPrescaler = 4;
    hqspi.Init.FifoThreshold = 4;
    hqspi.Init.SampleShifting = QSPI_SAMPLE_SHIFTING_NONE;
    hqspi.Init.FlashSize = 23;
    hqspi.Init.ChipSelectHighTime = QSPI_CS_HIGH_TIME_4_CYCLE;
    hqspi.Init.ClockMode = QSPI_CLOCK_MODE_0;
    hqspi.Init.FlashID = QSPI_FLASH_ID_1;
    hqspi.Init.DualFlash = QSPI_DUALFLASH_DISABLE;
    if (HAL_QSPI_Init(&hqspi) != HAL_OK) {
        Error_Handler();
    }
}

Method for reading:

W25QState W25QFlash::readFromAddr(uint8_t *buffer, uint16_t len, uint32_t addr) {
    while (this->isBusy() == W25QState::BUSY) {
        osDelay(1);
    }
 
    QSPI_CommandTypeDef com;
 
    com.InstructionMode = QSPI_INSTRUCTION_1_LINE; // QSPI_INSTRUCTION_...
    com.Instruction = W25Q_FAST_READ_QUAD_IO;     // Command
    com.AddressSize = QSPI_ADDRESS_24_BITS;
 
    com.AddressMode = QSPI_ADDRESS_4_LINES;
 
    com.Address = addr;
 
    com.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
    com.AlternateBytes = QSPI_ALTERNATE_BYTES_NONE;
    com.AlternateBytesSize = QSPI_ALTERNATE_BYTES_NONE;
 
    com.DummyCycles = 8;
    com.DataMode = QSPI_DATA_4_LINES;
    com.NbData = len;
 
    com.DdrMode = QSPI_DDR_MODE_DISABLE;
    com.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
    com.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
 
    int f = HAL_QSPI_Command(this->handle, &com, HAL_QSPI_TIMEOUT_DEFAULT_VALUE);
    if (f != HAL_OK) {
        return W25QState::ERR;
    }
    f = HAL_QSPI_Receive(this->handle, buffer, HAL_QSPI_TIMEOUT_DEFAULT_VALUE);
 
    if (f != HAL_OK) {
        return W25QState::ERR;
    }
 
    return W25QState::OK;
}

I tried changing a lot of settings in the source code (CS high time, dummy cycles, etc.) and in the registers of the flash chip (driver output strength) - but it is still not working.

Does anyone have an idea, what I can try to come closer to a solution?

PS: I double checked that the connection between the MCU and the W25 is correct.


_legacyfs_online_stmicro_images_0693W00000bjUJuQAM.png 

12 REPLIES 12

It's hard to debug this remotely like this.

My approach would be to build some test code

This would write a complex pattern to the memory.

The read and dump to the screen a read in Single, Dual and Quad mode, illustrating each either working or not-working, so some review / adjustment of settings could be made.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
KDJEM.1
ST Employee

Hello @PUrsu.1​ ,

Are you enabled the timeout counter?

It is mentioned in the the STM32F767 MCUs Errata sheet ES0334, for Memory-mapped read operations may fail when timeout counter is enabled. For that, the workaround is disable the timeout counter. To raise the chip select, perform an abort at the end of each memory-mapped read operation.

Thank you.

Kaouthar

To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.

KMacD
Associate II

I had the same problem as you and I did make changes to the function to implement the 0xFF for the first Dummy cycle, however the main difference that finally succeeded was to change my Prescaler and Chip Select high time. What I found was with a clock rate of 80 MHz and my values set as below I was able to rectify my issues.

hqspi.Instance = QUADSPI;
hqspi.Init.ClockPrescaler = 1;
hqspi.Init.FifoThreshold = 1;
hqspi.Init.SampleShifting = QSPI_SAMPLE_SHIFTING_NONE;
hqspi.Init.FlashSize = 23;
hqspi.Init.ChipSelectHighTime = QSPI_CS_HIGH_TIME_5_CYCLE;
hqspi.Init.ClockMode = QSPI_CLOCK_MODE_0;

 

Mathematically I should have been ok with a ChipSelectHighTime set to 4, which I had it set to for most of my troubleshooting, but in the end I bumped it to 5 and that completely solved my issue. I experimented and set it higher and that works fine too, but 5 is stable and optimal. Also as well, setting the prescaler high to reduce the frequency the chip communicates at has a negative effect on stability as well. It is good to finally get it to work and then to test its boundaries.

My final function is below for my W25Q128JV. Hope some of my solutions help.

W25Q_STATE W25Q_ReadRaw(uint8_t *buf, uint16_t data_len, uint32_t rawAddr) {
if (data_len > 256 || data_len == 0)
return W25Q_PARAM_ERR;

while (W25Q_IsBusy() == W25Q_BUSY)
w25q_delay(1);

QSPI_CommandTypeDef com;

com.InstructionMode = QSPI_INSTRUCTION_1_LINE; // QSPI_INSTRUCTION_...
com.Instruction = W25Q_FAST_READ_QUAD_IO; // Command
com.AddressSize = QSPI_ADDRESS_32_BITS;
com.AddressMode = QSPI_ADDRESS_4_LINES;
com.Address = ((rawAddr&0xFFFFFF) <<  8 ) | 0x000000FF ;
com.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
com.AlternateBytes = QSPI_ALTERNATE_BYTES_NONE;
com.AlternateBytesSize = QSPI_ALTERNATE_BYTES_NONE;

com.DummyCycles = 4;
com.DataMode = QSPI_DATA_4_LINES;
com.NbData = data_len;

com.DdrMode = QSPI_DDR_MODE_DISABLE;
com.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
com.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;

if (HAL_QSPI_Command(&hqspi, &com, HAL_QSPI_TIMEOUT_DEFAULT_VALUE)
!= HAL_OK)
return W25Q_SPI_ERR;

if (HAL_QSPI_Receive(&hqspi, buf, HAL_QSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
return W25Q_SPI_ERR;

return W25Q_OK;
}