cancel
Showing results for 
Search instead for 
Did you mean: 

STM32U5 OSPI communication with IS66WVO32M8 ISSI OctalRAM failing read operations

wwoods93
Associate

Hello,

I am working with the STM32U585AI using OCTOSPI2 to interface with the IS66WVO32M8 32 Mbyte ISSI OctalRAM. Currently I am facing an issue of read operations failing for both register and memory access, both in and out of OPI DTR mode. Register reads return a value of 0x8080 or 0x8888. Memory reads (using both HAL_OSPI_Receive() and HAL_OSPI_Receive_DMA() return some sequence of 0x80s and 0x88s in the amount of data requested (32 byte read returns 32 bytes of 0x80, 0x88, or some combination).

 

Here is my OCTOSPI2 initialization:

void MX_OCTOSPI2_Init(void)
{

  /* USER CODE BEGIN OCTOSPI2_Init 0 */

  /* USER CODE END OCTOSPI2_Init 0 */

  OSPIM_CfgTypeDef sOspiManagerCfg = {0};
  HAL_OSPI_DLYB_CfgTypeDef HAL_OSPI_DLYB_Cfg_Struct = {0};

  /* USER CODE BEGIN OCTOSPI2_Init 1 */

  /* USER CODE END OCTOSPI2_Init 1 */
  hospi2.Instance = OCTOSPI2;
  hospi2.Init.FifoThreshold = 1;
  hospi2.Init.DualQuad = HAL_OSPI_DUALQUAD_DISABLE;
  hospi2.Init.MemoryType = HAL_OSPI_MEMTYPE_MACRONIX_RAM;
  hospi2.Init.DeviceSize = 25;
  hospi2.Init.ChipSelectHighTime = 1;
  hospi2.Init.FreeRunningClock = HAL_OSPI_FREERUNCLK_DISABLE;
  hospi2.Init.ClockMode = HAL_OSPI_CLOCK_MODE_0;
  hospi2.Init.WrapSize = HAL_OSPI_WRAP_NOT_SUPPORTED;
  hospi2.Init.ClockPrescaler = 4;
  hospi2.Init.SampleShifting = HAL_OSPI_SAMPLE_SHIFTING_NONE;
  hospi2.Init.DelayHoldQuarterCycle = HAL_OSPI_DHQC_ENABLE;
  hospi2.Init.ChipSelectBoundary = 4;
  hospi2.Init.DelayBlockBypass = HAL_OSPI_DELAY_BLOCK_USED;
  hospi2.Init.MaxTran = 0;
  hospi2.Init.Refresh = 320;
  if (HAL_OSPI_Init(&hospi2) != HAL_OK)
  {
    Error_Handler();
  }
  sOspiManagerCfg.ClkPort = 2;
  sOspiManagerCfg.DQSPort = 2;
  sOspiManagerCfg.NCSPort = 2;
  sOspiManagerCfg.IOLowPort = HAL_OSPIM_IOPORT_2_LOW;
  sOspiManagerCfg.IOHighPort = HAL_OSPIM_IOPORT_2_HIGH;
  if (HAL_OSPIM_Config(&hospi2, &sOspiManagerCfg, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
  {
    Error_Handler();
  }
  HAL_OSPI_DLYB_Cfg_Struct.Units = 0;
  HAL_OSPI_DLYB_Cfg_Struct.PhaseSel = 0;
  if (HAL_OSPI_DLYB_SetConfig(&hospi2, &HAL_OSPI_DLYB_Cfg_Struct) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN OCTOSPI2_Init 2 */

  /* USER CODE END OCTOSPI2_Init 2 */

}

 

Register read:

Status Driver::readRegister(uint32_t reg_address, uint16_t* value) {
    if (!value) {
        return Status::INVALID_PARAM;
    }

    if (currentMode_ != OperatingMode::COMMAND_MODE) {
        if (disableMemoryMapped() != Status::OK) {
            return Status::ERROR;
        }
    }

    OSPI_RegularCmdTypeDef cmd = {};

    cmd.OperationType      = HAL_OSPI_OPTYPE_COMMON_CFG;
    cmd.FlashId            = HAL_OSPI_FLASH_ID_1;
    cmd.Instruction        = OCTALRAM_READ_REG_CMD; // 0xC000
    cmd.InstructionMode    = HAL_OSPI_INSTRUCTION_1_LINE;
    cmd.InstructionSize    = HAL_OSPI_INSTRUCTION_16_BITS;
    cmd.InstructionDtrMode = HAL_OSPI_INSTRUCTION_DTR_DISABLE;
    cmd.Address            = reg_address;
    cmd.AddressMode        = HAL_OSPI_ADDRESS_1_LINE;
    cmd.AddressSize        = HAL_OSPI_ADDRESS_32_BITS;
    cmd.AddressDtrMode     = HAL_OSPI_ADDRESS_DTR_DISABLE;
    cmd.AlternateBytesMode = HAL_OSPI_ALTERNATE_BYTES_NONE;
    cmd.DataMode           = HAL_OSPI_DATA_1_LINE;
    cmd.DataDtrMode        = HAL_OSPI_DATA_DTR_DISABLE;
    cmd.NbData             = 2U;
    cmd.DummyCycles        = 4U;
    cmd.DQSMode            = HAL_OSPI_DQS_DISABLE;
    cmd.SIOOMode           = HAL_OSPI_SIOO_INST_EVERY_CMD;

    if (HAL_OSPI_Command(ospiHandle_, &cmd, config_.timeoutMs) != HAL_OK) {
        return Status::ERROR;
    }

    uint8_t reg_data[2U];
    if (HAL_OSPI_Receive(ospiHandle_, reg_data, config_.timeoutMs) != HAL_OK) {
        return Status::ERROR;
    }

    *value = (reg_data[0U] << 8U) | reg_data[1U];
    return Status::OK;
}

 

And I am primarily focused on the DMA memory read (seeing same behavior with and without DMA):

 

Status Driver::readDMA(uint32_t address, uint8_t* data, uint32_t size, DMACallback callback) {
 if (!data || size == 0 || address + size > OCTALRAM_SIZE) {
        return Status::INVALID_PARAM;
    }

    if (dmaBusy_) {
        return Status::BUSY;
    }

    if (currentMode_ != OperatingMode::COMMAND_MODE) {
        if (disableMemoryMapped() != Status::OK) {
            return Status::ERROR;
        }
    }

    // memset(&dmaRxBuffer_, '\0', sizeof(dmaRxBuffer_));
    for (uint16_t i = 0; i < 512; ++i) {
        dmaRxBuffer_[i] = 0U;
    }

    dmaCallback_ = callback;
    dmaBusy_ = true;

    // read command
    OSPI_RegularCmdTypeDef cmd = {};
    cmd.OperationType      = HAL_OSPI_OPTYPE_COMMON_CFG;
    cmd.FlashId            = HAL_OSPI_FLASH_ID_1;
    cmd.Instruction        = OCTALRAM_READ_CMD; // 0x8000
    cmd.InstructionMode    = HAL_OSPI_INSTRUCTION_8_LINES;
    cmd.InstructionSize    = HAL_OSPI_INSTRUCTION_16_BITS;
    cmd.InstructionDtrMode = HAL_OSPI_INSTRUCTION_DTR_ENABLE;
    cmd.Address            = address;
    cmd.AddressMode        = HAL_OSPI_ADDRESS_8_LINES;
    cmd.AddressSize        = HAL_OSPI_ADDRESS_32_BITS;
    cmd.AddressDtrMode     = HAL_OSPI_ADDRESS_DTR_ENABLE;
    cmd.AlternateBytesMode = HAL_OSPI_ALTERNATE_BYTES_NONE;
    cmd.DataMode           = HAL_OSPI_DATA_8_LINES;
    cmd.DataDtrMode        = HAL_OSPI_DATA_DTR_ENABLE;
    cmd.NbData             = size;
    cmd.DummyCycles        = 5U;
    cmd.DQSMode            = HAL_OSPI_DQS_DISABLE;
    cmd.SIOOMode           = HAL_OSPI_SIOO_INST_EVERY_CMD;

    if (HAL_OSPI_Command(ospiHandle_, &cmd, config_.timeoutMs) != HAL_OK) {
        dmaBusy_ = false;
        return Status::ERROR;
    }

    if (HAL_OSPI_Receive_DMA(ospiHandle_, dmaRxBuffer_) != HAL_OK) {
        dmaBusy_ = false;
        return Status::ERROR;
    }
    while (dmaBusy_); // set in callback

    for (uint16_t i = 0; i < size; ++i) {
        data[i] = dmaRxBuffer_[i];
    }

    return Status::OK;
}

 I have referenced several other posts that have experienced similar issues with octospi and/or provide instruction on the same/similar memory device.

This post seems to indicate the same issue appearing on STM32H7:

https://community.st.com/t5/stm32-mcus-products/stm32h730-with-octalspi-issi-is66wvo8m8-psram/td-p/698387

And I have been unable to replicate even the partial success found by this user (again on STM32H7, not STM32U5 but using the IS66WVO32):

https://community.st.com/t5/stm32-mcus-products/problem-with-psram-peripherals-of-stm32h735/td-p/706406

 

DMA functions and interrupts are all working properly (and non-DMA/polling show the same behavior). I have experimented with using AP memory type setting for the conventional SPI commands as described in the second link above to no avail, and have tried a wide variety of configurations of the ISSI device itself. Unfortunately, I have limited ability to probe the device and cannot confirm definitively that the settings are being applied without being able to read the registers.

 

I believe at this point I am doing everything correctly. It seems that this is potentially an unresolved problem across other similar devices as well (based on other reports of similar OSPI memories reading back 0x88 under similar conditions), although none of the  STM32U575xx/STM32U585xx OCTOSPI-related entries seem to cover this failure mode.

What could be causing the junk read-back values? Is there a solution for the IS66WVO32M8 to work with the STM32U585 in any capacity? Changing memory chips effectively isn't an option for us with current timelines, but any feedback on the current approach or suggestions of different avenues to pursue would be greatly appreciated.

 

Thanks very much for your time.

 

0 REPLIES 0