cancel
Showing results for 
Search instead for 
Did you mean: 

What options are necessary in order to write/read data from HyperRAM / HyperFlash memories?

AGEBE.1
Associate II

Hi,

I'm trying to develop a program on a NUCLEO-L4R5ZI-P to write/read data from a S27K0641 (HYPERRAM) and S26K128 (HYPERFLASH).

First I choosed to use only Indirect mode to access the memory. Is it the best option?

Then, there are a lot of options available on HyperBus (such as Delay block bypass, Delay Hold-Quarter, ...) and I was wondering which one are critical in order to access the memories?

Here are the OCTOSPI configuration function generated by the IDE:

You will also find r/w short function which use Indirect mode.

static void MX_OCTOSPI1_Init(void)
{
 
  /* USER CODE BEGIN OCTOSPI1_Init 0 */
 
  /* USER CODE END OCTOSPI1_Init 0 */
 
  OSPI_HyperbusCfgTypeDef sHyperBusCfg = {0};
 
  /* USER CODE BEGIN OCTOSPI1_Init 1 */
 
  /* USER CODE END OCTOSPI1_Init 1 */
  /* OCTOSPI1 parameter configuration*/
  hospi1.Instance = OCTOSPI1;
  hospi1.Init.FifoThreshold = 1;
  hospi1.Init.DualQuad = HAL_OSPI_DUALQUAD_DISABLE;
  hospi1.Init.MemoryType = HAL_OSPI_MEMTYPE_HYPERBUS;
  hospi1.Init.DeviceSize = 22;
  hospi1.Init.ChipSelectHighTime = 1;
  hospi1.Init.FreeRunningClock = HAL_OSPI_FREERUNCLK_DISABLE;
  hospi1.Init.ClockMode = HAL_OSPI_CLOCK_MODE_0;
  hospi1.Init.ClockPrescaler = 1;
  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;
  if (HAL_OSPI_Init(&hospi1) != HAL_OK)
  {
    Error_Handler();
  }
  sHyperBusCfg.RWRecoveryTime = 0;
  sHyperBusCfg.AccessTime = 0;
  sHyperBusCfg.WriteZeroLatency = HAL_OSPI_NO_LATENCY_ON_WRITE;
  sHyperBusCfg.LatencyMode = HAL_OSPI_VARIABLE_LATENCY;
  if (HAL_OSPI_HyperbusCfg(&hospi1, &sHyperBusCfg, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN OCTOSPI1_Init 2 */
 
  /* USER CODE END OCTOSPI1_Init 2 */
 
}

Here is a function that configures the memory :

void ospi1_initialize(void)
{
	OSPI_HyperbusCfgTypeDef sHyperBusCfg = {0};
	OSPI_HyperbusCmdTypeDef scommand = {0};
 
	sHyperBusCfg.RWRecoveryTime = 4;
	sHyperBusCfg.AccessTime = 4;
	sHyperBusCfg.WriteZeroLatency = HAL_OSPI_NO_LATENCY_ON_WRITE;
	sHyperBusCfg.LatencyMode = HAL_OSPI_VARIABLE_LATENCY;
	if (HAL_OSPI_HyperbusCfg(&hospi1, &sHyperBusCfg, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
	{
	Error_Handler();
	}
	HAL_Delay(1);
	/*
	 * CONFIGURATION REGISTER 0
	 * 0b1000 1111 0001 0111
	 */
	uint8_t CR0[2];
	CR0[0] = 0b00010111;
	CR0[1] = 0b10001111;
	scommand.AddressSpace = HAL_OSPI_REGISTER_ADDRESS_SPACE ;
	scommand.AddressSize = HAL_OSPI_ADDRESS_16_BITS;
	scommand.DQSMode = HAL_OSPI_DQS_ENABLE;
	scommand.Address = 0x00010000;
	scommand.NbData = 2;
	if (HAL_OSPI_HyperbusCmd(&hospi1,&scommand,HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
	{
		Error_Handler();
	}
	if(HAL_OSPI_Transmit(&hospi1,CR0,HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
	{
		Error_Handler();
	}
	HAL_Delay(10);
	/*
	 * CONFIGURATION REGISTER 1
	 * 0b0000 0000 0000 0010
	 */
	uint8_t CR1[2];
	CR1[0] = 0;
	CR1[1] = 2;
	scommand.AddressSpace = HAL_OSPI_REGISTER_ADDRESS_SPACE ;
	scommand.AddressSize = HAL_OSPI_ADDRESS_16_BITS;
	scommand.DQSMode = HAL_OSPI_DQS_ENABLE;
	scommand.Address = 0x000100001;
	scommand.NbData = 2;
	if (HAL_OSPI_HyperbusCmd(&hospi1,&scommand,HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
	{
		Error_Handler();
	}
	if(HAL_OSPI_Transmit(&hospi1,CR1,HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
	{
		Error_Handler();
	}
	HAL_Delay(10);
 
}

And here are my functions to write/read to/from the memory:

void ospi1_write(uint32_t add, uint8_t *data)
{
	OSPI_HyperbusCfgTypeDef sHyperBusCfg = {0};
	OSPI_HyperbusCmdTypeDef scommand = {0};
 
	sHyperBusCfg.RWRecoveryTime = 4;
	sHyperBusCfg.AccessTime = 4;
	sHyperBusCfg.WriteZeroLatency = HAL_OSPI_NO_LATENCY_ON_WRITE;
	sHyperBusCfg.LatencyMode = HAL_OSPI_VARIABLE_LATENCY;
	if (HAL_OSPI_HyperbusCfg(&hospi1, &sHyperBusCfg, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
	{
	Error_Handler();
	}
	HAL_Delay(1);
	scommand.AddressSpace = HAL_OSPI_MEMORY_ADDRESS_SPACE ;
	scommand.AddressSize = HAL_OSPI_ADDRESS_16_BITS;
	scommand.DQSMode = HAL_OSPI_DQS_ENABLE;
	scommand.Address = add;
	scommand.NbData = sizeof(data);
	if (HAL_OSPI_HyperbusCmd(&hospi1,&scommand,HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
	{
		Error_Handler();
	}
	if(HAL_OSPI_Transmit(&hospi1,data,HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
	{
		Error_Handler();
	}
	HAL_Delay(10);
}
void ospi1_read(uint32_t add)
{
	OSPI_HyperbusCfgTypeDef sHyperBusCfg = {0};
	OSPI_HyperbusCmdTypeDef scommand = {0};
 
	sHyperBusCfg.RWRecoveryTime = 4;
	sHyperBusCfg.AccessTime = 4;
	sHyperBusCfg.WriteZeroLatency = HAL_OSPI_NO_LATENCY_ON_WRITE;
	sHyperBusCfg.LatencyMode = HAL_OSPI_VARIABLE_LATENCY;
	if (HAL_OSPI_HyperbusCfg(&hospi1, &sHyperBusCfg, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
	{
	Error_Handler();
	}
	HAL_Delay(1);
	scommand.AddressSpace = HAL_OSPI_MEMORY_ADDRESS_SPACE ;
	scommand.AddressSize = HAL_OSPI_ADDRESS_16_BITS;
	scommand.DQSMode = HAL_OSPI_DQS_ENABLE;
	scommand.Address = add;
	scommand.NbData = 2;
	if (HAL_OSPI_HyperbusCmd(&hospi1,&scommand,HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
	{
		Error_Handler();
	}
	if(HAL_OSPI_Receive(&hospi1,pdata,HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
	{
		Error_Handler();
	}
	HAL_Delay(10);
}

9 REPLIES 9

For a HyperRAM that appears almost identical to yours (based on the Data Sheets) the following is how I configured memory-mapped mode. I have no experience with HyperFlash so that's left as an exercise for the diligent student. Nor can I speak to your access functions. Good luck.

  • I set up the clocking such that 100 MHz is the the HyperRAM clock rate.
void MX_OCTOSPI1_Init(void)
{
  OSPIM_CfgTypeDef sOspiManagerCfg = {0};
  OSPI_HyperbusCfgTypeDef sHyperBusCfg = {0};
 
  hospi1.Instance = OCTOSPI1;
  hospi1.Init.FifoThreshold = 4;   /* works, haven't experimented. */
  hospi1.Init.DualQuad = HAL_OSPI_DUALQUAD_DISABLE;
  hospi1.Init.MemoryType = HAL_OSPI_MEMTYPE_HYPERBUS;
  hospi1.Init.DeviceSize = 23;   /* Your S27KL0641 device is 8 MB, so 23 address bits are needed. */
  hospi1.Init.ChipSelectHighTime = 1;   /* tCSHI */
  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 = 2;   /* My OCTOSPI1 module is clocked at 200 MHz ==> 100 MHz HyperRAM clock. */
  hospi1.Init.SampleShifting = HAL_OSPI_SAMPLE_SHIFTING_NONE;
  hospi1.Init.DelayHoldQuarterCycle = HAL_OSPI_DHQC_ENABLE;
  hospi1.Init.ChipSelectBoundary = 0;
  hospi1.Init.ClkChipSelectHighTime = 0;
  hospi1.Init.DelayBlockBypass = HAL_OSPI_DELAY_BLOCK_BYPASSED;
  hospi1.Init.MaxTran = 0;
  hospi1.Init.Refresh = 100;   /* THIS IS IMPORTANT IF YOU'RE NOT A FAN OF DRAM FADE.  (1 uS will work for both temperature grades.) */
  if (HAL_OSPI_Init(&hospi1) != HAL_OK)
  {
    Error_Handler();
  }
 
  /* I had to use OSPIM to get the signals routed properly.  YMMV. */
  sOspiManagerCfg.ClkPort = 2;
  sOspiManagerCfg.DQSPort = 2;
  sOspiManagerCfg.NCSPort = 1;
  sOspiManagerCfg.IOLowPort = HAL_OSPIM_IOPORT_2_LOW;
  sOspiManagerCfg.IOHighPort = HAL_OSPIM_IOPORT_1_HIGH;
 
  /* ??? should be set by CubeMX (the 0 from struct decl above will assert in
   * HAL_OSPIM_Config() if USE_FULL_ASSERT is enabled. */
  sOspiManagerCfg.Req2AckTime = 1;   
 
  if (HAL_OSPIM_Config(&hospi1, &sOspiManagerCfg, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
  {
    Error_Handler();
  }
  sHyperBusCfg.RWRecoveryTime = 4;   /* tRWR */
  sHyperBusCfg.AccessTime = 6;   /* tACC (Data Sheet implies 4 should work but doesn't for me) */
  sHyperBusCfg.WriteZeroLatency = HAL_OSPI_LATENCY_ON_WRITE;
  sHyperBusCfg.LatencyMode = HAL_OSPI_FIXED_LATENCY;
  if (HAL_OSPI_HyperbusCfg(&hospi1, &sHyperBusCfg, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
  {
    Error_Handler();
  }
 
  /* Memory-mapped mode setup */
  {
 
    OSPI_HyperbusCmdTypeDef sCommand = { 0 };
 
    OSPI_MemoryMappedTypeDef sMemMappedCfg = { 0 };
 
 
    /* Memory-mapped mode configuration --------------------------------------- */
    sCommand.AddressSpace = HAL_OSPI_MEMORY_ADDRESS_SPACE;
    sCommand.AddressSize  = HAL_OSPI_ADDRESS_32_BITS;
    sCommand.DQSMode      = HAL_OSPI_DQS_ENABLE;
    sCommand.Address      = 0;
    sCommand.NbData       = 1;
 
    if( HAL_OSPI_HyperbusCmd( &hospi1, &sCommand, HAL_OSPI_TIMEOUT_DEFAULT_VALUE ) != HAL_OK )
      {
 
        Error_Handler();
 
      }
 
 
    sMemMappedCfg.TimeOutActivation = HAL_OSPI_TIMEOUT_COUNTER_DISABLE;
 
    if( HAL_OSPI_MemoryMapped( &hospi1, &sMemMappedCfg ) != HAL_OK )
      {
 
        Error_Handler();
 
      }
 
  }
 
 
}

AGEBE.1
Associate II

Ok thanks!

But in this configuration you shared, how do you access the memory?

As memory with the base address OCTOSPI1_BASE.

So it would be something like that?

uint32_t RxHyperRAM[BUFFERSIZE];
 
/* For reading memory*/
uint16_t ospi1_read(uint32_t add)
{
	uint16_t res;
	 ram_add = (__IO uint32_t *)(OCTOSPI1_BASE + add);
	 res = *ram_add;
	 return res;
}
/* For writing memory*/
void ospi1_write(uint32_t add,uint8_t dat)
{
	 ram_add = (__IO uint32_t *)(OCTOSPI1_BASE + add);
	 *ram_add = dat;
}

If you wish.

One additional thing to be aware of: HyperRAM, just like (S)DRAM, etc., really, really, really cares about matching trace lengths. Prototyping on a Nucleo may not work well, if at all (especially at 100 MHz).

The writing functions seems to work properly, but the reading functions is blocking the program like it was waiting for a data to come but I don't understand why because the memory drives RWDS. With a logic analyser I obtain that frame:

0693W00000CzpPRQAZ.jpg

The OCTOSPI driver on my nucleoboard is limited to 64 MHz. Is it a problem?

Not sure but possibly adjusting some of the timing parameters might help. If not then I don't have any other ideas than to try to get some help from Cypress and/or ST.

Ok thank you for your help!