Skip to main content
Associate
October 16, 2025
Solved

STM32H747 Memory Mapped NOR-Flash AT25SF128A

  • October 16, 2025
  • 4 replies
  • 675 views

Hi,

I'm trying to implement an external loader for the Arduino Giga R1 board with AT25S128A 128Mbit of external flash. After following the guide given in the external loader repo, I'm running into the problem, that I can erase, write & read from the memory fine, however, as soon as I try to turn on memory mapped mode, all the data reads as 0xFF...FF, both in code and in the STM32CubeIDE memory viewer. I think my problems could be related to MCU configuration, I would be grateful if someone could give some guidance, see the relevant code below and attached. 

quadspi.c:

uint8_t CSP_QSPI_EnableMemoryMappedMode(void) {
	QSPI_CommandTypeDef sCommand = { 0 };
	QSPI_MemoryMappedTypeDef sMemMappedCfg = { 0 };

	// Enable Memory-Mapped mode
	sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE;
	sCommand.Instruction = QUAD_INOUT_FAST_READ_CMD;
	sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
	sCommand.AddressMode = QSPI_ADDRESS_4_LINES;
	sCommand.AddressSize = QSPI_ADDRESS_24_BITS;
	sCommand.DataMode = QSPI_DATA_4_LINES;
	sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_4_LINES;
	sCommand.AlternateBytesSize = QSPI_ALTERNATE_BYTES_8_BITS;
	sCommand.AlternateBytes = 0x00;
	sCommand.DummyCycles = 4;
	sCommand.DdrMode = QSPI_DDR_MODE_DISABLE;
	sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;

//	sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE;
//	sCommand.Instruction = QUAD_OUT_FAST_READ_CMD;
//	sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
//	sCommand.AddressMode = QSPI_ADDRESS_1_LINE;
//	sCommand.AddressSize = QSPI_ADDRESS_24_BITS;
//	sCommand.Address = 0;
//	sCommand.DataMode = QSPI_DATA_4_LINES;
//	sCommand.NbData = 0;
//	sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_1_LINE;
//	sCommand.AlternateBytesSize = QSPI_ALTERNATE_BYTES_8_BITS;
//	sCommand.AlternateBytes = 0x00;
//	sCommand.DummyCycles = 0;
//	sCommand.DdrMode = QSPI_DDR_MODE_DISABLE;
//	sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;

	sMemMappedCfg.TimeOutActivation = QSPI_TIMEOUT_COUNTER_DISABLE;
	sMemMappedCfg.TimeOutPeriod = 0;

	if (HAL_QSPI_MemoryMapped(&hqspi, &sCommand, &sMemMappedCfg) != HAL_OK) {
		return HAL_ERROR;
	}

	return HAL_OK;
}

main.c test snippet:

 CSP_QUADSPI_Init();

 for (var = 0; var < MEMORY_SECTOR_SIZE; var++) {
 buffer_test[var] = (var & 0xFF);
 }
 for (var = 0; var < SECTORS_COUNT; var++) {
 if (CSP_QSPI_EraseSector(var * MEMORY_SECTOR_SIZE, (var + 1) * MEMORY_SECTOR_SIZE - 1) != HAL_OK) {
 while (1) {}
 }
 if (CSP_QSPI_WriteMemory(buffer_test, var * MEMORY_SECTOR_SIZE, sizeof(buffer_test)) != HAL_OK) {
 while (1) {}
 }
 if (CSP_QSPI_ReadMemory(buffer_read, var * MEMORY_SECTOR_SIZE, sizeof(buffer_test)) != HAL_OK) {
 while (1) {}
 }
 }

 if (CSP_QSPI_EnableMemoryMappedMode() != HAL_OK) {
 while (1) {}
 }
 uint8_t verify_buffer[MEMORY_SECTOR_SIZE] = {0};
 for (var = 0; var < SECTORS_COUNT; var++) {
 if (memcpy(verify_buffer, (uint8_t*) (0x90000000 + var * MEMORY_SECTOR_SIZE), MEMORY_SECTOR_SIZE) != HAL_OK) {
 while (1) {}
 }
 }

 

 Thank you for your help.

Best answer by EmbeddedOrca

Hi Dmitry, 

I have finally solved the... I accidentally performed block erases instead of sector erases which led to my "tests" not working. Thank you very much for the input. 

Jonah

4 replies

KDJEM.1
Technical Moderator
October 16, 2025

Hello @EmbeddedOrca and welcome to the community;

 

Could you please check if the write operation is done successfully?

Note only read operations are allowed to the external flash memory in memory-mapped mode. The indirect mode supports read and write operations.

 

Thank you.

Kaouthar

To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.
Associate
October 16, 2025

Hi Kaouthar,

Thank you for your answer. I'm only doing read operations after activating memory mapped mode as far as I'm aware. Also, I've checked that the read operation works by setting a breakpoint after the first memory write-read sequence in the main function. 

BR,

Jonah

 

DmitryR
Associate III
October 16, 2025

Hello @EmbeddedOrca ,

 

consider configuring absolutely all kinds of transmission to 4-line mode.

 

With best regards,

Dmitry

Associate
October 16, 2025

Hi Dmitry,

I'm not quite sure what change exactly you are suggesting. As far as I can see I'm doing all operations in the fastest / most parallel operation the flash chip supports.

Best regards,

Jonah

DmitryR
Associate III
October 16, 2025

Hello @EmbeddedOrca ,

 

for example you have configuration QSPI_INSTRUCTION_1_LINE and QSPI_ADDRESS_4_LINES. Try to change configuration so that absolutely all modes are configured the same - all for 4 lines or all for 1 line.

 

Then, when inserting breakpoint changes behavior often means that you have a race condition.

 

With best regards,

Dmitry

Visitor II
November 19, 2025

Hi @EmbeddedOrca ,

 

I am also trying to implement an external loader for the arduino giga. The test application seems to work fine (with the help of the files you attached). Read, write erase & mem mapped works without much issue. However I am facing issues when I continue with the next steps to create the stlrd. Would it be possible to share also the other files needed to create the loader or loader itself?

 

It is my first time trying to create an external loader and I dont understand it fully how it works.

 

Thank you!

 

Mario

Associate
November 20, 2025

Hi @mpaj ,

Sorry for the late reply. Please find the whole project attached, the .stldr file is included as well. As far as i remember, you have to build the project in the release configuration for the M7 core and then rename the .elf file with .stldr extension.

All the best,

Jonah

Visitor II
November 21, 2025

@EmbeddedOrca Thank you a lot for your help! :)