cancel
Showing results for 
Search instead for 
Did you mean: 

My STM32 locks up when I try to access a memory mapped external RAM. Cannot be reprogrammed.

JDoe.7
Associate II

I have a custom PCB with a STM32H7A3ZI MCU, and a S27KL0642S27KS0642 Hyperbus RAM.

My code, as well as the app note (AN5050) I'm following sets up the RAM for memory mapped access.

I've checked and rechecked the pinout and configuration, but every time I try to access the memory address of the ram, the chip locks up completely. The debugger looses connection, and the chip won't program, the ST-LINK V2 gives the error message DEV_TARGET_NOT_HALTED.

I was eventually able to reprogram the board by power cycling it while simultainiously forcing the boot pin high with a probe.

The trace lengths are between 0.62in and 0.97in, except for CS which I (perhaps naively) allowed to be 1.3in.

Here's my current setup code:

OSPIM_CfgTypeDef sOspiManagerCfg = {0};
  OSPI_HyperbusCfgTypeDef sHyperBusCfg = {0};
 
  hospi1.Instance = OCTOSPI1;
  hospi1.Init.FifoThreshold = 4; 
  hospi1.Init.DualQuad = HAL_OSPI_DUALQUAD_DISABLE;
  hospi1.Init.MemoryType = HAL_OSPI_MEMTYPE_HYPERBUS;
  hospi1.Init.DeviceSize = 23; 
  hospi1.Init.ChipSelectHighTime = 1;  
  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;   
  if (HAL_OSPI_Init(&hospi1) != HAL_OK)
  {
    Error_Handler();
  }
 
  sOspiManagerCfg.ClkPort = 2;
  sOspiManagerCfg.DQSPort = 1;
  sOspiManagerCfg.NCSPort = 2;
  sOspiManagerCfg.IOLowPort = HAL_OSPIM_IOPORT_2_LOW;
  sOspiManagerCfg.IOHighPort = HAL_OSPIM_IOPORT_1_LOW;
 
  sOspiManagerCfg.Req2AckTime = 1;
 
  if (HAL_OSPIM_Config(&hospi1, &sOspiManagerCfg, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
  {
    Error_Handler();
  }
  sHyperBusCfg.RWRecoveryTime = 4;   
  sHyperBusCfg.AccessTime = 6;  
  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();
 
      }
 
  }

And my code to test it:

uint32_t testbuffer[200];
__IO uint32_t *OCTOSPI1_MEMMAPPED_ADD  = (__IO uint32_t *)(OCTOSPI1_BASE);
 
uint16_t index;
  for (index = 0; index < 200; index++){ //verify that the chip and debugger are working correctly
	  testbuffer[index] = index*12;
  }
  for (index = 0; index < 200; index++){
	  testbuffer[index] = OCTOSPI1_MEMMAPPED_ADD[index]; //try to read from the external ram, execution freezes here
  }
  for (index = 0; index < 200; index++){
	  OCTOSPI1_MEMMAPPED_ADD[index] = index*11;
  }
  for (index = 0; index < 200; index++){
	  testbuffer[index] = OCTOSPI1_MEMMAPPED_ADD[index];
  }

Does anyone know how to solve this, or even debug it? I get no errors, just the lock up.

The only thing I haven't tried is slowing the bus down to 10MHz and painstakingly soldering leads onto the signals for a logic analyzer.

I have noticed that if I upload this code to the older board that lacks the RAM chip, it does not lock up, it just reads some random value when accessing the memory location.

Thanks!

Edit:

Well I've found one mistake. In the fine print of the datasheet I noticed: "Tie the CK# input pin to either VccQ or VssQ if not connected to the host controller, but do not leave it floating." ..but I have left it floating. I wonder if this is the issue? Unfortunately it is difficult to fix.

9 REPLIES 9
JRS
Associate III

A quick info for debugging: If you break after execution of the HAL_OSPI_MemoryMapped Function, you should see the memory mapped space in the memory-window of the debugger at 0x90000000, It should display 0xffs up to the end of your mem-size 2^23. Before that function it should have been 0x00. In my case (AP Memory and Hyperflash) I also needed the delay block.

Guillaume K
ST Employee

Hello

Not sure but maybe it is needed to have the memory area declared as Device or Strongly ordered in the Memory Protection Unit.

see AN4838 chapter 3.4 "Cortex-M7 constraint speculative prefetch".

JDoe.7
Associate II

Whenever I try to check the memory location with the debugger it crashes the same way as if I executed the read in code.

I will try to implement the delay block and see if that helps, but I've been shooting in the dark for a long time, so I'm hoping to find a more systematic approach.

Thank you for the help!

Thank you for the suggestion, but how do you think that would help? Right now I can't access the memory mapped region at all. I'm not familiar with the MPU, but it seems tailored to controlling *what* can access certain memory regions. I have not explicitly enabled the MPU, as far as I am aware. I'm using the basic cubeMX generated code, besides the snippet I posted.

JDoe.7
Associate II

Ok, I just tried to implement the delay block, but if I try to use the calibration function from AN5050, it requires reading from the RAM, and that locks up the chip the same as when I do it.. so that's out.

JRS
Associate III

The configuration of the delay block is a bit difficult, but it should not affect the device crashing (in my case I just had nonsense chars in between).

Your config itself looks ok, to me. If the clocks are also done by cubemx it should at least not crash. You said, you checked the layout, still I would think it must be something in that way. 1,8V and differential clock? Otherwise I'm out of ideas.

JDoe.7
Associate II

I ended up painstakingly tapping all the signals with a logic analyzer. The result looks like this (see below). I increased the clock divider to 20, so it's running at 1MHz now. It appears that the MCU is accessing the ram over and over. I think that might be it working as designed (pre-fething), but I'm not sure. The chip is definitely doing something, because the MCU does not lock up in it's absence, and the reads do not go on forever.

0693W00000FDCc8QAH.png0693W00000FDCcDQAX.png

JRS
Associate III

I would have thought that the chip needed the differential clock to work, but as there is data, it seems otherwise. One final thing: Have you tried the direct readout before mem-mapping? It might give at least some info on where the program crashes and depending on your debugger the possibility to check the registers involved at that step.

The following worked for me:

uint16_t ReadHyperBusDataHWord(uint32_t Address)
{
	OSPI_HyperbusCmdTypeDef sCommand;
	uint16_t Data = 0;
	sCommand.AddressSpace = HAL_OSPI_MEMORY_ADDRESS_SPACE;
	sCommand.AddressSize = HAL_OSPI_ADDRESS_32_BITS;
	sCommand.DQSMode = HAL_OSPI_DQS_ENABLE;
	sCommand.Address = Address;
	sCommand.NbData = 2;
 
		if (HAL_OSPI_HyperbusCmd(&hospi1, &sCommand, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
		{
			Error_Handler();
		}
 
		if (HAL_OSPI_Receive(&hospi1, (uint8_t*)(&Data), HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
		{
			Error_Handler();
		}
	return Data;
}

Thanks very much, I've been experimenting with this extensively.

When reading from the RAM in this way the chip no longer locks up every run! Now I can finally do some real debugging!

I can read address 0 of the register space, and I get a value close to what I was expecting (read 1000 1000 1000 0001, expected 0000 1100 1000 0001). But changing the address to 2 or greater gives the same result? I think maybe it's an electrical issue at this point? I've experimented with all the settings ad-nauseum, and the logic analyzer shows a command/address burst that looks correct.