cancel
Showing results for 
Search instead for 
Did you mean: 

STM32H7 OCTOSPI mode Hyperbus, HyperRam access and Delay Block Configuration (LNGF doesn't get set)

CBecc.1
Associate II

Hi All,

I'm working on a STM32H7 custom board and I'm trying to access a Cypress S70KL HyperRam through the Hyperbus protocol using the OCTOSPI1.

I'm able to access in read/write the HyperRam but I want to use the delay block therefore in CubeMx I enabled the DelayBlock stuff.

The generated code snippet is:

hospi1.Init.DelayBlockBypass = HAL_OSPI_DELAY_BLOCK_USED;

The low level driver is generated by the CubeMX and the stm32h7xx_ll_delayblock.c has those three functions:

  • DelayBlock_Enable
  • DelayBlock_Disable
  • DelayBlock_Configure

DelayBlock_Enable or Configure functions never get called in any code related to the octospi.

According tho the H7 manual Delay Block section, it seems that the Enable function must be called to tune the delay block and actually enable it.

Therefore I tried to call DelayBlock_Enable after configuring the Memory Mapped access to the HyperRam but I get a timeout after one iteration because the LNGF flag is not set.

I suppose that even if I enabled the delay block in CubeMX (the code snippet above is used only to set the DLYBYP bit in the OCTOSPI_DCR1 register to take the sampling clock from the delay block) probably I'm not really using it because it has never been tuned and enabled.

Am I wrong?

I didn't find any example for my platform on how to tune the delay block for HyperRam in HyperBus mode.

I did find only one example on H7 (OSPI_HyperRAM_MemoryMapped) that claims to use the Delay Block but the Enable function is never called.

Is that correct? That function in this case doesn't need to be called?

Eventually that is not what is stated in the manual...

Can someone give a hint on the basic steps needed to configure the delay block for the octospi peripheral in hyperbus mode?

Thanks for your help.

1 ACCEPTED SOLUTION

Accepted Solutions

Hi Alex,

thanks for your reply...

Yes sure you need to enable SEN and DEN to allow the Delay Block validate the setting but the problem here is that you need a free running clock to validate any setting and the Delay Block Input must be connected to the clock...

Let me show you a picture:

0693W00000Ns1KMQAZ.png 

I hope the picture taken from annex an5050 is visible.

My problem is that when the hyperbus memory type is selected for the octospi, the delay block input switch automatically to DQS that is correct in general during normal access to the HyperRam but it is wrong during the calibration or any delay block setting because we need a free running clock and the input connected to that clock.

This happens only for HYPERBUS Memory Type that is the type I need to configure....

Yes, SEN and DEN bits need to be set because they enable the sampling of the free running clock.

Without this clock any configuration won't be valid (the valid flag LNGF in CFGR won't be set).

I'm not sure that is the same for any platform but it my case that is stated by the manual :

Bit 31 LNGF: Length valid flag
          This flag indicates when the delay line length 
          value contained in LNG[11:0] is valid after
          UNIT[6:0] bits changed.
          0: Length value in LNG is not valid.
          1: Length value in LNG is valid.

If you change UNIT or SEL in CFGR register you must wait that the LNGF Flag raises for the change to be valid... This can happen only if a clock is present at the delay block input and only if the input is actually the clock.

On other platforms or memory types I know for sure that is different because I went through many example in internet but they were all different from my case...

Usually they do the calibration with the free running clock and then they change the CFGR value on the fly...

But I didn't find anywhere an example when memory type is HYPERBUS...

In HYPERBUS on STM32H7 is different because it is not the clock that is delayed but it is the DQS that is mandatory for that kind of ram..

Hope this can be helpful if someone else meets my same issue...

Carlo

View solution in original post

11 REPLIES 11
Alex - APMemory
Senior II

Hi,

We don’t have the setting for HyperRAM and this also depends on each specific board and PCB design.

Fyi, you can find as an example the setting done in our Lab on STM32H735G-DK and APMemory 128Mb OPI, which is running well up to 130MHz (max frequency for 3V).

To find the right setting we adjusted the register(DLYB_CFGR) directly by referring to the STM specification. This setting needs to be tested one by one to find the best parameter.

Here is an example of what we found:

  • Platform: STM32H723
  • Board : STM32H735G-DK
  • IoT RAM: APMemory 128Mb OPI 3V PSRAM: APS12808L-3OBM-BA
  • Max. Clock rate: 130MHz
  • Driving strength: 50ohm
  • Delay block setting: DLYB_OCTOSPI2->CFGR = 0x2001

Alex

CBecc.1
Associate II

Hi Alex,

thanks for your reply.

My issue is not about the hyperarm itself but the delay block since in the STMH7B3 it must be tuned before doing any delay setting.

I mean I cannot set the CFGR register without tuning the delay block because the valid flag won't be set and the system won't work.

I solved in some way the issue of tuning the delay block though...even if the procedure is a bit odd...

The problem with the delay block on the STM32H7B3 with the hyperram (HYPERBUS memory type) is that selecting the memory type to HYPERBUS moves automatically the delay block input selector to the DQS signal...

It means that the delay block will calibrate to the DQS signal (that is not present) and not to the free running clock!

There is no way to reset this selector correctly because the OCTOSPI goes in BUSY state and registers cannot be changed anymore...

This doesn't happen if the memory type is different...for example micron...

In that case the input selector stays on the clock, delay block can be tuned with the free running clock and after that the delay block CFGR register can be set with the correct values and the OCTOSPI can be reset to the correct memory type HYPERBUS.

On other STM32 SoC is different and it seems that delay block CFGR can be set directly...unfortunately my SoC is different...

Hope this can be useful for someone else with the same issue..

Carlo

Alex - APMemory
Senior II

Hi Carlo,

I'm not sure about specific case for HyperRAM and STM32H7A/B, but just complete our initial message about CFGR adjustement using IoT RAM (Xccela OPI RAM format):

APMemory Lab team enables at first the SEN and DEN of the CR register before doing CFGR adjustments.

Regards

Alex

Hi Alex,

thanks for your reply...

Yes sure you need to enable SEN and DEN to allow the Delay Block validate the setting but the problem here is that you need a free running clock to validate any setting and the Delay Block Input must be connected to the clock...

Let me show you a picture:

0693W00000Ns1KMQAZ.png 

I hope the picture taken from annex an5050 is visible.

My problem is that when the hyperbus memory type is selected for the octospi, the delay block input switch automatically to DQS that is correct in general during normal access to the HyperRam but it is wrong during the calibration or any delay block setting because we need a free running clock and the input connected to that clock.

This happens only for HYPERBUS Memory Type that is the type I need to configure....

Yes, SEN and DEN bits need to be set because they enable the sampling of the free running clock.

Without this clock any configuration won't be valid (the valid flag LNGF in CFGR won't be set).

I'm not sure that is the same for any platform but it my case that is stated by the manual :

Bit 31 LNGF: Length valid flag
          This flag indicates when the delay line length 
          value contained in LNG[11:0] is valid after
          UNIT[6:0] bits changed.
          0: Length value in LNG is not valid.
          1: Length value in LNG is valid.

If you change UNIT or SEL in CFGR register you must wait that the LNGF Flag raises for the change to be valid... This can happen only if a clock is present at the delay block input and only if the input is actually the clock.

On other platforms or memory types I know for sure that is different because I went through many example in internet but they were all different from my case...

Usually they do the calibration with the free running clock and then they change the CFGR value on the fly...

But I didn't find anywhere an example when memory type is HYPERBUS...

In HYPERBUS on STM32H7 is different because it is not the clock that is delayed but it is the DQS that is mandatory for that kind of ram..

Hope this can be helpful if someone else meets my same issue...

Carlo

Alex - APMemory
Senior II

Ok, we have not tested HyperRAM, but only Xccela IoT RAM type

Upon need, if you wish to try, all OPI but also HPI, QSPI SDR & QSPI DDR available samples at Mouser

https://eu.mouser.com/c/?tradename=APMemory

Alex

CBecc.1
Associate II

Thanks a lot!

Alberto SAVIOTTI
Associate

I worked with the external HyperRAM on the discovery board and then on a custom PCB.

I'll share my experience just in case it could be helpful, since I had hard times to find the solution.

First of all using the CubeMX for the discovery board STM32H735G-DK doesn't use delay lines, I suppose setting

hospi1.Init.DelayBlockBypass = HAL_OSPI_DELAY_BLOCK_USED;

means delay lines are used, but you still need to configure them. After some digging I found best idea is to start from the available example:

OSPI_HyperRAM_MemoryMapped

found in the repository folder for CubeMX (usually C:\users\<current user>\STM32Cube\Repository).

This example will copy, but NOT use, files

stm32h7xx_hal_delayblock.h/c

You need to add proper calls to functions provided in these files to do the delay lines tuning.

This has to be done configuring the memory as you would normally do but in free running mode.

Here my code in main:

OSPIHandle.Instance = OCTOSPI2;
 
  HAL_OSPI_DeInit(&OSPIHandle);
 
  // Calibrate delay line
  DLYB_TypeDef * DLYB_OCTO2_BASE = (DLYB_TypeDef *)0x5200B000;
 
  OSPIHandle.Init.FifoThreshold         = 4;
  OSPIHandle.Init.DualQuad              = HAL_OSPI_DUALQUAD_DISABLE;
  OSPIHandle.Init.MemoryType            = HAL_OSPI_MEMTYPE_HYPERBUS;
  OSPIHandle.Init.DeviceSize            = OSPI_HYPERRAM_SIZE;
  OSPIHandle.Init.ChipSelectHighTime    = 8;
  OSPIHandle.Init.FreeRunningClock      = HAL_OSPI_FREERUNCLK_ENABLE;
  OSPIHandle.Init.ClockMode             = HAL_OSPI_CLOCK_MODE_0;
  OSPIHandle.Init.WrapSize              = HAL_OSPI_WRAP_NOT_SUPPORTED;
  OSPIHandle.Init.ClockPrescaler        = 2; // 4;
  OSPIHandle.Init.SampleShifting        = HAL_OSPI_SAMPLE_SHIFTING_NONE;
  OSPIHandle.Init.DelayHoldQuarterCycle = HAL_OSPI_DHQC_ENABLE;
  OSPIHandle.Init.DelayBlockBypass      = HAL_OSPI_DELAY_BLOCK_USED;
  OSPIHandle.Init.ChipSelectBoundary    = 23;
  OSPIHandle.Init.Refresh               = 250; /* The chip select should be released every 4us */
 
  if (HAL_OSPI_Init(&OSPIHandle) != HAL_OK)
  {
    Error_Handler() ;
  }
 
    if (HAL_OK != DelayBlock_Enable(DLYB_OCTO2_BASE))
    {
  	  Error_Handler();
    }
 
    HAL_OSPI_DeInit(&OSPIHandle);
 
    OSPIHandle.Init.FifoThreshold         = 4;
    OSPIHandle.Init.DualQuad              = HAL_OSPI_DUALQUAD_DISABLE;
    OSPIHandle.Init.MemoryType            = HAL_OSPI_MEMTYPE_HYPERBUS;
    OSPIHandle.Init.DeviceSize            = OSPI_HYPERRAM_SIZE;
    OSPIHandle.Init.ChipSelectHighTime    = 8;
    OSPIHandle.Init.FreeRunningClock      = HAL_OSPI_FREERUNCLK_DISABLE;
    OSPIHandle.Init.ClockMode             = HAL_OSPI_CLOCK_MODE_0;
    OSPIHandle.Init.WrapSize              = HAL_OSPI_WRAP_NOT_SUPPORTED;
    OSPIHandle.Init.ClockPrescaler        = 2; // After calibration works with 2 even if slightly above specs, so do not use in production code with this memory
    OSPIHandle.Init.SampleShifting        = HAL_OSPI_SAMPLE_SHIFTING_NONE;
    OSPIHandle.Init.DelayHoldQuarterCycle = HAL_OSPI_DHQC_ENABLE;
    OSPIHandle.Init.DelayBlockBypass      = HAL_OSPI_DELAY_BLOCK_USED;
    OSPIHandle.Init.ChipSelectBoundary    = 23;
    OSPIHandle.Init.Refresh               = 250; /* The chip select should be released every 4us */
 
    if (HAL_OSPI_Init(&OSPIHandle) != HAL_OK)
    {
      Error_Handler() ;
    }
 
  /* Configure the Hyperbus to access memory space -------------------------- */
  sHyperbusCfg.RWRecoveryTime   = OSPI_HYPERRAM_RW_REC_TIME;
  sHyperbusCfg.AccessTime       = OSPI_HYPERRAM_LATENCY;
  sHyperbusCfg.WriteZeroLatency = HAL_OSPI_LATENCY_ON_WRITE;
  sHyperbusCfg.LatencyMode      = HAL_OSPI_FIXED_LATENCY;
 
  if (HAL_OSPI_HyperbusCfg(&OSPIHandle, &sHyperbusCfg, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
  {
    Error_Handler();
  }
 
  /* 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(&OSPIHandle, &sCommand, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
  {
    Error_Handler();
  }
 
  sMemMappedCfg.TimeOutActivation = HAL_OSPI_TIMEOUT_COUNTER_DISABLE;
 
  if (HAL_OSPI_MemoryMapped(&OSPIHandle, &sMemMappedCfg) != HAL_OK)
  {
    Error_Handler();
  }

It has been proved working since with 2 as divider, it works only if you tune the memory, otherwise memory test as provided in the example, will fail.

There's little caveat for the clock divider: a -1 is applied in the HAL driver to the divider so the +1 in the formula found in the datasheet should not be considered; odd.

Note: when you find the number to use with your application (board) and you go in "production" apply the founded configuration directly, without performing tuning every time.

Important note: delay line is impacted by silicon and by pads (each sample will behave slightly differently) and by temperature. Without having fast and slow samples of a silicon and without doing tuning procedure at different temperatures (controlled) makes delay line usage very dangerous. Only using very conservative numbers a product is on the safe side. If possible, I suggest to use a conservative clock divider and do not use delay lines; this is the best way to guarantee no surprises on the field.

Alberto

Hi Alberto.

Thanks for you reply.

I worked on a custom board with STM32H7B3. I suspect it might be different from your SoC even if I didn't check...

I struggled a lot as you but my problem was not the free running clock setting (done correctly). The problem with my SoC was this setting:

OSPIHandle.Init.MemoryType            = HAL_OSPI_MEMTYPE_HYPERBUS;

When configured in this way It was impossible to tune it but I found the workaround explained above.

With STM32H7B3 and Hyperbus the behavior is odd. It seems only possible to delay the DQS signal so for using free running clock the only chance was to calibrate as I was using a different memory type.

When calibrated I can set the delay line correctly with no issues...

It would be nice if STM could check what I'm stating and give a reply on STM32H7B3...

I checked on Cube many examples and my feeling is that different SoC can have different ways to approach the same topic.

Delay block calibration and usage can be different even if the general idea is the same..

Thanks for sharing your experience.

It can be very helpful for others having the same troubles

Carlo

Hi Alex,

How can I find your APmemory example made with stm32h7