cancel
Showing results for 
Search instead for 
Did you mean: 

STM32WB + QSPI for nand flash

KWOOJ
Associate III

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;

}

1 ACCEPTED SOLUTION

Accepted Solutions
KWOOJ
Associate III

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.

View solution in original post

8 REPLIES 8

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
Up vote any posts that you find helpful, it shows what's working..

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?

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
Up vote any posts that you find helpful, it shows what's working..
KWOOJ
Associate III

Added waiting code.

It was applied to my program, but I didn't include it in the article.

Error handle occurs in QSPI communication when going from 2 to 3 and from 5 to 6 by debugging.

I haven't been able to find out why I'm having problems with this process

You don't mention a specific part or link to a datasheet.

Hard to know if you're logic / sequence is correct.

C​ode still looks to plough forward with no regard to completion.

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

Use the blocking, non-IT, methods and get the sequencing validated​, then work on how you signal completion.

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

I replaced NON-IT with IT in my code, and the error_handler doesn't appear.

It has been confirmed that the data is stored in the memory well, but the problem of not being able to read the data normally remains if the delay is removed between 5 and 6.

Thank you for your comment, it is a great help!

And I have attached the datasheet of the IC I am using.

KWOOJ
Associate III

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.