cancel
Showing results for 
Search instead for 
Did you mean: 

Generating external Loader (.stldr) for specific hardware

MiladChalipa
Senior

In the last weeks, I was working on running W25Q256 nor flash chip from vendor Winbond with STM32F746 MCU on a custom board. My guideline in this road is ST's how to run QSPI flash video tutorial (5-part video) and of course some genius guys in the community who's helped me a lot to rewrite the functions of QSPI flash (Init, Erase, Write, Memory-mapped). So far functions tested in the Main.c and I can read the pre-written data on the memory. The next step is to generate (.stldr) external loader file and modify Flash.ld file.

according to the video tutorial, I added Loader_Src.c, dev_inf.c, and dev_inf.h files to the workspace but there is a little confusion about flash.ld file that contains memory definitions and all other data and text stuff to assign to specific memory (>FLASH, >RAM, >QUADSPI).

for the point of concern, I use STM32F746 with IS42S32400F SD-RAM connected with 2-banks to MCU and of-course W25Q256 NOR-FLASH.

  1. how to modify flash.ld file to my specific condition and generate .stldr file using loader files added?
  2. I generated an external loader file before, but when I added the loader file to the CUBEPROGRAMMER directory, it didn't recognize by the programmer and got an error with blank fields in EL section of the programmer!

here I uploaded relevant files for check

STM32F746BGTX_FLASH.ld

/**
 ******************************************************************************
 * @file      LinkerScript.ld
 * @author    Auto-generated by STM32CubeIDE
 * @brief     Linker script for STM32F746BGTx Device from STM32F7 series
 *                      1024Kbytes FLASH
 *                      320Kbytes RAM
 *
 *            Set heap size, stack size and stack location according
 *            to application requirements.
 *
 *            Set memory bank area and size if external memory is used
 ******************************************************************************
 * @attention
 *
 * <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
 * All rights reserved.</center></h2>
 *
 * This software component is licensed by ST under BSD 3-Clause license,
 * the "License"; You may not use this file except in compliance with the
 * License. You may obtain a copy of the License at:
 *                        opensource.org/licenses/BSD-3-Clause
 *
 ******************************************************************************
 */
 
/* Entry Point */
ENTRY(Reset_Handler)
 
/* Highest address of the user mode stack */
_estack = ORIGIN(RAM) + LENGTH(RAM);	/* end of "RAM" Ram type memory */
 
_Min_Heap_Size = 0x200 ;	/* required amount of heap  */
_Min_Stack_Size = 0x400 ;	/* required amount of stack */
 
/* Memories definition */
MEMORY
{
  RAM    (xrw)    : ORIGIN = 0x20000000,  LENGTH = 320K
  FLASH    (rx)   : ORIGIN = 0x8000000,   LENGTH = 1024K
}
 
/* Sections */
SECTIONS
{
  /* The startup code into "FLASH" Rom type memory */
  .isr_vector :
  {
    . = ALIGN(4);
    KEEP(*(.isr_vector)) /* Startup code */
    . = ALIGN(4);
  } >FLASH
 
  /* The program code and other data into "FLASH" Rom type memory */
  .text :
  {
    . = ALIGN(4);
    *(.text)           /* .text sections (code) */
    *(.text*)          /* .text* sections (code) */
    *(.glue_7)         /* glue arm to thumb code */
    *(.glue_7t)        /* glue thumb to arm code */
    *(.eh_frame)
 
    KEEP (*(.init))
    KEEP (*(.fini))
 
    . = ALIGN(4);
    _etext = .;        /* define a global symbols at end of code */
  } >FLASH
 
  /* Constant data into "FLASH" Rom type memory */
  .rodata :
  {
    . = ALIGN(4);
    *(.rodata)         /* .rodata sections (constants, strings, etc.) */
    *(.rodata*)        /* .rodata* sections (constants, strings, etc.) */
    . = ALIGN(4);
  } >FLASH
 
  .ARM.extab   : { 
    . = ALIGN(4);
    *(.ARM.extab* .gnu.linkonce.armextab.*)
    . = ALIGN(4);
  } >FLASH
  
  .ARM : {
    . = ALIGN(4);
    __exidx_start = .;
    *(.ARM.exidx*)
    __exidx_end = .;
    . = ALIGN(4);
  } >FLASH
 
  .preinit_array     :
  {
    . = ALIGN(4);
    PROVIDE_HIDDEN (__preinit_array_start = .);
    KEEP (*(.preinit_array*))
    PROVIDE_HIDDEN (__preinit_array_end = .);
    . = ALIGN(4);
  } >FLASH
  
  .init_array :
  {
    . = ALIGN(4);
    PROVIDE_HIDDEN (__init_array_start = .);
    KEEP (*(SORT(.init_array.*)))
    KEEP (*(.init_array*))
    PROVIDE_HIDDEN (__init_array_end = .);
    . = ALIGN(4);
  } >FLASH
  
  .fini_array :
  {
    . = ALIGN(4);
    PROVIDE_HIDDEN (__fini_array_start = .);
    KEEP (*(SORT(.fini_array.*)))
    KEEP (*(.fini_array*))
    PROVIDE_HIDDEN (__fini_array_end = .);
    . = ALIGN(4);
  } >FLASH
 
  /* Used by the startup to initialize data */
  _sidata = LOADADDR(.data);
 
  /* Initialized data sections into "RAM" Ram type memory */
  .data : 
  {
    . = ALIGN(4);
    _sdata = .;        /* create a global symbol at data start */
    *(.data)           /* .data sections */
    *(.data*)          /* .data* sections */
 
    . = ALIGN(4);
    _edata = .;        /* define a global symbol at data end */
    
  } >RAM AT> FLASH
 
  /* Uninitialized data section into "RAM" Ram type memory */
  . = ALIGN(4);
  .bss :
  {
    /* This is used by the startup in order to initialize the .bss section */
    _sbss = .;         /* define a global symbol at bss start */
    __bss_start__ = _sbss;
    *(.bss)
    *(.bss*)
    *(COMMON)
 
    . = ALIGN(4);
    _ebss = .;         /* define a global symbol at bss end */
    __bss_end__ = _ebss;
  } >RAM
 
  /* User_heap_stack section, used to check that there is enough "RAM" Ram  type memory left */
  ._user_heap_stack :
  {
    . = ALIGN(8);
    PROVIDE ( end = . );
    PROVIDE ( _end = . );
    . = . + _Min_Heap_Size;
    . = . + _Min_Stack_Size;
    . = ALIGN(8);
  } >RAM
 
  /* Remove information from the compiler libraries */
  /DISCARD/ :
  {
    libc.a ( * )
    libm.a ( * )
    libgcc.a ( * )
  }
 
  .ARM.attributes 0 : { *(.ARM.attributes) } 
}

 Dev_inf.c

/*
 * Dev_Inf.c
 *
 */
#include "Dev_Inf.h"
#include "quadspi.h"
 
/* This structure contains information used by ST-LINK Utility to program and erase the device */
#if defined (__ICCARM__)
__root struct StorageInfo const StorageInfo  =  {
#else
struct StorageInfo const StorageInfo = {
#endif
    "QSPI_flashloader_CSP",                  // Device Name + version number
    NOR_FLASH,                           // Device Type
    0x90000000,                          // Device Start Address
    MEMORY_FLASH_SIZE,                   // Device Size in Bytes
    MEMORY_PAGE_SIZE,                    // Programming Page Size
    0xFF,                                // Initial Content of Erased Memory
 
    // Specify Size and Address of Sectors (view example below)
    {   {
            (MEMORY_FLASH_SIZE / MEMORY_SECTOR_SIZE),  // Sector Numbers,
            (uint32_t) MEMORY_SECTOR_SIZE
        },       //Sector Size
 
        { 0x00000000, 0x00000000 }
    }
};

1 ACCEPTED SOLUTION

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

View solution in original post

35 REPLIES 35
MiladChalipa
Senior

Loader_Src.c

#include "quadspi.h"
#include "main.h"
#include "gpio.h"
 
#define LOADER_OK   0x1
#define LOADER_FAIL 0x0
extern void SystemClock_Config(void);
 
 
int Init(void);
int Write(uint32_t Address, uint32_t Size, uint8_t* buffer);
int SectorErase(uint32_t EraseStartAddress, uint32_t EraseEndAddress);
int MassErase(void);
uint32_t CheckSum(uint32_t StartAddress, uint32_t Size, uint32_t InitVal);
uint64_t Verify(uint32_t MemoryAddr, uint32_t RAMBufferAddr, uint32_t Size, uint32_t missalignement);
 
 
/**
 * @brief  System initialization.
 * @param  None
 * @retval  LOADER_OK = 1   : Operation succeeded
 * @retval  LOADER_FAIL = 0 : Operation failed
 */
int Init(void) {
 
    *(uint32_t*)0xE000EDF0 = 0xA05F0000; //enable interrupts in debug
 
 
    SystemInit();
 
    /* ADAPTATION TO THE DEVICE
     *
     * change VTOR setting for H7 device
     * SCB->VTOR = 0x24000000 | 0x200;
     *
     * change VTOR setting for other devices
     * SCB->VTOR = 0x20000000 | 0x200;
     *
     * */
 
    SCB->VTOR = 0x20000000 | 0x200;
 
    __set_PRIMASK(0); //enable interrupts
 
    HAL_Init();
 
    SystemClock_Config();
 
    MX_GPIO_Init();
 
    __HAL_RCC_QSPI_FORCE_RESET();  //completely reset peripheral
    __HAL_RCC_QSPI_RELEASE_RESET();
 
    if (CSP_QUADSPI_Init() != HAL_OK) {
        __set_PRIMASK(1); //disable interrupts
        return LOADER_FAIL;
    }
 
 
    if (CSP_QSPI_EnableMemoryMappedMode() != HAL_OK) {
        __set_PRIMASK(1); //disable interrupts
        return LOADER_FAIL;
    }
 
 
    __set_PRIMASK(1); //disable interrupts
    return LOADER_OK;
}
 
/**
 * @brief   Program memory.
 * @param   Address: page address
 * @param   Size   : size of data
 * @param   buffer : pointer to data buffer
 * @retval  LOADER_OK = 1       : Operation succeeded
 * @retval  LOADER_FAIL = 0 : Operation failed
 */
int Write(uint32_t Address, uint32_t Size, uint8_t* buffer) {
 
    __set_PRIMASK(0); //enable interrupts
 
    if (HAL_QSPI_Abort(&hqspi) != HAL_OK) {
        __set_PRIMASK(1); //disable interrupts
        return LOADER_FAIL;
    }
 
 
    if (CSP_QSPI_WriteMemory((uint8_t*) buffer, (Address & (0x0fffffff)), Size) != HAL_OK) {
        __set_PRIMASK(1); //disable interrupts
        return LOADER_FAIL;
    }
 
    __set_PRIMASK(1); //disable interrupts
    return LOADER_OK;
}
 
/**
 * @brief   Sector erase.
 * @param   EraseStartAddress :  erase start address
 * @param   EraseEndAddress   :  erase end address
 * @retval  LOADER_OK = 1       : Operation succeeded
 * @retval  LOADER_FAIL = 0 : Operation failed
 */
int SectorErase(uint32_t EraseStartAddress, uint32_t EraseEndAddress) {
 
    __set_PRIMASK(0); //enable interrupts
 
    if (HAL_QSPI_Abort(&hqspi) != HAL_OK) {
        __set_PRIMASK(1); //disable interrupts
        return LOADER_FAIL;
    }
 
 
    if (CSP_QSPI_EraseSector(EraseStartAddress, EraseEndAddress) != HAL_OK) {
        __set_PRIMASK(1); //disable interrupts
        return LOADER_FAIL;
    }
 
    __set_PRIMASK(1); //disable interrupts
    return LOADER_OK;
}
 
/**
 * Description :
 * Mass erase of external flash area
 * Optional command - delete in case usage of mass erase is not planed
 * Inputs    :
 *      none
 * outputs   :
 *     none
 * Note: Optional for all types of device
 */
int MassErase(void) {
 
    __set_PRIMASK(0); //enable interrupts
 
    if (HAL_QSPI_Abort(&hqspi) != HAL_OK) {
        __set_PRIMASK(1); //disable interrupts
        return LOADER_FAIL;
    }
 
 
    if (CSP_QSPI_Erase_Chip() != HAL_OK) {
        __set_PRIMASK(1); //disable interrupts
        return LOADER_FAIL;
    }
 
    __set_PRIMASK(1); //disable interrupts
    return LOADER_OK;
}
 
/**
 * Description :
 * Calculates checksum value of the memory zone
 * Inputs    :
 *      StartAddress  : Flash start address
 *      Size          : Size (in WORD)
 *      InitVal       : Initial CRC value
 * outputs   :
 *     R0             : Checksum value
 * Note: Optional for all types of device
 */
uint32_t CheckSum(uint32_t StartAddress, uint32_t Size, uint32_t InitVal) {
    uint8_t missalignementAddress = StartAddress % 4;
    uint8_t missalignementSize = Size;
    int cnt;
    uint32_t Val;
 
    StartAddress -= StartAddress % 4;
    Size += (Size % 4 == 0) ? 0 : 4 - (Size % 4);
 
    for (cnt = 0; cnt < Size; cnt += 4) {
        Val = *(uint32_t*) StartAddress;
        if (missalignementAddress) {
            switch (missalignementAddress) {
                case 1:
                    InitVal += (uint8_t) (Val >> 8 & 0xff);
                    InitVal += (uint8_t) (Val >> 16 & 0xff);
                    InitVal += (uint8_t) (Val >> 24 & 0xff);
                    missalignementAddress -= 1;
                    break;
                case 2:
                    InitVal += (uint8_t) (Val >> 16 & 0xff);
                    InitVal += (uint8_t) (Val >> 24 & 0xff);
                    missalignementAddress -= 2;
                    break;
                case 3:
                    InitVal += (uint8_t) (Val >> 24 & 0xff);
                    missalignementAddress -= 3;
                    break;
            }
        } else if ((Size - missalignementSize) % 4 && (Size - cnt) <= 4) {
            switch (Size - missalignementSize) {
                case 1:
                    InitVal += (uint8_t) Val;
                    InitVal += (uint8_t) (Val >> 8 & 0xff);
                    InitVal += (uint8_t) (Val >> 16 & 0xff);
                    missalignementSize -= 1;
                    break;
                case 2:
                    InitVal += (uint8_t) Val;
                    InitVal += (uint8_t) (Val >> 8 & 0xff);
                    missalignementSize -= 2;
                    break;
                case 3:
                    InitVal += (uint8_t) Val;
                    missalignementSize -= 3;
                    break;
            }
        } else {
            InitVal += (uint8_t) Val;
            InitVal += (uint8_t) (Val >> 8 & 0xff);
            InitVal += (uint8_t) (Val >> 16 & 0xff);
            InitVal += (uint8_t) (Val >> 24 & 0xff);
        }
        StartAddress += 4;
    }
 
    return (InitVal);
}
 
/**
 * Description :
 * Verify flash memory with RAM buffer and calculates checksum value of
 * the programmed memory
 * Inputs    :
 *      FlashAddr     : Flash address
 *      RAMBufferAddr : RAM buffer address
 *      Size          : Size (in WORD)
 *      InitVal       : Initial CRC value
 * outputs   :
 *     R0             : Operation failed (address of failure)
 *     R1             : Checksum value
 * Note: Optional for all types of device
 */
uint64_t Verify(uint32_t MemoryAddr, uint32_t RAMBufferAddr, uint32_t Size, uint32_t missalignement) {
 
    __set_PRIMASK(0); //enable interrupts
    uint32_t VerifiedData = 0, InitVal = 0;
    uint64_t checksum;
    Size *= 4;
 
    if (CSP_QSPI_EnableMemoryMappedMode() != HAL_OK) {
        __set_PRIMASK(1); //disable interrupts
        return LOADER_FAIL;
    }
 
    checksum = CheckSum((uint32_t) MemoryAddr + (missalignement & 0xf),
                        Size - ((missalignement >> 16) & 0xF), InitVal);
    while (Size > VerifiedData) {
        if (*(uint8_t*) MemoryAddr++
            != *((uint8_t*) RAMBufferAddr + VerifiedData)) {
            __set_PRIMASK(1); //disable interrupts
            return ((checksum << 32) + (MemoryAddr + VerifiedData));
        }
        VerifiedData++;
    }
 
    __set_PRIMASK(1); //disable interrupts
    return (checksum << 32);
}

MiladChalipa
Senior

I start a new project from scratch by just configuring QSPI and nothing else, added loader related files, and built successfully. starting CUBEPROGRAMMER and external loader appears with correct values in the list (EL section) just OK along with the tutorial video. but when trying to load sample code has done with success but no changes in address 0x90000000! what is the problem?

external loader generation could have been easier, can't understand why ST doesn't take care of it!:unamused_face:

MiladChalipa
Senior

@Community member​ would you please give me a hand to solve it, I saw your earlier posts about generating stldr file but currently, I am in big confusion!

1.The ST tutorial said that we have to change the default linker script (generated by CubeIDE) with the one that the tutorial suggests, But in the suggested linker file, All the sections are assigned to RAM :fearful_face:.

2.I have the driver implementations, completely fine and running in main.c but when it comes to stldr generation, All suddenly not working at all :pouting_face:.

So please help me out getting through this issue, would you?

The loader is loaded into SRAM by the programmer, and executes from there.

The linker script needs to output two sections, one with the StorageInfo structure where the programmer pulls the device geometry, name and statistics from, and a program section.

I'm in the process of porting an example to GNU/GCC only, will attach the script here shortly.

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

This is for the H7 platform, but just needs the RAM changed to 0x20000004 for other STM32 families.

I'm not using the interrupts/vectors

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

@Community member​ I wish you the bests for 2021 and thank you for your reply in these early days of the year

I include your linker to my project and change the RAM address as you mentioned. firstly I got some errors about location counters (_end, e_stack, ...) in sysmem and startup files. I will try to fix them and get back soon.

Thanks.

The loaders shouldn't need startup.s or main(), the Init() function should clear any critical globals or BSS space.

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

@Community member​ with your linker provided, I'm able to read the external memory just for once (I mean, when I loaded generated stldr to CubeProgmrammer and connect, when hit the Read button, the memory reads properly at 0x90000000 but when hit it again...Read Error). I enable Verbosity level 3 and see that the error is because of the Init function timeout (screenshot attached). It seems the overall functions are OK but need minor adjustments. Would you please provide me a Loader_Src file OR help me fix mine:beaming_face_with_smiling_eyes:

I'm looking for your attack after you finished your porting project.

Loader_Src.c

#include "quadspi.h"
#include "main.h"
#include "gpio.h"
 
#define LOADER_OK   0x1
#define LOADER_FAIL 0x0
extern void SystemClock_Config(void);
 
/**
 * @brief  System initialization.
 * @param  None
 * @retval  LOADER_OK = 1   : Operation succeeded
 * @retval  LOADER_FAIL = 0 : Operation failed
 */
int
Init(void) {
 
    *(uint32_t*)0xE000EDF0 = 0xA05F0000; //enable interrupts in debug
 
 
    SystemInit();
 
    /* ADAPTATION TO THE DEVICE
     *
     * change VTOR setting for H7 device
     * SCB->VTOR = 0x24000000 | 0x200;
     *
     * change VTOR setting for other devices
     * SCB->VTOR = 0x20000000 | 0x200;
     *
     * */
 
    SCB->VTOR = 0x20000000 | 0x200;
 
    __set_PRIMASK(0); //enable interrupts
 
    HAL_Init();
 
    SystemClock_Config();
 
    MX_GPIO_Init();
 
    __HAL_RCC_QSPI_FORCE_RESET();  //completely reset peripheral
    __HAL_RCC_QSPI_RELEASE_RESET();
 
    if (CSP_QUADSPI_Init() != HAL_OK) {
        __set_PRIMASK(1); //disable interrupts
        return LOADER_FAIL;
    }
 
 
    if (CSP_QSPI_EnableMemoryMappedMode() != HAL_OK) {
        __set_PRIMASK(1); //disable interrupts
        return LOADER_FAIL;
    }
 
 
    __set_PRIMASK(1); //disable interrupts
    return LOADER_OK;
}
 
/**
 * @brief   Program memory.
 * @param   Address: page address
 * @param   Size   : size of data
 * @param   buffer : pointer to data buffer
 * @retval  LOADER_OK = 1       : Operation succeeded
 * @retval  LOADER_FAIL = 0 : Operation failed
 */
int
Write(uint32_t Address, uint32_t Size, uint8_t* buffer) {
 
    __set_PRIMASK(0); //enable interrupts
 
    if (HAL_QSPI_Abort(&hqspi) != HAL_OK) {
        __set_PRIMASK(1); //disable interrupts
        return LOADER_FAIL;
    }
 
 
    if (CSP_QSPI_WriteMemory((uint8_t*) buffer, (Address & (0x0fffffff)), Size) != HAL_OK) {
        __set_PRIMASK(1); //disable interrupts
        return LOADER_FAIL;
    }
 
    __set_PRIMASK(1); //disable interrupts
    return LOADER_OK;
}
 
/**
 * @brief   Sector erase.
 * @param   EraseStartAddress :  erase start address
 * @param   EraseEndAddress   :  erase end address
 * @retval  LOADER_OK = 1       : Operation succeeded
 * @retval  LOADER_FAIL = 0 : Operation failed
 */
int
SectorErase(uint32_t EraseStartAddress, uint32_t EraseEndAddress) {
 
    __set_PRIMASK(0); //enable interrupts
 
    if (HAL_QSPI_Abort(&hqspi) != HAL_OK) {
        __set_PRIMASK(1); //disable interrupts
        return LOADER_FAIL;
    }
 
 
    if (CSP_QSPI_EraseSector(EraseStartAddress, EraseEndAddress) != HAL_OK) {
        __set_PRIMASK(1); //disable interrupts
        return LOADER_FAIL;
    }
 
    __set_PRIMASK(1); //disable interrupts
    return LOADER_OK;
}
 
/**
 * Description :
 * Mass erase of external flash area
 * Optional command - delete in case usage of mass erase is not planed
 * Inputs    :
 *      none
 * outputs   :
 *     none
 * Note: Optional for all types of device
 */
int
MassErase(void) {
 
    __set_PRIMASK(0); //enable interrupts
 
    if (HAL_QSPI_Abort(&hqspi) != HAL_OK) {
        __set_PRIMASK(1); //disable interrupts
        return LOADER_FAIL;
    }
 
 
    if (CSP_QSPI_Erase_Chip() != HAL_OK) {
        __set_PRIMASK(1); //disable interrupts
        return LOADER_FAIL;
    }
 
    __set_PRIMASK(1); //disable interrupts
    return LOADER_OK;
}
 
/**
 * Description :
 * Calculates checksum value of the memory zone
 * Inputs    :
 *      StartAddress  : Flash start address
 *      Size          : Size (in WORD)
 *      InitVal       : Initial CRC value
 * outputs   :
 *     R0             : Checksum value
 * Note: Optional for all types of device
 */
uint32_t
CheckSum(uint32_t StartAddress, uint32_t Size, uint32_t InitVal) {
    uint8_t missalignementAddress = StartAddress % 4;
    uint8_t missalignementSize = Size;
    int cnt;
    uint32_t Val;
 
    StartAddress -= StartAddress % 4;
    Size += (Size % 4 == 0) ? 0 : 4 - (Size % 4);
 
    for (cnt = 0; cnt < Size; cnt += 4) {
        Val = *(uint32_t*) StartAddress;
        if (missalignementAddress) {
            switch (missalignementAddress) {
                case 1:
                    InitVal += (uint8_t) (Val >> 8 & 0xff);
                    InitVal += (uint8_t) (Val >> 16 & 0xff);
                    InitVal += (uint8_t) (Val >> 24 & 0xff);
                    missalignementAddress -= 1;
                    break;
                case 2:
                    InitVal += (uint8_t) (Val >> 16 & 0xff);
                    InitVal += (uint8_t) (Val >> 24 & 0xff);
                    missalignementAddress -= 2;
                    break;
                case 3:
                    InitVal += (uint8_t) (Val >> 24 & 0xff);
                    missalignementAddress -= 3;
                    break;
            }
        } else if ((Size - missalignementSize) % 4 && (Size - cnt) <= 4) {
            switch (Size - missalignementSize) {
                case 1:
                    InitVal += (uint8_t) Val;
                    InitVal += (uint8_t) (Val >> 8 & 0xff);
                    InitVal += (uint8_t) (Val >> 16 & 0xff);
                    missalignementSize -= 1;
                    break;
                case 2:
                    InitVal += (uint8_t) Val;
                    InitVal += (uint8_t) (Val >> 8 & 0xff);
                    missalignementSize -= 2;
                    break;
                case 3:
                    InitVal += (uint8_t) Val;
                    missalignementSize -= 3;
                    break;
            }
        } else {
            InitVal += (uint8_t) Val;
            InitVal += (uint8_t) (Val >> 8 & 0xff);
            InitVal += (uint8_t) (Val >> 16 & 0xff);
            InitVal += (uint8_t) (Val >> 24 & 0xff);
        }
        StartAddress += 4;
    }
 
    return (InitVal);
}
 
/**
 * Description :
 * Verify flash memory with RAM buffer and calculates checksum value of
 * the programmed memory
 * Inputs    :
 *      FlashAddr     : Flash address
 *      RAMBufferAddr : RAM buffer address
 *      Size          : Size (in WORD)
 *      InitVal       : Initial CRC value
 * outputs   :
 *     R0             : Operation failed (address of failure)
 *     R1             : Checksum value
 * Note: Optional for all types of device
 */
uint64_t
Verify(uint32_t MemoryAddr, uint32_t RAMBufferAddr, uint32_t Size, uint32_t missalignement) {
 
    __set_PRIMASK(0); //enable interrupts
    uint32_t VerifiedData = 0, InitVal = 0;
    uint64_t checksum;
    Size *= 4;
 
    if (CSP_QSPI_EnableMemoryMappedMode() != HAL_OK) {
        __set_PRIMASK(1); //disable interrupts
        return LOADER_FAIL;
    }
 
    checksum = CheckSum((uint32_t) MemoryAddr + (missalignement & 0xf),
                        Size - ((missalignement >> 16) & 0xF), InitVal);
    while (Size > VerifiedData) {
        if (*(uint8_t*) MemoryAddr++
            != *((uint8_t*) RAMBufferAddr + VerifiedData)) {
            __set_PRIMASK(1); //disable interrupts
            return ((checksum << 32) + (MemoryAddr + VerifiedData));
        }
        VerifiedData++;
    }
 
    __set_PRIMASK(1); //disable interrupts
    return (checksum << 32);
}

0693W000006HL2LQAW.png

MiladChalipa
Senior

I made some changes in the Init function and finally, it is OK, I checked the loader in st-link utility and there is no error when reading and initializing. But now when sector-erase, it actually erases the coresponding sector but with fail message! I think the next challenge would be making erase functions work. @Community member​ 

this is the working Init function (at least for me):

int Init(void) {
 
	*(uint32_t*)0xE000EDF0=0xA05F0000;
 
	SystemInit();
    SCB->VTOR = 0x20000000 | 0x200;
 
    __set_PRIMASK(0); //enable interrupts
 
	HAL_Init();
    SystemClock_Config();
 
 
    __HAL_RCC_GPIOF_CLK_ENABLE();
    __HAL_RCC_GPIOH_CLK_ENABLE();
    __HAL_RCC_GPIOB_CLK_ENABLE();
    __HAL_RCC_GPIOA_CLK_ENABLE();
 
    MX_GPIO_Init();
    if(A == 0)
    {
    	MX_QUADSPI_Init();
    }
    QSPI_ResetChip();
    /*    CSP_QUADSPI_Init();
    CSP_QSPI_EnableMemoryMappedMode();*/
 
    __HAL_RCC_QSPI_FORCE_RESET();  //completely reset peripheral
    __HAL_RCC_QSPI_RELEASE_RESET();
 
    if (CSP_QUADSPI_Init() != HAL_OK) {
        __set_PRIMASK(1); //disable interrupts
        return LOADER_FAIL;
    }
 
 
    if (CSP_QSPI_EnableMemoryMappedMode() != HAL_OK) {
        __set_PRIMASK(1); //disable interrupts
        return LOADER_FAIL;
    }
 
 
    __set_PRIMASK(1); //disable interrupts
 
    A++;
 
    return LOADER_OK;
}

and this is the erase which has an error but actually working!

int SectorErase(uint32_t EraseStartAddress, uint32_t EraseEndAddress) {
 
    __set_PRIMASK(0); //enable interrupts
 
    if (HAL_QSPI_Abort(&hqspi) != HAL_OK) {
        __set_PRIMASK(1); //disable interrupts
        return LOADER_FAIL;
    }
 
 
    if (CSP_QSPI_EraseSector(EraseStartAddress, EraseEndAddress) != HAL_OK) {
        __set_PRIMASK(1); //disable interrupts
        return LOADER_FAIL;
    }
 
    __set_PRIMASK(1); //disable interrupts
    return LOADER_OK;
}

And if you curious about CSP_QSPI_EraseSector :

uint8_t
CSP_QSPI_EraseSector(uint32_t EraseStartAddress, uint32_t EraseEndAddress) {
 
    QSPI_CommandTypeDef sCommand;
 
    EraseStartAddress = EraseStartAddress
                        - EraseStartAddress % MEMORY_SECTOR_SIZE;
 
    /* Erasing Sequence -------------------------------------------------- */
    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 = SECTOR_ERASE_CMD;
    sCommand.AddressMode = QSPI_ADDRESS_1_LINE;
 
    sCommand.DataMode = QSPI_DATA_NONE;
    sCommand.DummyCycles = 0;
 
    while (EraseEndAddress >= EraseStartAddress) {
        sCommand.Address = (EraseStartAddress & 0x0FFFFFFF);
 
        if (QSPI_WriteEnable() != HAL_OK) {
            return HAL_ERROR;
        }
 
        if (HAL_QSPI_Command(&hqspi, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE)
            != HAL_OK) {
            return HAL_ERROR;
        }
        EraseStartAddress += MEMORY_SECTOR_SIZE;
 
        if (QSPI_AutoPollingMemReady() != HAL_OK) {
            return HAL_ERROR;
        }
    }
 
    return HAL_OK;
}