2024-03-04 06:34 AM
Hello I am in the task of adding a new flash as an external flash via QSPI interface with the MCU STM32F777ZITx.
The flash that I want to add is S25FL256L as an external flash. I am not finding any references which I can use with this flash. Also it is not getting clear to me whether I need to make an external loader for mapping the external flash in memory mapped mode or only configuration is needed ?
2024-03-04 06:53 AM
2024-03-04 07:18 AM
An "external loader" is needed only if you want CubeIDE debugger load the content of your QSPI flash automatically when you start debugging (or running). Also if you use CubeProgrammer to program the QSPI flash. If you use other way to load the QSPI flash content, external loader is not needed. For example - if the ext. flash is used to store data that your application produces, or receives from outside.
Here is the one part of the ST BSP driver for similar flash chip S25FL512s:
https://github.com/STMicroelectronics/stm32-s25fl512s
2024-03-04 10:06 AM
I am facing this problem where the call to the CSP_QSPI_EnableMemoryMappedMode does not fail but the external flash looks like this even after writing something
2024-03-04 10:25 AM - edited 2024-03-04 10:41 AM
You'll need an External Loader if you want the tools to download content.
To see the memory in the Debugger, etc, you'll need for your code to have successfully brought up the QSPI interface, pins, and external memory itself.
You should be able to implement read, write, and command functions to interact with the memory. Try reading the JEDEC ID and some pages first. Once you have that working you can provide this "Read Template" functionality to the Memory Mapping mode startup process, and then access to the 0x90000000 region will use that to allow the MCU to read the content.
Yours looks like the memory mapping still isn't working, and the access to 0x90000000 is faulting.
Start by reading the data/sheets and manuals for your S25FL256 memory, and get that working in your own BSP code.
2024-03-04 10:27 AM
>>Also it is not getting clear to me whether I need to make an external loader for mapping the external flash in memory mapped mode or only configuration is needed ?
Configuration here, but blank content will be 0xFF
Unconfigured, accesses will Hard Fault. Have a Hard Fault Handler that outputs actionable information so you can diagnose / debug the situation.
2024-03-04 10:31 AM
I mean the confusion I have is that to view the memory map in the debugging window external loader is not needed right ?
2024-03-04 10:46 AM
No, but the memory needs to be up and running. It needs to be visible to the MCU to be visible in the Debugger.
The way ST does things this will be deep into main() once you've called all the functions. What *ARM* wanted was this do be done in SystemInit(), so the memory is viable for C runtime initialization and the scatter loader, so that in main() you had a nearly complete operating environment working.
In other platforms the alternative is a "Debug Script" which peeks/pokes the system and peripheral registers to bring up the clocks, GPIO, and QSPI peripheral, and the attached memory.
ST could perhaps use the Init() function of the External Loader in-lieu of the platform suitable debugger script, but I'm not sure things are at that level of sophistication a decade in.
2024-03-05 12:19 AM
Also I believe no modifications in the .ld script just to read the manufacturer ID ?
2024-03-05 04:06 AM - edited 2024-03-05 04:32 AM
No modifications in the .ld script. See below code to read S25FL256 ID on STM32F7. Change the ID for S25FL512 per the data sheet.
int8_t BSP_QSPI_FlashDetect(struct QSPI_FlashInfo *pInfo;)
{
uint8_t rc;
// Ensure it is reset to normal "indirect" mode
if (QSPI_ResetMemory(&QSPIHandle) != QSPI_OK)
{
return QSPI_NOT_SUPPORTED;
}
HAL_Delay(100); //?? needs delay after reset?
uint8_t id_buf[6];
rc = BSP_QSPI_ReadFlashID(id_buf, sizeof(id_buf));
if (QSPI_OK != rc) {
dbgprintf("ReadID failed: %u\n", (unsigned)rc);
return -1;
}
// Infineon S25FL256LAGNFI010
const uint8_t id2_data[] = { 0x01, 0x60, 0x19, };
// 0x19-> 32MB, 0x18 -> 16 MB
// see [DS2, table 51]
unsigned fl_mb = 0;
if (0 == memcmp(id2_data, id_buf, 2)) {
qi.FlashModel = 'S';
switch(id_buf[2]) {
case 0x18: fl_mb = 16; break;
case 0x19: fl_mb = 32; break;
case 0x1A: fl_mb = 64; break;
default:
dbgprintf("ERROR: QSPI Flash size code no match: %2.2X\n", id_buf[2]);
return QSPI_NOT_SUPPORTED;
}
} else {
dbgprintf("ERROR: QSPI Flash ID no match: %2.2X %2.2X\n", id_buf[0], id_buf[1]);
return QSPI_NOT_SUPPORTED;
}
// Fill the flash characteristics:
// In 3-byte address mode, only 16 MB are available!
pInfo->FlashSize = fl_mb * 1024u*1024u;
pInfo->EraseSectorSize = 4*1024u; //4K
pInfo->BigEraseSectorSize = 64*1024u; //64K
pInfo->ProgPageSize = 256;
pInfo->EraseSectorsNumber = pInfo->FlashSize/pinfo->EraseSectorSize;
pInfo->ProgPagesNumber = pInfo->FlashSize/pInfo->ProgPageSize;
pInfo->DummyCycles = 0; //dummy cycles not configured yet! TODO
return QSPI_OK;
}
int8_t BSP_QSPI_ReadFlashID(uint8_t *id_buf, unsigned size)
{
QSPI_HandleTypeDef *Ctx = &QSPIHandle;
if (!id_buf || size < 1 || size > 256) {
return QSPI_NOT_SUPPORTED;
}
QSPI_CommandTypeDef s_command = {
.InstructionMode = QSPI_INSTRUCTION_1_LINE,
.Instruction = 0x9F,
.AddressMode = QSPI_ADDRESS_NONE,
.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE,
.DataMode = QSPI_DATA_1_LINE,
.NbData = 0,
.DummyCycles = 0,
.DdrMode = QSPI_DDR_MODE_DISABLE,
.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY,
.SIOOMode = QSPI_SIOO_INST_EVERY_CMD,
};
/* Configure the command */
s_command.NbData = size;
if (HAL_QSPI_Command(Ctx, (void*)&s_command, 10) != HAL_OK)
{
return QSPI_ERROR;
}
/* Reception of the data */
if (HAL_QSPI_Receive(Ctx, id_buf, 10) != HAL_OK)
{
return QSPI_ERROR;
}
return QSPI_OK;
}