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

STM32WB + QSPI for nand flash

  • April 13, 2023
  • 8 replies
  • 10364 views

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.
Best answer by KWOOJ

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..