Skip to main content
Visitor II
November 27, 2020
Question

STM32CubeMx configuration of the OCTOSPI for QUAD SPI NOR Flash.

  • November 27, 2020
  • 6 replies
  • 2353 views

Hi,

There's no CubeMX example of STM32H72x OCTOSPI configuration for QUAD SPI NOR flash, neither in the AN5050.

Is there some example for that?

    This topic has been closed for replies.

    6 replies

    Super User
    November 27, 2020

    There's quite a few octospi examples in the STM32CubeH7 repository. Here's one:

    https://github.com/STMicroelectronics/STM32CubeH7/blob/beced99ac090fece04d1e0eb6648b8075e156c6c/Projects/STM32H735G-DK/Examples/OSPI/OSPI_HyperRAM_MemoryMapped/Src/main.c

    Examples for other chips within the family should not need many, if any, changes.

    AsantosAuthor
    Visitor II
    November 27, 2020

    Thanks TDK,

    but I need an example or orientation how to use the OCTOSPI in QUAD SPI mode for NOR Flash. I don't understand how ST didn't predict that people would need to know how to use QUADSPI nor flash in the OCTOSPI interface. There should be an application note for that.

    AsantosAuthor
    Visitor II
    December 7, 2020

    Hi,

    I could port the erase function and the function that put the quad-spi flash in memory mapped mode. So I can erase and read the quad-spi nor flash. However, my flash programming function only programs the first two bytes.

    For example:

    if I do:

    QSPI_EraseFlash(0);

     for(i=0;i<256;i++) TxBuffer[i] = 0x31+i;

     QSPI_WriteFlash(TxBuffer, 0,256);

    Memory_Mapped_Mode();

     QSPI_ReadFlash_MP(RxBuffer,0,256);

    RxBuffer = 0x31, 0x32, 0xFF, 0xFF,...,0xFF

    And, if I do:

    QSPI_EraseFlash(0);

     for(i=0;i<256;i++) TxBuffer[i] = 0x31+i;

     QSPI_WriteFlash(TxBuffer, 0,256);

     QSPI_WriteFlash(TxBuffer, 2,256);

    Memory_Mapped_Mode();

     QSPI_ReadFlash_MP(RxBuffer,0,256);

    RxBuffer = 0x31, 0x32, 0x31, 0x32,0xFF,...,0xFF

    I need help to figure out what's wrong with the function:

    (The result is the same for sCommand.DataMode = HAL_OSPI_DATA_4_LINES and for sCommand.DataMode = HAL_OSPI_DATA_1_LINE)

    void QSPI_WriteFlash(uint8_t* buf, uint32_t addr, uint32_t len)

     {

      OSPI_RegularCmdTypeDef sCommand;

      

      OSPI_WriteEnable(&hospi1);

     sCommand.OperationType   = HAL_OSPI_OPTYPE_COMMON_CFG;

     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.AddressSize    = HAL_OSPI_ADDRESS_24_BITS;

     sCommand.AddressDtrMode   = HAL_OSPI_ADDRESS_DTR_DISABLE;

     sCommand.AlternateBytesMode = HAL_OSPI_ALTERNATE_BYTES_NONE;

     sCommand.DataDtrMode    = HAL_OSPI_DATA_DTR_DISABLE;

     sCommand.DQSMode      = HAL_OSPI_DQS_DISABLE;

     sCommand.SIOOMode      = HAL_OSPI_SIOO_INST_EVERY_CMD;

     sCommand.AddressMode  = HAL_OSPI_ADDRESS_1_LINE;

     //sCommand.DataMode = HAL_OSPI_DATA_4_LINES;

     sCommand.DataMode = HAL_OSPI_DATA_1_LINE;

     //sCommand.Instruction  = 0x32; // QUAD_IN_FAST_PROG_CMD

     sCommand.Instruction  = 0x02; // QUAD_IN_FAST_PROG_CMD

     sCommand.Address    = addr;

     sCommand.NbData    = len;

     sCommand.DummyCycles  = 0;

      

     if (HAL_OSPI_Command(&hospi1, &sCommand, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)

     {

      Error_Handler();

     }

      

     if (HAL_OSPI_Transmit(&hospi1, buf,HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)

     {

      Error_Handler();

     }

      

     //OSPI_AutoPollingMemReady(&hospi1);

      HAL_Delay(200);

     }

    AsantosAuthor
    Visitor II
    December 8, 2020

    When call the funciont HAL_QSPI_Transmit from a H743 board. The transfer bytes between CS_LOW and CS_HIGH are: 0x02 0x00 0x00 0x00 0x41 0x42 0x43 0x44

    Programming correctly the bytes 0x41, 0x42, 0x43 and 0x44 at address 0;

    When call the HAL_OSPI_Transmit function in the function QSPI_WriteFlash above, from a H723 board. The transfer bytes between the first CS_LOW and CS_HIGH are: 0x02 0x00 0x00 0x00 0x41 0x42 and for the second CS_LOW and CS_HIGH are: 0x02 0x00 0x00 0x2 0x43 0x44. Programming only the bytes 0x41 and 0x42 at address 0.

    I tried the HAL_OSPI_Transmit_IT function with the same result.

    Does it have a bug in the function HAL_OSPI_Transmit when used in Quad SPI mode?

    Has anyone used this function to program a QUAD SPI NOR FLASH?

    Visitor II
    December 4, 2024

    Raising this from the dead...but were you/anyone able to figure this out? I'm also attempting to do the same. 

    Graduate II
    December 4, 2024

    Yes, it's not that hard. ie Not Rocket Sciencery

    ST doesn't typically provide examples for every possible use case, they show how THEIR boards work, and they provide Reference Manuals defining HOW the HW works. Plus all the source to the HAL is provided.

    For H7Ax / H72x how to send an 8-bit read command to a Quad SPI device in it's 1-Bit base mode

    //****************************************************************************
    
    static uint8_t OSPI_ReadStatus(OSPI_HandleTypeDef *hospi, uint32_t Reg, uint32_t *pStatusReg)
    {
     OSPI_RegularCmdTypeDef sCommand = {0};
     uint32_t data[2] = {0};
    
     sCommand.OperationType = HAL_OSPI_OPTYPE_COMMON_CFG;
     sCommand.FlashId = HAL_OSPI_FLASH_ID_1;
    
     sCommand.NbData = 1;
    
     switch(Reg)
     {
     case 0 : sCommand.Instruction = READ_STATUS_REG1_CMD; break; // REG1
     case 1 : sCommand.Instruction = READ_STATUS_REG2_CMD; break; // REG2
     case 2 : sCommand.Instruction = READ_STATUS_REG3_CMD; break; // REG3
     case 0x9F : // READID
     sCommand.Instruction = 0x9F;
     sCommand.NbData = 3;
     break;
     default:
     return(OSPI_ERROR);
     }
    
    #ifdef DUAL
     sCommand.NbData <<= 1;
    #endif // DUAL
    
     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_1_LINE;
     sCommand.DataDtrMode = HAL_OSPI_DATA_DTR_DISABLE;
     sCommand.DummyCycles = 0;
     sCommand.DQSMode = HAL_OSPI_DQS_DISABLE;
     sCommand.SIOOMode = HAL_OSPI_SIOO_INST_EVERY_CMD;
    
     /* Send the command */
     if (HAL_OSPI_Command(hospi, &sCommand, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
     {
     return(OSPI_ERROR);
     }
    
     /* Receive the data */
     if (HAL_OSPI_Receive(hospi, (void *)data, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
     {
     return(OSPI_ERROR);
     }
    
    #ifdef DUAL
     if (Reg == 0x9F) // RDID
     data[0] = (data[0] & 0xFF) | ((data[0] & 0xFF0000) >> 16) | ((data[1] & 0xFF) << 16);
    #endif // DUAL
    
     if (pStatusReg)
     *pStatusReg = data[0];
    
     return(OSPI_OK);
    }
    
    //****************************************************************************

      

    Visitor II
    December 19, 2024

    I'll start a new thread for what I'm dealing with.  I was hoping for a quick answer from the original poster to see if there was some obvious gotcha that he had worked through

    Graduate II
    December 19, 2024

    https://community.st.com/t5/stm32-mcus-products/migrating-from-quad-spi-stm32h750-to-octo-spi-stm32h733/td-p/755438

    >>obvious gotcha.. 

    In the cutty-pasty sense, clearing large local/auto variables is strongly suggested, it helps when you skip field initialization, and random stack junk has undesirable results in HAL

    OSPI_RegularCmdTypeDef sCommand = {0};

    Part and command selection is done here now, and not in the HAL_xSPI_Init phase

    sCommand.OperationType = HAL_OSPI_OPTYPE_COMMON_CFG;
    sCommand.FlashId = HAL_OSPI_FLASH_ID_1;

    Some STM32 have OSPIM, others don't, and that can cause all kinds of pretzel logic in OSPI1 vs OSPI2, and pin mappings