cancel
Showing results for 
Search instead for 
Did you mean: 

STM32H730 with OctalSPI ISSI IS66WVO8M8 PSRAM

taylors
Associate II

Hello community,

I'm looking for some direction on how to setup the OSPI bus to communitcate with an external PSRAM part from ISSI - IS66WVO8M8 (datasheet attached). I've read through application notes and a handful of example projects but am having a hard time getting the logic to sync.

 A few things I've done:

  • The STM32H7 OSPI bus is set to run at 133MHz with no prescalar (133 because of another OSPI peripheral connected to OSPI1 not shown here)
  • The read operation (page 9) and write operation (page 13) show a data ordering D1/D0, so Makronix was selected. Have tried both Makronix and Makronix RAM as the type
  • Page 19 shows the register read operation waveform - DQS should be enabled
  • Page 8 shows the register command and address values, lengths, etc. 

If you look in the MX_OCTOSPI2_Init function, I am trying to read from the ID register to confirm the correct part, run a quick and dirty write/read check, and then use the part as a GUI framebuffer.  

static void MX_OCTOSPI2_Init(void)
{

  /* USER CODE BEGIN OCTOSPI2_Init 0 */

  /* USER CODE END OCTOSPI2_Init 0 */

  OSPIM_CfgTypeDef sOspiManagerCfg = {0};

  /* USER CODE BEGIN OCTOSPI2_Init 1 */

  /* USER CODE END OCTOSPI2_Init 1 */
  /* OCTOSPI2 parameter configuration*/
  hospi2.Instance = OCTOSPI2;
  hospi2.Init.FifoThreshold = 1;
  hospi2.Init.DualQuad = HAL_OSPI_DUALQUAD_DISABLE;
  hospi2.Init.MemoryType = HAL_OSPI_MEMTYPE_APMEMORY;
  hospi2.Init.DeviceSize = 26;
  hospi2.Init.ChipSelectHighTime = 1;
  hospi2.Init.FreeRunningClock = HAL_OSPI_FREERUNCLK_DISABLE;
  hospi2.Init.ClockMode = HAL_OSPI_CLOCK_MODE_0;
  hospi2.Init.WrapSize = HAL_OSPI_WRAP_32_BYTES;
  hospi2.Init.ClockPrescaler = 1;
  hospi2.Init.SampleShifting = HAL_OSPI_SAMPLE_SHIFTING_NONE;
  hospi2.Init.DelayHoldQuarterCycle = HAL_OSPI_DHQC_DISABLE;
  hospi2.Init.ChipSelectBoundary = 0;
  hospi2.Init.DelayBlockBypass = HAL_OSPI_DELAY_BLOCK_BYPASSED;
  hospi2.Init.MaxTran = 0;
  hospi2.Init.Refresh = 0;
  if (HAL_OSPI_Init(&hospi2) != HAL_OK)
  {
    Error_Handler();
  }
  sOspiManagerCfg.ClkPort = 2;
  sOspiManagerCfg.DQSPort = 2;
  sOspiManagerCfg.NCSPort = 2;
  sOspiManagerCfg.IOLowPort = HAL_OSPIM_IOPORT_2_LOW;
  sOspiManagerCfg.IOHighPort = HAL_OSPIM_IOPORT_2_HIGH;
  if (HAL_OSPIM_Config(&hospi2, &sOspiManagerCfg, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN OCTOSPI2_Init 2 */
  OSPI_RegularCmdTypeDef command = { 0 };

  // Read the ID register
  command.OperationType = HAL_OSPI_OPTYPE_COMMON_CFG;
  command.FlashId = HAL_OSPI_FLASH_ID_1;
  command.Instruction = 0xC000;
  command.InstructionMode = HAL_OSPI_INSTRUCTION_8_LINES;
  command.InstructionSize = HAL_OSPI_INSTRUCTION_16_BITS;
  command.InstructionDtrMode = HAL_OSPI_INSTRUCTION_DTR_ENABLE;
  command.Address = 0;
  command.AddressMode = HAL_OSPI_ADDRESS_8_LINES;
  command.AddressSize = HAL_OSPI_ADDRESS_32_BITS;
  command.AddressDtrMode = HAL_OSPI_ADDRESS_DTR_ENABLE;
  command.AlternateBytes = HAL_OSPI_ALTERNATE_BYTES_NONE;
  command.DummyCycles = 2;
  command.DataMode = HAL_OSPI_DATA_8_LINES;
  command.NbData = 4;
  command.DataDtrMode = HAL_OSPI_DATA_DTR_ENABLE;
  command.DQSMode = HAL_OSPI_DQS_ENABLE;

  if (HAL_OSPI_Command(&hospi2, &command, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
  {
	Error_Handler();
  }
//
  uint32_t id = 0;
  if (HAL_OSPI_Receive(&hospi2, (uint8_t*) &id, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
  {
  	Error_Handler();
  }

  if (id == 0)
  {
	  Error_Handler();
  }

  // Read the config register
  command.OperationType = HAL_OSPI_OPTYPE_COMMON_CFG;
  command.Instruction = 0xC000;
  command.InstructionMode = HAL_OSPI_INSTRUCTION_8_LINES;
  command.InstructionSize = HAL_OSPI_INSTRUCTION_16_BITS;
  command.InstructionDtrMode = HAL_OSPI_INSTRUCTION_DTR_ENABLE;
  command.Address = 0x00040000;
  command.AddressMode = HAL_OSPI_ADDRESS_8_LINES;
  command.AddressSize = HAL_OSPI_ADDRESS_32_BITS;
  command.AddressDtrMode = HAL_OSPI_ADDRESS_DTR_ENABLE;
  command.AlternateBytes = HAL_OSPI_ALTERNATE_BYTES_NONE;
  command.DataMode = HAL_OSPI_DATA_8_LINES;
  command.NbData = 4;
  command.DataDtrMode = HAL_OSPI_DATA_DTR_ENABLE;
  command.DummyCycles = 2;
  command.DQSMode = HAL_OSPI_DQS_ENABLE;

  if (HAL_OSPI_Command(&hospi2, &command, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
  {
    Error_Handler();
  }

  uint32_t config = 0;
  if (HAL_OSPI_Receive(&hospi2, (uint8_t*) &config, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
  {
    Error_Handler();
  }

  if (id == 0)
  {
    Error_Handler();
  }

  OSPI_MemoryMappedTypeDef config = {
    .TimeOutActivation = HAL_OSPI_TIMEOUT_COUNTER_ENABLE,
	.TimeOutPeriod = 0,
  };
  if (HAL_OSPI_MemoryMapped(&hospi2, &config) != HAL_OK)
  {
    Error_Handler();
  }

  uint8_t* src;
  uint32_t errorCount = 0;
  // write test
  src=(uint8_t*) OCTOSPI2_BASE;
  for (uint32_t i = 0; i < 0x0FFFFFFF; i++)
	*src++ = i & 0xFF;

  // Read test
  src=(uint8_t*) OCTOSPI2_BASE;
    for (uint32_t i = 0; i < 0x0FFFFFFF; i++)
  	  if (*src++ != (i & 0xFF))
  		errorCount++;

  if (errorCount != 0)
	while(1);
  /* USER CODE END OCTOSPI2_Init 2 */
}

 As it is now the read operation will stall if the DQSM is enabled. If I disable DQSM then the read returns `0x88888888` instead of an expected value.

Any feedback and help on this is appreciated. Thanks in advance!

 - Taylor

2 REPLIES 2

Does the ID read properly, as what?

All the code beyond that is unworkable, for RAM you'd need to properly create Read and Write command templates.

With the right commands, and configuration operation type

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

In my attached code I am performing a read operation in lines 46 to 78. The goal is to read the ID register, should be a 16-bit value with data encoded into it representing the number of rows and columns in the part. Should be something like 0x2883 or something similar. The datasheet says it will read out the same 16-bit value twice, so it should be 0x28832883, assuming that is the exact value. 

The Read/Write command is shown in the same lines of code, 46-78, to read the ID reg. Then, I had understood that by putting the part into memory-mapped mode that the peripheral would handle the formatting such that you could access the part using pointers instead of directly using the peripheral. All of the example projects I have seen follow this methodology after putting the memory into memory-mapped mode.