cancel
Showing results for 
Search instead for 
Did you mean: 

STM32H7B0 OCTA SPI not working for APS6404 QSPI RAM

OGhis
Senior

Hi,

We try to send an receive data to the external APS6404 RAM.
Therefore we read the application note AN5050 and copy the function from page 55 (7.2.5).

At first the function HAL_RCCEx_OCTOSPIDelayConfig() we cannot find in the library.
What is correct function what we must us than or what we must change in the source code?

Without executing the function DelayBlock_Calibration() the MCU blocks when we read some data.

Here is our code:

#define LINEAR_BURST_READ 0x20
#define LINEAR_BURST_WRITE 0xA0
#define DUMMY_CLOCK_CYCLES_SRAM_READ 5
#define DUMMY_CLOCK_CYCLES_SRAM_WRITE 4
/* Exported macro -----------------------------------------------------*/
#define BUFFERSIZE (COUNTOF(aTxBuffer) - 1)
#define COUNTOF(__BUFFER__) (sizeof(__BUFFER__) / sizeof(*(__BUFFER__)))
#define DLYB_BUFFERSIZE (COUNTOF(Cal_buffer) - 1)
#define EXTENDEDBUFFERSIZE (1048576)

uint8_t aTxBuffer[] = " **OCTOSPI/Octal-spi PSRAM Memory-mapped communication example** " \
                      " **OCTOSPI/Octal-spi PSRAM Memory-mapped communication example** " \
                      " **OCTOSPI/Octal-spi PSRAM Memory-mapped communication example** ";
__IO uint8_t *mem_addr;
uint32_t address = 0;
uint16_t index1;   /* index1 counter of bytes used when reading/
                      writing 256 bytes buffer */
uint16_t index2;   /* index2 counter of 256 bytes buffer used when reading/
                      writing the 1Mbytes extended buffer */

void user_main(void) {
  EnableMemMapped();
  DelayBlock_Calibration();
  test_memory();
}


void test_memory(void) {

  mem_addr = (__IO uint8_t*) (OCTOSPI1_BASE + address);
  /*Writing 1Mbyte (256Byte BUFFERSIZE x 4096 times) */
  for (index2 = 0; index2 < EXTENDEDBUFFERSIZE / BUFFERSIZE; index2++) {
    for (index1 = 0; index1 < BUFFERSIZE; index1++) {
      *mem_addr = aTxBuffer[index1];
      mem_addr++;
    }
  }
  /*----------------------------------------------------------------------*/
  /* Reading Sequence of 1Mbyte */
  mem_addr = (__IO uint8_t*) (OCTOSPI1_BASE + address);
  /*Reading 1Mbyte (256Byte BUFFERSIZE x 4096 times)*/
  for (index2 = 0; index2 < EXTENDEDBUFFERSIZE/BUFFERSIZE; index2++) {
    for (index1 = 0; index1 < BUFFERSIZE; index1++) {
      if (*mem_addr != aTxBuffer[index1]) {   // <<== blocks here
        /*if data read is corrupted we can toggle a led here: example blue led*/
        __NOP();   
      }
      mem_addr++;
    }
  }
}

#if 1
void DelayBlock_Calibration(void) {
  /*buffer used for calibration*/
  uint8_t Cal_buffer[] = "****Delay Block Calibration Buffer ****" \
                         "****Delay Block Calibration Buffer ****" \
                         "****Delay Block Calibration Buffer ****" \
                         "****Delay Block Calibration Buffer ****" \
                         "****Delay Block Calibration Buffer ****" \
                         "****Delay Block Calibration Buffer ****";
  uint16_t index;
  __IO uint8_t *mem_addr;
  uint8_t test_failed;
  uint8_t delay = 0x0;
  uint8_t Min_found = 0;
  uint8_t Max_found = 0;
  uint8_t Min_Window = 0x0;
  uint8_t Max_Window = 0xF;
  uint8_t Mid_window = 0;
  uint8_t calibration_ongoing = 1;

  /* Write the Cal_buffer to the memory*/
  mem_addr = (__IO uint8_t*) (OCTOSPI1_BASE);

  for (index = 0; index < DLYB_BUFFERSIZE; index++) {
    *mem_addr = Cal_buffer[index];
    mem_addr++;
  }

  while (calibration_ongoing) {
    /* update the Delayblock calibration */
    HAL_RCCEx_OCTOSPIDelayConfig(delay, 0);   // <<== not found
    test_failed = 0;
    mem_addr = (__IO uint8_t*) (OCTOSPI1_BASE);
    for (index = 0; index < DLYB_BUFFERSIZE; index++) {
      /* Read the Cal_buffer from the memory*/
      if (*mem_addr != Cal_buffer[index]) {
        /*incorrect data read*/
        test_failed = 1;
      }
      mem_addr++;
    }
    /* search for the Min window */
    if (Min_found != 1) {
      if (test_failed == 1) {
        if (delay < 15) {
          delay++;
        } else {
          /* If delay set to maximum and error still detected: can't use external
           PSRAM */
          Error_Handler();
        }
      } else {
        Min_Window = delay;
        Min_found = 1;
        delay = 0xF;
      }
    }
    /* search for the Max window */
    else if (Max_found != 1) {
      if (test_failed == 1) {
        if (delay > 0) {
          delay--;
        } else {
          /* If delay set to minimum and error still detected: can't use external
           PSRAM */
          Error_Handler();
        }
      } else {
        Max_Window = delay;
        Max_found = 1;
      }
    }
    /* min and max delay window found, configure the delay block with the middle
     window value and exit calibration */
    else {
      Mid_window = (Max_Window + Min_Window) / 2;
      HAL_RCCEx_OCTOSPIDelayConfig(Mid_window, 0);     // <<== not found
      /* exit calibration */
      calibration_ongoing = 0;
    }
  }
}
#endif


void EnableMemMapped(void) {

  OSPI_RegularCmdTypeDef sCommand;
  OSPI_MemoryMappedTypeDef sMemMappedCfg;

  sCommand.FlashId = HAL_OSPI_FLASH_ID_1;
  sCommand.InstructionMode = HAL_OSPI_INSTRUCTION_8_LINES;
  sCommand.InstructionSize = HAL_OSPI_INSTRUCTION_8_BITS;
  sCommand.InstructionDtrMode = HAL_OSPI_INSTRUCTION_DTR_DISABLE;
  sCommand.AddressMode = HAL_OSPI_ADDRESS_8_LINES;
  sCommand.AddressSize = HAL_OSPI_ADDRESS_32_BITS;
  sCommand.AddressDtrMode = HAL_OSPI_ADDRESS_DTR_ENABLE;
  sCommand.AlternateBytesMode = HAL_OSPI_ALTERNATE_BYTES_NONE;
  sCommand.DataMode = HAL_OSPI_DATA_8_LINES;
  sCommand.DataDtrMode = HAL_OSPI_DATA_DTR_ENABLE;
  sCommand.DQSMode = HAL_OSPI_DQS_ENABLE;
  sCommand.SIOOMode = HAL_OSPI_SIOO_INST_EVERY_CMD;
  sCommand.Address = 0;
  sCommand.NbData = 1;
  /* Memory-mapped mode configuration for Linear burst write operations */
  sCommand.OperationType = HAL_OSPI_OPTYPE_WRITE_CFG;
  sCommand.Instruction = LINEAR_BURST_WRITE;
  sCommand.DummyCycles = DUMMY_CLOCK_CYCLES_SRAM_WRITE;
  if (HAL_OSPI_Command(&hospi1, &sCommand, HAL_OSPI_TIMEOUT_DEFAULT_VALUE)
      != HAL_OK) {
    Error_Handler();
  }
  /* Memory-mapped mode configuration for Linear burst read operations */
  sCommand.OperationType = HAL_OSPI_OPTYPE_READ_CFG;
  sCommand.Instruction = LINEAR_BURST_READ;
  sCommand.DummyCycles = DUMMY_CLOCK_CYCLES_SRAM_READ;

  if (HAL_OSPI_Command(&hospi1, &sCommand, HAL_OSPI_TIMEOUT_DEFAULT_VALUE)
      != HAL_OK) {
    Error_Handler();
  }
  /*Disable timeout counter for memory mapped mode*/
  sMemMappedCfg.TimeOutActivation = HAL_OSPI_TIMEOUT_COUNTER_DISABLE;
  /*Enable memory mapped mode*/
  if (HAL_OSPI_MemoryMapped(&hospi1, &sMemMappedCfg) != HAL_OK) {
    Error_Handler();
  }
}

 

17 REPLIES 17
KDJEM.1
ST Employee

Hi @OGhis ,

 

Which OCTOSPI frequency are you using? Could you please refer to the STM32H7B0 datasheet (OCTOSPI characteristics table) and to the memory datasheet and check whether the OCTOSPI frequency used is supported by the OCTOSPI interface and by the memory datasheet?

Is the cache is enabled? Please try to disable it?

Could you please take a look at this video and check MPU configuration. May this post help you.

 

Thank you.

Kaouthar

To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.

Hi,

I had works at 132Mhz clock without any data error in the RAM.
What was so very strangs is when we set the clock at a lower frequency we having mutch more errors.

Yesterday it was working fine until we re-powered the MCU.

What we had changed:
- Wrap size to 32 byte
- Device size to 23 bit (8Mb)
- changed the clock from 80 to 132 Mhz.

Than in the software we had:
- reset the RAM chip
- set the RAM in 32 byte wrap mode


OGhis_1-1724416530551.png

OGhis_2-1724416544524.png

 

OGhis_0-1724416448812.png

Maybe the RAM was in a different mode than we expected, due to the constant changes in RAM mode.

Are the settings for resetting the RAM and setting in Wrap 32 byte correct done? (see code)

 

HAL_StatusTypeDef EnterQuadMode(OSPI_HandleTypeDef *pHdlr) {

  HAL_StatusTypeDef errCode;
  OSPI_RegularCmdTypeDef sCommand = {0};

  sCommand.FlashId = HAL_OSPI_FLASH_ID_1;
  sCommand.InstructionMode = HAL_OSPI_INSTRUCTION_1_LINE;
  sCommand.InstructionSize = HAL_OSPI_INSTRUCTION_8_BITS;
  sCommand.InstructionDtrMode = HAL_OSPI_INSTRUCTION_DTR_DISABLE;
  sCommand.AddressMode = HAL_OSPI_ADDRESS_NONE;
  sCommand.AlternateBytesMode = HAL_OSPI_ALTERNATE_BYTES_NONE;
  sCommand.DataMode = HAL_OSPI_DATA_NONE;
  sCommand.DQSMode = HAL_OSPI_DQS_DISABLE;
  sCommand.SIOOMode = HAL_OSPI_SIOO_INST_EVERY_CMD;

  sCommand.OperationType = HAL_OSPI_OPTYPE_COMMON_CFG;
  sCommand.DummyCycles = DUMMY_CLOCK_CYYCLES_ENTER_QUAD_MODE;


  /* reset enable */
  sCommand.Instruction = AP6404_RESET_ENABLE;
  errCode = HAL_OSPI_Command(pHdlr,
                             &sCommand,
                             HAL_OSPI_TIMEOUT_DEFAULT_VALUE);
  if (errCode != HAL_OK) {
    return (errCode);
  }

  /*reset */
  sCommand.Instruction = AP6404_RESET;
  errCode = HAL_OSPI_Command(pHdlr,
                             &sCommand,
                             HAL_OSPI_TIMEOUT_DEFAULT_VALUE);
  if (errCode != HAL_OK) {
    return (errCode);
  }

  /* 32 byte boudary enable */
  sCommand.Instruction = AP6404_WRAP_BOUNDARY_TOGGLE;
  errCode = HAL_OSPI_Command(pHdlr,
                             &sCommand,
                             HAL_OSPI_TIMEOUT_DEFAULT_VALUE);
  if (errCode != HAL_OK) {
    return (errCode);
  }

  /*Enter QUAD mode*/
  sCommand.Instruction = AP6404_ENTER_QUAD_MODE;
  errCode = HAL_OSPI_Command(pHdlr,
                             &sCommand,
                             HAL_OSPI_TIMEOUT_DEFAULT_VALUE);
  if (errCode != HAL_OK) {
    return (errCode);
  }

  return(HAL_OK);
}

 



 





KDJEM.1
ST Employee

Hi @OGhis ,

 

Is there any change when you disable WRAP?

Is the cache is enabled? Could you please disable it?

Could you please check the MPU configuration? May this discussion can help you.

KDJEM1_0-1724425531863.png

 

 

Thank you.

Kaouthar

To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.

Hi,

We don't not way you ask to configure the MPU to resolve our issue.
Second the link and picture you send to us isn't not for our AP6404.

So let us step by step verify the configuration

With the code below we can write and read to the memory without any data error.
But therefore we must at each write cyclus wating with 40 NOP() otherwise the memory check will be fail.

So at first please verify at first if the commands for the configuration of the AP6404 in QSPI mode are correct.

The step we use are:
- exit from QSPI mode
- in SPI mode we reset the externel chip (not sure if this is correct done)
- Set the RAM in wrap bondary mode (this is disable, wont not works)
- set the QSPI RAM in QUAD mode.
- enable the memory mapping mode

The MCU works at 280MHz and the QSPI is set at 132 MHz

 

#define EXTENDEDBUFFERSIZE (1 << 23)

#define AP6404_READ_READ            (0x03)
#define AP6404_FAST_READ            (0x0B)
#define AP6404_QUAD_READ            (0xEB)
#define AP6404_WRITE                (0x02)
#define AP6404_QUAD_WRITE           (0x38)
#define AP6404_ENTER_QUAD_MODE      (0x35)
#define AP6404_EXIT_QUAD_MODE       (0xF5)
#define AP6404_RESET_ENABLE         (0x66)
#define AP6404_RESET                (0x99)
#define AP6404_WRAP_BOUNDARY_TOGGLE (0xC0)
#define AP6404_READ_ID              (0x9F)

#define DUMMY_CLOCK_CYCLES_SRAM_FAST_READ_QUAD   (6)
#define DUMMY_CLOCK_CYCLES_SRAM_WRITE            (0)
#define DUMMY_CLOCK_CYYCLES_0_delay              (0)

#define write_delay() \
    __NOP();__NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); \
    __NOP();__NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); \
    __NOP();__NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); \
    __NOP();__NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP();

void main(void) {
......
  AP6404_ExitQuadMode(&hospi1);
  AP6404_Reset(&hospi1);
//  AP6404_WrapBoundaryToggle(&hospi1);
  AP6404_EnterQuadMode(&hospi1);
  AP6404_EnableMemMapped(&hospi1);

  if (AP6404_memory_test() != HAL_OK) {
    MODLEDS_CtrlSet(eMODLED_DBG2, MODLEDS_FLASHING_PATTERN_ON);
  } else {
    MODLEDS_CtrlSet(eMODLED_DBG2, MODLEDS_FLASHING_PATTERN_OFF);
  }
}

HAL_StatusTypeDef AP6404_memory_test(void) {

  volatile uint32_t errCnt = 0;
  volatile uint64_t *pAddr;
  uint32_t cnt = 0;
  volatile uint32_t  retries;
  uint64_t counter;
  uint64_t offset = 0ULL;

  for (pAddr = (volatile uint64_t *) OCTOSPI1_BASE;
       pAddr < (volatile uint64_t *)(OCTOSPI1_BASE + EXTENDEDBUFFERSIZE);
       pAddr++) {
    *pAddr = 0x0000000000000000uLL;
    write_delay();
  }

  for (retries = 0; retries < 10; retries++) {
    counter = 0x0001020304050607uLL + offset;

    for (pAddr = (volatile uint64_t *) OCTOSPI1_BASE;
         pAddr < (volatile uint64_t *)(OCTOSPI1_BASE + EXTENDEDBUFFERSIZE);
         pAddr++) {
      *pAddr = counter;
      write_delay();
      counter += 0x0101010101010101uLL;
    }


    counter = 0x0001020304050607uLL + offset;
    // volatile uint64_t value;
    for (pAddr = (volatile uint64_t *) OCTOSPI1_BASE;
         pAddr < (volatile uint64_t *)(OCTOSPI1_BASE + EXTENDEDBUFFERSIZE);
         pAddr++) {
      // value = *pAddr;
      if (*pAddr != counter) {
        errCnt++;
      }
      cnt++;
      counter += 0x0101010101010101uLL;
    }
    offset += 0x0807060504030201ULL;
  }

  if (errCnt != 0) {
    DEBUG_LOG(DBG_Error, "RAM check errors: %d/%d", errCnt, cnt);
    return(HAL_ERROR);
  }

  return(HAL_OK);
}

HAL_StatusTypeDef AP6404_ExitQuadMode(OSPI_HandleTypeDef *pHdlr) {

  HAL_StatusTypeDef errCode;
  OSPI_RegularCmdTypeDef sCommand = {0};

  sCommand.FlashId = HAL_OSPI_FLASH_ID_1;
  sCommand.InstructionMode = HAL_OSPI_INSTRUCTION_1_LINE;
  sCommand.InstructionSize = HAL_OSPI_INSTRUCTION_8_BITS;
  sCommand.InstructionDtrMode = HAL_OSPI_INSTRUCTION_DTR_DISABLE;
  sCommand.AddressMode = HAL_OSPI_ADDRESS_NONE;
  sCommand.AlternateBytesMode = HAL_OSPI_ALTERNATE_BYTES_NONE;
  sCommand.DataMode = HAL_OSPI_DATA_NONE;
  sCommand.DQSMode = HAL_OSPI_DQS_DISABLE;
  sCommand.SIOOMode = HAL_OSPI_SIOO_INST_EVERY_CMD;

  sCommand.OperationType = HAL_OSPI_OPTYPE_COMMON_CFG;
  sCommand.DummyCycles   = DUMMY_CLOCK_CYYCLES_0_delay;

  /*Exit QUAD mode*/
  sCommand.Instruction = AP6404_EXIT_QUAD_MODE;
  errCode = HAL_OSPI_Command(pHdlr,
                             &sCommand,
                             HAL_OSPI_TIMEOUT_DEFAULT_VALUE);
  if (errCode != HAL_OK) {
    return (errCode);
  }

  return(HAL_OK);
}

HAL_StatusTypeDef AP6404_Reset(OSPI_HandleTypeDef *pHdlr) {

  HAL_StatusTypeDef errCode;
  OSPI_RegularCmdTypeDef sCommand = {0};

  sCommand.FlashId = HAL_OSPI_FLASH_ID_1;
  sCommand.InstructionMode = HAL_OSPI_INSTRUCTION_1_LINE;
  sCommand.InstructionSize = HAL_OSPI_INSTRUCTION_8_BITS;
  sCommand.InstructionDtrMode = HAL_OSPI_INSTRUCTION_DTR_DISABLE;
  sCommand.AddressMode = HAL_OSPI_ADDRESS_NONE;
  sCommand.AlternateBytesMode = HAL_OSPI_ALTERNATE_BYTES_NONE;
  sCommand.DataMode = HAL_OSPI_DATA_NONE;
  sCommand.DQSMode = HAL_OSPI_DQS_DISABLE;
  sCommand.SIOOMode = HAL_OSPI_SIOO_INST_EVERY_CMD;

  sCommand.OperationType = HAL_OSPI_OPTYPE_COMMON_CFG;
  sCommand.DummyCycles = DUMMY_CLOCK_CYYCLES_0_delay;

  /* reset enable */
  sCommand.Instruction = AP6404_RESET_ENABLE;
  errCode = HAL_OSPI_Command(pHdlr,
                             &sCommand,
                             HAL_OSPI_TIMEOUT_DEFAULT_VALUE);
  if (errCode != HAL_OK) {
    return (errCode);
  }

  /*reset */
  sCommand.Instruction = AP6404_RESET;
  sCommand.DummyCycles = DUMMY_CLOCK_CYYCLES_0_delay;
  errCode = HAL_OSPI_Command(pHdlr,
                             &sCommand,
                             HAL_OSPI_TIMEOUT_DEFAULT_VALUE);
  if (errCode != HAL_OK) {
    return (errCode);
  }

  return(HAL_OK);
}

HAL_StatusTypeDef AP6404_WrapBoundaryToggle(OSPI_HandleTypeDef *pHdlr) {

  HAL_StatusTypeDef errCode;
  OSPI_RegularCmdTypeDef sCommand = {0};

  sCommand.FlashId = HAL_OSPI_FLASH_ID_1;
  sCommand.InstructionMode = HAL_OSPI_INSTRUCTION_1_LINE;
  sCommand.InstructionSize = HAL_OSPI_INSTRUCTION_8_BITS;
  sCommand.InstructionDtrMode = HAL_OSPI_INSTRUCTION_DTR_DISABLE;
  sCommand.AddressMode = HAL_OSPI_ADDRESS_NONE;
  sCommand.AlternateBytesMode = HAL_OSPI_ALTERNATE_BYTES_NONE;
  sCommand.DataMode = HAL_OSPI_DATA_NONE;
  sCommand.DQSMode = HAL_OSPI_DQS_DISABLE;
  sCommand.SIOOMode = HAL_OSPI_SIOO_INST_EVERY_CMD;

  sCommand.OperationType = HAL_OSPI_OPTYPE_COMMON_CFG;
  sCommand.DummyCycles = DUMMY_CLOCK_CYYCLES_0_delay;

  /* 32 byte boudary enable */
  sCommand.Instruction = AP6404_WRAP_BOUNDARY_TOGGLE;
  errCode = HAL_OSPI_Command(pHdlr,
                             &sCommand,
                             HAL_OSPI_TIMEOUT_DEFAULT_VALUE);
  if (errCode != HAL_OK) {
    return (errCode);
  }

  return(HAL_OK);
}

HAL_StatusTypeDef AP6404_EnterQuadMode(OSPI_HandleTypeDef *pHdlr) {

  HAL_StatusTypeDef errCode;
  OSPI_RegularCmdTypeDef sCommand = {0};

  sCommand.FlashId = HAL_OSPI_FLASH_ID_1;
  sCommand.InstructionMode = HAL_OSPI_INSTRUCTION_1_LINE;
  sCommand.InstructionSize = HAL_OSPI_INSTRUCTION_8_BITS;
  sCommand.InstructionDtrMode = HAL_OSPI_INSTRUCTION_DTR_DISABLE;
  sCommand.AddressMode = HAL_OSPI_ADDRESS_NONE;
  sCommand.AlternateBytesMode = HAL_OSPI_ALTERNATE_BYTES_NONE;
  sCommand.DataMode = HAL_OSPI_DATA_NONE;
  sCommand.DQSMode = HAL_OSPI_DQS_DISABLE;
  sCommand.SIOOMode = HAL_OSPI_SIOO_INST_EVERY_CMD;

  sCommand.OperationType = HAL_OSPI_OPTYPE_COMMON_CFG;
  sCommand.DummyCycles = DUMMY_CLOCK_CYYCLES_0_delay;

  /*Enter QUAD mode*/
  sCommand.Instruction = AP6404_ENTER_QUAD_MODE;
  errCode = HAL_OSPI_Command(pHdlr,
                             &sCommand,
                             HAL_OSPI_TIMEOUT_DEFAULT_VALUE);
  if (errCode != HAL_OK) {
    return (errCode);
  }

  return(HAL_OK);
}

HAL_StatusTypeDef AP6404_EnableMemMapped(OSPI_HandleTypeDef *pHdlr) {

  HAL_StatusTypeDef errCode;
  OSPI_RegularCmdTypeDef sCommand = {0};
  OSPI_MemoryMappedTypeDef sMemMappedCfg = {0};

  sCommand.FlashId = HAL_OSPI_FLASH_ID_1;
  sCommand.InstructionMode = HAL_OSPI_INSTRUCTION_4_LINES;
  sCommand.InstructionSize = HAL_OSPI_INSTRUCTION_8_BITS;
  sCommand.InstructionDtrMode = HAL_OSPI_INSTRUCTION_DTR_DISABLE;
  sCommand.AddressMode = HAL_OSPI_ADDRESS_4_LINES;
  sCommand.AddressSize = HAL_OSPI_ADDRESS_24_BITS;
  sCommand.AddressDtrMode = HAL_OSPI_ADDRESS_DTR_DISABLE;
  sCommand.AlternateBytesMode = HAL_OSPI_ALTERNATE_BYTES_NONE;
  sCommand.DataMode = HAL_OSPI_DATA_4_LINES;
  sCommand.DataDtrMode = HAL_OSPI_DATA_DTR_DISABLE;
  sCommand.SIOOMode = HAL_OSPI_SIOO_INST_EVERY_CMD;
  sCommand.Address = 0;
  sCommand.NbData = 1;

  /* Memory-mapped mode configuration for Quad Read mode 4-4-4*/
  sCommand.OperationType = HAL_OSPI_OPTYPE_READ_CFG;
  sCommand.Instruction = AP6404_QUAD_READ;
  sCommand.DummyCycles = DUMMY_CLOCK_CYCLES_SRAM_FAST_READ_QUAD;
  errCode = HAL_OSPI_Command(pHdlr,
                             &sCommand,
                             HAL_OSPI_TIMEOUT_DEFAULT_VALUE);
  if (errCode != HAL_OK) {
    return(errCode);
  }

  /* Memory-mapped mode configuration for Quad Write mode -4-4*/
  sCommand.DQSMode = HAL_OSPI_DQS_ENABLE;
  sCommand.OperationType = HAL_OSPI_OPTYPE_WRITE_CFG;
  sCommand.Instruction = AP6404_QUAD_WRITE;
  sCommand.DummyCycles = DUMMY_CLOCK_CYCLES_SRAM_WRITE;
  errCode = HAL_OSPI_Command(pHdlr,
                             &sCommand,
                             HAL_OSPI_TIMEOUT_DEFAULT_VALUE);
  if (errCode != HAL_OK) {
    return (errCode);
  }
  /*Disable timeout counter for memory mapped mode*/
  sMemMappedCfg.TimeOutActivation = HAL_OSPI_TIMEOUT_COUNTER_DISABLE;
  /*Enable memory mapped mode*/
  errCode = HAL_OSPI_MemoryMapped(pHdlr, &sMemMappedCfg);
  if (errCode != HAL_OK) {
    return (errCode);
  }

  return(HAL_OK);
}

 

OGhis_0-1724524960098.pngOGhis_1-1724524981863.pngOGhis_2-1724525010838.png

 



 

Hi,

With the source code from my previous post, it seems to work with no additional delays while placing the data in the QSPI region memory (0x9000000).
But this only works if we make the write speed lower that the clock speed of the QSPI.
The failure of the write has something to do with the write speed.

How should we adjust the settings so that no subsequent write operation can happen before the QSPI has sent the data to the external memory?

In mxCube we have 2 parameter “Chip Select Boundary” and “Refresch Rate” which we don't understand how to adjust (probably has to do with this)

How we must calculate these values?

OGhis_0-1724784679865.png

 

KDJEM.1
ST Employee

Hello @OGhis ,

 

- Chip select boundary (CSBOUND) configured depending on the memory datasheet. The chip select must go high when crossing the page boundary (2^CSBOUND) bytes defines the page size).
- Refresh rate (REFRESH) required for PSRAMs memories. The chip select must go high each (REFRECH x OCTOSPI clock cycles), configured depending on the memory datasheet.

- Sample shifting (SSHT) recommended to be enabled in STR mode and disabled in DTR mode.
- Delay hold quarter cycle (DHQC) enabled in DTR mode and disabled in STR mode.

For more information, I advise you to refer to AN5050 precisely 7.2.4 OCTOSPI configuration and parameter setting section.

 

Thank you.

Kaouthar

To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.

Hi,

We have read several times the application note and follow the setting of section 7.4.2.
The only parameter we had changed was the "Refrech Rate" from 241 to 872. This because we working at 109Mhz and the datasheet of the APS6404L-3SQR-SN says that the refresh time was 8µs.

Than we have try all the combination of the parameters "Sample shifting" and "Delay hold quarter cycle"
The only combination that works is "Sample shifting" = None and "Delay hold quarter cycle" = Enable
Also we had try some other values for the parameters "Maximum transfert" and "chip select high time"

With all these parameter changes, the problem persists. (between 0 and 8 write and read back compare failure)
During the memory test, we do about 37.75 million read and write operations
When we decrease the QSPI clock have many times more failures (from 109 to 80 MHz, MCU clock was 280MHz)
When we decrease the MCU clock to 140MHz we must also decrease the QSPI clock to 108Mhz. 
In this case after 100 memory test cycles we have no more errors.
The problem we have then is that we don't have enough CPU speed for the ADC. (At least 200Mhz)
When the CPU speed goes under the 200Mhz, the clock prescaler of the ADC has no option more to divide the clock by 1 or 2. We have need this to use a sample rate of 1 mega samples. Why the clock speed of the CPU affects the ADC is also very strange. The ADC has his own clock (48Mhz)

So it does have something to do with the QSPI clock and the write speed to the QSPI memory mapped address space.

Could it be when we write to the memory space that the MCU is not waiting long enough for the QSPI?
Or what else would trigger this problem?

KDJEM.1
ST Employee

Hello @OGhis ,

 

when we try wrting 64bits long data, than he write correct the data to the RAM memory.

I think your issue is solved. What's the change you've made so that writing is failed again? 

For Octo-SPI AP Memory device configuration, the delay block must be enabled. For detailed examples, refer to AN5050 Section 6.

Please try with other clock source. In STM32H7B0 , any of the four different clock sources, (rcc_hclk3, pll1_q_ck, pll2_r_ck, per_ck) can be used for OCTOSPI clock source.  

Could you please check your PCB "Getting started with STM32H7A3/7B3 line and STM32H7B0 Value line
microcontroller hardware development"

 

Thank you.

Kaouthar

 

 

To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.