cancel
Showing results for 
Search instead for 
Did you mean: 

Issue Interfacing with AP memory.

Kamurasi-Jordan-Arthur
Associate III
  1. Greeting
  2. what want to achive
  3. The current state.
  4. What we have tried.

Hey there Community,
We are running a project were we need to interface with an AP memory on a custom made board. We intend on using the PSRAM for image capture for a 5mpx image dumped by the dcmipp peripheral. To test the PSRAM separately, we came up with a test to confirm that we get no errors while interacting with it.
We are failing to communicate with the memory at frequencies higher than 100Mhz, and seeing a large number of errors at 100Mhz and zero errors at 50Mhz. This is a big hinderance because the memory should be able to be set all the way to 250Mhz and we do also see these errors appear in the images taken.
We have attached the specifications we are working with as well as the configurations we are using.

Specifications

  1. STM32N657X0HxQ
  2. APS256XXN-OBx9
  3. XSPI interface (x16) (xspi1)

Other Specifications

  1. Memory mapped mode
  2. Schematic similar to the STM32N6 DK.

Below are the materials used to aid with the configuration.

  1. AP memory datasheet.
  2. Getting started with Octo-SPI, Hexadeca-SPI, and XSPI interfaces on STM32 MCUs.
  3. Cube MX example (XSPI_PSRAM_MemoryMapped) for the n6 series

Our Current configurations.
XSPI interface configuration code.

...
/* Reset Command **************************************************************/
/**
  * @brief  Reset the memory
  * @PAram  Ctx Component object pointer
  * @retval error status
  */
int32_t APS256XX_Reset(XSPI_HandleTypeDef *Ctx)
{
  XSPI_RegularCmdTypeDef sCommand = {0};

  /* Initialize the command */
  sCommand.OperationType      = HAL_XSPI_OPTYPE_COMMON_CFG;
  sCommand.InstructionMode    = HAL_XSPI_INSTRUCTION_8_LINES;
  sCommand.InstructionWidth   = HAL_XSPI_INSTRUCTION_8_BITS;
  sCommand.InstructionDTRMode = HAL_XSPI_INSTRUCTION_DTR_DISABLE;
  sCommand.Instruction        = APS256XX_RESET_CMD;
  sCommand.AddressMode        = HAL_XSPI_ADDRESS_8_LINES;
  sCommand.AddressWidth       = HAL_XSPI_ADDRESS_24_BITS;
  sCommand.AddressDTRMode     = HAL_XSPI_ADDRESS_DTR_DISABLE;
  sCommand.Address            = 0;
  sCommand.AlternateBytesMode = HAL_XSPI_ALT_BYTES_NONE;
  sCommand.DataMode           = HAL_XSPI_DATA_NONE;
  sCommand.DataLength         = 0;
  sCommand.DummyCycles        = 0;
  sCommand.DQSMode            = HAL_XSPI_DQS_DISABLE;
 #if defined (XSPI_CCR_SIOO)
  sCommand.SIOOMode            = HAL_XSPI_SIOO_INST_EVERY_CMD;
 #endif

  /* Configure the command */
  if (HAL_XSPI_Command(Ctx, &sCommand, HAL_XSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
  {
    return APS256XX_ERROR;
  }

  /* Need to wait tRST */
  HAL_Delay(1);
  return 0/*APS256XX_OK*/;
}
....
void MX_XSPI1_Init(void)
{

  /* USER CODE BEGIN XSPI1_Init 0 */

  /* USER CODE END XSPI1_Init 0 */

  XSPIM_CfgTypeDef sXspiManagerCfg = {0};

  /* USER CODE BEGIN XSPI1_Init 1 */

  /* USER CODE END XSPI1_Init 1 */
  hxspi1.Instance = XSPI1;
  hxspi1.Init.FifoThresholdByte = 4;
  hxspi1.Init.MemoryMode = HAL_XSPI_SINGLE_MEM;
  hxspi1.Init.MemoryType = HAL_XSPI_MEMTYPE_APMEM_16BITS;
  hxspi1.Init.MemorySize = HAL_XSPI_SIZE_256MB;
  hxspi1.Init.ChipSelectHighTimeCycle = 5;
  hxspi1.Init.FreeRunningClock = HAL_XSPI_FREERUNCLK_DISABLE;
  hxspi1.Init.ClockMode = HAL_XSPI_CLOCK_MODE_0;
  hxspi1.Init.WrapSize = HAL_XSPI_WRAP_NOT_SUPPORTED;
  hxspi1.Init.ClockPrescaler = 0;
  hxspi1.Init.SampleShifting = HAL_XSPI_SAMPLE_SHIFT_NONE;
  hxspi1.Init.DelayHoldQuarterCycle = HAL_XSPI_DHQC_DISABLE;
  hxspi1.Init.ChipSelectBoundary = HAL_XSPI_BONDARYOF_2KB;
  hxspi1.Init.MaxTran = 0;
  hxspi1.Init.Refresh = 0;
  hxspi1.Init.MemorySelect = HAL_XSPI_CSSEL_NCS1;
  if (HAL_XSPI_Init(&hxspi1) != HAL_OK)
  {
    Error_Handler();
  }
  sXspiManagerCfg.nCSOverride = HAL_XSPI_CSSEL_OVR_NCS1;
  sXspiManagerCfg.IOPort = HAL_XSPIM_IOPORT_1;
  sXspiManagerCfg.Req2AckTime = 1;
  if (HAL_XSPIM_Config(&hxspi1, &sXspiManagerCfg, HAL_XSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN XSPI1_Init 2 */
  APS256XX_Reset(&hxspi1);
  /* USER CODE END XSPI1_Init 2 */

}


void HAL_XSPI_MspInit(XSPI_HandleTypeDef* xspiHandle)
{

  GPIO_InitTypeDef GPIO_InitStruct = {0};
  RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0};
  if(xspiHandle->Instance==XSPI1)
  {
  /* USER CODE BEGIN XSPI1_MspInit 0 */
  /* XSPI power enable */
  __HAL_RCC_PWR_CLK_ENABLE();
  HAL_PWREx_EnableVddIO2(); // change, IO3 for XSPI2
  HAL_PWREx_ConfigVddIORange(PWR_VDDIO2, PWR_VDDIO_RANGE_1V8);

  /* USER CODE END XSPI1_MspInit 0 */

  /** Initializes the peripherals clock
  */
    PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_XSPI1;
    PeriphClkInitStruct.Xspi1ClockSelection = RCC_XSPI1CLKSOURCE_IC4;
    PeriphClkInitStruct.ICSelection[RCC_IC4].ClockSelection = RCC_ICCLKSOURCE_PLL1;
    PeriphClkInitStruct.ICSelection[RCC_IC4].ClockDivider = 10;
    if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK)
    {
      Error_Handler();
    }

    /* XSPI1 clock enable */
    HAL_RCC_XSPIM_CLK_ENABLED++;
    if(HAL_RCC_XSPIM_CLK_ENABLED==1){
      __HAL_RCC_XSPIM_CLK_ENABLE();
    }
    __HAL_RCC_XSPI1_CLK_ENABLE();

    __HAL_RCC_GPIOP_CLK_ENABLE();
    __HAL_RCC_GPIOO_CLK_ENABLE();
    /**XSPI1 GPIO Configuration
    PP7     ------> XSPIM_P1_IO7
    PP6     ------> XSPIM_P1_IO6
    PP0     ------> XSPIM_P1_IO0
    PP4     ------> XSPIM_P1_IO4
    PP1     ------> XSPIM_P1_IO1
    PP15     ------> XSPIM_P1_IO15
    PP5     ------> XSPIM_P1_IO5
    PP12     ------> XSPIM_P1_IO12
    PP3     ------> XSPIM_P1_IO3
    PP2     ------> XSPIM_P1_IO2
    PP13     ------> XSPIM_P1_IO13
    PO2     ------> XSPIM_P1_DQS0
    PP11     ------> XSPIM_P1_IO11
    PP8     ------> XSPIM_P1_IO8
    PP14     ------> XSPIM_P1_IO14
    PO3     ------> XSPIM_P1_DQS1
    PO0     ------> XSPIM_P1_NCS1
    PP9     ------> XSPIM_P1_IO9
    PP10     ------> XSPIM_P1_IO10
    PO4     ------> XSPIM_P1_CLK
    */
    GPIO_InitStruct.Pin = GPIO_PIN_7|GPIO_PIN_6|GPIO_PIN_0|GPIO_PIN_4
                          |GPIO_PIN_1|GPIO_PIN_15|GPIO_PIN_5|GPIO_PIN_12
                          |GPIO_PIN_3|GPIO_PIN_2|GPIO_PIN_13|GPIO_PIN_11
                          |GPIO_PIN_8|GPIO_PIN_14|GPIO_PIN_9|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_XSPIM_P1;
    HAL_GPIO_Init(GPIOP, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = GPIO_PIN_2|GPIO_PIN_3|GPIO_PIN_0|GPIO_PIN_4;
    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_XSPIM_P1;
    HAL_GPIO_Init(GPIOO, &GPIO_InitStruct);

    /* XSPI1 interrupt Init */
    HAL_NVIC_SetPriority(XSPI1_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(XSPI1_IRQn);
  /* USER CODE BEGIN XSPI1_MspInit 1 */

  /* USER CODE END XSPI1_MspInit 1 */
  }
....


void MX_EXTMEM_MANAGER_Init(void)
{

  ....
  /* EXTMEMORY_2 */
  extmem_list_config[1].MemType = EXTMEM_PSRAM;
  extmem_list_config[1].Handle = (void*)&hxspi1;
  extmem_list_config[1].ConfigType = EXTMEM_LINK_CONFIG_16LINES;

  extmem_list_config[1].PsramObject.psram_public.MemorySize = HAL_XSPI_SIZE_256MB;
  extmem_list_config[1].PsramObject.psram_public.FreqMax = 100 * 1000000u;
  extmem_list_config[1].PsramObject.psram_public.NumberOfConfig = 3u;

  /* Config */
  extmem_list_config[1].PsramObject.psram_public.config[0].WriteMask = 0x40u;
  extmem_list_config[1].PsramObject.psram_public.config[0].WriteValue = 0x40u;
  extmem_list_config[1].PsramObject.psram_public.config[0].REGAddress = 0x08u;

  extmem_list_config[1].PsramObject.psram_public.config[1].WriteMask = 0x1Cu;
  extmem_list_config[1].PsramObject.psram_public.config[1].WriteValue = 0x04u;
  extmem_list_config[1].PsramObject.psram_public.config[1].REGAddress = 0x00u;

  extmem_list_config[1].PsramObject.psram_public.config[2].WriteMask = 0xE0u;
  extmem_list_config[1].PsramObject.psram_public.config[2].WriteValue = 0x80u;
  extmem_list_config[1].PsramObject.psram_public.config[2].REGAddress = 0x04u;

  /* Memory command configuration */
  extmem_list_config[1].PsramObject.psram_public.ReadREG           = 0x40u;
  extmem_list_config[1].PsramObject.psram_public.WriteREG          = 0xC0u;
  extmem_list_config[1].PsramObject.psram_public.ReadREGSize       = 2u;
  extmem_list_config[1].PsramObject.psram_public.REG_DummyCycle    = 4u;
  extmem_list_config[1].PsramObject.psram_public.Write_command     = 0xA0u;
  extmem_list_config[1].PsramObject.psram_public.Write_DummyCycle  = 3u;
  extmem_list_config[1].PsramObject.psram_public.Read_command      = 0x20u;
  extmem_list_config[1].PsramObject.psram_public.WrapRead_command  = 0x00u;
  extmem_list_config[1].PsramObject.psram_public.Read_DummyCycle   = 3u;

  EXTMEM_Init(EXTMEMORY_2, HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_XSPI1));

  /* USER CODE BEGIN MX_EXTMEM_Init_PostTreatment */
  // Map the memory

  ....

  if (EXTMEM_OK != EXTMEM_MemoryMappedMode(EXTMEMORY_2 , EXTMEM_ENABLE))
  {
	  Error_Handler();
  }
  /* USER CODE END MX_EXTMEM_Init_PostTreatment */
}



The PSRAM Test code.

The test aims to sweep over the entire memory doing a:

  1. An address test.
  2. A walking bit  test.
  3. and lastly an pattern test.

And return the number of Errors or a success message over USART.

#include "main.h"
#include <stdio.h>
#include <stdint.h>

#ifdef PSRAM_TEST

/* ===== CONFIG ===== */
#define KB                  (1024U)
#define MB                  (1024U * 1024U)
#define PSRAM_SIZE_BYTES    (32U * MB)
#define PSRAM_SIZE_WORDS    (PSRAM_SIZE_BYTES / 2U)      /* 16M words */
#define PAGE_SIZE_WORDS     (1024U)                       /* 1K words per page in X16 mode */
#define PAGE_SIZE_BYTES     (PAGE_SIZE_WORDS * 2U)        /* 2KB per page */

/* BASE_ADDR is now 16-bit pointer */
#define BASE_ADDR ((volatile uint16_t *)XSPI1_BASE)

/* ===== GLOBAL ===== */
static uint32_t errorCount = 0;

/* ===== UTIL ===== */
static void report_error(uint32_t word_idx, uint16_t expected, uint16_t actual) {
//    printf("ERR @word[0x%08lX] byte_addr=0x%08lX: exp=0x%04X got=0x%04X\r\n",
//           word_idx, word_idx * 2U, expected, actual);
    errorCount++;
}

/* =========================================================
   1. ADDRESS LINE TEST
   ========================================================= */
static void psram_address_test(void) {
    printf("\r\n[Address Test]\r\n\r\n");

    /* max offset in words */
    uint32_t max_offset = PSRAM_SIZE_WORDS - 1U;

    BASE_ADDR[0] = 0xAAAA;

    for (uint32_t offset = 1U; offset <= max_offset; offset <<= 1U) {
        BASE_ADDR[offset] = 0x5555;

        printf("Testing address line: 0x%08lX (byte addr: 0x%08lX)\r\n",
               offset, offset * 2U);

        if (BASE_ADDR[0] != 0xAAAA) {
            printf("Address fault at word offset: 0x%08lX\r\n", offset);
            errorCount++;
        }
    }

    HAL_Delay(1);
}

/* =========================================================
   2. WALKING BIT TEST (DATA LINES)
   ========================================================= */
static void psram_walking_bit_test(void) {
    printf("\r\n[Walking Bit Test]\r\n\r\n");

    /* 16 bits now so walk all 16 bits */
    for (uint8_t bit = 0U; bit < 16U; bit++) {

        uint16_t pattern = (uint16_t)(1U << bit);
        printf("\r\nTesting bit idx: %u", bit);

        printf("\r\n ---- normal pattern ----\r\n\r\n");

        for (uint32_t i = 0U; i < PSRAM_SIZE_WORDS; i++) {
            BASE_ADDR[i] = pattern;
        }

        HAL_Delay(1);

        for (uint32_t i = 0U; i < PSRAM_SIZE_WORDS; i++) {
            uint16_t actual = BASE_ADDR[i];
            if (actual != pattern) {
                report_error(i, pattern, actual);
            }
        }

        printf("\r\n ---- inverse pattern ----\r\n\r\n");

        uint16_t inv_pattern = (uint16_t)(~(1U << bit));

        for (uint32_t i = 0U; i < PSRAM_SIZE_WORDS; i++) {
            BASE_ADDR[i] = inv_pattern;
        }

        HAL_Delay(1);

        for (uint32_t i = 0U; i < PSRAM_SIZE_WORDS; i++) {
            uint16_t actual = BASE_ADDR[i];
            if (actual != inv_pattern) {
                report_error(i, inv_pattern, actual);
            }
        }
    }
}

/* =========================================================
   3. PATTERN TEST
   ========================================================= */
static void psram_pattern_test(void) {
    printf("\r\n[Pattern Test]\r\n\r\n");

    /* ---- write ---- */
    for (uint32_t i = 0U; i < PSRAM_SIZE_WORDS; i++) {
        /* pattern uses both bytes of the 16-bit word */
        uint16_t pattern = (uint16_t)(
            ((i & 0xFFU) ^ ((i >> 8U) & 0xFFU)) |          /* low byte */
            ((((i + 1U) & 0xFFU) ^ ((i >> 7U) & 0xFFU)) << 8U)  /* high byte */
        );
        BASE_ADDR[i] = pattern;
    }

    HAL_Delay(1);

    /* ---- read ---- */
    for (uint32_t i = 0U; i < PSRAM_SIZE_WORDS; i++) {
        uint16_t expected = (uint16_t)(
            ((i & 0xFFU) ^ ((i >> 8U) & 0xFFU)) |
            ((((i + 1U) & 0xFFU) ^ ((i >> 7U) & 0xFFU)) << 8U)
        );
        uint16_t actual = BASE_ADDR[i];

        if (actual != expected) {
            report_error(i, expected, actual);
        }
    }
}

/* =========================================================
   MAIN TEST ENTRY
   ========================================================= */
void psram_test(void) {

    printf("\r\n==== PSRAM TEST START ====\r\n");
    printf("Mode: X16 | Size: %lu MB | Pages: %lu x %u bytes\r\n",
           PSRAM_SIZE_BYTES / MB,
           PSRAM_SIZE_BYTES / PAGE_SIZE_BYTES,
           PAGE_SIZE_BYTES);

    errorCount = 0;

    psram_address_test();
    psram_walking_bit_test();
    psram_pattern_test();

    if (errorCount == 0) {
        printf("\r\n==== SUCCESS: NO ERRORS ====\r\n");
    } else {
        printf("\r\n==== FAIL: %lu ERRORS ====\r\n", errorCount);
    }
}

#endif

Order of function calls

/* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_RAMCFG_Init();
  MX_I2C1_Init();
  MX_USART1_UART_Init();
  MX_DCMIPP_Init();
  MX_XSPI2_Init();
  MX_XSPI1_Init();
  MX_JPEG_Init();
  MX_FileX_Init();
  MX_UART4_Init();
  MX_EXTMEM_MANAGER_Init();
  /* USER CODE BEGIN 2 */
  SystemIsolation_Config();
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */

	#ifdef PSRAM_TEST
	  psram_test();

	  while(1){
		if(reRunpsram_test){
			//Rerun the test
		  reRunpsram_test = 0;
		  psram_test();
		}
	  }

   #endif
...

The XSPI input clock is 200MHz.

Observation

  • The psram test, runs with variable number of error counts in the thousands on each run but in a similar range.

What has been tried (In regards to removing error count).

  • We experimented at different frequencies while setting up the memory to utilize the correct latency as per the frequency we intended to communicate. 

The system fails if we request to operate the PSRAM at max frequencies above 100MHz in the MX_EXTMEM_MANAGER_Init and lose connection to the debug session on pausing to investigate

  extmem_list_config[1].PsramObject.psram_public.MemorySize = HAL_XSPI_SIZE_256MB;
  extmem_list_config[1].PsramObject.psram_public.FreqMax = 200 * 1000000u;
  extmem_list_config[1].PsramObject.psram_public.NumberOfConfig = 3u;  
/* Config */
  extmem_list_config[1].PsramObject.psram_public.config[0].WriteMask = 0x40u;
  extmem_list_config[1].PsramObject.psram_public.config[0].WriteValue = 0x40u;
  extmem_list_config[1].PsramObject.psram_public.config[0].REGAddress = 0x08u;

  extmem_list_config[1].PsramObject.psram_public.config[1].WriteMask = 0x1Cu;
  extmem_list_config[1].PsramObject.psram_public.config[1].WriteValue = 0x10u;
  extmem_list_config[1].PsramObject.psram_public.config[1].REGAddress = 0x00u;

  extmem_list_config[1].PsramObject.psram_public.config[2].WriteMask = 0xE0u;
  extmem_list_config[1].PsramObject.psram_public.config[2].WriteValue = 0x20u;
  extmem_list_config[1].PsramObject.psram_public.config[2].REGAddress = 0x04u;

  /* Memory command configuration */
  extmem_list_config[1].PsramObject.psram_public.ReadREG           = 0x40u;
  extmem_list_config[1].PsramObject.psram_public.WriteREG          = 0xC0u;
  extmem_list_config[1].PsramObject.psram_public.ReadREGSize       = 2u;
  extmem_list_config[1].PsramObject.psram_public.REG_DummyCycle    = 4u;
  extmem_list_config[1].PsramObject.psram_public.Write_command     = 0xA0u;
  extmem_list_config[1].PsramObject.psram_public.Write_DummyCycle  = 6u;
  extmem_list_config[1].PsramObject.psram_public.Read_command      = 0x20u;
  extmem_list_config[1].PsramObject.psram_public.WrapRead_command  = 0x00u;
  extmem_list_config[1].PsramObject.psram_public.Read_DummyCycle   = 6u;

However at Max Freq of 66MHz, we are able to see No Errors returned in the PSRAM test. Though this gives us a distorted image when we set the dcmipp to dump with a memory running at such a low frequency.

  extmem_list_config[1].PsramObject.psram_public.MemorySize = HAL_XSPI_SIZE_256MB;
  extmem_list_config[1].PsramObject.psram_public.FreqMax = 50 * 1000000u;
  extmem_list_config[1].PsramObject.psram_public.NumberOfConfig = 3u;  
/* Config */
  extmem_list_config[1].PsramObject.psram_public.config[0].WriteMask = 0x40u;
  extmem_list_config[1].PsramObject.psram_public.config[0].WriteValue = 0x40u;
  extmem_list_config[1].PsramObject.psram_public.config[0].REGAddress = 0x08u;

  extmem_list_config[1].PsramObject.psram_public.config[1].WriteMask = 0x1Cu;
  extmem_list_config[1].PsramObject.psram_public.config[1].WriteValue = 0x00u;
  extmem_list_config[1].PsramObject.psram_public.config[1].REGAddress = 0x00u;

  extmem_list_config[1].PsramObject.psram_public.config[2].WriteMask = 0xE0u;
  extmem_list_config[1].PsramObject.psram_public.config[2].WriteValue = 0x00u;
  extmem_list_config[1].PsramObject.psram_public.config[2].REGAddress = 0x04u;

  /* Memory command configuration */
  extmem_list_config[1].PsramObject.psram_public.ReadREG           = 0x40u;
  extmem_list_config[1].PsramObject.psram_public.WriteREG          = 0xC0u;
  extmem_list_config[1].PsramObject.psram_public.ReadREGSize       = 2u;
  extmem_list_config[1].PsramObject.psram_public.REG_DummyCycle    = 4u;
  extmem_list_config[1].PsramObject.psram_public.Write_command     = 0xA0u;
  extmem_list_config[1].PsramObject.psram_public.Write_DummyCycle  = 2u;
  extmem_list_config[1].PsramObject.psram_public.Read_command      = 0x20u;
  extmem_list_config[1].PsramObject.psram_public.WrapRead_command  = 0x00u;
  extmem_list_config[1].PsramObject.psram_public.Read_DummyCycle   = 2u;

We reduced the drive strength from the default 25 ohms to 50 ohms, this had no effect.

  extmem_list_config[1].PsramObject.psram_public.config[0].WriteMask = 0x41u;
  extmem_list_config[1].PsramObject.psram_public.config[0].WriteValue = 0x41u;
  extmem_list_config[1].PsramObject.psram_public.config[0].REGAddress = 0x08u;​

 

  • Lowered and increased the page boundary and refresh values. These did have a slight effect, but did not clear all the errors.
  hxspi1.Init.ChipSelectBoundary = ..;
  hxspi1.Init.Refresh = ..;​

What we need help with

  • What configurations are available when interacting with AP memory that we haven't tried or we got wrong that could reduce the errors in the PSRAM test, as these errors appear in the images we take in a different test.
  • There is a section on calibration in the application note AN5050 that speaks of an automated PHY calibration process for the STM32N6, that is enabled when the PRESCALER is set and the BUSY flag is set. To our understanding, these appear to be already taking place in the EXTMEM_Init. Is this understanding correct or do we need more steps to start the calibration.
6 REPLIES 6
TDK
Super User

Maybe it's a layout issue. 200 MHz signals require some care. How does your layout look?

> HAL_XSPI_SAMPLE_SHIFT_NONE

Also may try playing with this. If you have a scope, look at signals to determine the correct offset.

If you feel a post has answered your question, please click "Accept as Solution".
Michael5
Associate

@TDK 
According to AN5050, Sample shifting is only recommended when you are in STR mode, we are using DTR for this memory. What is recommended is Delay hold quarter cycle which in theory should shift the sampling by a quarter cycle when sampling the DQS clock from the memory.
But according to this we found this to be deprecated, which explains why changing it had no effect. And we didn't seem to find a substitute for it anywhere in the generated code.

/** @defgroup XSPI_DelayHoldQuarterCycle XSPI Delay Hold Quarter Cycle
  * @note These constants are deprecated and are not expected to be used anymore.
  * @{
  */
#define HAL_XSPI_DHQC_DISABLE                (0x00000000U)              /*!< No Delay                         */
#define HAL_XSPI_DHQC_ENABLE                 ((uint32_t)XSPI_TCR_DHQC)  /*!< Delay Hold 1/4 cycle             */
/**
  * @}
  */

 In regards to the layout, we've reduced the length between all the lines to 1mm(difference between data lines and CLK is no longer than 1mm compared to almost 7mm on the STM32N6 DK), routed them only on top and bottom with a 6 layer PCB stack up and used L2 AND L5 as clear ground, but also ground via guarding around the group. We are partly certain it isn't the layout. The main difference in schematic would be the absence of series 0 ohm resistors present on each of the lines.

I confirm what @Michael5 says
@TDK  thanks so much  for your reply, 
Looking forward to reading you thoughts in light of this recent information addon.

tylerl
Associate

Hello,

We are running into almost exactly the same issue but are using the external RAM for display frame buffering.  We've also followed the APMemory app note(attached) for transitioning from -OBRx to -OBx9 and have had no luck.

 

I'm hoping someone has made some progress on this issue.

Hello 
On our end we discovered that we had not set the OTP fuses that setup the memory to work with external memories powered at 1v8 which is what we have in our design. It appears these come preconfigured for the STM32N6 DK but are default unset.

Follow this guide if your setup is similar and hopefully if fixes your issue as well.
How to program the OTP fuse bits in the STM32N6 

tylerl
Associate

Thank you for responding so quickly!  That was exactly our problem.  Our RAM is working perfectly now.