cancel
Showing results for 
Search instead for 
Did you mean: 

IS66WVO32M8 OSPI problems

ccuebler
Associate II

Hi All!

I try to use 2 pieces of IS66WVO32M8 PSRAM with multiplexed OSPI ( only the NSS pins not shared ) with STM32F585 in memory mapped mode.

Previously, I used 2 pieces of APMemory's APS12808L in memory mapped mode without any issues.

I reconfigured all the necessary parameters to IS66... according the datasheets (AN5050, STM32F585 OSPI errata), and other's suggestions in the forum, like: 
https://community.st.com/t5/stm32-mcus-products/problem-with-psram-peripherals-of-stm32h735/m-p/706406#M257198
or 
https://community.st.com/t5/stm32-mcus-products/problem-with-psram-peripherals-of-stm32h735/td-p/706406

I can read the ID and configuration registers, I can also modify them (Yellow square), but when I write directly or indirectly to the memory area, and read back for verification, it causes an error.
I tried to change the OSPI speed, using 55, 80, 100 MHz (with recalculated refresh rate using 4us tCEM:  220, 320, 400, 640), with- or without delay block, DHQC enabled/disabled (I know the errata), and DQS values, etc., but didn't work, except that some settings were totally wrong for configuration registers.
I don't know exactly what the error is: writing to memory area or reading it.
My biggest success is that I can read the same data from the same address in both memory mapped mode and normal mode (blue and green squares), but this data is not the same as what I wrote (pink square).


ccuebler_0-1758270421684.png

 

There is someone who configured and use successfully this type of PSRAM ?
Maybe I missed something ?

There is My ISSI PSRAM related routines, please check it:

#define ISSI_READ_DUMMY_CYCLES 5
#define ISSI_WRITE_DUMMY_CYCLES 0

#define ISSI_READ_COMMAND 0xA000
#define ISSI_WRITE_COMMAND 0x2000

#define ISSI_WRAPPED_READ_COMMAND 0x8000
#define ISSI_WRAPPED_WRITE_COMMAND 0x0000


#define ISSI_READ_CFG 0xC000
#define ISSI_WRITE_CFG 0x4000
#define ISSI_READ_PATTERN 0xF000

/*************************************************************************
 * @brief  Write ISSI register
 * 
 * @PAram  Ctx Component object pointer
 * @PAram  reg Register 
 * @PAram  Address Register address
 * @PAram  Value Register value pointer
 * @retval error status
 *************************************************************************/
uint32_t ISSI_WriteReg(OSPI_HandleTypeDef *Ctx, uint16_t reg, uint32_t Address, uint8_t *Value, uint32_t count)
{
  OSPI_RegularCmdTypeDef sCommand1={0};

  if (Ctx->Instance == OCTOSPI1) {
    sCommand1.FlashId            = HAL_OSPI_FLASH_ID_1;
  } else
  if (Ctx->Instance == OCTOSPI2) {
    sCommand1.FlashId            = HAL_OSPI_FLASH_ID_2;
  }
    

  sCommand1.OperationType      = HAL_OSPI_OPTYPE_COMMON_CFG;
  sCommand1.InstructionMode    = HAL_OSPI_INSTRUCTION_8_LINES;
  sCommand1.InstructionSize    = HAL_OSPI_INSTRUCTION_16_BITS;
  sCommand1.InstructionDtrMode = HAL_OSPI_INSTRUCTION_DTR_ENABLE;
  sCommand1.Instruction        = reg;
  sCommand1.AddressMode        = HAL_OSPI_ADDRESS_8_LINES;
  sCommand1.AddressSize        = HAL_OSPI_ADDRESS_32_BITS;
  sCommand1.AddressDtrMode     = HAL_OSPI_ADDRESS_DTR_DISABLE;
  sCommand1.Address            = Address;
  sCommand1.AlternateBytesMode = HAL_OSPI_ALTERNATE_BYTES_NONE;
  sCommand1.DataMode           = HAL_OSPI_DATA_8_LINES;
  sCommand1.DataDtrMode        = HAL_OSPI_DATA_DTR_DISABLE;
  sCommand1.NbData             = count;
  sCommand1.DummyCycles        = ISSI_WRITE_DUMMY_CYCLES;
  sCommand1.DQSMode            = HAL_OSPI_DQS_DISABLE;
  sCommand1.SIOOMode           = HAL_OSPI_SIOO_INST_EVERY_CMD;

  // Configure the command 
  if (HAL_OSPI_Command(Ctx, &sCommand1, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
  {
    return HAL_ERROR;
  }

  // Transmission of the data 
  if (HAL_OSPI_Transmit(Ctx, (uint8_t *)(Value), HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
  {
    return HAL_ERROR;
  }

  return HAL_OK;
}




/*************************************************************************
 * @brief  Read ISSI register value
 * 
 * @PAram  Ctx Component object pointer
 * @PAram  reg Register 
 * @PAram  Address Register address
 * @PAram  Value Register value pointer
 * @PAram  LatencyCode Latency used for the access
 * @retval error status
 *************************************************************************/
uint32_t ISSI_ReadReg(OSPI_HandleTypeDef *Ctx, uint16_t reg, uint32_t Address, uint8_t *Value, uint32_t count)
{
    OSPI_RegularCmdTypeDef sCommand;
    
    if (Ctx->Instance == OCTOSPI1) {
        sCommand.FlashId            = HAL_OSPI_FLASH_ID_1;
    } else
    if (Ctx->Instance == OCTOSPI2) {
        sCommand.FlashId            = HAL_OSPI_FLASH_ID_2;
    }
    
    

    sCommand.OperationType      = HAL_OSPI_OPTYPE_COMMON_CFG;
    sCommand.InstructionMode    = HAL_OSPI_INSTRUCTION_8_LINES;
    sCommand.InstructionSize    = HAL_OSPI_INSTRUCTION_16_BITS;
    sCommand.InstructionDtrMode = HAL_OSPI_INSTRUCTION_DTR_ENABLE;
    sCommand.Instruction        = reg;
    sCommand.AddressMode        = HAL_OSPI_ADDRESS_8_LINES;
    sCommand.AddressSize        = HAL_OSPI_ADDRESS_32_BITS;
    sCommand.AddressDtrMode     = HAL_OSPI_ADDRESS_DTR_DISABLE;
    sCommand.Address            = Address;
    sCommand.AlternateBytesMode = HAL_OSPI_ALTERNATE_BYTES_NONE;
    sCommand.DataMode           = HAL_OSPI_DATA_8_LINES;
    sCommand.DataDtrMode        = HAL_OSPI_DATA_DTR_DISABLE;
    sCommand.NbData             = count;
    sCommand.DummyCycles        = ISSI_READ_DUMMY_CYCLES;
    sCommand.DQSMode            = HAL_OSPI_DQS_ENABLE;
    sCommand.SIOOMode           = HAL_OSPI_SIOO_INST_EVERY_CMD;

    // Configure the command 
    if (HAL_OSPI_Command(Ctx, &sCommand, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
    {
        return HAL_ERROR;
    }

    // Reception of the data 
    if (HAL_OSPI_Receive(Ctx, (uint8_t *)Value, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
    {
        return HAL_ERROR;
    }

    return HAL_OK;
  }




/*********************************************
 * @brief Configure ISSI PSRAM
 * 
 * @PAram hospi OSPI handle
 * @return Size of the RAM in megabytes
*********************************************/
uint16_t  Configure_ISSI(OSPI_HandleTypeDef *hospi)
{
    uint8_t regW_MR0[4]={0x31, 0x32, 0x33, 0x34};  // MR0 + MR1
    uint8_t regR_MR0[4]={0};

    uint16_t regVal = 0;
    uint16_t id = 0;
    uint32_t size = 0;

    // Read ID
    if (ISSI_ReadReg(hospi, ISSI_READ_CFG, 0x00000000, (uint8_t*)(&id), 2 ) == HAL_OK)
    {
        Debug("Memory ID reg: 0x%04X\n", id);

        if ((id & 0x0F) == 0x03 ) // ISSI 
        {
            size = (1 << (((id >> 4) & 0x0F)+1)) * (1<<(((id >> 8) & 0x0F)+1)) ;

            Debug("Memory Type: ISSI Column: %d bits, Rows: %d bits, Voltage: %s V, Size = %d Mbytes \n", 
              ((id >> 4) & 0x0F)+1, 
              ((id >> 8) & 0x0F)+1, 
              (id >> 13) == 1?"3.0":"1.8", 
              size / 1024 / 1024
            );
        }
    }


    // Read and modify configuration register
    if (ISSI_ReadReg( hospi, ISSI_READ_CFG, 0x00040000, (uint8_t*)( &regVal ), 2 ) == HAL_OK)
    {
      /* ISSI configuration register
      default: 0xF022    
      F0 = 1 111 000 0 : Noraml op, 24Ohm, Reserved, DQSM: 0
      22 = 0010 0 0 10 : Latency: 5Clock, Variable, 32 burst len
      1111000000100010
      1111000000001010
      */
        Debug("ISSI Config value: 0x%04X\n",regVal);
 
        regVal |=  (1<<3); // Fix latency
//        regVal &=  ~(0x70); // Latancy code: 3 cycle

        // Check the write was success
        if (ISSI_WriteReg( hospi, ISSI_WRITE_CFG, 0x00040000, (uint8_t*)( &regVal), 2 ) == HAL_OK)
        {
            uint16_t newRegVal = 0;
            ISSI_ReadReg( hospi, ISSI_READ_CFG, 0x00040000, (uint8_t*)( &newRegVal), 2 );
            Debug("ISSI New Config value: 0x%04X -> 0x%04X - %s\n",
                  regVal, newRegVal, newRegVal == regVal?"SUCCESS":"FAIL");
        }
        else 
            ERROR("ISSI reRead Configuration Error!\n");   
    }
    else 
        ERROR("ISSI Read Configuration Error!\n");
/*

    // Read preamble register value   
    if (ISSI_ReadReg(hospi, ISSI_READ_PATTERN, 0x00000001, (uint8_t*)( &regVal), 2 ) == HAL_OK)
    {
        Debug("ISSI Preamble Pattern: 0x%04X \n", regVal);
    }
    else
        ERROR("ISSI Read Preamble Error!\n");
*/

    hexdump("ISSI Not memory mapped write buffer:",regW_MR0,4);

    //  Test conventioanl (direct) SPI transfer to memory
    if (ISSI_WriteReg(  hospi, ISSI_WRITE_COMMAND, 0x00000010, regW_MR0, 4  ) == HAL_OK)
    {
        if (ISSI_ReadReg( hospi, ISSI_READ_COMMAND, 0x00000010, regR_MR0, 4 ) == HAL_OK)
        {
            hexdump("ISSI continuous burst: Addr: 0x10",regR_MR0,4);
        }
    }


    if (ISSI_WriteReg(  hospi, ISSI_WRITE_COMMAND, 0x00000020, regW_MR0, 4  ) == HAL_OK)
    {
        if (ISSI_ReadReg( hospi, ISSI_READ_COMMAND, 0x00000020, regR_MR0, 4 ) == HAL_OK)
        {
            hexdump("ISSI continuous burst: Addr: 0x20",regR_MR0,4);
        }
    }


    if (ISSI_WriteReg(  hospi, 0x0000, 0x00000030, regW_MR0, 4  ) == HAL_OK)
    {
        if (ISSI_ReadReg( hospi, 0x8000, 0x00000030, regR_MR0, 4 ) == HAL_OK)
        {
            hexdump("ISSI wrapped burst: Addr: 0x30",regR_MR0,4);
        }
    }

    return size / 1024 / 1024;
}



/*********************************************
 * @brief Initialize OSPI to ISSI PSRAM
 * 
 * @PAram hospi return handle of the configured OSPI
 * @PAram Instance Instance of the OSPI (OCTOSPI1 / OCTOSPI2)
*********************************************/
void OSPI_ISSI_PSRAM_Init(OSPI_HandleTypeDef *hospi, OCTOSPI_TypeDef  *Instance) 
{
    OSPIM_CfgTypeDef sOspiManagerCfg = {0};


    hospi->Instance                     = Instance;
    hospi->Init.FifoThreshold           = 4; //Not used in memory mapped mode 
    hospi->Init.DualQuad                = HAL_OSPI_DUALQUAD_DISABLE;
    hospi->Init.MemoryType              = HAL_OSPI_MEMTYPE_MACRONIX_RAM;
    hospi->Init.DeviceSize              = 25;
    hospi->Init.ChipSelectHighTime      = 3; // CS High time in clock period, before next Read/Write 100MHz = 10ns
    hospi->Init.FreeRunningClock        = HAL_OSPI_FREERUNCLK_DISABLE;
    hospi->Init.ClockMode               = HAL_OSPI_CLOCK_MODE_0;
    hospi->Init.WrapSize                = HAL_OSPI_WRAP_NOT_SUPPORTED;
    hospi->Init.ClockPrescaler          = 2; // Base: HSE = 16MHz  PLL1*N=20 PLL1/Q=2 => Base=160MHz -> Precaler=2 -> OSPI=80 MHz 
    hospi->Init.SampleShifting          = HAL_OSPI_SAMPLE_SHIFTING_NONE; // None
    hospi->Init.DelayHoldQuarterCycle   = HAL_OSPI_DHQC_ENABLE;
    hospi->Init.ChipSelectBoundary      = 8; //32 MB / 128 KB = 256 → 2^8
    hospi->Init.DelayBlockBypass        = HAL_OSPI_DELAY_BLOCK_USED;
    hospi->Init.MaxTran                 = 0;
    hospi->Init.Refresh                 = 320; //640; //320 -> // 

  /* 
  Refresh value: 
    OCTOSPI Clock period x Refresh = tCEM 
  
  160MHz = 0,00000000625 sec
  100MHz = 0,00000001 sec
  80MHz  = 0,0000000125 sec
  55MHz  = 0,0000000182 sec
  4 us = 0,000004 sec
  8 us = 0,000008 sec
  
  Refresh = tCEM / Clock -> 640


  4 us @ 80MHz  -> 320
  4 us @ 100MHz -> 400
  4 us @ 160MHz -> 640
  8 us @ 80MHz  -> 640
  8 us @ 160MHz -> 1280
  
  4 us @ 55MHz  -> 220

  ISSI : 
    tCSM Chip Select Maximum Low Time ( ~ 85°C @ 166MHz ) = 4.0 us
  APMem:
    tCEM CE# low pulse width Standard temp @ 109MHz = 8 us
  */


    if (HAL_OSPI_Init(hospi) != HAL_OK)
    {
        ERROR("OSPI Init Error!\n");
        Error_Handler();
    }

    // OSPI Manager configuration : 2 device multiplexed , except CS
    sOspiManagerCfg.ClkPort    = 1;
    sOspiManagerCfg.DQSPort    = 1;
    sOspiManagerCfg.NCSPort    = (Instance == OCTOSPI1)?1:2;
    sOspiManagerCfg.IOLowPort  = HAL_OSPIM_IOPORT_1_LOW;
    sOspiManagerCfg.IOHighPort = HAL_OSPIM_IOPORT_1_HIGH;
    if (HAL_OSPIM_Config(hospi, &sOspiManagerCfg, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
    {
        ERROR("OSPI Manager Init Error!\n");
        Error_Handler();
    }
    

    // Configure Delay block if need
    if (hospi->Init.DelayBlockBypass  == HAL_OSPI_DELAY_BLOCK_USED)
    {
        HAL_OSPI_DLYB_CfgTypeDef HAL_OSPI_DLYB_Cfg_Struct = {0};
        HAL_OSPI_DLYB_Cfg_Struct.Units = 0;
        HAL_OSPI_DLYB_Cfg_Struct.PhaseSel = 0;
        if (HAL_OSPI_DLYB_SetConfig(hospi, &HAL_OSPI_DLYB_Cfg_Struct) != HAL_OK)
        {
            ERROR("OSPI Delay Block Init Error!\n");
            Error_Handler();
        }
    }
        
    Debug("%s() - Success!\n", __FUNCTION__);

}



/*********************************************
 * @brief Initialize ISSI PSRAM to memory mapped mode
 * 
 * @PAram hospi handle of the OSPI
 * @return true - Initilaization success
 * @return false - something went wrong
*********************************************/
bool PSRAM_ISSI_ModuleInit( OSPI_HandleTypeDef *hospi ) 
{

    OSPI_MemoryMappedTypeDef sMemMappedCfg;
    OSPI_RegularCmdTypeDef sCommand = {0};

    /* Enable Compensation cell */
    EnableCompensationCell();
    Debug("CompensationCell enabled\n");


    if (hospi->Init.DelayBlockBypass  == HAL_OSPI_DELAY_BLOCK_USED)
    {

        LL_DLYB_CfgTypeDef dlyb_cfg, dlyb_cfg_test;

        // Delay block configuration
        
        if (HAL_OSPI_DLYB_GetClockPeriod(hospi,&dlyb_cfg) != HAL_OK)
        {
            Debug("%s() - HAL_OSPI_DLYB_GetClockPeriod Error!\n",__FUNCTION__);
            Error_Handler() ;
        }

        dlyb_cfg.Units = 0;

        // when DTR, PhaseSel is divided by 4 (emperic value)
        dlyb_cfg.PhaseSel /= 4;

        // save the present configuration for check
        dlyb_cfg_test = dlyb_cfg;

        // set delay block configuration
        HAL_OSPI_DLYB_SetConfig(hospi,&dlyb_cfg);

        // check the set value
        HAL_OSPI_DLYB_GetConfig(hospi,&dlyb_cfg);
        if ((dlyb_cfg.PhaseSel != dlyb_cfg_test.PhaseSel) || (dlyb_cfg.Units != dlyb_cfg_test.Units))
        {
            Debug("%s() - HAL_OSPI_DLYB_GetConfig Error!\n",__FUNCTION__);
            return false ;
        }
    }


    // Configure_APMemory(hospi);
    uint16_t ramSize = Configure_ISSI(hospi);

    // Configure Memory Mapped mode
    if (hospi->Instance == OCTOSPI1) 
    {
        sCommand.FlashId            = HAL_OSPI_FLASH_ID_1;
    } 
    else if (hospi->Instance == OCTOSPI2) 
    {
        sCommand.FlashId            = HAL_OSPI_FLASH_ID_2;
    }


    // Configure Write command

    sCommand.OperationType      = HAL_OSPI_OPTYPE_WRITE_CFG;
    sCommand.Instruction        = ISSI_WRITE_COMMAND;//APS6408_WRITE_CMD;
    sCommand.DummyCycles        = ISSI_WRITE_DUMMY_CYCLES;//DUMMY_CLOCK_CYCLES_WRITE;

    sCommand.InstructionMode    = HAL_OSPI_INSTRUCTION_8_LINES;
    sCommand.InstructionSize    = HAL_OSPI_INSTRUCTION_16_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_DISABLE;

    sCommand.AlternateBytesMode = HAL_OSPI_ALTERNATE_BYTES_NONE;

    sCommand.DataMode           = HAL_OSPI_DATA_8_LINES;
    sCommand.DataDtrMode        = HAL_OSPI_ADDRESS_DTR_DISABLE;

    sCommand.DQSMode            = HAL_OSPI_DQS_ENABLE;
    sCommand.SIOOMode           = HAL_OSPI_SIOO_INST_EVERY_CMD;
    

    if (HAL_OSPI_Command(hospi, &sCommand, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
    {
        ERROR("Configure Write Command Error! \n");
        OSPI_Error();
        return false;
    }


    // Configure read command  
    sCommand.OperationType      = HAL_OSPI_OPTYPE_READ_CFG;
    sCommand.Instruction        = ISSI_READ_COMMAND; //APS6408_READ_CMD;
    sCommand.DummyCycles        = ISSI_READ_DUMMY_CYCLES; 
    sCommand.DQSMode            = HAL_OSPI_DQS_ENABLE;

    if (HAL_OSPI_Command(hospi, &sCommand, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
    {
        ERROR("Configure Read Command Error !\n");
        OSPI_Error();
        return false;
    }


    // Enable memory mapped mode 
    sMemMappedCfg.TimeOutActivation = HAL_OSPI_TIMEOUT_COUNTER_ENABLE;
    sMemMappedCfg.TimeOutPeriod     = 0xA0;//34;

    if (HAL_OSPI_MemoryMapped(hospi, &sMemMappedCfg) != HAL_OK)
    {
        ERROR("Configure Memory mapped mode Error !\n");
        OSPI_Error();
        return false;
    }


    Debug("%s() - Success: %d Mbyte \n",__FUNCTION__, ramSize);
    return true;
}



/*************************************
 * @brief PSRAM Initialization
 *************************************/
void PSRAM_Init()
{
    bool ret = true;
    Debug("=== PSRAM 1 INIT ===\n");
    OSPI_ISSI_PSRAM_Init(&hospi1_psram, OCTOSPI1);
    if (PSRAM_ISSI_ModuleInit( &hospi1_psram ) == true)
    {
        hexdump("OSPI1 Data MemoryMapped Mode",(uint8_t*)OCTOSPI1_BASE, 128 );

        if (PSRAM_Test( OCTOSPI1_BASE ) == true){
            Debug("PSRAM 1 test Success!\n");
        } else {
            ERROR("PSRAM 1 test Error!\n");
            ret = false;
        }
    }
    else 
    ret = false;

    if (ret == false){
        ERROR("OSPI PSRAM initialization failed!\n");
        Error_Handler();
    }
}

Thank You!

0 REPLIES 0