Skip to main content
Visitor II
August 14, 2025
Solved

mt25ql512abb in memory mapped mode not working

  • August 14, 2025
  • 1 reply
  • 632 views

I am writing a custom driver for the mt25ql512abb as the one on STM's github doesnt work for my STM32L412KB, I have gotten reading, writing and erasing working but when I try enter memory mapped mode DQ[0-3] on the flash just goes high

Here is my function that im using, I am setting the XIP bit on the Volatile configuration register first (i have confirmed this is working) then I enter memory mapped mode, i have set the dummy cycles to 10 on the volatile and non-volatile configuration registers as well.

 

 
uint8_t CSP_QSPI_EnableMemoryMappedMode(void) {



QSPI_CommandTypeDef sCommand;

QSPI_MemoryMappedTypeDef sMemMappedCfg;



/* Enable Memory-Mapped mode-------------------------------------------------- */



sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE;

sCommand.AddressSize = QSPI_ADDRESS_32_BITS;

sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;

sCommand.DdrMode = QSPI_DDR_MODE_DISABLE;

sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;

sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;

sCommand.AddressMode = QSPI_ADDRESS_4_LINES;

sCommand.DataMode = QSPI_DATA_4_LINES;

sCommand.NbData = 0;

sCommand.Address = 0;

sCommand.Instruction = 0xeb;

sCommand.DummyCycles = 10;



sMemMappedCfg.TimeOutActivation = QSPI_TIMEOUT_COUNTER_DISABLE;



uint8_t config = 0xa3;

if(QSPI_WriteVCR(&config) != HAL_OK) {

return HAL_ERROR;

}



if (HAL_QSPI_MemoryMapped(&hqspi, &sCommand, &sMemMappedCfg) != HAL_OK) {

return HAL_ERROR;

}

return HAL_OK;

}

 

Here is my working read memory function

 
uint8_t CSP_QSPI_ReadMemory(uint8_t* buffer, uint32_t address, uint32_t buffer_size) {



QSPI_CommandTypeDef sCommand;

uint32_t end_addr, current_size, current_addr;



/* Calculation of the size between the write address and the end of the page */

current_addr = 0;



while (current_addr <= address) {

current_addr += MEMORY_PAGE_SIZE;

}

current_size = current_addr - address;



/* Check if the size of the data is less than the remaining place in the page */

if (current_size > buffer_size) {

current_size = buffer_size;

}



/* Initialize the adress variables */

current_addr = address;

end_addr = address + buffer_size;



sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE;

sCommand.AddressSize = QSPI_ADDRESS_32_BITS;

sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;

sCommand.DdrMode = QSPI_DDR_MODE_DISABLE;

sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;

sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;

sCommand.Instruction = 0xeb;

sCommand.AddressMode = QSPI_ADDRESS_4_LINES;

sCommand.DataMode = QSPI_DATA_4_LINES;

sCommand.NbData = buffer_size;

sCommand.Address = address;

sCommand.DummyCycles = 10;



/* Perform the write page by page */

do {

sCommand.Address = current_addr;

sCommand.NbData = current_size;



if (current_size == 0) {

return HAL_OK;

}



/* Configure the command */

if (HAL_QSPI_Command(&hqspi, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE)

!= HAL_OK) {

return HAL_ERROR;

}



/* Transmission of the data */

if (HAL_QSPI_Receive(&hqspi, buffer, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) {

return HAL_ERROR;

}



/* Configure automatic polling mode to wait for end of program */

if (QSPI_AutoPollingMemReady(HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) {

return HAL_ERROR;

}



/* Update the address and size variables for next page programming */

current_addr += current_size;

buffer += current_size;

current_size =

((current_addr + MEMORY_PAGE_SIZE) > end_addr) ?

(end_addr - current_addr) : MEMORY_PAGE_SIZE;

} while (current_addr <= end_addr);



return HAL_OK;



}

 

any help would be great thanks

    This topic has been closed for replies.
    Best answer by Tesla DeLorean

    I mean you print the content to the console using a pointer to 0x90000000, so you can observe it reading content.

    Or you inspect in the debugger AFTER the memory has been mapped.

    On the CM7 you need to configure the MPU for code/execution access, I don't recall if the L4 / CM4 needs this, and found no example on the CubeL4 GitHub

    Have a viable Hard Fault Handler to report / dump issue if you end up there.

    The linker script just directs what content is placed in external memory, getting code there and calling it is more involved. It does need to be mapped first. Generally one would build a boot loader to bring up the system, pins and memory and then transfer control.

    The CM4 not being a particularly good choice as it lacks a cache, so code/data from external memory will be relatively slow.

    1 reply

    Graduate II
    August 14, 2025

    Use the Code Format </> icon to post code inline, that way it retains formatting and indentation, and doesn't appear as a wall of text. Use the 'V' icon in upper right of pane to edit you initial post to fix it.

    QSPI_CommandTypeDef sCommand = {0};
    QSPI_MemoryMappedTypeDef sMemMappedCfg = {0};

    I'd clear the local/auto variables to ensure there's not random stack junk in them.

    If the Read method works properly, the template for the  Memory Mapped should too. I don't think you need to set the VCR to XIP for this to work.

    If you dump the 0x90000000 memory content from your app what does that look like? Does it Hard Fault?

    You might want to configure the MPU for execution, but there's probably an example in CubeL4

     

    fhumphrysAuthor
    Visitor II
    August 14, 2025

    sorry fixed the code import, could you explain what you mean by dumping the memory content, and do you mean configure the MPU for external flash as i have put this  QSPI (rx) : ORIGIN = 0x90000000, LENGTH = 64M in my linker script, along with this

     .extFlashMem :
     {
     	*(.extFlashMem)
     } >QSPI
    Graduate II
    August 14, 2025

    I mean you print the content to the console using a pointer to 0x90000000, so you can observe it reading content.

    Or you inspect in the debugger AFTER the memory has been mapped.

    On the CM7 you need to configure the MPU for code/execution access, I don't recall if the L4 / CM4 needs this, and found no example on the CubeL4 GitHub

    Have a viable Hard Fault Handler to report / dump issue if you end up there.

    The linker script just directs what content is placed in external memory, getting code there and calling it is more involved. It does need to be mapped first. Generally one would build a boot loader to bring up the system, pins and memory and then transfer control.

    The CM4 not being a particularly good choice as it lacks a cache, so code/data from external memory will be relatively slow.