Skip to main content
Explorer II
January 8, 2024
Question

Configuring OSPI in QSPI with Memory Mapped

  • January 8, 2024
  • 6 replies
  • 3773 views

I am trying to setup my STM32H725 to use serial RAM in memory mapped mode. The memory I am using is:

IS66WVS4M8ALL RAM Datasheet

I have used IOC to setup the OCTOSPI1 as a QSPI peripheral and mapped CS IO0/1/2/3 CLK from the uC to the RAM.

I have tried to firstly set the RAM for 4 pin access, then setup the cfg for read and write, finally enable the memory mapped mode. Though it does not work, in debug mode it typically crashes at some point.

I have modified the init for Octospi accordingly:

 

static void MX_OCTOSPI1_Init(void)

{

 

/* USER CODE BEGIN OCTOSPI1_Init 0 */

 

/* USER CODE END OCTOSPI1_Init 0 */

 

OSPIM_CfgTypeDef sOspiManagerCfg = {0};

 

/* USER CODE BEGIN OCTOSPI1_Init 1 */

 

/* USER CODE END OCTOSPI1_Init 1 */

/* OCTOSPI1 parameter configuration*/

hospi1.Instance = OCTOSPI1;

hospi1.Init.FifoThreshold = 1;

hospi1.Init.DualQuad = HAL_OSPI_DUALQUAD_DISABLE;

hospi1.Init.MemoryType = HAL_OSPI_MEMTYPE_MICRON;

hospi1.Init.DeviceSize = 25;

hospi1.Init.ChipSelectHighTime = 5;

hospi1.Init.FreeRunningClock = HAL_OSPI_FREERUNCLK_DISABLE;

hospi1.Init.ClockMode = HAL_OSPI_CLOCK_MODE_0;

hospi1.Init.WrapSize = HAL_OSPI_WRAP_NOT_SUPPORTED;

hospi1.Init.ClockPrescaler = 2;

hospi1.Init.SampleShifting = HAL_OSPI_SAMPLE_SHIFTING_NONE;

hospi1.Init.DelayHoldQuarterCycle = HAL_OSPI_DHQC_ENABLE;

hospi1.Init.ChipSelectBoundary = 0;

hospi1.Init.DelayBlockBypass = HAL_OSPI_DELAY_BLOCK_BYPASSED;

hospi1.Init.MaxTran = 0;

hospi1.Init.Refresh = 241;

if (HAL_OSPI_Init(&hospi1) != HAL_OK)

{

Error_Handler();

}

sOspiManagerCfg.ClkPort = 1;

sOspiManagerCfg.NCSPort = 1;

sOspiManagerCfg.IOLowPort = HAL_OSPIM_IOPORT_1_LOW;

if (HAL_OSPIM_Config(&hospi1, &sOspiManagerCfg, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)

{

Error_Handler();

}

 

/* USER CODE BEGIN OCTOSPI1_Init 2 */

OSPI_RegularCmdTypeDef sCommand;

OSPI_MemoryMappedTypeDef sMemMappedCfg;

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_4_LINES;

sCommand.AddressSize = HAL_OSPI_ADDRESS_24_BITS;

sCommand.AddressDtrMode = HAL_OSPI_ADDRESS_DTR_ENABLE;

sCommand.AlternateBytesMode = HAL_OSPI_ALTERNATE_BYTES_NONE;

sCommand.DataMode = HAL_OSPI_DATA_1_LINE;

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;

sCommand.DummyCycles = 0;

 

/* Command SPI to be in QSPI Mode */

sCommand.OperationType = HAL_OSPI_OPTYPE_COMMON_CFG;

sCommand.Instruction = 0x35; //set to quad mode

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

HAL_OK)

{

Error_Handler();

}

 

uint8_t dummyData[] = {0,0,0,0};

if (HAL_OSPI_Transmit(&hospi1, dummyData, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) !=

HAL_OK)

{

Error_Handler();

}

 

 

 

sCommand.InstructionMode = HAL_OSPI_INSTRUCTION_4_LINES;

sCommand.DataMode = HAL_OSPI_DATA_4_LINES;

 

/* Configure write operations */

sCommand.OperationType = HAL_OSPI_OPTYPE_WRITE_CFG;

sCommand.Instruction = 0x38;

sCommand.DummyCycles = 0;

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

HAL_OK)

{

Error_Handler();

}

/* Configure read operations */

sCommand.OperationType = HAL_OSPI_OPTYPE_READ_CFG;

sCommand.Instruction = 0xEB; //QCmd, QIO, upto 104MHz

sCommand.DummyCycles = 6;

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

HAL_OK)

{

Error_Handler();

}

 

sMemMappedCfg.TimeOutActivation = HAL_OSPI_TIMEOUT_COUNTER_DISABLE;

/*Enable memory mapped mode*/

if (HAL_OSPI_MemoryMapped(&hospi1, &sMemMappedCfg) != HAL_OK)

{

Error_Handler();

}

 

 

volatile uint32_t *externalFlash = 0x90000000;

uint32_t val1 = externalFlash[0];

HAL_Delay(1);

uint32_t val2 = externalFlash[1];

HAL_Delay(1);

externalFlash[0] = 10;

HAL_Delay(1);

externalFlash[1] = 10;

HAL_Delay(1);

val1 = externalFlash[0];

HAL_Delay(1);

val2 = externalFlash[1];

HAL_Delay(1);

/* USER CODE END OCTOSPI1_Init 2 */

 

}

 

 

    This topic has been closed for replies.

    6 replies

    Visitor II
    January 8, 2024

    Utilize the debugging features of your development environment. Check if there are any specific error codes returned by the HAL functions. Also, monitor the SPI signals using an oscilloscope if possible to ensure that the signals are as expected

    Explorer II
    January 8, 2024

    Sure - so I was able to do that for the config sections and that helped a lot. Now I am stepping line by line towards the end. The write commands run (I will have a scope to test it) but the read commands hang the device. I do not know how I could debug these lines of code? I just get "Target is not responding, retrying..."?

    Technical Moderator
    January 8, 2024

    Hello @sternpost_0122 

    You need to configure your target in Single SPI mode then to enter QuadMode, you need to set AddressMode, DataMode to None 

    FBelaid_0-1704720274625.png

     

    Explorer II
    January 8, 2024

    Thanks - I did try that but I wasn't sure how to send that command. So if I set the DataMode/AddreMode to none it will use HAL_OSPI_Command to send the command as well?

    Explorer II
    January 8, 2024

    Found a few topics:

    STM32H723 - Problem with Serial RAM in memory mapp... - Page 2 - STMicroelectronics Community

    stm32h7 - STM32H723 - Problem with Serial RAM in memory mapped mode - Stack Overflow

     

    Seems that it just doesn't work.... I copied most of the code from the second link and based on the advice that uint_64 works I just cast(is that the term) my byte array as a uint64_t.  

    Not the prettiest solution but I am getting sumerr = 0 always now.

    //Write in byte format

    for(uint32_t i = 0; i < 8000; i++){

    NMB[i] = i;

    }

     

    uint64_t *internal_buffer =(uint64_t *) NMB;

    uint64_t *external_flash = (uint64_t *) 0x90000000;

     

    //Pretend it is a uint64_t

    for(uint32_t i = 0; i < 1000; i++){

    external_flash[i] = internal_buffer[i];

    }

     

    //Clear local copy

    for(uint32_t i = 0; i < 8000; i++){

    NozzleMaskBuffer[i] = 0;

    }

     

    uint32_t sumerr = 0;

     

    //Get new version (assuming its uint64_t)

    for(uint32_t i = 0; i < 1000; i++){

    internal_buffer[i] = external_flash[i];

    }

     

    //Compare

    for(uint32_t i = 0; i < 8000; i++){

    if(NMB[i] != (i%256)){

    sumerr++;}

    }

     

    HAL_Delay(10);

     

    Graduate II
    January 8, 2024

    With Memory Mapped it is just stuffing templates filled with the address of the interaction.

    To debug the operations it will be easier to use the direct commands, and validate expectations there. That way you're less likely to stall the processor, and lose debug access.

    Also I'd strongly recommend clearing complex structures used as auto/local variables, so random stack junk is not applied to the peripheral registers.