Skip to main content
KWOOJ
Associate II
April 13, 2023
Solved

STM32WB + QSPI for nand flash

My development environment is stm32cubeMX and IAR.

​

​

First of all, the configuration I programmed is like this.

1. Init (write Status Register WP-E set 1)

2. Block Erase (to the address where i will store the data)

3. Write data to buffer

4. Program Execute

5. Load data (load data in physical memory page to data buffer)

6. Read data

​

​If Delay is not used between 2 and 5, HAL_QSPI_Command_IT function is passed to Error_Handler.

I want to make it work without this delay.

If a delay is inserted or executed line by line, it operates normally without going over to Error_Handler.

​Are QSPI commands not usable consecutively?

​

void Flash_Init(void)

{

 sCommand.InstructionMode  = QSPI_INSTRUCTION_1_LINE;

 sCommand.AddressSize    = QSPI_ADDRESS_24_BITS;

 sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;

 sCommand.DdrMode      = QSPI_DDR_MODE_DISABLE;

 sCommand.SIOOMode     = QSPI_SIOO_INST_EVERY_CMD;

  

 Flash_Write_Status_Register(0x02); //set WP-E 1

}

​

void Flash_Erase(uint32_t address)

{

 QSPI_AutoPollingMemReady(&hqspi);

  

 QSPI_WriteEnable(&hqspi);

​

 sCommand.Instruction = SECTOR_ERASE_CMD;

 sCommand.AddressMode = QSPI_ADDRESS_1_LINE;

 sCommand.AddressSize = QSPI_ADDRESS_24_BITS;

 sCommand.Address   = address;

 sCommand.DataMode  = QSPI_DATA_NONE;

 sCommand.DummyCycles = 0;

 sCommand.SIOOMode     = QSPI_SIOO_INST_EVERY_CMD;

 sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;

​

 if (HAL_QSPI_Command_IT(&hqspi, &sCommand) != HAL_OK)

 {

  Error_Handler();

 }

 Flash_Wait_Busy();

}

​

void Flash_Write(void)

{

 uint32_t address = 0x0000;

​

 QSPI_AutoPollingMemReady(&hqspi);  

 QSPI_WriteEnable(&hqspi);

 Flash_Wait_Busy();

​

 sCommand.Instruction = PAGE_PROG_CMD;

 sCommand.AddressMode = QSPI_ADDRESS_1_LINE;

 sCommand.AddressSize = QSPI_ADDRESS_16_BITS;

 sCommand.Address   = address;

 sCommand.DataMode  = QSPI_DATA_1_LINE;

 sCommand.NbData   = BUFFERSIZE;

 sCommand.DummyCycles = 0;

 sCommand.SIOOMode     = QSPI_SIOO_INST_EVERY_CMD;

 sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;

​

 if (HAL_QSPI_Command(&hqspi, &sCommand, HAL_QSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)

 {

  Error_Handler();

 }

​

 if (HAL_QSPI_Transmit_IT(&hqspi, aTxBuffer) != HAL_OK) 

 {

  Error_Handler();

 }

​

}

​

void Flash_Program_Execute(uint32_t address)

{

 QSPI_AutoPollingMemReady(&hqspi);

 QSPI_WriteEnable(&hqspi);

  

 sCommand.Instruction = PROGRAM_EXECUTE;

 sCommand.AddressMode = QSPI_ADDRESS_1_LINE;

 sCommand.AddressSize = QSPI_ADDRESS_24_BITS;

 sCommand.Address   = address;

 sCommand.DataMode  = QSPI_DATA_NONE;

 sCommand.DummyCycles = 0;

 sCommand.SIOOMode     = QSPI_SIOO_INST_EVERY_CMD;

 sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;

​

 if (HAL_QSPI_Command_IT(&hqspi, &sCommand) != HAL_OK)

 {

  Error_Handler();

 }

}

​

​

void Flash_Load_StorageData(uint32_t address)

{

 QSPI_AutoPollingMemReady(&hqspi);

 Flash_Wait_Busy();

​

 sCommand.Instruction = PAGE_DATA_READ;

 sCommand.InstructionMode  = QSPI_INSTRUCTION_1_LINE;

 sCommand.AddressMode = QSPI_ADDRESS_1_LINE;

 sCommand.Address   = address;

 sCommand.AddressSize = QSPI_ADDRESS_24_BITS;

 sCommand.DataMode  = QSPI_DATA_NONE;

 sCommand.DummyCycles = 0;

 sCommand.SIOOMode     = QSPI_SIOO_INST_EVERY_CMD;

 sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;

​

 if (HAL_QSPI_Command_IT(&hqspi, &sCommand) != HAL_OK)

 {

  Error_Handler();

 }

}

​

void Flash_Read(void)

{

 uint16_t address = 0x0000;

 Flash_Wait_Busy();

 QSPI_AutoPollingMemReady(&hqspi);

​

 sCommand.Instruction = READ_CMD;

 sCommand.AddressMode = QSPI_ADDRESS_1_LINE;

 sCommand.AddressSize = QSPI_ADDRESS_16_BITS;

 sCommand.Address   = address;

 sCommand.DataMode  = QSPI_DATA_1_LINE;

 sCommand.NbData   = BUFFERSIZE;

 sCommand.DummyCycles = 8;

 sCommand.SIOOMode     = QSPI_SIOO_INST_EVERY_CMD;

 sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;

​

 if (HAL_QSPI_Command(&hqspi, &sCommand, HAL_QSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)

 {

  Error_Handler();

 }

  

 if (HAL_QSPI_Receive_IT(&hqspi, aRxBuffer) != HAL_OK)

 {

  Error_Handler();

 }

}

​

--------------------------------------------------------------------Add 14/04/2023

void Flash_Wait_Busy(void)

{

  while((Flash_Read_BusyBeat(0xC0) & 0x01) == 0x01);

}

uint8_t Flash_Read_BusyBeat(uint8_t address)

{

  

 QSPI_WriteDisable(&hqspi);

  

 sCommand.Instruction = READ_STATUS_REG_CMD;

 sCommand.AddressMode = QSPI_ADDRESS_1_LINE;

 sCommand.AddressSize = QSPI_ADDRESS_8_BITS;

 sCommand.Address   = address;

 sCommand.DataMode  = QSPI_DATA_1_LINE;

 sCommand.DummyCycles = 0;

 sCommand.SIOOMode     = QSPI_SIOO_INST_EVERY_CMD;

 sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;

 sCommand.DdrMode      = QSPI_DDR_MODE_DISABLE;

 if (HAL_QSPI_Command(&hqspi, &sCommand, HAL_QSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)

 {

  Error_Handler();

 }

  

 if (HAL_QSPI_Receive_IT(&hqspi, &BusyBeat) != HAL_OK)

 {

  Error_Handler();

 }

 QSPI_WriteEnable(&hqspi);

 return BusyBeat;

}

This topic has been closed for replies.
KWOOJ
KWOOJBest answer
Associate II
April 17, 2023

The problem was solved by adding the action of checking the busy bit before reading.

From now on, I think I'll have to upload it to my entire program to see if there's anything wrong with it.

Thanks for your help with my problem.

8 replies

Tesla DeLorean
Guru
April 13, 2023

Yes QSPI supports commands consecutively, but not concurrently.

​

T​he memory device must complete its current operation before starting the next.

​

T​he IT commands complete immediately, you'll need to spin somewhere until you get the interrupt/callback. Or sequence the process in the callback, with a lot of error / exception handling.

Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
KWOOJ
KWOOJAuthor
Associate II
April 13, 2023

Thanks for answer​!

I understand that QSPI does not support commands concurrently.

So I'm sending a command when the memory is ready to run by checking the Busy bit.

Do I need to do other processing besides checking the busy bit?

Tesla DeLorean
Guru
April 13, 2023

You'd do whatever the memory part's data​ sheet/manual says is necessary.

​

Don't see any of the callback or related waiting code presented. ​

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