cancel
Showing results for 
Search instead for 
Did you mean: 

How to make QSPI transmission without delay between Command and Data?

Irek
Associate III

I need to communicate with FPGA by QuadSPI. I use the NUCLEO-H743ZI2 and FreeRTOS with STM32Cub IDE.
So my code to write data to FPGA looks next:

uint32_t qspi_write(const uint8_t* RXbuf, uint8_t* TXbuf, uint16_t* tx_length) {
	sCommand.InstructionMode 	= QSPI_INSTRUCTION_NONE; /* Specifies the Instruction Mode: value of @ref QSPI_InstructionMode */
	sCommand.Instruction		= 0; /* Specifies the Instruction to be sent: value (8-bit) between 0x00 and 0xFF */
	sCommand.AddressMode		= QSPI_ADDRESS_4_LINES; /* Specifies the Address Mode: value of @ref QSPI_AddressMode */
	sCommand.AddressSize		= QSPI_ADDRESS_32_BITS; /* Specifies the Address Size: value of @ref QSPI_AddressSize */
	sCommand.Address			= *(uint32_t *) RXbuf; /* Specifies the Address to be sent (Size from 1 to 4 bytes according AddressSize): value (32-bits) between 0x0 and 0xFFFFFFFF */
	sCommand.AlternateByteMode	= QSPI_ALTERNATE_BYTES_NONE; /* Specifies the Alternate Bytes Mode: value of @ref QSPI_AlternateBytesMode */
	sCommand.AlternateBytesSize	= QSPI_ALTERNATE_BYTES_8_BITS; /* Specifies the Alternate Bytes Size: value of @ref QSPI_AlternateBytesSize */
	sCommand.AlternateBytes		= 0; /* Specifies the Alternate Bytes to be sent (Size from 1 to 4 bytes according AlternateBytesSize): value (32-bits) between 0x0 and 0xFFFFFFFF */
	sCommand.DummyCycles		= 1; /* Specifies the Number of Dummy Cycles: number between 0 and 31 */
	sCommand.DataMode			= QSPI_DATA_4_LINES; /* Specifies the Data Mode (used for dummy cycles and data phases): value of @ref QSPI_DataMode */
	sCommand.NbData				= (uint32_t) *tx_length; /* Specifies the number of bytes to transfer: value between 0 and 0xFFFFFFFF (0 means undefined length until end of memory)*/
	sCommand.DdrMode			= QSPI_DDR_MODE_DISABLE; /* Specifies the double data rate mode for address, alternate byte and data phase: value of @ref QSPI_DdrMode */
	sCommand.DdrHoldHalfCycle	= QSPI_DDR_HHC_ANALOG_DELAY; /* Specifies if the DDR hold is enabled: value of @ref QSPI_DdrHoldHalfCycle */
	sCommand.SIOOMode			= QSPI_SIOO_INST_EVERY_CMD; /* Specifies the send instruction only once mode: value of @ref QSPI_SIOOMode */

	configPRINTF( ("qspi: Command to Address = 0x%08x\n", sCommand.Address) );
	HAL_StatusTypeDef result = HAL_QSPI_Command(&hqspi, &sCommand, QSPI_TIMEOUT_VALUE);
	if ( result != HAL_OK ) {
		qspi_error_handler(result);
    	return result;
	}

	configPRINTF( ("qspi: Transmit NbData = %d\n", (uint16_t) *tx_length) );
//	result = HAL_QSPI_Transmit(&hqspi, TXbuf, QSPI_TIMEOUT_VALUE);
	result = HAL_QSPI_Transmit_IT(&hqspi, TXbuf);
    if ( result != HAL_OK ) {
    	qspi_error_handler(result);
    	return result;
    }
	return HAL_QSPI_ERROR_NONE;
}

As result, I see by Logic Analyser the next picture:
Untitled.png
The first burst of clocks corresponds to the transmission if Command, the 2nd - to the Data. The gap between two bursts  is about 0.76 mks in the case of using of HAL_QSPI_Transmit_IT and 1.5 mks in case of HAL_QSPI_Transmit which is somehow strange.
But the main question how I have to organize QSPI transmission without delay between Command and Data?


18 REPLIES 18
CTapp.1
Senior II

Possibly a silly question, but how long does the call to configPRINTF() take?

@CTapp.1 
If I comment the all configPRINTF() in the code the gap between burst do not change - this I tested before writing a post. 
I should mention that my previous project on the same board was used MBed OS - and there was not any gap inside QSPI transmissions. So STM32H7 hardware is able to transmit without any gap/delay. So how to program the same in the FreeRTOS?

 

urbito
Senior II

i am on the same page as CTapp.1, you should not have those "prints" on a transmission, normally those kind of prints add a delay around 50/100ms.

Irek
Associate III

@urbito :
Ok, I have to repeat test. Here is results: 

Code:

//	configPRINTF( ("qspi: Command to Address = 0x%08x\n", sCommand.Address) );
	HAL_StatusTypeDef result = HAL_QSPI_Command(&hqspi, &sCommand, QSPI_TIMEOUT_VALUE);
//	if ( result != HAL_OK ) {
//		qspi_error_handler(result);
//    	return result;
//	}

//	configPRINTF( ("qspi: Transmit NbData = %d\n", (uint16_t) *tx_length) );
//	result = HAL_QSPI_Transmit(&hqspi, TXbuf, QSPI_TIMEOUT_VALUE);
	result = HAL_QSPI_Transmit_IT(&hqspi, TXbuf);
//    if ( result != HAL_OK ) {
//    	qspi_error_handler(result);
//    	return result;
//    }

	return HAL_QSPI_ERROR_NONE;

Logic Analyser:
Untitled.png

Inspect HAL_QSPI_Command source and construct a multi-byte variant 

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

I tried to combine the HAL_QSPI_Command and HAL_QSPI_Transmit functions in a single function without additional conditional checks or __HAL_LOCK like functions use.
The result is the same - I see the gap between Command and Data sections during QSPI transmission. 

I looked the MBed's realization of the qspi.write - they use same HAL functions:

    if (HAL_QSPI_Command(&obj->handle, &st_command, HAL_QSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) {
        status = QSPI_STATUS_ERROR;
    } else {
        if (HAL_QSPI_Transmit(&obj->handle, (uint8_t *)data, HAL_QSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) {
            status = QSPI_STATUS_ERROR;
        }
    }

So obviously either I or FreeRTOS configure some QSPI registers in a wrong way. But I did not find in STM's manuals any explanation about delay between Command and Data transmission.

Any idea what should I check now?

 

 

Could it be that FreeRTOS performs a task switch after the command is initiated and the task waits for completion ?

Irek
Associate III

@Ozone 
I don't think so - as I understand it, FreeRTOS switches tasks using Ticks, which is 1 ms. In this case gap between Command and Data is 0.8-1.6 mks - much smaller. But I am just beginner in using FreeRTOS so I do not know many details... 

Many RTOSes switch to other tasks if the currently running one is waiting for a signal/event to occur.
A lot depends on configuration and task setup.