cancel
Showing results for 
Search instead for 
Did you mean: 

STM32H573 XSPI strange behavior

PThiering
Visitor

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 */

 

 

1 ACCEPTED SOLUTION

Accepted Solutions
PThiering
Visitor

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

 

View solution in original post

1 REPLY 1
PThiering
Visitor

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