2025-09-19 1:51 AM
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).
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*)( ®Val ), 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*)( ®Val), 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*)( ®Val), 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!