cancel
Showing results for 
Search instead for 
Did you mean: 

W25Q80DV QSPI with STM32F412VET3 - Strange things I don't understand.

Lq
Associate II

Hi everyone.

So I have W25Q80DV QSPI with STM32F412VET, I would like to use it to store some data. As per datasheet for W25Q80DV its flash is 8mbit and so I have the following initialization code : 

hqspi.Instance = QUADSPI;

hqspi.Init.ClockPrescaler = 2;

hqspi.Init.FifoThreshold = 1;

hqspi.Init.SampleShifting = QSPI_SAMPLE_SHIFTING_NONE;

hqspi.Init.FlashSize = 19;

hqspi.Init.ChipSelectHighTime = QSPI_CS_HIGH_TIME_1_CYCLE;

hqspi.Init.ClockMode = QSPI_CLOCK_MODE_0;

hqspi.Init.FlashID = QSPI_FLASH_ID_2;

hqspi.Init.DualFlash = QSPI_DUALFLASH_DISABLE;

HAL_StatusTypeDef status = HAL_QSPI_Init(&hqspi);


According to the datasheet, FlashSize should be 19, since the flash size is 8mbit. But with flashsize being 19, the write operations (particlarly when I call HAL_Transmit) times out.
If I set the FlashSize to 31, it works as expected which I find odd.

Additionally my code for writing :


static
HAL_StatusTypeDef QSPI_PageProgram(uint32_t addr, uint8_t *txBuf) {
QSPI_CommandTypeDef s_command = {0};

s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE;

s_command.Instruction = PAGE_PROGRAM_CMD;

s_command.AddressMode = QSPI_ADDRESS_1_LINE;

s_command.AddressSize = QSPI_ADDRESS_24_BITS; // 24-Bit-Adresse

s_command.Address = addr;

s_command.DataMode = QSPI_DATA_1_LINE;

s_command.DummyCycles = 0;

s_command.NbData = 4;

s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;




HAL_StatusTypeDef status = HAL_QSPI_Command(&hqspi, &s_command, HAL_QSPI_TIMEOUT_DEFAULT_VALUE);

if (status != HAL_OK) {

return status;

}




status = HAL_QSPI_Transmit(&hqspi, txBuf, HAL_QSPI_TIMEOUT_DEFAULT_VALUE); //TIMEOUT here with flashsize = 19




return status;

}



One more question : Since I am new to embedded stuff I don't fully understand how the external flash memory actually works. If I would like to use the QSPI I assume I need to flash it somehow using CubeProgrammer, probably by using an external loader. Because when I debug using the IDE, it works as expected (despite difficulty to debug - I guess I need to enable memory mapping mode).

but it is not clear to me how to do this, there are some external loaders available in CubeProgrammer but not for my board

Thanks!

 

7 REPLIES 7

How are the pins configured on your board?

The write page methods support writing up to 256 bytes, at a 256-byte aligned address. You can write anywhere in the page, but the total will drop as you move into the the page.

The bit width of the address shouldn't be an issue with an 8mbit / 1MB NOR FLASH

For write you'd need to use write-enable, and then wait for completion of the write. It shouldn't be taking over a few dozen milliseconds. The erase can run to seconds depending on the part and the erase size.

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

Hi, thanks for the answer.

Here's the pin configuration : 

HAL_GPIO_WritePin(GPIOE, EN_M5_Pin|EN_M4_Pin, GPIO_PIN_RESET);


HAL_GPIO_WritePin(GPIOC, Motor_All_Sleep_Pin|LED2_Pin|LED1_Pin, GPIO_PIN_RESET);
HAL_GPIO_WritePin(UART_TX_ENABLE_GPIO_Port, UART_TX_ENABLE_Pin, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOB, EN_M2_Pin|EN_M3_Pin|EN_M1_Pin, GPIO_PIN_RESET);


HAL_GPIO_WritePin(EN_M0_GPIO_Port, EN_M0_Pin, GPIO_PIN_RESET);


PEPin PEPin */

GPIO_InitStruct.Pin = SW3_Pin|SW4_Pin|SW5_Pin|SW6_Pin

|SW1_Pin|SW2_Pin;

GPIO_InitStruct.Mode = GPIO_MODE_INPUT;

GPIO_InitStruct.Pull = GPIO_NOPULL;

HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);







GPIO_InitStruct.Pin = EN_M5_Pin|EN_M4_Pin;

GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;

GPIO_InitStruct.Pull = GPIO_NOPULL;

GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;

HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);




/*Configure GPIO pins : PCPin PCPin PCPin */

GPIO_InitStruct.Pin = Motor_All_Sleep_Pin|LED2_Pin|LED1_Pin;

GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;

GPIO_InitStruct.Pull = GPIO_NOPULL;

GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;

HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);







GPIO_InitStruct.Pin = GPIO_PIN_1;

GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;

GPIO_InitStruct.Pull = GPIO_NOPULL;

HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);







GPIO_InitStruct.Pin = UART_TX_ENABLE_Pin;

GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;

GPIO_InitStruct.Pull = GPIO_NOPULL;

GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;

HAL_GPIO_Init(UART_TX_ENABLE_GPIO_Port, &GPIO_InitStruct);







GPIO_InitStruct.Pin = EN_M2_Pin|EN_M3_Pin|EN_M1_Pin;

GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;

GPIO_InitStruct.Pull = GPIO_NOPULL;

GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;

HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);







GPIO_InitStruct.Pin = EN_M0_Pin;

GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;

GPIO_InitStruct.Pull = GPIO_NOPULL;

GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;

HAL_GPIO_Init(EN_M0_GPIO_Port, &GPIO_InitStruct);







PDPin PDPin PDPin PDPin

PDPin PDPin PDPin */

GPIO_InitStruct.Pin = EndStop_M3_D09_Pin|EndStop_M3_D10_Pin|EndStop_M2_D11_Pin|EndStop_M2_D13_Pin

|EndStop_M1_D14_Pin|EndStop_M4_D02_Pin|EndStop_M4_D03_Pin|EndStop_M5_D04_Pin

|EndStop_M5_D05_Pin|EndStop_M6_D06_Pin|EndStop_M6_D07_Pin;

GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING_FALLING;

GPIO_InitStruct.Pull = GPIO_NOPULL;

HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);







GPIO_InitStruct.Pin = EndStop_M1_D15_Pin;

GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;

GPIO_InitStruct.Pull = GPIO_NOPULL;

HAL_GPIO_Init(EndStop_M1_D15_GPIO_Port, &GPIO_InitStruct);







HAL_NVIC_SetPriority(EXTI2_IRQn, 0, 0);

HAL_NVIC_EnableIRQ(EXTI2_IRQn);




HAL_NVIC_SetPriority(EXTI3_IRQn, 0, 0);

HAL_NVIC_EnableIRQ(EXTI3_IRQn);




HAL_NVIC_SetPriority(EXTI4_IRQn, 0, 0);

HAL_NVIC_EnableIRQ(EXTI4_IRQn);




HAL_NVIC_SetPriority(EXTI9_5_IRQn, 0, 0);

HAL_NVIC_EnableIRQ(EXTI9_5_IRQn);




HAL_NVIC_SetPriority(EXTI15_10_IRQn, 0, 0);

HAL_NVIC_EnableIRQ(EXTI15_10_IRQn);

I do write-enable before page programming. I think the process of that shouldn't be an issue, since It works as expected if hqspi.Init.FlashSize = 31. Which is odd, I have no clue why it has to be 31, as per datasheet it actually should be 19. As soon as I use 19, then any HAL_QSPI_Transmit/ HAL_QSPI_Receive operation times out unless the AddressMode of the command is set to QSPI_ADDRESS_NONE.

Thanks.

Not sure I'm going to be able mine anything useful there.

Perhaps you have the MSP code initializing the QSPI pins/clocks?

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

I missed this part : 

 __HAL_RCC_GPIOE_CLK_ENABLE();

 __HAL_RCC_GPIOC_CLK_ENABLE();

 __HAL_RCC_GPIOH_CLK_ENABLE();

 __HAL_RCC_GPIOA_CLK_ENABLE();

 __HAL_RCC_GPIOB_CLK_ENABLE();

 __HAL_RCC_GPIOD_CLK_ENABLE();

 

But that is all I have. Additionally this is how I initialize HAL QSPI.

static void W25Q80_Initialize() {

hqspi.Instance = QUADSPI;

hqspi.Init.ClockPrescaler = 2;

hqspi.Init.FifoThreshold = 1;

hqspi.Init.SampleShifting = QSPI_SAMPLE_SHIFTING_NONE;

hqspi.Init.FlashSize = 31; //19 fails

hqspi.Init.ChipSelectHighTime = QSPI_CS_HIGH_TIME_1_CYCLE;

hqspi.Init.ClockMode = QSPI_CLOCK_MODE_0;

hqspi.Init.FlashID = QSPI_FLASH_ID_2;

hqspi.Init.DualFlash = QSPI_DUALFLASH_DISABLE;

HAL_StatusTypeDef status = HAL_QSPI_Init(&hqspi);

if (status != HAL_OK) {

Error_Handler();

}

}

Man this is getting hard.

Can you communicate the pins used to interface the QSPI memory? Or schematic illustrating such

The BSP_QSPI_MspInit() or HAL_QSPI_MspInit() function from the MSP code.

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



Sorry, I'm still new to this.

I think this is what you're referring to

void HAL_QSPI_MspInit(QSPI_HandleTypeDef* hqspi)

{

  GPIO_InitTypeDef GPIO_InitStruct = {0};

  if(hqspi->Instance==QUADSPI)

  {

  /* USER CODE BEGIN QUADSPI_MspInit 0 */

  /* USER CODE END QUADSPI_MspInit 0 */

    /* Peripheral clock enable */

    __HAL_RCC_QSPI_CLK_ENABLE();

    __HAL_RCC_GPIOC_CLK_ENABLE();

    __HAL_RCC_GPIOB_CLK_ENABLE();

    __HAL_RCC_GPIOE_CLK_ENABLE();

    /**QUADSPI GPIO Configuration

    PC4     ------> QUADSPI_BK2_IO2

    PC5     ------> QUADSPI_BK2_IO3

    PB1     ------> QUADSPI_CLK

    PE7     ------> QUADSPI_BK2_IO0

    PE8     ------> QUADSPI_BK2_IO1

    PC11     ------> QUADSPI_BK2_NCS

    */

    GPIO_InitStruct.Pin = GPIO_PIN_4|GPIO_PIN_5;

    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;

    GPIO_InitStruct.Pull = GPIO_NOPULL;

    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;

    GPIO_InitStruct.Alternate = GPIO_AF10_OTG_FS;

    HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = GPIO_PIN_1;

    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;

    GPIO_InitStruct.Pull = GPIO_NOPULL;

    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;

    GPIO_InitStruct.Alternate = GPIO_AF9_QSPI;

    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = GPIO_PIN_7|GPIO_PIN_8;

    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;

    GPIO_InitStruct.Pull = GPIO_NOPULL;

    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;

    GPIO_InitStruct.Alternate = GPIO_AF10_OTG_FS;

    HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = QUADSPI_BK2_NCS_Pin;

    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;

    GPIO_InitStruct.Pull = GPIO_NOPULL;

    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;

    GPIO_InitStruct.Alternate = GPIO_AF9_QSPI;

    HAL_GPIO_Init(QUADSPI_BK2_NCS_GPIO_Port, &GPIO_InitStruct);

  /* USER CODE BEGIN QUADSPI_MspInit 1 */

  /* USER CODE END QUADSPI_MspInit 1 */

  }

}

 

Tentative External Loader to test board/part with STM32 Cube Programmer

https://github.com/cturvey/stm32extldr/blob/main/f4_w25q80/README.md

 

PB1:AF9 CLK

PC11:AF9 NCS BK2

PE7:AF10 IO0 BK2

PE8:AF10 IO1 BK2

PC4:AF10 IO2 BK2

PC5:AF10 IO3 BK2

 

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