2023-10-23 12:13 PM - edited 2023-10-23 12:14 PM
Hi,
I need the project used to generate the external loader: MX25LM51245G_STM32H573I-DK.stldr. My custom board uses a STM32H563VIT6 and the same octo-spi flash from Macronix used in the STM32H573I-DK board. But with different gpios connections. So this project would be of great help to develop the external flash loader for my board.
Ari
2024-07-27 10:51 PM
Hello!
i have followed your advise , i have instrumented with UART
i found someting really strange to me:
the problem occours in this piece of code (that work without problem in the main):
2024-07-28 12:39 AM
Make sure hospi1 structure has the instance defined, there is not static initialization in loaders. Perhaps Hard Faulting or delays not working
2024-07-29 10:39 PM
Hi!
you were right!
the problem was the call to the HAL_XSPI_DeInit(&hospi1) before the call to MX_OCTOSPI1_Init()!
its not possible to just remove the HAL_XSPI_DeInit(&hospi1), because during the sectors erase the init is called before each sector erase by the st programmer
so i use this method:
now i am able to read an sector erase the external memory!!!
but not to write....
the write function is called multiple times.. but only the first is going OK
2024-07-30 01:53 AM
found the issue..
the HAL_XSPI_Abort(&hospi1) if don't have anything to abort return an error..
hospi->ErrorCode = HAL_OSPI_ERROR_INVALID_SEQUENCE;
the first time we call it the memory is in memory mapped mode.. so it is necessary and it work.. the second time it is not necessary and return error..
i have added a check on the status of the periferal before call the abort function and added the function that enable memory mapped mode at the end of the write (i do'n know if is necessary the last call of the write)..
so .. only the chip erase now is missing (its optional)
2024-07-30 06:52 AM
finally all is working!
the chip erase was a problem of timeout , the default autopolling have HAL_XSPI_TIMEOUT_DEFAULT_VALUE for timeout that is 5s, my memory have a typical erasing time of 140s to max 200s so i have increased the value to 200s and now its working!
i have tried to remove the offset to RAM (xrw) : ORIGIN = 0x20003004, LENGTH = 256K - 12292 but its actually necessary .. i think only ST could explain why!
i attache to this comment my working linker file and loader_src.c
thank you to everyone for the really precious advise!
2024-07-30 10:00 AM
Yes, the 0x20003004 needs a bit more documentation from ST, but is what other working H5 loaders use.
The +4 offset comes from the fact that ST stuffs opcodes at +0 to call the entry point functions, ie Init(), Read(), etc.
/**
* @brief Initializes the QSPI interface.
* @retval QSPI memory status
*/
static uint8_t BSP_XSPI_Init(XSPI_HandleTypeDef *hospi)
{
//memset(hospi, 0, sizeof(XSPI_HandleTypeDef));
hospi->Instance = OCTOSPI1; // For DeInit to bite on
/* Call the DeInit function to reset the driver */
if (HAL_XSPI_DeInit(hospi) != HAL_OK)
{
return(XSPI_ERROR);
}
/* System level initialization */
BSP_XSPI_MspInit(hospi, NULL);
/* OSPI initialization */
hospi->Init.FifoThresholdByte = 1; // 1..32 Interrupt threshold
...
2025-01-19 02:23 AM - edited 2025-01-19 02:23 AM
Hi,
i'm trying to develop a QuadSPI custom loader for STM32H563ZI with Macronix flash MX25L25645G. I started using the custom loader example attached in youtube video of ST (https://www.youtube.com/watch?v=XqCq0xtQmbI) ,porting library from QSPI to XSPI.
I found some differences in autopolling function:
in XSPI autopolling funcion is missing the "cmd" parameter, how do I manage this for example in the function below?
static uint8_t QSPI_WriteEnable(void) {
QSPI_CommandTypeDef sCommand;
QSPI_AutoPollingTypeDef sConfig;
/* Enable write operations ------------------------------------------ */
sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE;
sCommand.Instruction = WRITE_ENABLE_CMD;
sCommand.AddressMode = QSPI_ADDRESS_NONE;
sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
sCommand.DataMode = QSPI_DATA_NONE;
sCommand.DummyCycles = 0;
sCommand.DdrMode = QSPI_DDR_MODE_DISABLE;
sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
if (HAL_QSPI_Command(&hqspi, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE)
!= HAL_OK) {
return HAL_ERROR;
}
/* Configure automatic polling mode to wait for write enabling ---- */
sConfig.Match = 0x02;
sConfig.Mask = 0x02;
sConfig.MatchMode = QSPI_MATCH_MODE_AND;
sConfig.StatusBytesSize = 1;
sConfig.Interval = 0x10;
sConfig.AutomaticStop = QSPI_AUTOMATIC_STOP_ENABLE;
sCommand.Instruction = READ_STATUS_REG_CMD;
sCommand.DataMode = QSPI_DATA_1_LINE;
if (HAL_QSPI_AutoPolling(&hqspi, &sCommand, &sConfig,
HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) {
return HAL_ERROR;
}
return HAL_OK;
}
Thank you.
2025-01-19 09:33 AM
You can make your own wrapper, but the model now is that you send the command before calling the function, so the function just iterates on the matching against the data stream
//****************************************************************************
/**
* @brief This function read the SR of the memory and wait the EOP.
* @PAram hospi: QSPI handle
* @PAram Timeout
* @retval None
*/
static uint8_t XSPI_AutoPollingMemReady(XSPI_HandleTypeDef *hospi, uint32_t Timeout)
{ // sourcer32@gmail.com
XSPI_RegularCmdTypeDef sCommand = {0};
XSPI_AutoPollingTypeDef sConfig = {0};
sCommand.OperationType = HAL_XSPI_OPTYPE_COMMON_CFG;
sCommand.IOSelect = XSPI_IOSELECT;
/* Configure automatic polling mode to wait for memory ready */
sCommand.Instruction = READ_STATUS_REG1_CMD;
sCommand.InstructionMode = HAL_XSPI_INSTRUCTION_1_LINE;
sCommand.InstructionWidth = HAL_XSPI_INSTRUCTION_8_BITS;
sCommand.InstructionDTRMode = HAL_XSPI_INSTRUCTION_DTR_DISABLE;
sCommand.AddressMode = HAL_XSPI_ADDRESS_NONE;
sCommand.AlternateBytesMode = HAL_XSPI_ALT_BYTES_NONE;
sCommand.DataMode = HAL_XSPI_DATA_1_LINE;
sCommand.DataDTRMode = HAL_XSPI_DATA_DTR_DISABLE;
sCommand.DataLength = 1;
sCommand.DummyCycles = 0;
sCommand.DQSMode = HAL_XSPI_DQS_DISABLE;
sCommand.SIOOMode = HAL_XSPI_SIOO_INST_EVERY_CMD;
if (HAL_XSPI_Command(hospi, &sCommand, HAL_XSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
return(XSPI_ERROR);
}
sConfig.MatchValue = 0; // 0=READY,1=BUSY
sConfig.MatchMask = SR1_BUSY;
sConfig.MatchMode = HAL_XSPI_MATCH_MODE_AND;
sConfig.IntervalTime = AUTO_POLLING_INTERVAL;
sConfig.AutomaticStop = HAL_XSPI_AUTOMATIC_STOP_ENABLE;
if (HAL_XSPI_AutoPolling(hospi, &sConfig, Timeout) != HAL_OK)
{
return(XSPI_ERROR);
}
return(XSPI_OK);
}
//****************************************************************************
//****************************************************************************
/**
* @brief This function send a Write Enable and wait it is effective.
* @PAram hospi: QSPI handle
* @retval None
*/
static uint8_t XSPI_WriteEnable(XSPI_HandleTypeDef *hospi)
{ // sourcer32@gmail.com
XSPI_RegularCmdTypeDef sCommand = {0};
XSPI_AutoPollingTypeDef sConfig = {0};
sCommand.OperationType = HAL_XSPI_OPTYPE_COMMON_CFG;
sCommand.IOSelect = XSPI_IOSELECT;
/* Enable write operations */
sCommand.Instruction = WRITE_ENABLE_CMD;
sCommand.InstructionMode = HAL_XSPI_INSTRUCTION_1_LINE;
sCommand.InstructionWidth = HAL_XSPI_INSTRUCTION_8_BITS;
sCommand.InstructionDTRMode = HAL_XSPI_INSTRUCTION_DTR_DISABLE;
sCommand.AddressMode = HAL_XSPI_ADDRESS_NONE;
sCommand.AlternateBytesMode = HAL_XSPI_ALT_BYTES_NONE;
sCommand.DataMode = HAL_XSPI_DATA_NONE;
sCommand.DummyCycles = 0;
sCommand.DQSMode = HAL_XSPI_DQS_DISABLE;
sCommand.SIOOMode = HAL_XSPI_SIOO_INST_EVERY_CMD;
if (HAL_XSPI_Command(hospi, &sCommand, HAL_XSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
return(XSPI_ERROR);
}
sCommand.Instruction = READ_STATUS_REG1_CMD;
sCommand.DataMode = HAL_XSPI_DATA_1_LINE;
sCommand.DataDTRMode = HAL_XSPI_DATA_DTR_DISABLE;
sCommand.DataLength = 1;
if (HAL_XSPI_Command(hospi, &sCommand, HAL_XSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
return(XSPI_ERROR);
}
/* Configure automatic polling mode to wait for write enabling */
sConfig.MatchValue = SR1_WREN;
sConfig.MatchMask = SR1_WREN;
sConfig.MatchMode = HAL_XSPI_MATCH_MODE_AND;
sConfig.IntervalTime = AUTO_POLLING_INTERVAL;
sConfig.AutomaticStop = HAL_XSPI_AUTOMATIC_STOP_ENABLE;
if (HAL_XSPI_AutoPolling(hospi, &sConfig, HAL_XSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
return(XSPI_ERROR);
}
return(XSPI_OK);
}
//***************************************************************************
2025-01-19 09:55 AM
Hello Berto!
you have to call first the HAL_XSPI_Command function and after that the HAL_XSPI_AutoPolling function.
Here my write enable for a MX25L512 , i hope this helps
static uint8_t QSPI_WriteEnable(void)
{
XSPI_RegularCmdTypeDef sCommand;
XSPI_AutoPollingTypeDef sConfig;
// Enable write operations ------------------------------------------ */
sCommand.OperationType = HAL_XSPI_OPTYPE_COMMON_CFG;
sCommand.IOSelect = HAL_XSPI_SELECT_IO_3_0;
sCommand.Instruction = WRITE_ENABLE_CMD;
sCommand.InstructionMode = HAL_XSPI_INSTRUCTION_1_LINE;
sCommand.InstructionWidth = HAL_XSPI_INSTRUCTION_8_BITS;
sCommand.InstructionDTRMode = HAL_XSPI_INSTRUCTION_DTR_DISABLE;
sCommand.Address = 0;
sCommand.AddressMode = HAL_XSPI_ADDRESS_NONE;
sCommand.AddressWidth = HAL_XSPI_ADDRESS_8_BITS;
sCommand.AddressDTRMode = HAL_XSPI_ADDRESS_DTR_DISABLE;
sCommand.AlternateBytes = 0;
sCommand.AlternateBytesMode = HAL_XSPI_ALT_BYTES_NONE;
sCommand.AlternateBytesWidth = HAL_XSPI_ALT_BYTES_8_BITS;
sCommand.AlternateBytesDTRMode = HAL_XSPI_ALT_BYTES_DTR_DISABLE;
sCommand.DataMode = HAL_XSPI_DATA_NONE;
sCommand.DataLength = 0;
sCommand.DataDTRMode = HAL_XSPI_DATA_DTR_DISABLE;
sCommand.DummyCycles = 0;
sCommand.DQSMode = HAL_XSPI_DQS_DISABLE;
sCommand.SIOOMode = HAL_XSPI_SIOO_INST_EVERY_CMD;
if(HAL_XSPI_Command(&hospi1, &sCommand, HAL_XSPI_TIMEOUT_DEFAULT_VALUE)!= HAL_OK)
{
return HAL_ERROR;
}
// Configure automatic polling mode to wait for write enabling ----
sCommand.OperationType = HAL_XSPI_OPTYPE_COMMON_CFG;
sCommand.IOSelect = HAL_XSPI_SELECT_IO_3_0;
sCommand.Instruction = READ_STATUS_REG_CMD;
sCommand.InstructionMode = HAL_XSPI_INSTRUCTION_1_LINE;
sCommand.InstructionWidth = HAL_XSPI_INSTRUCTION_8_BITS;
sCommand.InstructionDTRMode = HAL_XSPI_INSTRUCTION_DTR_DISABLE;
sCommand.Address = 0;
sCommand.AddressMode = HAL_XSPI_ADDRESS_NONE;
sCommand.AddressWidth = HAL_XSPI_ADDRESS_8_BITS;
sCommand.AddressDTRMode = HAL_XSPI_ADDRESS_DTR_DISABLE;
sCommand.AlternateBytes = 0;
sCommand.AlternateBytesMode = HAL_XSPI_ALT_BYTES_NONE;
sCommand.AlternateBytesWidth = HAL_XSPI_ALT_BYTES_8_BITS;
sCommand.AlternateBytesDTRMode = HAL_XSPI_ALT_BYTES_DTR_DISABLE;
sCommand.DataMode = HAL_XSPI_DATA_1_LINE;
sCommand.DataLength = 1;
sCommand.DataDTRMode = HAL_XSPI_DATA_DTR_DISABLE;
sCommand.DummyCycles = 0;
sCommand.DQSMode = HAL_XSPI_DQS_DISABLE;
sCommand.SIOOMode = HAL_XSPI_SIOO_INST_EVERY_CMD;
sConfig.MatchValue = 0x02;
sConfig.MatchMask = 0x02;
sConfig.MatchMode = HAL_XSPI_MATCH_MODE_AND;
sConfig.IntervalTime = 0x10;
sConfig.AutomaticStop = HAL_XSPI_AUTOMATIC_STOP_ENABLE;
if(HAL_XSPI_Command(&hospi1, &sCommand, HAL_XSPI_TIMEOUT_DEFAULT_VALUE)!= HAL_OK)
{
return HAL_ERROR;
}
if(HAL_XSPI_AutoPolling(&hospi1, &sConfig, HAL_XSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
return HAL_ERROR;
}
return HAL_OK;
}
the first command is the actual WRITE_ENABLE_CMD
the second one is a READ_STATUS_REG_CMD and the with the autopolling command we reiterate the registry reading until the value readed match the sConfig.MatchValue = 0x02; using the bitmask sConfig.MatchMask = 0x02
2025-01-19 10:21 AM
@Berto What are the pin usages for your STM32H563ZI + MX25L25645G combo