Skip to main content
Graduate
August 18, 2024
Question

STM32H7B0 OCTA SPI not working for APS6404 QSPI RAM

  • August 18, 2024
  • 7 replies
  • 3600 views

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();
 }
}

 

    This topic has been closed for replies.

    7 replies

    Technical Moderator
    August 19, 2024

    Hello @OGhis ,

     

    The AN5050 shared some examples with STM32L4P5G-DK board. For STM32H7 delay block calibration and PSRAM, I recommend you to refer to DLYB_OSPI_PSRAM_ExhaustiveTuning example and get inspired to configure your project. This example describes how to tune delay block with OSPI PSRAM in indirect Read/Write mode with STM32U5.

    Also I advise you to take a look at this discussion and at OSPI examples with STM32H7 may help you.

     

    Thank you.

    Kaouthar

    OGhisAuthor
    Graduate
    August 19, 2024

    Hi,

    None of your suggestions meet our expectations.
    - The  DLYB_OSPI_PSRAM_ExhaustiveTuning example, our STM32H7B0VBTx has no DLYB option.
    - The project use an APS6408L but we use an APS6404L-3SQR-SN has only 4 data bits.
    OSPI examples with STM32H7 examples is for HyperRam chips and not QSPI
     

    What we must change in the sCommand?  (we want to use it in memory mapped mode)
    See code below:

     

     

    void EnableMemMapped(void) {
    
     OSPI_RegularCmdTypeDef sCommand;
     OSPI_MemoryMappedTypeDef sMemMappedCfg;
    
     sCommand.FlashId = HAL_OSPI_FLASH_ID_1;
     sCommand.InstructionMode = HAL_OSPI_INSTRUCTION_4_LINES; 
     sCommand.InstructionSize = HAL_OSPI_INSTRUCTION_8_BITS; ==> 4 of 8 bits
     sCommand.InstructionDtrMode = HAL_OSPI_INSTRUCTION_DTR_DISABLE;
     sCommand.AddressMode = HAL_OSPI_ADDRESS_8_LINES; ==> 4 or 8 lines
     sCommand.AddressSize = HAL_OSPI_ADDRESS_24_BITS; ==> 24 or 32 bits
     sCommand.AddressDtrMode = HAL_OSPI_ADDRESS_DTR_ENABLE; ==> ??
     sCommand.AlternateBytesMode = HAL_OSPI_ALTERNATE_BYTES_NONE;
     sCommand.DataMode = HAL_OSPI_DATA_8_LINES; ==> 4 or 8 lines
     sCommand.DataDtrMode = HAL_OSPI_DATA_DTR_ENABLE; ==> enable or disable
     sCommand.DQSMode = HAL_OSPI_DQS_DISABLE;
     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; ==> ==> (Value was 0x20 AP6408, but what for the AP6404??
     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; ==> 0xA0 for the AP6408 but what using for the AP6404 ??
     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(); }
    }

     

     

     

    OGhis_1-1724094765515.png

    Are these settings coorect?

    OGhis_0-1724094125923.png

    Btw: when executing the commands, we don't have any signal of the QSPI bus

     

    Technical Moderator
    August 20, 2024

    Hi @OGhis ,

     

    Thank you for coming back to the community and I apologize that my suggestions did not meet your expectations.

    About the settings: Device Size defines the memory size in number of bytes = 2^(DEVSIZE+1).

    For 8MBytes memory the Device Size must be configure 23 as mentioned in AN5050 table8.STM32CubeMX - Configuration of OCTOSPI parameters.

    Could you please try with this sCommand:

    /*Function to Enable Memory mapped mode in Quad mode 4-4-4*/
    void EnableMemMappedQuadMode(void)
    {
     OSPI_RegularCmdTypeDef sCommand;
     OSPI_MemoryMappedTypeDef sMemMappedCfg;
     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 = FAST_READ_QUAD;
     sCommand.DummyCycles = FAST_READ_QUAD_DUMMY_CYCLES;
     if (HAL_OSPI_Command(&hospi1, &sCommand, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
     {
     Error_Handler();
     }
     /* Memory-mapped mode configuration for Quad Write mode -4-4*/
     sCommand.OperationType = HAL_OSPI_OPTYPE_WRITE_CFG;
     sCommand.Instruction = QUAD_WRITE;
     sCommand.DummyCycles = WRITE_QUAD_DUMMY_CYCLES;
     sCommand.DQSMode = HAL_OSPI_DQS_ENABLE;
     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();
     }
    }

     

    Please don't forgot to check the dummy cycle in main.h

    #define FAST_READ_QUAD 0xEB
    #define QUAD_WRITE 0x38
    
    #define FAST_READ_QUAD_DUMMY_CYCLES 6
    #define WRITE_QUAD_DUMMY_CYCLES 0

    I hope this help you.

    Please take a look at How to configure OctoSPI and QuadSPI with an STM32, I think it is very helpful.

    Thank you.

    Kaouthar

    OGhisAuthor
    Graduate
    August 20, 2024

    Hi,

    Thanks for the information

    We seen now signals on all the I/O pins of the AP6404, but when we write an read back the data we have always the same data 0x88. (same data over the hole memory size, started from address 0x90000000)

    What else can we verify and what could still be misconfigured?

    btw: the AP6404 has a command to put the chip in quad spi mode.
    Why is this missing in your proposed source code?  => AP6404_ENTER_QUAD_MODE (0x35)

    Technical Moderator
    August 21, 2024

    Hi @OGhis ,

    I only provided some configuration for read and write operation in memory mapped mode like that you shared, not all the code.

    The SPI Quad mode enable operation command (0x35) is available only in SPI mode to switch the device into quad IO mode before enter in memory mapped:

    KDJEM1_0-1724226608516.png

     

    void EnterQuadMode(void)
    {
     OSPI_RegularCmdTypeDef sCommand;
     sCommand.OperationType = HAL_OSPI_OPTYPE_COMMON_CFG;
     sCommand.FlashId = HAL_OSPI_FLASH_ID_1;
     sCommand.Instruction = ENTER_QUAD_MODE;
     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.DummyCycles = ENTER_QUAD_DUMMY_CYCLES;
     sCommand.DQSMode = HAL_OSPI_DQS_DISABLE;
     sCommand.SIOOMode = HAL_OSPI_SIOO_INST_EVERY_CMD;
     /*Enter QUAD mode*/
     if (HAL_OSPI_Command(&hospi1, &sCommand, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
     {
     Error_Handler();
     }
    }

     

    Thank you.

    Kaouthar

    Technical Moderator
    August 22, 2024

    Hello @OGhis ,

     

    Glad to know that you are now able to write and read.

    Please take a look at these discussions, I think you encountering the same issue:

    Solved: Re: STM32H7B0RBT6 with QSPI PSRAM APS6404L-3SQR - STMicroelectronics Community

    Solved: Re: [STM32H7B0][APS6404L-3SQR] Issue with Write in... - STMicroelectronics Community

    Concerning the 64 bit writes , there is an errata "Memory-mapped write error response when DQS output is disabled".

    KDJEM1_0-1724311931154.png

    So with this errata we need to enable the DQS when doing memory mapped writes even if the memory do not support DQS. This is the workaround.

    Now concerning products with AXI bus (OCTOSPI memory mapped region on AXI not AHB) the memory mapped write are always done in multiple of the AXI bus size (64-bit).

    So when you do a 8-16-32 bit write , the OCTOSPI will output 64-bit and mask the rest using DQS pin.

    The problem is if the memory do not support DQS (which is in our case), the rest of the AXI data will be written to the memory. 

    Please let me know if your request in answered or not?

    Thank you.

    Kaouthar

    OGhisAuthor
    Graduate
    August 22, 2024

    Hi,

    If I understand correctly, is there no other option than to write data to the AP6404 in 64 bit in my case due missing DQS pin?

    Can we resolve the issue as follow
    1 DMA in halfword mode for my ADC which stores the samples in the internal RAM memory buffer.
    At the end of the tranfert we start a second DMA.
    We have seen that the MDMA has a 64bit option.
    With this MDMA we store the internal ADC RAM buffer to 0x900000000 in 64 bit mode and that writes the QSPI it to the AP6404.

    To read back the samples, we start another MDMA in 64 bit mode to an internal RAM buffer. This buffer can then be used to send the samples via the USB interface.

    Is this a good workarround solution for us?

    OGhisAuthor
    Graduate
    August 22, 2024

    Hi,

    We also did a very simple memory test and we see that it misses a few writes.
    There are between 20 and 90 locations that has an incorrect value.
    The location is random and the value in memory is always 0x0000000000000000uLL.

    The problem is always during the write cyclus.
    What can be wrong here?

    We did the memory test like this;

    void test_memory(void) {
    
     volatile uint64_t *pAddr;
     uint64_t counter = 0x0001020304050607uLL;
    
     for (pAddr = (volatile uint64_t *) OCTOSPI1_BASE;
     pAddr < (volatile uint64_t *)(OCTOSPI1_BASE + EXTENDEDBUFFERSIZE);
     pAddr++) {
     *pAddr = counter;
     counter += 0x0101010101010101uLL;
     }
    
     uint32_t errCnt = 0;
     uint32_t cnt = 0;
     counter = 0x0001020304050607uLL;
     volatile uint64_t value;
     for (pAddr = (volatile uint64_t *) OCTOSPI1_BASE;
     pAddr < (volatile uint64_t *)(OCTOSPI1_BASE + EXTENDEDBUFFERSIZE);
     pAddr++) {
     value = *pAddr;
     if (value != counter) {
     errCnt++;
     }
     cnt++;
     counter += 0x0101010101010101uLL;
     }
    
     if (errCnt != 0) {
     DEBUG_LOG(DBG_Error, "RAM check errors: %d/%d", errCnt, cnt);
     }
    }

     

    Technical Moderator
    August 23, 2024

    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

    OGhisAuthor
    Graduate
    August 23, 2024

    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);
    }

     



     





    Technical Moderator
    August 23, 2024

    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

    OGhisAuthor
    Graduate
    August 24, 2024

    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

     



     

    OGhisAuthor
    Graduate
    August 27, 2024

    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

     

    Technical Moderator
    August 28, 2024

    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

    OGhisAuthor
    Graduate
    August 28, 2024

    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?

    Technical Moderator
    September 5, 2024

    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