Skip to main content
Visitor II
January 9, 2025
Solved

STM32H573 XSPI strange behavior

  • January 9, 2025
  • 1 reply
  • 823 views

Dear Forum Members,

I'm developing a hardware with a small LCD screen which is using a QSPI interface. I succeeded with an STM32H723 with its OCTOSPI interface through DMA, and I got good results, but I encountered memory mapping problems with the complicated split RAM structure of that MCU, so I switched to an STM32H573, which has all of its 640k RAM in one continous block.

Signals used for data transmission: D0~D3, NCS, SCK. For commands and data headers, the protocol uses D0 only in 1-bit SPI mode, than pixel data is being sent in 4-bit QSPI format for each line.

I'm struggling with the XSPI interface setting up correctly for the new microcontroller, it does not send out any data (viewed on a scope), even the NCS signal is not pulled down on HAL_XSPI_Transmit or HAL_XSPI_Command calls. I think I missed some registers which are not generated by the STM32Cube IDE. I've found AN5050, which is mostly about how to attach an external memory chip through these interfaces.

I think I missed setting up or initializing some functions which were not set up completely by the CubeIDE.

 

Working init code I used for the previous MCU generated by STM32Cube IDE, and added some default headers for commands: 

 

 

 

static void MX_OCTOSPI1_Init(void)
{

 /* USER CODE BEGIN OCTOSPI1_Init 0 */

 /* USER CODE END OCTOSPI1_Init 0 */

 OSPIM_CfgTypeDef sOspiManagerCfg = {0};

 /* USER CODE BEGIN OCTOSPI1_Init 1 */

 /* USER CODE END OCTOSPI1_Init 1 */
 /* OCTOSPI1 parameter configuration*/
 hospi1.Instance = OCTOSPI1;
 hospi1.Init.FifoThreshold = 16;
 hospi1.Init.DualQuad = HAL_OSPI_DUALQUAD_DISABLE;
 hospi1.Init.MemoryType = HAL_OSPI_MEMTYPE_MICRON;
 hospi1.Init.DeviceSize = 32;
 hospi1.Init.ChipSelectHighTime = 5;
 hospi1.Init.FreeRunningClock = HAL_OSPI_FREERUNCLK_DISABLE;
 hospi1.Init.ClockMode = HAL_OSPI_CLOCK_MODE_0;
 hospi1.Init.WrapSize = HAL_OSPI_WRAP_NOT_SUPPORTED;
 hospi1.Init.ClockPrescaler = 4;
 hospi1.Init.SampleShifting = HAL_OSPI_SAMPLE_SHIFTING_NONE;
 hospi1.Init.DelayHoldQuarterCycle = HAL_OSPI_DHQC_DISABLE;
 hospi1.Init.ChipSelectBoundary = 0;
 hospi1.Init.DelayBlockBypass = HAL_OSPI_DELAY_BLOCK_BYPASSED;
 hospi1.Init.MaxTran = 0;
 hospi1.Init.Refresh = 0;
 if (HAL_OSPI_Init(&hospi1) != HAL_OK)
 {
 Error_Handler();
 }
 sOspiManagerCfg.ClkPort = 1;
 sOspiManagerCfg.NCSPort = 1;
 sOspiManagerCfg.IOLowPort = HAL_OSPIM_IOPORT_1_LOW;
 if (HAL_OSPIM_Config(&hospi1, &sOspiManagerCfg, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
 {
 Error_Handler();
 }
 /* USER CODE BEGIN OCTOSPI1_Init 2 */



 /* 0xde is the first byte every transmit */
 OSPI_Cmdhandler.Instruction = LCD_INS_DATA;
 /* qspi 24bit address, lcd command is set in A15~A8 */
 OSPI_Cmdhandler.Address = 0x000000;
 OSPI_Cmdhandler.DummyCycles = 0;
 OSPI_Cmdhandler.InstructionMode = HAL_OSPI_INSTRUCTION_1_LINE; // anything except pixel data is 1-bit
 OSPI_Cmdhandler.AddressMode = HAL_OSPI_ADDRESS_1_LINE;
 OSPI_Cmdhandler.AddressSize = HAL_OSPI_ADDRESS_24_BITS;
 OSPI_Cmdhandler.DataMode = HAL_OSPI_DATA_NONE;
 OSPI_Cmdhandler.NbData = 0;

 OSPI_Cmdhandler.SIOOMode = HAL_OSPI_SIOO_INST_EVERY_CMD;
 OSPI_Cmdhandler.DQSMode 		 = HAL_OSPI_DQS_DISABLE;

 // OSPI_Cmdhandler.AlternateByteMode = HAL_OSPI_ALTERNATE_BYTES_NONE;
 // OSPI_Cmdhandler.DdrMode = HAL_OSPI_DDR_MODE_DISABLE;
 // OSPI_Cmdhandler.DdrHoldHalfCycle = HAL_OSPI_DDR_HHC_ANALOG_DELAY;
 /* USER CODE END OCTOSPI1_Init 2 */

}

 

 

LCD Transmit function: (works perfectly on the STM32H723)

 

 

void lcd_transmit(uint32_t cmd, uint32_t len, uint8_t *dat)

{
	OSPI_Cmdhandler.Address = 0x00000000;
	if (len == 0) { /* write command, no parameter, one line in use */
		OSPI_Cmdhandler.Instruction = LCD_INS_CMD;
		OSPI_Cmdhandler.Address |= cmd << 8;
		OSPI_Cmdhandler.DataMode = HAL_OSPI_DATA_NONE;
		OSPI_Cmdhandler.NbData = 0;
		/* interrupt mode */
		HAL_OSPI_Command(&hospi1, &OSPI_Cmdhandler,
				HAL_OSPI_TIMEOUT_DEFAULT_VALUE);
		// HAL_OSPI_Command_IT(&hospi1, &OSPI_Cmdhandler);

	} else if (len <= INIT_DAT_LEN) { /* write command with parameter, only 1 line in use */
		OSPI_Cmdhandler.Instruction = LCD_INS_CMD;
		OSPI_Cmdhandler.Address |= cmd << 8;
		OSPI_Cmdhandler.DataMode = HAL_OSPI_DATA_1_LINE;
		OSPI_Cmdhandler.NbData = len;
		/* interrupt mode */
		// HAL_OSPI_Command_IT(&hospi1, &OSPI_Cmdhandler);
		// HAL_OSPI_Transmit_IT(&hospi1, dat);
		HAL_OSPI_Command(&hospi1, &OSPI_Cmdhandler,
				HAL_OSPI_TIMEOUT_DEFAULT_VALUE);
		HAL_OSPI_Transmit(&hospi1, dat, HAL_OSPI_TIMEOUT_DEFAULT_VALUE);
	} else { /* write display data by hbyte length, data must be sent over QSPI */
		OSPI_Cmdhandler.Instruction = LCD_INS_DATA;
		OSPI_Cmdhandler.Address |= cmd << 8;
		OSPI_Cmdhandler.DataMode = HAL_OSPI_DATA_4_LINES;
		OSPI_Cmdhandler.NbData = len;
		/* mdma mode */

		HAL_OSPI_Command(&hospi1, &OSPI_Cmdhandler, HAL_OSPI_TIMEOUT_DEFAULT_VALUE);
		HAL_OSPI_Transmit_DMA(&hospi1, dat);

		//
		// HAL_Delay(1);
		// HAL_OSPI_Transmit(&hospi1, dat,HAL_OSPI_TIMEOUT_DEFAULT_VALUE);

	}

	// HAL_OSPI_AutoPollingMemReady(&hospi, HAL_QPSI_TIMEOUT_DEFAULT_VALUE);
	// HAL_Delay(1);

}

 

 

 

 

Code which is not working for STM32H573

 

 

static void MX_OCTOSPI1_Init(void)
{

 /* USER CODE BEGIN OCTOSPI1_Init 0 */

 /* USER CODE END OCTOSPI1_Init 0 */

 /* USER CODE BEGIN OCTOSPI1_Init 1 */

 /* USER CODE END OCTOSPI1_Init 1 */
 /* OCTOSPI1 parameter configuration*/
 hospi1.Instance = OCTOSPI1;
 hospi1.Init.FifoThresholdByte = 16;
 hospi1.Init.MemoryMode = HAL_XSPI_SINGLE_MEM;
 hospi1.Init.MemoryType = HAL_XSPI_MEMTYPE_MICRON;
 hospi1.Init.MemorySize = HAL_XSPI_SIZE_16B;
 hospi1.Init.ChipSelectHighTimeCycle = 5;
 hospi1.Init.FreeRunningClock = HAL_XSPI_FREERUNCLK_DISABLE;
 hospi1.Init.ClockMode = HAL_XSPI_CLOCK_MODE_0;
 hospi1.Init.WrapSize = HAL_XSPI_WRAP_NOT_SUPPORTED;
 hospi1.Init.ClockPrescaler = 50;
 hospi1.Init.SampleShifting = HAL_XSPI_SAMPLE_SHIFT_NONE;
 hospi1.Init.DelayHoldQuarterCycle = HAL_XSPI_DHQC_DISABLE;
 hospi1.Init.ChipSelectBoundary = HAL_XSPI_BONDARYOF_16B;
 hospi1.Init.DelayBlockBypass = HAL_XSPI_DELAY_BLOCK_BYPASS;
 hospi1.Init.Refresh = 0;
 if (HAL_XSPI_Init(&hospi1) != HAL_OK)
 {
 Error_Handler();
 }
 /* USER CODE BEGIN OCTOSPI1_Init 2 */

 /* USER CODE END OCTOSPI1_Init 2 */

}

 

 

 

GPIO mappings in the HAL_MSP file:

 

 

void HAL_XSPI_MspInit(XSPI_HandleTypeDef* hxspi)
{
 GPIO_InitTypeDef GPIO_InitStruct = {0};
 RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0};
 if(hxspi->Instance==OCTOSPI1)
 {
 /* USER CODE BEGIN OCTOSPI1_MspInit 0 */

 /* USER CODE END OCTOSPI1_MspInit 0 */

 /** Initializes the peripherals clock
 */
 PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_OSPI;
 PeriphClkInitStruct.OspiClockSelection = RCC_OSPICLKSOURCE_HCLK;
 if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK)
 {
 Error_Handler();
 }

 /* Peripheral clock enable */
 __HAL_RCC_OSPI1_CLK_ENABLE();

 __HAL_RCC_GPIOA_CLK_ENABLE();
 __HAL_RCC_GPIOB_CLK_ENABLE();
 /**OCTOSPI1 GPIO Configuration
 PA6 ------> OCTOSPI1_IO3
 PA7 ------> OCTOSPI1_IO2
 PB0 ------> OCTOSPI1_IO1
 PB1 ------> OCTOSPI1_IO0
 PB2 ------> OCTOSPI1_CLK
 PB10 ------> OCTOSPI1_NCS
 */
 GPIO_InitStruct.Pin = GPIO_PIN_6;
 GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
 GPIO_InitStruct.Pull = GPIO_NOPULL;
 GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
 GPIO_InitStruct.Alternate = GPIO_AF6_OCTOSPI1;
 HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

 GPIO_InitStruct.Pin = GPIO_PIN_7;
 GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
 GPIO_InitStruct.Pull = GPIO_NOPULL;
 GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
 GPIO_InitStruct.Alternate = GPIO_AF10_OCTOSPI1;
 HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

 GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1;
 GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
 GPIO_InitStruct.Pull = GPIO_NOPULL;
 GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
 GPIO_InitStruct.Alternate = GPIO_AF6_OCTOSPI1;
 HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

 GPIO_InitStruct.Pin = GPIO_PIN_2|GPIO_PIN_10;
 GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
 GPIO_InitStruct.Pull = GPIO_NOPULL;
 GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
 GPIO_InitStruct.Alternate = GPIO_AF9_OCTOSPI1;
 HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

 /* OCTOSPI1 DMA Init */
 /* GPDMA1_REQUEST_OCTOSPI1 Init */
 handle_GPDMA1_Channel0.Instance = GPDMA1_Channel0;
 handle_GPDMA1_Channel0.Init.Request = GPDMA1_REQUEST_OCTOSPI1;
 handle_GPDMA1_Channel0.Init.BlkHWRequest = DMA_BREQ_SINGLE_BURST;
 handle_GPDMA1_Channel0.Init.Direction = DMA_MEMORY_TO_PERIPH;
 handle_GPDMA1_Channel0.Init.SrcInc = DMA_SINC_FIXED;
 handle_GPDMA1_Channel0.Init.DestInc = DMA_DINC_FIXED;
 handle_GPDMA1_Channel0.Init.SrcDataWidth = DMA_SRC_DATAWIDTH_WORD;
 handle_GPDMA1_Channel0.Init.DestDataWidth = DMA_DEST_DATAWIDTH_WORD;
 handle_GPDMA1_Channel0.Init.Priority = DMA_LOW_PRIORITY_HIGH_WEIGHT;
 handle_GPDMA1_Channel0.Init.SrcBurstLength = 1;
 handle_GPDMA1_Channel0.Init.DestBurstLength = 1;
 handle_GPDMA1_Channel0.Init.TransferAllocatedPort = DMA_SRC_ALLOCATED_PORT0|DMA_DEST_ALLOCATED_PORT0;
 handle_GPDMA1_Channel0.Init.TransferEventMode = DMA_TCEM_BLOCK_TRANSFER;
 handle_GPDMA1_Channel0.Init.Mode = DMA_NORMAL;
 if (HAL_DMA_Init(&handle_GPDMA1_Channel0) != HAL_OK)
 {
 Error_Handler();
 }

 __HAL_LINKDMA(hxspi, hdmatx, handle_GPDMA1_Channel0);

 if (HAL_DMA_ConfigChannelAttributes(&handle_GPDMA1_Channel0, DMA_CHANNEL_NPRIV) != HAL_OK)
 {
 Error_Handler();
 }

 /* OCTOSPI1 interrupt Init */
 HAL_NVIC_SetPriority(OCTOSPI1_IRQn, 14, 0);
 HAL_NVIC_EnableIRQ(OCTOSPI1_IRQn);
 /* USER CODE BEGIN OCTOSPI1_MspInit 1 */

 /* USER CODE END OCTOSPI1_MspInit 1 */

 }

}

 

 

 

Then, in the main loop I tried to send out something:

(also tried with Transmit_IT or Transmit_DMA but the same result, software runs)

If I set free running clock ON, then the clock can be seen on the scope.

 

 

 /* Initialize all configured peripherals */
 MX_GPIO_Init();
 MX_GPDMA1_Init();
 MX_OCTOSPI1_Init();
 MX_DCACHE1_Init();
 MX_ICACHE_Init();
 /* USER CODE BEGIN 2 */
 
 XSPI_RegularCmdTypeDef sCommand1={0};
	/*Initialize the write register command */
	sCommand1.OperationType = HAL_XSPI_OPTYPE_COMMON_CFG;

	 sCommand1.InstructionMode = HAL_XSPI_INSTRUCTION_1_LINE;
	 sCommand1.InstructionWidth = HAL_XSPI_INSTRUCTION_16_BITS;
	 sCommand1.InstructionDTRMode = HAL_XSPI_INSTRUCTION_DTR_DISABLE;
	 sCommand1.Instruction = 0xEA;
	 sCommand1.AddressMode = HAL_XSPI_ADDRESS_1_LINE;
	 sCommand1.AddressWidth = HAL_XSPI_ADDRESS_24_BITS;
	 sCommand1.AddressDTRMode = HAL_XSPI_ADDRESS_DTR_DISABLE;
	 sCommand1.Address = 0xFF;
	 sCommand1.AlternateBytesMode = HAL_XSPI_ALT_BYTES_NONE;
	 sCommand1.DataMode = HAL_XSPI_DATA_4_LINES;
	 sCommand1.DataDTRMode = HAL_XSPI_DATA_DTR_DISABLE;
	 sCommand1.DataLength = 8;
	 sCommand1.DummyCycles = 0;
	 sCommand1.DQSMode = HAL_XSPI_DQS_DISABLE;
	 sCommand1.IOSelect = HAL_XSPI_SELECT_IO_3_0;
	 // sCommand1.SIOOMode = HAL_XSPI_SIOO_INST_ONLY_FIRST_CMD;

	/* Configure the command*/
	 HAL_XSPI_Command(&hospi1, &sCommand1, 5000);

	uint8_t tmp[16]= { 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16 };

	HAL_XSPI_Transmit(&hospi1, &tmp[0], 100);
 /* USER CODE END 2 */

 /* Infinite loop */
 /* USER CODE BEGIN WHILE */
 while (1)
 {


	 HAL_XSPI_Command(&hospi1, &sCommand1, 1000);
	 HAL_XSPI_Transmit(&hospi1, &tmp[0],1000);
	 // HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_10);

	 HAL_Delay(1);

 /* USER CODE END WHILE */

 /* USER CODE BEGIN 3 */
 }
 /* USER CODE END 3 */

 

 

    This topic has been closed for replies.
    Best answer by PThiering

    I think the problem was resolved. There's a "memory size" setting in CubeMX which had to be set to "512k / 4mbit" and then the thing begon sending data. Idk why... 

    For further reference, there was the fix.

     

    PThiering_0-1736427268631.png

     

    1 reply

    PThieringAuthorAnswer
    Visitor II
    January 9, 2025

    I think the problem was resolved. There's a "memory size" setting in CubeMX which had to be set to "512k / 4mbit" and then the thing begon sending data. Idk why... 

    For further reference, there was the fix.

     

    PThiering_0-1736427268631.png