cancel
Showing results for 
Search instead for 
Did you mean: 

DMA QSPI transmit and receive complete

Ehill.16
Senior

I need to know when a DMA QSPI flash transmit and receive are complete. How do I use the QSPI_DMATxCplt and QSPI_DMARxCplt functions. 

10 REPLIES 10
Imen.D
ST Employee

Hello @Ehill.16​ ,

This QSPI DMA function is used for transmitting data: HAL_QSPI_Transmit_DMA(&QSPIHandle, aTxBuffer) != HAL_OK,

         if (HAL_QSPI_Transmit_DMA(&QSPIHandle, aTxBuffer) != HAL_OK)
          {
            Error_Handler();
          }
 
          step++;
        }
        break;
 
      case 3:
        if(TxCplt != 0)
        {
          TxCplt = 0;
          StatusMatch = 0;
 
          /* Configure automatic polling mode to wait for end of program ----- */  
          QSPI_AutoPollingMemReady(&QSPIHandle);
        
          step++;
        }

Then, an interruption will be generated, and the HAL_QSPI_RxCpltCallback() function will be called:

void HAL_QSPI_RxCpltCallback(QSPI_HandleTypeDef *hqspi)
{
 RxCplt++;
}

Note that you should add the HAL_QSPI_RxCpltCallback() function in the main.c.

I recommend you to refer to the QSPI_ReadWrite_DMA example in the STM32CubeF7 MCU package and get inspired or re-use the available sections : STM32Cube_FW_F7_Vx.xx.x\Projects\STM32F769I_EVAL\Examples\QSPI\QSPI_ReadWrite_DMA

This example describes how to erase part of a QSPI memory, write data in DMA mode, read data in DMA mode.

I hope my answer is helpful.

Please select my answer as Best if it fully answered your question.

Imen

When your question is answered, please close this topic by clicking "Accept as Solution".
Thanks
Imen

Thanks for the reply.

I added the QSPI_AutoPollingMemRead line to the QspiReadDataDMA function:

uint8_t QspiReadDataDMA(uint32_t address, uint32_t size, uint8_t *pData) {
	QSPI_CommandTypeDef s_command;
	QSPI_AutoPollingTypeDef s_config;
 
	/* Initialize the read command */
	s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE;
	s_command.Instruction = QUAD_INOUT_FAST_READ_CMD;
	s_command.AddressMode = QSPI_ADDRESS_4_LINES;
	s_command.AddressSize = QSPI_ADDRESS_24_BITS;
	s_command.Address = address;
	s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
	s_command.AlternateBytes = 0;
	s_command.AlternateBytesSize = 0;
	s_command.DataMode = QSPI_DATA_4_LINES; // QSPI_DATA_4_LINES
	s_command.DummyCycles = 0;
	s_command.NbData = size;
	s_command.DdrMode = QSPI_DDR_MODE_DISABLE;
	s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
	s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
 
	/* Configure the command */
	printf("HAL_QSPI_Command\n");
	if (HAL_QSPI_Command(&hqspi, &s_command,
	HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) {
		printf("HAL_ERROR\n");
		return HAL_ERROR;
	}
 
	/* Reception of the data */
	printf("HAL_QSPI_Receive\n");
	if (HAL_QSPI_Receive_DMA(&hqspi, pData) != HAL_OK) {
		printf("HAL_ERROR\n"); // Timeout after 5000mS
		return HAL_ERROR;
	}
 
    /* Configure automatic polling mode to wait for end of program ----- */
    QSPI_AutoPollingMemReady(&hqspi, HAL_QPSI_TIMEOUT_DEFAULT_VALUE);
 
 
	return HAL_OK;
}

Here is the callback function:

void HAL_QSPI_RxCpltCallback(QSPI_HandleTypeDef *hqspi) {
	/* Prevent unused argument(s) compilation warning */
	//UNUSED(hqspi);
	RxCplt = 1;
}

This callback function never executes when the QspiReadDataDMA function is called.

Imen.D
ST Employee

Hello @Ehill.16​ ,

1- You should add this condition: while (RxCplt ==0); because the read transaction take time. So, you need to make sure that the read transaction has been completed before checking if the memory is ready (automatic polling mode): QSPI_AutoPollingMemReady(&hqspi, HAL_QPSI_TIMEOUT_DEFAULT_VALUE);

uint8_t QspiReadDataDMA(uint32_t address, uint32_t size, uint8_t *pData) {
	QSPI_CommandTypeDef s_command;
	QSPI_AutoPollingTypeDef s_config;
 
	/* Initialize the read command */
	s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE;
	s_command.Instruction = QUAD_INOUT_FAST_READ_CMD;
	s_command.AddressMode = QSPI_ADDRESS_4_LINES;
	s_command.AddressSize = QSPI_ADDRESS_24_BITS;
	s_command.Address = address;
	s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
	s_command.AlternateBytes = 0;
	s_command.AlternateBytesSize = 0;
	s_command.DataMode = QSPI_DATA_4_LINES; // QSPI_DATA_4_LINES
	s_command.DummyCycles = 0;
	s_command.NbData = size;
	s_command.DdrMode = QSPI_DDR_MODE_DISABLE;
	s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
	s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
 
	/* Configure the command */
	printf("HAL_QSPI_Command\n");
	if (HAL_QSPI_Command(&hqspi, &s_command,
	HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) {
		printf("HAL_ERROR\n");
		return HAL_ERROR;
	}
 
	/* Reception of the data */
	printf("HAL_QSPI_Receive\n");
	if (HAL_QSPI_Receive_DMA(&hqspi, pData) != HAL_OK) {
		printf("HAL_ERROR\n"); // Timeout after 5000mS
		return HAL_ERROR;
	}
 
while (RxCplt ==0);  //  add this condition 
 
    /* Configure automatic polling mode to wait for end of program ----- */
    QSPI_AutoPollingMemReady(&hqspi, HAL_QPSI_TIMEOUT_DEFAULT_VALUE);
  
	return HAL_OK;
}

2 - Don't modify the HAL_QSPI_RxCpltCallback() function in the stm32f7xx_hal_qspi.c, you should add this function in the main.c :

void HAL_QSPI_RxCpltCallback(QSPI_HandleTypeDef *hqspi)
{
 RxCplt++;
}

I hope that is clear now for you.

Imen

When your question is answered, please close this topic by clicking "Accept as Solution".
Thanks
Imen

Thanks for your reply. I did add that while condition but the HAL_QSPI_RxCpltCallback never executes! I don't understand why. I am using the stm32746g_discovery_qspi.c initialization function.

Imen.D
ST Employee

Try to debug and localize where the code hangs/stop and the kind of message gives.

I suggest to start with the QSPI example available under STM32CubeF7 MCU package, to confirm if the problem here seems related to your hardware or software environment: STM32Cube_FW_F7_Vx.xx.x\Projects\STM32F769I_EVAL\Examples\QSPI\QSPI_ReadWrite_DMA

If the issue still exist, you can share you project code, to check your configuration setting.

Imen

When your question is answered, please close this topic by clicking "Accept as Solution".
Thanks
Imen

The program works so far as writing to, reading from, and erasing the QUADSPI flash memory. For some reason the global QSPI interrupt is not firing and consequently either is the rx complete or the tx complete interrupts.

Will this example work on the STM32F746G Discovery board?

Hi Imen,

Well, it is working, the Rx and Tx callback functions are firing and I can measure the time it takes to read and write QSPI flash memory. One thing, the Reading and writing of QSPI flash memory without DMA, doesn't cause the callbacks to execute. I am assuming that I probably need to disable the DMA channel for that to work? I am posting a code snippet of the case statements for writing and reading QSPI flash memory. The transfer rate seems a little slow. The write to flash is 127KB/s and reading flash is 632KB/s. Does this seem right?

		switch (button) {// button is set in the GPIO callback function according to what button is pressed
		case 1: // if 1 command ( command to write a const string to the QSPI Flash memory )
			DWT->CYCCNT = 0;
			start = DWT->CYCCNT; // get the core cycle count and store it in start variable
			TxCplt = 0;
			QspiWriteDataDMA(0, sizeof(aTxBuffer), aTxBuffer);
			while (TxCplt ==0);  //  add this condition
			finish = DWT->CYCCNT; // get the core cycle count and store it in finish variable
			totalmS = (finish - start);	// calculate the time it took in core cycles to send 140KB's
			sprintf(result, " %d B/s ", CalcQSPITransRate(totalmS));// calculate transfer speed in bytes/second
			ssd1306_SetCursor(2, 0);
			ssd1306_WriteString("QSPI flash write:", Font_7x10, White);
			ssd1306_SetCursor(0, 11);
			ssd1306_WriteString(result, Font_7x10, White);
			ssd1306_UpdateScreen();
			button = 0;
			break;
		case 2: // if 2 command, read the QSPI Flash memory and send what was read to the USB
			DWT->CYCCNT = 0;
			start = DWT->CYCCNT; // get the core cycle count and store it in start variable
			RxCplt = 0;
			QspiReadDataDMA(0, sizeof(aDST_Buffer), aDST_Buffer);
			while (RxCplt ==0);  //  add this condition
			finish = DWT->CYCCNT; // get the core cycle count and store it in finish variable
			totalmS = (finish - start);	// calculate the time it took in core cycles to send 140KB's
			sprintf(result, " %d B/s ", CalcQSPITransRate(totalmS));// calculate transfer speed in bytes/second
			ssd1306_SetCursor(2, 22);
			ssd1306_WriteString("QSPI flash read:", Font_7x10, White);
			ssd1306_SetCursor(0, 33);
			ssd1306_WriteString(result, Font_7x10, White);
			ssd1306_UpdateScreen();
			button = 0;
			break;

0693W000004K8v1QAC.jpg 

Question, if I wanted to right the last page of the QSPI Flash memory, would I use 255 as the address?

Thanks so much for your help with this!

Now I am reading 1.4 MB/s.