cancel
Showing results for 
Search instead for 
Did you mean: 

STM32H5 external loader

AMend.7
Associate III

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

53 REPLIES 53
ABasi.2
Associate III

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):

uint8_t CSP_QUADSPI_Init(void)
{
 
uint8_t mark1[] = "MARK1";
uint8_t mark2[] = "MARK2";
uint8_t mark3[] = "MARK3";
 
HAL_UART_Transmit(&huart3,mark1,sizeof(mark1),1000);
 
  //prepare QSPI peripheral for ST-Link Utility operations
  if(HAL_XSPI_DeInit(&hospi1) != HAL_OK)
  {
  HAL_UART_Transmit(&huart3,mark2,sizeof(mark2),1000);
  return HAL_ERROR;
  }
 
  HAL_UART_Transmit(&huart3,mark3,sizeof(mark3),1000);
 
  MX_OCTOSPI1_Init();
 
  if(QSPI_ResetChip() != HAL_OK)
  {
    return HAL_ERROR;
  }
 
  HAL_Delay(1);
 
  if(QSPI_AutoPollingMemReady() != HAL_OK)
  {
    return HAL_ERROR;
  }
 
  if(QSPI_WriteEnable() != HAL_OK)
  {
    return HAL_ERROR;
  }
 
  if(QSPI_Configuration() != HAL_OK)
  {
    return HAL_ERROR;
  }
 
  return HAL_OK;
}
 
on the UART we can see "MARK1",but the code does'nt return from HAL_XSPI_DeInit(&hospi1)
after "MARK1" nothing more appen on the UART, no "MARK2" and no "MARK3"
 
it seems the code is stuck inside HAL_XSPI_DeInit(&hospi1) that is code written by cube ide , the function is in the file stm32h5xx_hal_xspi.c 
 
i attach the file at this message
 
 
 
 

 

Make sure hospi1 structure has the instance defined, there is not static initialization in loaders. Perhaps Hard Faulting or delays not working

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
ABasi.2
Associate III

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:

uint8_t CSP_QUADSPI_Init(void)
{
 
  console(consoleDefault,"INIT QUADSPI\r\n");
 
  //prepare QSPI peripheral for ST-Link Utility operations
 
  if(hospi1.Instance == OCTOSPI1)
  {
       if(HAL_XSPI_DeInit(&hospi1) != HAL_OK)
       {
        console(consoleDefault,"DEINIT ERROR\r\n");
       return HAL_ERROR;
      }
     console(consoleDefault,"DEINIT OK\r\n");
  }
 
  MX_OCTOSPI1_Init();
 
  if(QSPI_ResetChip() != HAL_OK)
  {
    return HAL_ERROR;
  }
 
  HAL_Delay(1);
 
  if(QSPI_AutoPollingMemReady() != HAL_OK)
  {
    return HAL_ERROR;
  }
 
  if(QSPI_WriteEnable() != HAL_OK)
  {
    return HAL_ERROR;
  }
 
  if(QSPI_Configuration() != HAL_OK)
  {
    return HAL_ERROR;
  }
 
  return HAL_OK;
}

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

 

int
Write(uint32_t Address, uint32_t Size, uint8_t* buffer) {
 
 
console(consoleDefault,"WRITE\r\n");
__set_PRIMASK(0); //enable interrupts
 
 
if(hospi1.Instance != OCTOSPI1)
{
console(consoleDefault,"INSTANCE err\r\n");
}
 
if (HAL_XSPI_Abort(&hospi1) != HAL_OK) {
    console(consoleDefault,"WRITE abort err\r\n");
        __set_PRIMASK(1); //disable interrupts
        return LOADER_FAIL;
    }
 
    if (CSP_QSPI_WriteMemory((uint8_t*) buffer, (Address & (0x0fffffff)), Size) != HAL_OK) {
    console(consoleDefault,"WRITE err\r\n");
        __set_PRIMASK(1); //disable interrupts
        return LOADER_FAIL;
    }
 
    __set_PRIMASK(1); //disable interrupts
    return LOADER_OK;
}
 
the second time the HAL_XSPI_Abort return ERROR!
 
i don't know why this firmware is like the Omero odyssey...

 

 

 

ABasi.2
Associate III

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)

ABasi.2
Associate III

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!

 

 

 

 

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
...
Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Berto
Associate II

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:

  • HAL_StatusTypeDef HAL_QSPI_AutoPolling (QSPI_HandleTypeDef *hqspi, QSPI_CommandTypeDef *cmd, QSPI_AutoPollingTypeDef *cfg, uint32_t Timeout);

 

  • HAL_StatusTypeDef HAL_XSPI_AutoPolling(XSPI_HandleTypeDef *hxspi, XSPI_AutoPollingTypeDef *const pCfg,
    uint32_t Timeout)

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.

 

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

https://github.com/STMicroelectronics/stm32-mx25lm51245g/blob/d2dc02bdadf6b9874384d8725694ef14c7b6988e/mx25lm51245g.c#L85

//****************************************************************************

/**
  * @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);
}

//***************************************************************************
Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..

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

 

@Berto What are the pin usages for your STM32H563ZI + MX25L25645G combo

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..