Index: trunk/firmware/FSBL/CubeMX/Middlewares/ST/STM32_ExtMem_Manager/boot/stm32_boot_xip.c
===================================================================
--- trunk/firmware/FSBL/CubeMX/Middlewares/ST/STM32_ExtMem_Manager/boot/stm32_boot_xip.c	(revision 20)
+++ trunk/firmware/FSBL/CubeMX/Middlewares/ST/STM32_ExtMem_Manager/boot/stm32_boot_xip.c	(revision 20)
@@ -0,0 +1,191 @@
+/**
+  ******************************************************************************
+  * @file    stm32_boot_xip.c
+  * @author  MCD Application Team
+  * @brief   This file manages booting in execute-in-place (XIP) mode.
+  ******************************************************************************
+  * @attention
+  *
+  * Copyright (c) 2022 STMicroelectronics.
+  * All rights reserved.
+  *
+  * This software is licensed under terms that can be found in the LICENSE file
+  * in the root directory of this software component.
+  * If no LICENSE file comes with this software, it is provided AS-IS.
+  *
+  ******************************************************************************
+  */
+
+/* Includes ------------------------------------------------------------------*/
+#include "stm32_boot_xip.h"
+#include "stm32_extmem_conf.h"
+
+/** @addtogroup BOOT
+  * @{
+  */
+
+/** @addtogroup BOOT_XIP
+  * @{
+  */
+
+/* Private typedefs ----------------------------------------------------------*/
+/* Private defines -----------------------------------------------------------*/
+
+/* Offset of the image from the boot memory base */
+#ifndef EXTMEM_XIP_IMAGE_OFFSET
+#define EXTMEM_XIP_IMAGE_OFFSET 0
+#endif /* EXTMEM_XIP_IMAGE_OFFSET */
+
+/* Offset of the vector table from the start of the image */
+#ifndef EXTMEM_HEADER_OFFSET
+#define EXTMEM_HEADER_OFFSET 0
+#endif /* EXTMEM_HEADER_OFFSET */
+
+/* Private macros ------------------------------------------------------------*/
+/* Private variables ---------------------------------------------------------*/
+/* Private function prototypes -----------------------------------------------*/
+BOOTStatus_TypeDef JumpToApplication(void);
+BOOTStatus_TypeDef MapMemory(void);
+BOOTStatus_TypeDef GetBaseAddress(uint32_t MemIndex, uint32_t *BaseAddress);
+
+/**
+  *  @addtogroup BOOT_XIP_Exported_Functions Boot XIP exported functions
+  * @{
+  */
+
+/**
+  * @brief Boots the application by mapping the memory and jumping to the application.
+  * @retval BOOTStatus_TypeDef Status of the operation.
+  */
+BOOTStatus_TypeDef BOOT_Application(void)
+{
+  BOOTStatus_TypeDef retr;
+
+  /* Mount the memory */
+  retr = MapMemory();
+  if (BOOT_OK == retr)
+  {
+    /* Jump on the application */
+    retr = JumpToApplication();
+  }
+  return retr;
+}
+
+/**
+  * @}
+  */
+
+/**
+  *  @defgroup BOOT_XIP_Private_Functions Boot XIP private functions
+  * @{
+  */
+
+/**
+  * @brief  Maps the external memory.
+  * @retval BOOTStatus_TypeDef Status of the operation.
+  */
+BOOTStatus_TypeDef MapMemory(void)
+{
+  BOOTStatus_TypeDef retr = BOOT_OK;
+
+  /* Map all the memory */
+  for (uint8_t index = 0; index < (sizeof(extmem_list_config) / sizeof(EXTMEM_DefinitionTypeDef)); index++)
+  {
+    switch (EXTMEM_MemoryMappedMode(index, EXTMEM_ENABLE))
+    {
+      case EXTMEM_ERROR_NOTSUPPORTED :
+        if (EXTMEM_MEMORY_BOOTXIP ==  index)
+        {
+          retr = BOOT_ERROR_INCOMPATIBLEMEMORY;
+        }
+        else
+        {
+          /* We consider the memory will be not used any more */
+          EXTMEM_DeInit(index);
+        }
+      case EXTMEM_OK:
+        break;
+      default :
+        retr = BOOT_ERROR_MAPPEDMODEFAIL;
+        break;
+    }
+  }
+  return retr;
+}
+
+/**
+  * @brief  Jumps to the application using its vector table.
+  * @retval BOOTStatus_TypeDef Status of the operation.
+  */
+BOOTStatus_TypeDef JumpToApplication(void)
+{
+  uint32_t primask_bit;
+  typedef  void (*pFunction)(void);
+  static pFunction JumpToApp;
+  uint32_t Application_vector;
+
+  if (EXTMEM_OK != EXTMEM_GetMapAddress(EXTMEM_MEMORY_BOOTXIP, &Application_vector))
+  {
+    return BOOT_ERROR_INCOMPATIBLEMEMORY;
+  }
+
+  /* Suspend SysTick */
+  HAL_SuspendTick();
+
+#if defined(__ICACHE_PRESENT) && (__ICACHE_PRESENT == 1U)
+  /* if I-Cache is enabled, disable I-Cache-----------------------------------*/
+  if (SCB->CCR & SCB_CCR_IC_Msk)
+  {
+    SCB_DisableICache();
+  }
+#endif /* __ICACHE_PRESENT */
+
+#if defined(__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U)
+  /* if D-Cache is enabled, disable D-Cache-----------------------------------*/
+  if (SCB->CCR & SCB_CCR_DC_Msk)
+  {
+    SCB_DisableDCache();
+  }
+#endif /* __DCACHE_PRESENT */
+
+  /* Initialize user application's Stack Pointer & Jump to user application  */
+  primask_bit = __get_PRIMASK();
+  __disable_irq();
+
+  /* Apply offsets for image location and vector table offset */
+  Application_vector += EXTMEM_XIP_IMAGE_OFFSET + EXTMEM_HEADER_OFFSET;
+
+  SCB->VTOR = (uint32_t)Application_vector;
+  JumpToApp = (pFunction)(*(__IO uint32_t *)(Application_vector + 4u));
+
+#if (defined(__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1))
+  /* on ARM v8m, set MSPLIM before setting MSP to avoid unwanted stack overflow faults */
+  __set_MSPLIM(0x00000000);
+#elif (defined(__ARM_ARCH_8_1M_MAIN__ ) && (__ARM_ARCH_8_1M_MAIN__ == 1))
+  /* on ARM v8m, set MSPLIM before setting MSP to avoid unwanted stack overflow faults */
+  __set_MSPLIM(0x00000000);
+#elif (defined(__ARM_ARCH_8M_BASE__ ) && (__ARM_ARCH_8M_BASE__ == 1))
+  /* on ARM v8m, set MSPLIM before setting MSP to avoid unwanted stack overflow faults */
+  __set_MSPLIM(0x00000000);
+#endif  /* __ARM_ARCH_8M_MAIN__ or __ARM_ARCH_8_1M_MAIN__ or __ARM_ARCH_8M_BASE__ */
+
+  __set_MSP(*(__IO uint32_t *) Application_vector);
+
+  /* Re-enable the interrupts */
+  __set_PRIMASK(primask_bit);
+
+  JumpToApp();
+  return BOOT_OK;
+}
+
+/**
+  * @}
+  */
+
+/**
+  * @}
+ */
+
+/**
+  * @}
+  */
Index: trunk/firmware/FSBL/CubeMX/Middlewares/ST/STM32_ExtMem_Manager/boot/stm32_boot_xip.h
===================================================================
--- trunk/firmware/FSBL/CubeMX/Middlewares/ST/STM32_ExtMem_Manager/boot/stm32_boot_xip.h	(revision 20)
+++ trunk/firmware/FSBL/CubeMX/Middlewares/ST/STM32_ExtMem_Manager/boot/stm32_boot_xip.h	(revision 20)
@@ -0,0 +1,76 @@
+/**
+  ******************************************************************************
+  * @file    stm32_boot_xip.h
+  * @author  MCD Application Team
+  * @brief   Header for stm32_boot_xip.c file.
+  ******************************************************************************
+  * @attention
+  *
+  * Copyright (c) 2023 STMicroelectronics.
+  * All rights reserved.
+  *
+  * This software is licensed under terms that can be found in the LICENSE file
+  * in the root directory of this software component.
+  * If no LICENSE file comes with this software, it is provided AS-IS.
+  *
+  ******************************************************************************
+  */
+/* USER CODE END Header */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __STM32_BOOT_XIP_H__
+#define __STM32_BOOT_XIP_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Includes ------------------------------------------------------------------*/
+
+/** @addtogroup BOOT_XIP
+  * @{
+  */
+
+/* Exported defines ---------------------------------------------------------*/
+/**
+  *  @defgroup BOOT_XIP_Private_Defines Boot XIP exported definitions
+  * @{
+  */
+/**
+  * @brief List of status codes for XIP
+  */
+typedef enum
+{
+  BOOT_OK,                                 /*!< Operation successful */
+  BOOT_ERROR_UNSUPPORTED_MEMORY,           /*!< Unsupported memory type */
+  BOOT_ERROR_NOBASEADDRESS,                /*!< No base address for the memory */
+  BOOT_ERROR_MAPPEDMODEFAIL,               /*!< Error during memory mapping */
+  BOOT_ERROR_INCOMPATIBLEMEMORY,           /*!< Selected memory not compatible with XIP boot */
+  BOOT_ERROR_DRIVER,                       /*!< Error in driver operation */
+} BOOTStatus_TypeDef;
+
+/**
+  * @}
+  */
+
+/* Private function prototypes -----------------------------------------------*/
+/**
+  *  @defgroup BOOT_XIP_Exported_Functions Boot XIP exported functions
+  * @{
+  */
+
+BOOTStatus_TypeDef BOOT_Application(void);
+
+/**
+  * @}
+  */
+
+/**
+  * @}
+  */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __STM32_BOOT_XIP_H__ */
Index: trunk/firmware/FSBL/CubeMX/Middlewares/ST/STM32_ExtMem_Manager/nor_sfdp/stm32_sfdp_data.c
===================================================================
--- trunk/firmware/FSBL/CubeMX/Middlewares/ST/STM32_ExtMem_Manager/nor_sfdp/stm32_sfdp_data.c	(revision 20)
+++ trunk/firmware/FSBL/CubeMX/Middlewares/ST/STM32_ExtMem_Manager/nor_sfdp/stm32_sfdp_data.c	(revision 20)
@@ -0,0 +1,2979 @@
+/**
+  ******************************************************************************
+  * @file    stm32_sfdp_data.c
+  * @author  MCD Application Team
+  * @brief   This file includes a driver for SFDP support
+  ******************************************************************************
+  * @attention
+  *
+  * Copyright (c) 2022 STMicroelectronics.
+  * All rights reserved.
+  *
+  * This software is licensed under terms that can be found in the LICENSE file
+  * in the root directory of this software component.
+  * If no LICENSE file comes with this software, it is provided AS-IS.
+  *
+  ******************************************************************************
+  */
+
+/* Includes ------------------------------------------------------------------*/
+#include "stm32_extmem_conf.h"
+
+#if defined(EXTMEM_DRIVER_NOR_SFDP) && (EXTMEM_DRIVER_NOR_SFDP == 1)
+#include "stm32_sfdp_driver_api.h"
+#include "stm32_sfdp_data.h"
+#if EXTMEM_DRIVER_NOR_SFDP_DEBUG_LEVEL != 0 && defined(EXTMEM_MACRO_DEBUG)
+#include <stdio.h>
+#endif /* EXTMEM_DRIVER_NOR_SFDP_DEBUG_LEVEL != 0 && EXTMEM_MACRO_DEBUG */
+#include <string.h>
+
+/** @defgroup NOR_SFDP_DATA Data module
+  * @ingroup NOR_SFDP
+  * @{
+  */
+
+/* Private defines ------------------------------------------------------------*/
+/** @defgroup NOR_SFDP_DATA_Private_Defines Private Defines
+  * This group contains all private defines of the NOR SFDP data module.
+  * @{
+  */
+
+/** @brief Reset method definition
+  *
+  * Defines the reset method used for SFDP.
+  */
+typedef enum
+{
+  RESET_NONE,
+  RESET_FH_4DATA_8CLOCK,
+  RESET_FH_4DATA_10CLOCK,
+  RESET_FH_4DATA_16CLOCK,
+  RESET_INSTRUCTION_F0,
+  RESET_INSTRUCTION_66_99,
+  RESET_ERROR
+} RESET_METHOD;
+
+/** @brief TRUE definition
+  *
+  * Defines the value for true.
+  */
+#define EXTMEM_SFDP_TRUE  1u      /**< True value */
+
+/** @brief FALSE definition
+  *
+  * Defines the value for false.
+  */
+#define EXTMEM_SFDP_FALSE 0u      /**< False value */
+
+/** @brief No address management definition
+  *
+  * Value indicating no address management case.
+  */
+#define EXTMEM_ADDRESS_NONE 0xFFu      /**< No address management */
+
+/**
+  * @brief Clock definition for 200 MHz
+  */
+#define CLOCK_200MHZ   200000000u
+/**
+  * @brief Clock definition for 166 MHz
+  */
+#define CLOCK_166MHZ   166000000u
+/**
+  * @brief Clock definition for 133 MHz
+  */
+#define CLOCK_133MHZ   133000000u
+/**
+  * @brief Clock definition for 100 MHz
+  */
+#define CLOCK_100MHZ   100000000u
+
+/**
+  * @brief SFDP signature
+  */
+#define SFDP_SIGNATURE                0x50444653U
+#define SFDP_SIGNATURE_INVERTED       0x44505346U
+/**
+  * @brief SFDP header size
+  */
+#define SFDP_HEADER_SIZE              8U
+
+/**
+  * @brief SFDP param header size
+  */
+#define SFDP_PARAM_HEADER_SIZE        8U
+
+/**
+  * @brief SFDP basic table default size
+  */
+#define SFDP_PARAMS_BASIC_TABLE_DEFAULTSIZE  23u
+
+/**
+  * @brief SFDP Basic Parameter Table (MSB and LSB)
+  */
+#define SFDP_BASIC_PARAMETER_TABLE_MSB    0xFFU
+#define SFDP_BASIC_PARAMETER_TABLE_LSB    0x00U
+
+/**
+  * @brief Maximum Flash size reachable by 24-bit addressing
+  */
+#define SFDP_24B_ADDRESS_MAX_FLASH_SIZE   24U
+
+/**
+  * @brief DEBUG macro string
+  */
+#if EXTMEM_DRIVER_NOR_SFDP_DEBUG_LEVEL > 3 && defined(EXTMEM_MACRO_DEBUG)
+#define SFDP_DEBUG_STR(_STR_)     do{                              \
+                                      EXTMEM_MACRO_DEBUG("\t\tSFDP::");\
+                                      EXTMEM_MACRO_DEBUG(_STR_);       \
+                                      EXTMEM_MACRO_DEBUG("\n");        \
+                                    }while(0);
+#else
+#define SFDP_DEBUG_STR(_STR_)
+#endif /* EXTMEM_DRIVER_NOR_SFDP_DEBUG_LEVEL > 3 && EXTMEM_MACRO_DEBUG */
+
+/**
+  * @brief DEBUG macro string + integer value
+  */
+#if EXTMEM_DRIVER_NOR_SFDP_DEBUG_LEVEL > 3 && defined(EXTMEM_MACRO_DEBUG)
+#define SFDP_DEBUG_INT(_STR_,_INT_) do {                                                \
+                                         char int_char[50];                             \
+                                         EXTMEM_MACRO_DEBUG("\t\tSFDP::");              \
+                                         (void)sprintf(int_char,"%s0x%x",_STR_, _INT_); \
+                                         EXTMEM_MACRO_DEBUG((uint8_t *)int_char);       \
+                                         EXTMEM_MACRO_DEBUG("\n");                      \
+                                       }while(0);
+#else
+#define SFDP_DEBUG_INT(_STR_,_INT_)
+#endif /* EXTMEM_DRIVER_NOR_SFDP_DEBUG_LEVEL > 3 && EXTMEM_MACRO_DEBUG */
+
+/**
+  * @brief DEBUG macro for function call
+  */
+#define CHECK_FUNCTION_CALL(_FUNC_)  do{                             \
+                                         retr = _FUNC_;              \
+                                         if ( EXTMEM_SFDP_OK != retr)\
+                                         {                           \
+                                           goto error;               \
+                                         }                           \
+                                       }while(0);
+
+/**
+  * @}
+  */
+
+/* Private typedefs ---------------------------------------------------------*/
+/** @defgroup NOR_SFDP_DATA_Private_TypeDefs Private typedefs
+  * @{
+  */
+
+/**
+  * @brief Memory link configuration structure.
+  */
+typedef struct
+{
+  SAL_XSPI_PhysicalLinkTypeDef PhyLink;    /*!< Physical link type */
+  uint8_t                      DummyCycle; /*!< Number of dummy cycles */
+} TableConfig_t;
+
+
+/**
+  * @brief SFDP parameter header structure.
+  */
+typedef struct
+{
+  uint8_t ID_lsb;                 /*!< Least significant byte of ID */
+  uint8_t Minor_revision;         /*!< Minor revision */
+  uint8_t Major_revision;         /*!< Major revision */
+  uint8_t Length;                 /*!< Length of the table */
+  uint8_t TableAddressPointer[3]; /*!< Table address pointer */
+  uint8_t ID_msb;                 /*!< Most significant byte of ID */
+} SFDP_ParameterHeader_t;
+
+/**
+  * @brief SFDP parameter table structure.
+  */
+typedef struct
+{
+  SFDP_ParamID_TypeDef type;  /*!< List of parameter tables available */
+  uint32_t address;           /*!< Address of the table */
+  uint8_t size;               /*!< Size of the table */
+} SFDP_ParameterTable_t;
+
+/**
+  * @brief SFDP JEDEC Basic Parameters structure.
+  */
+typedef struct
+{
+  uint32_t size;
+  union
+  {
+    uint8_t data_BYTE[23 * 4]; /*!< Data in bytes format */
+    uint32_t data_DWORD[23];   /*!< Data in DWORD format */
+    struct
+    {
+      struct
+      {
+        uint32_t BlockSectorEraseSizes:2;
+        uint32_t WriteGranularity:1;
+        uint32_t VolatileRegisterProtect:1;
+        uint32_t WriteEnableInstructionVolatileRegister:1;
+        uint32_t :3;
+        uint32_t _4KEraseInstruction:8;
+        uint32_t Support_1S1S2SFastRead:1;
+        uint32_t AddressBytes:2;
+        uint32_t Support_DTR:1;
+        uint32_t Support_1S2S2SFastRead:1;
+        uint32_t Support_1S4S4SFastRead:1;
+        uint32_t Support_1S1S4SFastRead:1;
+        uint32_t :8;
+      } D1;
+      struct
+      {
+        uint32_t FlashSize;
+      } D2;
+
+      /* Fast read */
+      struct
+      {
+        uint32_t _1S4S4S_DummyClock:5;
+        uint32_t _1S4S4S_ModeClock:3;
+        uint32_t _1S4S4S_FastReadInstruction:8;
+        uint32_t _1S1S4S_DummyClock:5;
+        uint32_t _1S1S4S_ModeClock:3;
+        uint32_t _1S1S4S_FastReadInstruction:8;
+      } D3;
+      struct
+      {
+        uint32_t _1S1S2S_DummyClock:5;
+        uint32_t _1S1S2S_ModeClock:3;
+        uint32_t _1S1S2S_FastReadInstruction:8;
+        uint32_t _1S2S2S_DummyClock:5;
+        uint32_t _1S2S2S_ModeClock:3;
+        uint32_t _1S2S2S_FastReadInstruction:8;
+      } D4;
+      struct
+      {
+        uint32_t _2S2S2S_FastReadSupport:1;
+        uint32_t :3;
+        uint32_t _4S4S4S_FastReadSupport:1;
+        uint32_t :27;
+      } D5;
+      struct
+      {
+        uint32_t :16;
+        uint32_t _2S2S2S_DummyClock:5;
+        uint32_t _2S2S2S_ModeClock:3;
+        uint32_t _2S2S2S_FastReadInstruction:8;
+      } D6;
+      struct
+      {
+        uint32_t :16;
+        uint32_t _4S4S4S_DummyClock:5;
+        uint32_t _4S4S4S_ModeClock:3;
+        uint32_t _4S4S4S_FastReadInstruction:8;
+      } D7;
+
+      /* Erase */
+      struct
+      {
+        uint32_t EraseType1_Size:8;
+        uint32_t EraseType1_Instruction:8;
+        uint32_t EraseType2_Size:8;
+        uint32_t EraseType2_Instruction:8;
+      } D8;
+      struct
+      {
+        uint32_t EraseType3_Size:8;
+        uint32_t EraseType3_Instruction:8;
+        uint32_t EraseType4_Size:8;
+        uint32_t EraseType4_Instruction:8;
+      } D9;
+
+      /* Timing */
+      struct
+      {
+        uint32_t MutliplierEraseTime:4;
+        uint32_t EraseType1_TypicalTime_count:5;
+        uint32_t EraseType1_TypicalTime_units:2;
+        uint32_t EraseType2_TypicalTime_count:5;
+        uint32_t EraseType2_TypicalTime_units:2;
+        uint32_t EraseType3_TypicalTime_count:5;
+        uint32_t EraseType3_TypicalTime_units:2;
+        uint32_t EraseType4_TypicalTime_count:5;
+        uint32_t EraseType4_TypicalTime_units:2;
+      } D10;
+      struct
+      {
+        uint32_t MutliplierProgamTime:4;
+        uint32_t PageSize:4;
+        uint32_t PageProgram_TypicalTime:6;
+        uint32_t ByteProgram_TypicalTime:5;
+        uint32_t AddByteProgram_TypicalTime:5;
+
+        uint32_t ChipErase_TypicalTime_count:5;   /* 28:24 count */
+        uint32_t ChipErase_TypicalTime_units:2;   /* 30:29 units (00b: 16 ms, 01b: 256 ms, 10b: 4 s, 11b: 64 s) */
+
+        uint32_t :1;
+      } D11;
+      struct
+      {
+        uint32_t ProhibitedOpDuringProgramSuspend:4;
+        uint32_t ProhibitedOpDuringEraseSuspend:4;
+        uint32_t :1;
+        uint32_t ProgramResumeToSuspendInterval:4;
+        uint32_t SuspendInProgress_ProgramMaxLatency:7;
+        uint32_t EraseResumeToSuspendInterval:4;
+        uint32_t SuspendInProgress_EraseMaxLatency:7;
+        uint32_t :1;
+      } D12;
+      struct
+      {
+        uint32_t ProgramResume_Intruction:8;
+        uint32_t ProgramSuspend_Intruction:8;
+        uint32_t Resume_Intruction:8;
+        uint32_t Suspend_Intruction:8;
+      } D13;
+      struct
+      {
+        uint32_t :2;
+        uint32_t StatusRegister:6;
+        uint32_t ExitDeepPowerdownDelay:7;
+        uint32_t ExitDeepPowerdown_Instruction:8;
+        uint32_t EnterDeepPowerdown_Instruction:8;
+        uint32_t DeepPowerdown_Support:1;
+      } D14;
+      struct
+      {
+        uint32_t _4S4S4S_DisableSequence:4;
+        uint32_t _4S4S4S_EnableSequence:5;
+        uint32_t _0S4S4S_Support:1;
+        uint32_t _0S4S4S_ExitMethod:6;
+        uint32_t _0S4S4S_EntryMethod:4;
+        uint32_t QuadEnableRequirement:3;
+        uint32_t HoldORReset_Disable:1;
+        uint32_t :8;
+      } D15;
+      struct
+      {
+        uint32_t VolatileNonVolatileRegister_WriteEnable:7;
+        uint32_t :1;
+        uint32_t SoftResetRescueSequence_Support:6;
+        uint32_t Exit4ByteAddressing:10;
+        uint32_t Enter4ByteAddressing:8;
+      } D16;
+      /* Added one for octal management, this part depends on the information size of the flash device */
+      struct
+      {
+        uint32_t _1S8S8S_DummyClock:5;
+        uint32_t _1S8S8S_ModeClock:3;
+        uint32_t _1S8S8S_FastReadInstruction:8;
+        uint32_t _1S1S8S_DummyClock:5;
+        uint32_t _1S1S8S_ModeClock:3;
+        uint32_t _1S1S8S_FastReadInstruction:8;
+      } D17;
+      struct
+      {
+        uint32_t :18;
+        uint32_t VariableOutputDriverStrength:5;
+        uint32_t JEDECSPIProtocolReset:1;
+        uint32_t DataStrobeSTRMode:2;
+        uint32_t DataSTrobeQPISTRMode:1;
+        uint32_t DataSTrobeQPIDTRMode:1;
+        uint32_t :1;
+        uint32_t OctalDTRCommandExtension:2;
+        uint32_t OctalByteOrder:1;
+      } D18;
+      struct
+      {
+        uint32_t _8s8s8s_DisableSequence:4;
+        uint32_t _8s8s8s_EnableSequence:5;
+        uint32_t _8S8S8S_Support:1;
+        uint32_t _8S8S8S_ExitMethod:6;
+        uint32_t _8S8S8S_EnterMethod:4;
+        uint32_t OctalRequirement:3;
+        uint32_t :9;
+      } D19;
+      struct
+      {
+        uint32_t _4S4S4S_MaximumSpeedWithoutStrobe:4; /* 1111b: not supported, 1110b: not characterized, 1010b: Reserved
+                                                         1100b: 400 MHz, 1011b: 333 MHz, 1010b: 266 MHz, 1001b: 250 MHz
+                                                         1000b: 200 MHz, 0111b: 166 MHz, 0110b: 133 MHz, 0101b: 100 MHz
+                                                         0100b: 80 MHz,  0011b: 66 MHz, 0010b: 50 MHz, 0001b: 33 MHz */
+        uint32_t _4S4S4S_MaximumSpeedWithStrobe:4;
+        uint32_t _4S4D4D_MaximumSpeedWithoutStrobe:4;
+        uint32_t _4S4D4D_MaximumSpeedWithStrobe:4;
+        uint32_t _8S8S8S_MaximumSpeedWithoutStrobe:4;
+        uint32_t _8S8S8S_MaximumSpeedWithStrobe:4;
+        uint32_t _8D8D8D_MaximumSpeedWithoutStrobe:4;
+        uint32_t _8D8D8D_MaximumSpeedWithStrobe:4;
+      } D20;
+      struct
+      {
+        uint32_t _1S1D1D_FastReadSupport:1;
+        uint32_t _1S2D2D_FastReadSupport:1;
+        uint32_t _1S4D4D_FastReadSupport:1;
+        uint32_t _4S4D4D_FastReadSupport:1;
+        uint32_t :28;
+      } D21;
+      struct
+      {
+        uint32_t _1S1D1D_DummyClock:5;
+        uint32_t _1S1D1D_ModeClock:3;
+        uint32_t _1S1D1D_FastReadInstruction:8;
+        uint32_t _1S2D2D_DummyClock:5;
+        uint32_t _1S2D2D_ModeClock:3;
+        uint32_t _1S2D2D_FastReadInstruction:8;
+      } D22;
+      struct
+      {
+        uint32_t _1S4D4D_DummyClock:5;
+        uint32_t _1S4D4D_ModeClock:3;
+        uint32_t _1S4D4D_FastReadInstruction:8;
+        uint32_t _4S4D4D_DummyClock:5;
+        uint32_t _4S4D4D_ModeClock:3;
+        uint32_t _4S4D4D_FastReadInstruction:8;
+      } D23;
+    } Param_DWORD;
+  } Params;
+} SFDP_JEDECBasic_Params_t;
+
+/**
+  * @brief SFDP JEDEC 4ByteAddress Params definition
+  */
+typedef union
+{
+  uint8_t data_BYTE[2 * 4]; /*!< data in BYTE format */
+  uint32_t data_DWORD[2];   /*!< data in DWORD format */
+  struct
+  {
+    struct
+    {
+      uint32_t Support_1S1S1S_ReadCommand:1;       /*!< Instruction=13h */
+      uint32_t Support_1S1S1S_FastReadCommand:1;   /*!< Instruction=0Ch */
+      uint32_t Support_1S1S2S_FastReadCommand:1;   /*!< Instruction=3Ch */
+      uint32_t Support_1S2S2S_FastReadCommand:1;   /*!< Instruction=BCh */
+      uint32_t Support_1S1S4S_FastReadCommand:1;   /*!< Instruction=6Ch */
+      uint32_t Support_1S4S4S_FastReadCommand:1;   /*!< Instruction=ECh */
+      uint32_t Support_1S1S1S_PageProgramCommand:1;/*!< Instruction=12h */
+      uint32_t Support_1S1S4S_PageProgramCommand:1;/*!< Instruction=34h */
+      uint32_t Support_1S4S4S_PageProgramCommand:1;/*!< Instruction=3Eh */
+      uint32_t Support_EraseCommandType1size:1;    /*!< support of erase type1 */
+      uint32_t Support_EraseCommandType2size:1;    /*!< Instruction lookup in next Dword */
+      uint32_t Support_EraseCommandType3size:1;    /*!< Instruction lookup in next Dword */
+      uint32_t Support_EraseCommandType4size:1;    /*!< Instruction lookup in next Dword */
+      uint32_t Support_1S1D1D_DTRReadCommand:1;    /*!< Instruction=0Eh */
+      uint32_t Support_1S2D2D_DTRReadCommand:1;    /*!< Instruction=BEh */
+      uint32_t Support_1S4D4D_DTRReadCommand:1;    /*!< Instruction=EEh */
+      uint32_t Support_VolatileIndividualSectorLockReadCommand:1;  /* Instruction=E0h */
+      uint32_t Support_VolatileIndividualSectorLockWriteCommand:1; /* Instruction=E1h */
+      uint32_t Support_NVolatileIndividualSectorLockReadCommand:1; /* Instruction=E2h */
+      uint32_t Support_NVolatileIndividualSectorLockWriteCommand:1;/* Instruction=E3h */
+      uint32_t Support_1S1S8S_FastReadCommand:1;   /* Instruction=7Ch */
+      uint32_t Support_1S8S8S_FastReadCommand:1;   /* Instruction=CCh */
+      uint32_t Support_1S8D8D_DTRReadCommand:1;    /* Instruction=FDh */
+      uint32_t Support_1S1S8S_PageProgramCommand:1;/* Instruction=84h */
+      uint32_t Support_1S8S8S_PageProgramCommand:1;/* Instruction=8Eh */
+      uint32_t :7;
+    } D1;
+    struct
+    {
+      uint32_t InstructionEraseType1:8;  /* common usage is:21h for   4 kbyte erase*/
+      uint32_t InstructionEraseType2:8;  /* common usage is:5Ch for  32 kbyte erase*/
+      uint32_t InstructionEraseType3:8;  /* common usage is:DCh for  64 kbyte erase*/
+      uint32_t InstructionEraseType4:8;  /* common usage is:DCh for 256 kbyte erase*/
+    } D2;
+  } Param_DWORD;
+} SFDP_JEDEC4ByteAddress_Params_t;
+
+
+/**
+  * @brief SFDP JEDEC XSPI10 Params definition
+  */
+typedef union
+{
+  uint8_t  data_BYTE[6 * 4];   /*!< data in BYTE format */
+  uint32_t data_DWORD[6];      /*!< data in DWORD format */
+  struct
+  {
+    /* Command Codes used in 8D-8D-8D protocol mode */
+    struct
+    {
+      uint32_t ReadFastWrapCommand:8; /* 0 means not supported */
+      uint32_t ReadFastCommand:8;
+      uint32_t :6;
+      uint32_t NumberOfDataBytesForWriteRegisterCommand:1;
+      uint32_t NumberOfAdditionnalModifierBytesForWriteRegisterCommand:1;
+      uint32_t NumberOfAdditionnalModifierBytesForStatusConfigRegisterCommand:1;
+      uint32_t InitialLaLatencyForReadNonVolatileRegisterCommand:1;
+      uint32_t InitialLatencyForReadVolatileRegisterCommand:1;
+      uint32_t NumberOfAdditionalModifierBytesForReadRegisterCommand:1;
+      uint32_t InitialLatencyForReadStatusRegisterCommand:1;
+      uint32_t NumberOfAdditionalModifierBytesForReadStatusRegisterCommand:1;
+      uint32_t SFDPCommand_8D8D8DMode_DummyCycles:1;
+      uint32_t SFDPCommand_8D8D8DMode_AddressBytes:1;
+    } D1;
+    /* Commands Codes used in 8D-8D-8D protocol mode */
+    struct
+    {
+      uint32_t WriteNVolatileRegisterCommand:8;
+      uint32_t WriteVolatileRegisterCommand:8;
+      uint32_t ReadNVolatileRegisterCommand:8;
+      uint32_t ReadVolatileRegisterCommand:8;
+    } D2;
+    /* Memory Commands in 8D-8D-8D protocol mode */
+    struct
+    {
+      uint32_t :10;
+      uint32_t EnterDefaultProtocolMode_support:1;
+      uint32_t SoftResetAndEnterDefaultProtocolMode_support:1;
+      uint32_t ResetEnable_support:1;
+      uint32_t SoftReset_support:1;
+      uint32_t ExitDeepPowerDown_support:1;
+      uint32_t EnterDeepPowerDown_support:1;
+      uint32_t WriteNVolatileRegister_support:1;
+      uint32_t WriteVolatileRegister_support:1;
+      uint32_t WriteRegister_support:1;
+      uint32_t ClearFlagStatusReg_support:1;
+      uint32_t WriteStatusConfigurationRegister_support:1;
+      uint32_t ReadNVolatileRegister_support:1;
+      uint32_t ReadVolatileRegister_support:1;
+      uint32_t ReadRegister_support:1;
+      uint32_t ReadFlagStatusRegister_support:1;
+      uint32_t ReadConfigurationRegister_support:1;
+      uint32_t EraseChip_support:1;
+      uint32_t Erase_32Kbytes_support:1;
+      uint32_t Erase_4Kbytes_support:1;
+      uint32_t SetupReadWrap_support:1;
+      uint32_t ReadFastWrap_support:1;
+      uint32_t ReadSFDP_8D8D8D:1;
+    } D3;  /* this naming to be aligned with the specification */
+    /* Dummy cycles used for various frequencies */
+    struct
+    {
+      uint32_t :2;
+      uint32_t Operation200Mhz_ConfigPattern:5;
+      uint32_t Operation200Mhz_DummyCycle:5;
+      uint32_t :20;
+    } D4;
+    /* Dummy cycles used for various frequencies */
+    struct
+    {
+      uint32_t :2;
+      uint32_t Operation100Mhz_ConfigPattern:5;
+      uint32_t Operation100Mhz_DummyCycle:5;
+      uint32_t Operation133Mhz_ConfigPattern:5;
+      uint32_t Operation133Mhz_DummyCycle:5;
+      uint32_t Operation166Mhz_ConfigPattern:5;
+      uint32_t Operation166Mhz_DummyCycle:5;
+    } D5;
+    /* Default Dummy cycles after POR */
+    struct
+    {
+      uint32_t _8D8D8DDefaultPOR_DummyCycle:5;
+      uint32_t _8S8S8SDefaultPOR_DummyCycle:5;
+      uint32_t :22;
+    } D6;
+
+  } Param_DWORD;
+} SFDP_JEDEC_XSPI10_t; /* contains the command codes used in 8D-8D-8D protocol mode */
+
+/**
+  * @brief SFDP JEDEC octal ddr params definition
+  */
+typedef union
+{
+  uint8_t  data_BYTE[8 * 4]; /*!< data in BYTE format */
+  uint32_t data_DWORD[8];    /*!< data in DWORD format */
+  struct
+  {
+    /* 1st DWORD - First Command Sequence */
+    struct
+    {
+      uint32_t Byte3CommandSequence:8;
+      uint32_t Byte2CommandSequence:8;
+      uint32_t Byte1CommandSequence:8;
+      uint32_t LengthCommand:8;
+    } D1;
+    /* 2nd DWORD - First Command Sequence (continued)*/
+    struct
+    {
+      uint32_t Byte7CommandSequence:8;
+      uint32_t Byte6CommandSequence:8;
+      uint32_t Byte5CommandSequence:8;
+      uint32_t Byte4CommandSequence:8;
+    } D2;
+    /* 1st DWORD - Second Command Sequence */
+    struct
+    {
+      uint32_t Byte3CommandSequence:8;
+      uint32_t Byte2CommandSequence:8;
+      uint32_t Byte1CommandSequence:8;
+      uint32_t LengthCommand:8;
+    } D3;
+    /* 2nd DWORD - Second Command Sequence (continued)*/
+    struct
+    {
+      uint32_t Byte7CommandSequence:8;
+      uint32_t Byte6CommandSequence:8;
+      uint32_t Byte5CommandSequence:8;
+      uint32_t Byte4CommandSequence:8;
+    } D4;
+    /* 1st DWORD - third Command Sequence */
+    struct
+    {
+      uint32_t Byte3CommandSequence:8;
+      uint32_t Byte2CommandSequence:8;
+      uint32_t Byte1CommandSequence:8;
+      uint32_t LengthCommand:8;
+    } D5;
+    /* 2nd DWORD - third Command Sequence (continued)*/
+    struct
+    {
+      uint32_t Byte7CommandSequence:8;
+      uint32_t Byte6CommandSequence:8;
+      uint32_t Byte5CommandSequence:8;
+      uint32_t Byte4CommandSequence:8;
+    } D6;
+    /* 1st DWORD - fourth Command Sequence */
+    struct
+    {
+      uint32_t Byte3CommandSequence:8;
+      uint32_t Byte2CommandSequence:8;
+      uint32_t Byte1CommandSequence:8;
+      uint32_t LengthCommand:8;
+    } D7;
+    /* 2nd DWORD - fourth Command Sequence (continued)*/
+    struct
+    {
+      uint32_t Byte7CommandSequence:8;
+      uint32_t Byte6CommandSequence:8;
+      uint32_t Byte5CommandSequence:8;
+      uint32_t Byte4CommandSequence:8;
+    } D8;
+  } Param_DWORD;
+} SFDP_JEDEC_OCTALDDR_t; /* contains the command codes used in 8D-8D-8D protocol mode */
+
+/**
+  * @brief SFDP JEDEC SCCR Params definition
+  */
+typedef union
+{
+  uint8_t  data_b[28 * 4];   /*!< data in byte format */
+  uint32_t data_DWORD[28];   /*!< data in DWORD format */
+  struct
+  {
+
+    uint32_t AddressOffsetVolatileRegister;
+    uint32_t AddressOffsetNonVolatileRegister;
+
+
+    /* Generic Addressable Read/Write Status/Control register commands for volatile registers */
+    struct
+    {
+      uint32_t NbDummyCyclesReadStatusControlRegisterCommandForVolatileRegisters_1S1S1S:4;
+      uint32_t :2;
+      uint32_t NbDummyCyclesReadRegisterCmdVolatileRegister_8D8D8D_mode:4;
+      uint32_t NbDummyCyclesReadRegisterCmdVolatileRegister_8S8S8S_mode:4;
+      uint32_t NbDummyCyclesReadRegisterCmdVolatileRegister_4S4D4D_mode:4;
+      uint32_t NbDummyCyclesReadRegisterCmdVolatileRegister_4S4S4S_mode:4;
+      uint32_t NbDummyCyclesReadRegisterCmdVolatileRegister_2S2S2S_mode:4;
+      uint32_t NbDummyCyclesReadRegisterCmdVolatileRegister_1S1S1S_mode:2;
+
+      uint32_t NbAddressBytesGenericAddressableReadWriteStatusControlRegisterCommandsVolatileRegisters:2;
+      uint32_t GenericAddressableWriteRegisterCmdVolatileRegister_support:1;
+      uint32_t GenericAddressableReadRegisterCmdVolatileRegister_support:1;
+    } D3;
+    /* Generic Addressable Read/Write Status/Control register commands for non-volatile registers */
+    struct
+    {
+      uint32_t NbDummyCyclesReadStatusControlRegisterCommandForNVolatileRegisters_1S1S1S:4;
+      uint32_t :2;
+      uint32_t NbDummyCyclesReadRegisterCmdNonVolatileRegister_8D8D8D_mode:4;
+      uint32_t NbDummyCyclesReadRegisterCmdNonVolatileRegister_8S8S8S_mode:4;
+      uint32_t NbDummyCyclesReadRegisterCmdNonVolatileRegister_4S4D4D_mode:4;
+      uint32_t NbDummyCyclesReadRegisterCmdNonVolatileRegister_4S4S4S_mode:4;
+      uint32_t NbDummyCyclesReadRegisterCmdNonVolatileRegister_2S2S2S_mode:4;
+      uint32_t NbDummyCyclesReadRegisterCmdNonVolatileRegister_1S1S1S_mode:2;
+
+      uint32_t NbAddressBytesGenericAddressableReadWriteStatusControlRegisterCommandsNVolatileRegisters:2;
+      uint32_t GenericAddressableWriteRegisterCmdNonVolatileRegister_support:1;
+      uint32_t GenericAddressableReadRegisterCmdNonVolatileRegister_support:1;
+    } D4;
+    /* WIP (Required for xSPI) */
+    struct
+    {
+      uint32_t CommandWriteAccess:8;
+      uint32_t CommandReadAccess:8;
+      uint32_t AddressRegisterOrModesSupported:8; /*  If Bit 28 is 1: Address of register where bit is located
+                                                      Local address AAAA-AAAA
+                                                      If Bit 28 is 0: Modes supported and dummy cycles
+                                                      used for direct command
+                                                  */
+      uint8_t  WIPBitLocationRegister:3;
+      uint32_t LocalAddressForWIP:1;
+      uint32_t BitAccessedByCommandsUsingAddress:1;
+      uint32_t :1;
+      uint32_t WIPpolarity:1;
+      uint32_t WIPBitAvailable:1;
+    } D5;
+    /* WEL */
+    struct
+    {
+      uint32_t CommandWriteAccess:8;
+      uint32_t CommandReadAccess:8;
+      uint32_t AddressRegisterOrModesSupported:8; /*  If Bit 28 is 1: Address of register where bit is located
+                                                      Local address AAAA-AAAA
+                                                      If Bit 28 is 0: Modes supported and dummy cycles
+                                                      used for direct command
+                                                  */
+      uint8_t  WELBitLocationRegister:3;
+      uint32_t WELLocalAddress:1;
+      uint32_t BitAccessedByCommandsUsingAddress:1;
+      uint32_t WELWriteAccessBit:1;
+      uint32_t WELpolarity:1;
+      uint32_t WELBitAvailable:1;
+    } D6;
+    /* Program Error */
+    struct
+    {
+      uint32_t CommandWriteAccess:8;
+      uint32_t CommandReadAccess:8;
+      uint32_t AddressRegisterOrModesSupported:8; /*  If Bit 28 is 1: Address of register where bit is located
+                                                      Local address AAAA-AAAA
+                                                      If Bit 28 is 0: Modes supported and dummy cycles
+                                                      used for direct command
+                                                  */
+      uint8_t  BitLocationRegister:3;
+      uint32_t LocalAddress:1;
+      uint32_t BitAccessedByCommandsUsingAddress:1;
+      uint32_t Sharing:1;
+      uint32_t Polarity:1;
+      uint32_t BitAvailable:1;
+    } D7;
+    /* Erase Error */
+    struct
+    {
+      uint32_t CommandWriteAccess:8;
+      uint32_t CommandReadAccess:8;
+      uint32_t AddressRegisterOrModesSupported:8; /*  If Bit 28 is 1: Address of register where bit is located
+                                                      Local address AAAA-AAAA
+                                                      If Bit 28 is 0: Modes supported and dummy cycles
+                                                      used for direct command
+                                                  */
+      uint8_t  BitLocationRegister:3;
+      uint32_t LocalAddress:1;
+      uint32_t BitAccessedByCommandsUsingAddress:1;
+      uint32_t Sharing:1;
+      uint32_t Polarity:1;
+      uint32_t BitAvailable:1;
+    } D8;
+    /* 9th DWORD * Variable Dummy Cycle Settings * Volatile Register */
+    struct
+    {
+      uint32_t CommandWriteAccess:8;
+      uint32_t CommandReadAccess:8;
+      uint32_t AddressRegisterOrModesSupported:8; /*  If Bit 28 is 1: Address of register where bit is located
+                                                      Local address AAAA-AAAA
+                                                      If Bit 28 is 0: Modes supported and dummy cycles
+                                                      used for direct command
+                                                  */
+      uint8_t  BitLocationLSBPhysicalBitsRegister:3;
+      uint32_t LocalAddress:1;
+      uint32_t BitAccessedByCommandsUsingAddress:1;
+      uint32_t NumberBitsUsedToSetWaitStates:2;
+      uint32_t BitAvailable:1;
+    } D9;
+    /* 10th DWORD * Variable Dummy Cycle Settings * Non Volatile Register */
+    struct
+    {
+      uint32_t CommandWriteAccess:8;
+      uint32_t CommandReadAccess:8;
+      uint32_t AddressRegisterOrModesSupported:8; /*  If Bit 28 is 1: Address of register where bit is located
+                                                      Local address AAAA-AAAA
+                                                      If Bit 28 is 0: Modes supported and dummy cycles
+                                                      used for direct command
+                                                  */
+      uint8_t  BitLocationLSBPhysicalBitsRegister:3;
+      uint32_t LocalAddress:1;
+      uint32_t BitAccessedByCommandsUsingAddress:1;
+      uint32_t NumberBitsUsedToSetWaitStates:2;
+      uint32_t BitAvailable:1;
+    } D10;
+    /* 11th DWORD * Variable Dummy Cycle Settings * bit patterns */
+    struct
+    {
+      uint32_t :2;
+      uint32_t BitPatternUsedToSet_22DummyCycles:5;
+      uint32_t Support_22DummyCycles:1;
+      uint32_t BitPatternUsedToSet_24DummyCycles:5;
+      uint32_t Support_24DummyCycles:1;
+      uint32_t BitPatternUsedToSet_26DummyCycles:5;
+      uint32_t Support_26DummyCycles:1;
+      uint32_t BitPatternUsedToSet_28DummyCycles:5;
+      uint32_t Support_28DummyCycles:1;
+      uint32_t BitPatternUsedToSet_30DummyCycles:5;
+      uint32_t Support_30DummyCycles:1;
+    } D11;
+    /* 12th DWORD * Variable Dummy Cycle Settings * bit patterns */
+    struct
+    {
+      uint32_t :2;
+      uint32_t BitPatternUsedToSet_12DummyCycles:5;
+      uint32_t Support_12DummyCycles:1;
+      uint32_t BitPatternUsedToSet_14DummyCycles:5;
+      uint32_t Support_14DummyCycles:1;
+      uint32_t BitPatternUsedToSet_16DummyCycles:5;
+      uint32_t Support_16DummyCycles:1;
+      uint32_t BitPatternUsedToSet_18DummyCycles:5;
+      uint32_t Support_18DummyCycles:1;
+      uint32_t BitPatternUsedToSet_20DummyCycles:5;
+      uint32_t Support_20DummyCycles:1;
+    } D12;
+    /* 13th DWORD * Variable Dummy Cycle Settings * bit patterns */
+    struct
+    {
+      uint32_t :2;
+      uint32_t BitPatternUsedToSet_2DummyCycles:5;
+      uint32_t Support_2DummyCycles:1;
+      uint32_t BitPatternUsedToSet_4DummyCycles:5;
+      uint32_t Support_4DummyCycles:1;
+      uint32_t BitPatternUsedToSet_6DummyCycles:5;
+      uint32_t Support_6DummyCycles:1;
+      uint32_t BitPatternUsedToSet_8DummyCycles:5;
+      uint32_t Support_8DummyCycles:1;
+      uint32_t BitPatternUsedToSet_10DummyCycles:5;
+      uint32_t Support_10DummyCycles:1;
+    } D13;
+    /* 14th DWORD * QPI Mode Enable Volatile */
+    struct
+    {
+      uint32_t CommandWriteAccess:8;
+      uint32_t CommandReadAccess:8;
+      uint32_t AddressRegisterOrModesSupported:8; /*  If Bit 28 is 1: Address of register where bit is located
+                                                      Local address AAAA-AAAA
+                                                      If Bit 28 is 0: Modes supported and dummy cycles
+                                                      used for direct command
+                                                  */
+      uint8_t  BitLocationRegister:3;
+      uint32_t LocalAddress:1;
+      uint32_t BitAccessedByCommandsUsingAddress:1;
+      uint32_t :1;
+      uint32_t BitPolarity:1;
+      uint32_t BitAvailable:1;
+    } D14;
+    /* 15th DWORD * QPI Mode Enable - Non Volatile */
+    struct
+    {
+      uint32_t CommandWriteAccess:8;
+      uint32_t CommandReadAccess:8;
+      uint32_t AddressRegisterOrModesSupported:8; /*  If Bit 28 is 1: Address of register where bit is located
+                                                      Local address AAAA-AAAA
+                                                      If Bit 28 is 0: Modes supported and dummy cycles
+                                                      used for direct command
+                                                  */
+      uint8_t  BitLocationRegister:3;
+      uint32_t LocalAddress:1;
+      uint32_t BitAccessedByCommandsUsingAddress:1;
+      uint32_t :1;
+      uint32_t BitPolarity:1;
+      uint32_t BitAvailable:1;
+    } D15;
+    /* 16th DWORD * Octal Mode Enable Volatile */
+    struct
+    {
+      uint32_t CommandWriteAccess:8;
+      uint32_t CommandReadAccess:8;
+      uint32_t AddressRegisterOrModesSupported:8; /*  If Bit 28 is 1: Address of register where bit is located
+                                                      Local address AAAA-AAAA
+                                                      If Bit 28 is 0: Modes supported and dummy cycles
+                                                      used for direct command
+                                                  */
+      uint8_t  BitLocationRegister:3;
+      uint32_t LocalAddress:1;
+      uint32_t BitAccessedByCommandsUsingAddress:1;
+      uint32_t :1;
+      uint32_t BitPolarity:1;
+      uint32_t BitAvailable:1;
+    } D16;
+    /* 17th DWORD * Octal Mode Enable - Non Volatile */
+    struct
+    {
+      uint32_t CommandWriteAccess:8;
+      uint32_t CommandReadAccess:8;
+      uint32_t AddressRegisterOrModesSupported:8; /*  If Bit 28 is 1: Address of register where bit is located
+                                                      Local address AAAA-AAAA
+                                                      If Bit 28 is 0: Modes supported and dummy cycles
+                                                      used for direct command
+                                                  */
+      uint8_t  BitLocationRegister:3;
+      uint32_t LocalAddress:1;
+      uint32_t BitAccessedByCommandsUsingAddress:1;
+      uint32_t :1;
+      uint32_t BitPolarity:1;
+      uint32_t BitAvailable:1;
+    } D17;
+    /* 18th DWORD * STR or DTR mode select * Volatile */
+    struct
+    {
+      uint32_t CommandWriteAccess:8;
+      uint32_t CommandReadAccess:8;
+      uint32_t AddressRegisterOrModesSupported:8; /*  If Bit 28 is 1: Address of register where bit is located
+                                                      Local address AAAA-AAAA
+                                                      If Bit 28 is 0: Modes supported and dummy cycles
+                                                      used for direct command
+                                                  */
+      uint8_t  BitLocationRegister:3;
+      uint32_t LocalAddress:1;
+      uint32_t BitAccessedByCommandsUsingAddress:1;
+      uint32_t :1;
+      uint32_t BitPolarity:1;
+      uint32_t BitAvailable:1;
+    } D18;
+    /* 19th DWORD * STR or DTR mode select * Non Volatile */
+    struct
+    {
+      uint32_t CommandWriteAccess:8;
+      uint32_t CommandReadAccess:8;
+      uint32_t AddressRegisterOrModesSupported:8; /*  If Bit 28 is 1: Address of register where bit is located
+                                                      Local address AAAA-AAAA
+                                                      If Bit 28 is 0: Modes supported and dummy cycles
+                                                      used for direct command
+                                                  */
+      uint8_t  BitLocationRegister:3;
+      uint32_t LocalAddress:1;
+      uint32_t BitAccessedByCommandsUsingAddress:1;
+      uint32_t :1;
+      uint32_t BitPolarity:1;
+      uint32_t BitAvailable:1;
+    } D19;
+    /* 20th DWORD * STR Octal Mode Enable * Volatile */
+    struct
+    {
+      uint32_t CommandWriteAccess:8;
+      uint32_t CommandReadAccess:8;
+      uint32_t AddressRegisterOrModesSupported:8; /*  If Bit 28 is 1: Address of register where bit is located
+                                                      Local address AAAA-AAAA
+                                                      If Bit 28 is 0: Modes supported and dummy cycles
+                                                      used for direct command
+                                                  */
+      uint8_t  BitLocationRegister:3;
+      uint32_t LocalAddress:1;
+      uint32_t BitAccessedByCommandsUsingAddress:1;
+      uint32_t :1;
+      uint32_t BitPolarity:1;
+      uint32_t BitAvailable:1;
+    } D20;
+    /* 21th DWORD * STR Octal Mode Enable * Non Volatile */
+    struct
+    {
+      uint32_t CommandWriteAccess:8;
+      uint32_t CommandReadAccess:8;
+      uint32_t AddressRegisterOrModesSupported:8; /*  If Bit 28 is 1: Address of register where bit is located
+                                                      Local address AAAA-AAAA
+                                                      If Bit 28 is 0: Modes supported and dummy cycles
+                                                      used for direct command
+                                                  */
+      uint8_t  BitLocationRegister:3;
+      uint32_t LocalAddress:1;
+      uint32_t BitAccessedByCommandsUsingAddress:1;
+      uint32_t :1;
+      uint32_t BitPolarity:1;
+      uint32_t BitAvailable:1;
+    } D21;
+    /* 22th DWORD * DTR Octal Mode Enable * Volatile */
+    struct
+    {
+      uint32_t CommandWriteAccess:8;
+      uint32_t CommandReadAccess:8;
+      uint32_t AddressRegisterOrModesSupported:8; /*  If Bit 28 is 1: Address of register where bit is located
+                                                      Local address AAAA-AAAA
+                                                      If Bit 28 is 0: Modes supported and dummy cycles
+                                                      used for direct command
+                                                  */
+      uint8_t  BitLocationRegister:3;
+      uint32_t LocalAddress:1;
+      uint32_t BitAccessedByCommandsUsingAddress:1;
+      uint32_t :1;
+      uint32_t BitPolarity:1;
+      uint32_t BitAvailable:1;
+    } D22;
+    /* 23th DWORD * DTR Octal Mode Enable * Non Volatile */
+    struct
+    {
+      uint32_t CommandWriteAccess:8;
+      uint32_t CommandReadAccess:8;
+      uint32_t AddressRegisterOrModesSupported:8; /*  If Bit 28 is 1: Address of register where bit is located
+                                                      Local address AAAA-AAAA
+                                                      If Bit 28 is 0: Modes supported and dummy cycles
+                                                      used for direct command
+                                                  */
+      uint8_t  BitLocationRegister:3;
+      uint32_t LocalAddress:1;
+      uint32_t BitAccessedByCommandsUsingAddress:1;
+      uint32_t :1;
+      uint32_t BitPolarity:1;
+      uint32_t BitAvailable:1;
+    } D23;
+    /* 24th DWORD * DPD Status */
+    struct
+    {
+      uint32_t CommandWriteAccess:8;
+      uint32_t CommandReadAccess:8;
+      uint32_t AddressRegisterOrModesSupported:8; /*  If Bit 28 is 1: Address of register where bit is located
+                                                      Local address AAAA-AAAA
+                                                      If Bit 28 is 0: Modes supported and dummy cycles
+                                                      used for direct command
+                                                  */
+      uint8_t  BitLocationRegister:3;
+      uint32_t LocalAddress:1;
+      uint32_t BitAccessedByCommandsUsingAddress:1;
+      uint32_t :1;
+      uint32_t BitPolarity:1;
+      uint32_t BitAvailable:1;
+    } D24;
+    /* 25th DWORD * UDPD Status */
+    struct
+    {
+      uint32_t CommandWriteAccess:8;
+      uint32_t CommandReadAccess:8;
+      uint32_t AddressRegisterOrModesSupported:8; /*  If Bit 28 is 1: Address of register where bit is located
+                                                      Local address AAAA-AAAA
+                                                      If Bit 28 is 0: Modes supported and dummy cycles
+                                                      used for direct command
+                                                  */
+      uint8_t  BitLocationRegister:3;
+      uint32_t LocalAddress:1;
+      uint32_t BitAccessedByCommandsUsingAddress:1;
+      uint32_t :1;
+      uint32_t BitPolarity:1;
+      uint32_t BitAvailable:1;
+    } D25;
+    /* 26th DWORD * Output Driver Strength - Volatile */
+    struct
+    {
+      uint32_t CommandWriteAccess:8;
+      uint32_t CommandReadAccess:8;
+      uint32_t AddressRegisterOrModesSupported:8; /*  If Bit 28 is 1: Address of register where bit is located
+                                                      Local address AAAA-AAAA
+                                                      If Bit 28 is 0: Modes supported and dummy cycles
+                                                      used for direct command
+                                                  */
+      uint8_t  BitLocationRegister:3;
+      uint32_t LocalAddress:1;
+      uint32_t BitAccessedByCommandsUsingAddress:1;
+      uint32_t :1;
+      uint32_t NumberOfPhysicalBits:2;
+    } D26;
+    /* 27th DWORD * Output Driver Strength - Non Volatile */
+    struct
+    {
+      uint32_t CommandWriteAccess:8;
+      uint32_t CommandReadAccess:8;
+      uint32_t AddressRegisterOrModesSupported:8; /*  If Bit 28 is 1: Address of register where bit is located
+                                                      Local address AAAA-AAAA
+                                                      If Bit 28 is 0: Modes supported and dummy cycles
+                                                      used for direct command
+                                                  */
+      uint8_t  BitLocationRegister:3;
+      uint32_t LocalAddress:1;
+      uint32_t BitAccessedByCommandsUsingAddress:1;
+      uint32_t :1;
+      uint32_t NumberOfPhysicalBits:2;
+    } D27;
+    /* 27th DWORD * Output Driver Strength - Non Volatile */
+    struct
+    {
+      uint32_t :16;
+      uint32_t BitPatternSupportDriverType4 :3;
+      uint32_t BitPatternSupportDriverType3 :3;
+      uint32_t BitPatternSupportDriverType2 :3;
+      uint32_t BitPatternSupportDriverType1 :3;
+      uint32_t BitPatternSupportDriverType0 :3;
+    } D28;
+
+
+  } Param_DWORD;
+} SFDP_JEDEC_SCCR_Map_t; /* contains the command codes used in 8D-8D-8D protocol mode */
+
+/**
+  * @}
+  */
+
+/* Private variables ---------------------------------------------------------*/
+/** @defgroup NOR_SFDP_DATA_Private_Variables Private Variables
+  * @{
+  */
+/**
+  * @brief this variable contains all the table available on a memory
+  */
+static SFDP_ParameterTable_t     sfdp_param_info[SFDP_MAX_NB_OF_PARAM];
+
+/**
+  * @brief this variable contains the JEDEC basic table info
+  */
+static SFDP_JEDECBasic_Params_t        JEDEC_Basic = {0};
+
+/**
+  * @brief this variable contains the JEDEC address 4-Byte address table info
+  */
+static SFDP_JEDEC4ByteAddress_Params_t JEDEC_Address4Bytes = {0};
+
+/**
+  * @brief this variable contains the JEDEC XSPIV1.0 table info
+  */
+static SFDP_JEDEC_XSPI10_t             JEDEC_XSPI10;
+
+/**
+  * @brief this variable contains the JEDEC SCCR table info
+  */
+static SFDP_JEDEC_SCCR_Map_t           JEDEC_SCCR_Map;
+
+/**
+  * @brief this variable contains the JEDEC octal DDR table info
+  */
+static SFDP_JEDEC_OCTALDDR_t           JEDEC_OctalDdr;
+
+
+/**
+  * @}
+  */
+
+/* Private functions ---------------------------------------------------------*/
+/** @defgroup NOR_SFDP_DATA_Private_Functions Private Functions
+  * @{
+  */
+SFDP_StatusTypeDef sfdp_get_paraminfo(EXTMEM_DRIVER_NOR_SFDP_ObjectTypeDef *Object, uint32_t sfdp_address,
+                                      SFDP_ParameterTable_t *Param_info);
+SFDP_StatusTypeDef sfdp_enter_octal_mode(EXTMEM_DRIVER_NOR_SFDP_ObjectTypeDef *Object);
+uint32_t sfdp_getfrequencevalue(uint32_t BitField);
+SFDP_StatusTypeDef sfdp_set_dummycycle(EXTMEM_DRIVER_NOR_SFDP_ObjectTypeDef *Object, uint32_t Value);
+/**
+  * @}
+  */
+
+/** @defgroup NOR_SFDP_DATA_Private_JEDEC_Functions Private Functions for JEDEC decoding
+  * @{
+  */
+SFDP_StatusTypeDef JEDEC_Basic_ManageQuadEnableRequirement(EXTMEM_DRIVER_NOR_SFDP_ObjectTypeDef *Object);
+SFDP_StatusTypeDef JEDEC_Basic_Manage4S4S4SEnableSequence(EXTMEM_DRIVER_NOR_SFDP_ObjectTypeDef *Object);
+
+/** @defgroup NOR_SFDP_DATA_Private_Singature_Functions Private Functions for SFDP signature
+  * @{
+  */
+SFDP_StatusTypeDef CheckSFDP_Signature(EXTMEM_DRIVER_NOR_SFDP_ObjectTypeDef *Object, uint32_t Signature);
+/**
+  * @}
+  */
+
+
+/** @defgroup NOR_SFDP_DATA_Exported_Functions Exported Functions
+  * @{
+  */
+
+/**
+  * @brief Reads the SFDP header for the current configuration and adjusts the memory type if required.
+  * @param Object Pointer to the NOR SFDP memory instance object descriptor.
+  * @param sfdp_header Pointer to the SFDP header structure to be filled.
+  * @retval SFDP_StatusTypeDef Status of the operation: EXTMEM_SFDP_OK if successful, error code otherwise.
+  */
+SFDP_StatusTypeDef SFDP_ReadHeader(EXTMEM_DRIVER_NOR_SFDP_ObjectTypeDef *Object, SFDP_HeaderTypeDef *sfdp_header)
+{
+  SFDP_StatusTypeDef retr;
+  uint8_t retry_counter = 0;
+  SFDP_DEBUG_STR(__func__);
+
+  do
+  {
+    /* Reset the signature value */
+    sfdp_header->Signature = 0;
+
+    /* send the SFDP command to read the header */
+    if (HAL_OK != SAL_XSPI_GetSFDP(&Object->sfdp_private.SALObject, 0, (uint8_t *)sfdp_header, SFDP_HEADER_SIZE))
+    {
+      retr = EXTMEM_SFDP_ERROR_SFDPREAD;
+      goto error;
+    }
+
+    /* view the header signature value  */
+    SFDP_DEBUG_INT("SFDP signature::", sfdp_header->Signature);
+
+    switch (CheckSFDP_Signature(Object, sfdp_header->Signature))
+    {
+      case EXTMEM_SFDP_OK:
+        SFDP_DEBUG_INT("param_number=", sfdp_header->param_number);
+        SFDP_DEBUG_INT("AccessProtocol=", sfdp_header->AccessProtocol);
+        retr = EXTMEM_SFDP_OK;
+        retry_counter = 2u;
+        break;
+      case EXTMEM_SFDP_ERROR_SIGNATUREMTYPE:
+        retr = EXTMEM_SFDP_ERROR_SIGNATURE;
+        retry_counter++;
+        break;
+      /* case EXTMEM_SFDP_ERROR_SIGNATURE :*/
+      default :
+        retr = EXTMEM_SFDP_ERROR_SIGNATURE;
+        retry_counter = 2u;
+        break;
+    }
+  } while (retry_counter < 2u);
+
+error:
+  return retr;
+}
+
+/**
+  * @brief Retrieves the SFDP header for the NOR memory device.
+  * @param Object Pointer to the NOR SFDP memory instance object descriptor.
+  * @param sfdp_header Pointer to the SFDP header structure to be filled.
+  * @retval SFDP_StatusTypeDef Status of the operation: EXTMEM_SFDP_OK if successful, error code otherwise.
+  */
+SFDP_StatusTypeDef SFDP_GetHeader(EXTMEM_DRIVER_NOR_SFDP_ObjectTypeDef *Object, SFDP_HeaderTypeDef *sfdp_header)
+{
+  SFDP_StatusTypeDef retr = EXTMEM_SFDP_ERROR_SIGNATURE;
+  SFDP_DEBUG_STR(__func__);
+  const TableConfig_t table_config[] =
+  {
+    {PHY_LINK_1S1S1S, 8u},
+    {PHY_LINK_4S4S4S, 2u},
+    {PHY_LINK_4S4S4S, 8u},
+    {PHY_LINK_4S4S4S, 6u},
+    {PHY_LINK_8D8D8D, 8u},
+    {PHY_LINK_8D8D8D, 20u},
+    {PHY_LINK_8D8D8D, 10u},
+    {PHY_LINK_8D8D8D, 16u}
+  };
+
+  /* Loop to find the link configuration of the memory */
+  for (uint8_t index = 0u;
+       (index < (sizeof(table_config) / sizeof(TableConfig_t))) &&
+       (retr == EXTMEM_SFDP_ERROR_SIGNATURE)
+       ; index++)
+  {
+    /* Set the command mode */
+    SFDP_DEBUG_STR("try a command configuration");
+
+    /* Configure the link */
+    Object->sfdp_private.DriverInfo.SpiPhyLink  = table_config[index].PhyLink;
+    (void)SAL_XSPI_MemoryConfig(&Object->sfdp_private.SALObject, PARAM_PHY_LINK,
+                                &Object->sfdp_private.DriverInfo.SpiPhyLink);
+    SAL_XSPI_SET_SFDPDUMMYCYLE(Object->sfdp_private.SALObject, table_config[index].DummyCycle);
+
+    /* Loop on the instruction extension */
+    for (uint8_t IExt = 0u;
+         (IExt < 2u) && (retr == EXTMEM_SFDP_ERROR_SIGNATURE); IExt++)
+    {
+      SAL_XSPI_SET_COMMANDEXTENSION(Object->sfdp_private.SALObject, IExt);
+      /* Read the sfdp header */
+      if (EXTMEM_SFDP_OK == SFDP_ReadHeader(Object, sfdp_header))
+      {
+        retr = EXTMEM_SFDP_OK;
+      }
+
+      if (table_config[index].PhyLink < PHY_LINK_4S4S4S)
+      {
+        /* Config 1 is invalid so exit the loop */
+        break;
+      }
+    }
+  }
+  return retr;
+}
+
+/**
+  * @brief Collects all SFDP parameter table information and builds driver data.
+  * @param Object Pointer to the NOR SFDP memory instance object descriptor.
+  * @retval SFDP_StatusTypeDef Status of the operation: EXTMEM_SFDP_OK if successful, error code otherwise.
+  */
+SFDP_StatusTypeDef SFDP_CollectData(EXTMEM_DRIVER_NOR_SFDP_ObjectTypeDef *Object)
+{
+  SFDP_StatusTypeDef retr = EXTMEM_SFDP_OK;
+  uint32_t sfdp_address = SFDP_HEADER_SIZE;
+  SFDP_DEBUG_STR(__func__);
+
+  /* Reset the table mask */
+  Object->sfdp_private.Sfdp_table_mask = 0;
+
+  /* Reset the param info */
+  (void)memset(sfdp_param_info, 0x0, sizeof(sfdp_param_info));
+
+  /* Get the table param info */
+  for (uint8_t index = 0u; index < (Object->sfdp_private.Sfdp_param_number + 1u); index++)
+  {
+    CHECK_FUNCTION_CALL(sfdp_get_paraminfo(Object, sfdp_address, &sfdp_param_info[index]))
+    Object->sfdp_private.Sfdp_table_mask |= (uint32_t)sfdp_param_info[index].type;
+    sfdp_address += SFDP_PARAM_HEADER_SIZE;
+  }
+
+  /* Read each table param to extract the information to build the driver */
+  for (uint8_t index = 0u; sfdp_param_info[index].type != SFDP_PARAMID_UNKNOWN; index++)
+  {
+    uint8_t *ptr = NULL;
+    uint32_t size = sfdp_param_info[index].size;
+    switch (sfdp_param_info[index].type)
+    {
+      case SFDP_PARAMID_BASIC_SPIPROTOCOL:
+        JEDEC_Basic.size = sfdp_param_info[index].size;
+        ptr = JEDEC_Basic.Params.data_BYTE;
+        break;
+      case SFDP_PARAMID_4BYTE_ADDRESS_INSTRUCTION:
+        ptr = JEDEC_Address4Bytes.data_BYTE;
+        break;
+      case SFDP_PARAMID_STATUS_CONTROL_CONFIG_REGISTER_MAP:
+        ptr = JEDEC_SCCR_Map.data_b;
+        break;
+      case SFDP_PARAMID_XSPI_V1_0:
+        ptr = JEDEC_XSPI10.data_BYTE;
+        break;
+      case SFDP_PARAMID_OCTAL_DDR:
+        ptr = JEDEC_OctalDdr.data_BYTE;
+        break;
+      default :
+        SFDP_DEBUG_STR("the table is not yet handled by the SW");
+        break;
+    }
+    if (ptr != NULL)
+    {
+      if (HAL_OK != SAL_XSPI_GetSFDP(&Object->sfdp_private.SALObject,
+                                     sfdp_param_info[index].address,
+                                     ptr, size * 4u))
+      {
+        retr = EXTMEM_SFDP_ERROR_DRIVER;
+        goto error;
+      }
+    }
+
+    if (SFDP_PARAMID_BASIC_SPIPROTOCOL == sfdp_param_info[index].type)
+    {
+      /* Save data about the reset procedure */
+      Object->sfdp_private.Reset_info = JEDEC_Basic.Params.Param_DWORD.D16.SoftResetRescueSequence_Support;
+    }
+  }
+
+error:
+  return retr;
+}
+
+/**
+  * @brief Resets the NOR memory device using the SFDP-defined reset procedure.
+  * @param Object Pointer to the NOR SFDP memory instance object descriptor.
+  * @retval SFDP_StatusTypeDef Status of the operation: EXTMEM_SFDP_OK if successful, error code otherwise.
+  */
+SFDP_StatusTypeDef SFDP_MemoryReset(EXTMEM_DRIVER_NOR_SFDP_ObjectTypeDef *Object)
+{
+  RESET_METHOD reset_method;
+  SFDP_StatusTypeDef retr = EXTMEM_SFDP_ERROR_NO_PARAMTABLE_BASIC;
+  uint32_t sfdp_address = SFDP_HEADER_SIZE;
+  uint8_t find = 0u;
+  SFDP_DEBUG_STR(__func__);
+
+  /* Get the table param info */
+  for (uint8_t index = 0u; index < (Object->sfdp_private.Sfdp_param_number + 1u); index++)
+  {
+    retr = sfdp_get_paraminfo(Object, sfdp_address, &sfdp_param_info[0]);
+    if (EXTMEM_SFDP_OK == retr)
+    {
+      /* Check if the table is basic table */
+      if (SFDP_PARAMID_BASIC_SPIPROTOCOL == sfdp_param_info[0].type)
+      {
+        /* Read the JEDEC basic param */
+        if (HAL_OK != SAL_XSPI_GetSFDP(&Object->sfdp_private.SALObject,
+                                       sfdp_param_info[0].address,
+                                       JEDEC_Basic.Params.data_BYTE,
+                                       ((uint32_t)sfdp_param_info[0].size) * 4u))
+        {
+          retr = EXTMEM_SFDP_ERROR_DRIVER;
+        }
+        else
+        {
+          retr = EXTMEM_SFDP_OK;
+          find = 1u;
+        }
+      }
+    }
+
+    if ((EXTMEM_SFDP_OK != retr) || (1u == find))
+    {
+      /* Stop reading, if there is an error or if the table has been found */
+      break;
+    }
+    /* Look for the next table */
+    sfdp_address += SFDP_PARAM_HEADER_SIZE;
+  }
+
+  /* If an error has been returned or if the table has not been found */
+  if ((EXTMEM_SFDP_OK != retr) || (0u == find))
+  {
+    retr = EXTMEM_SFDP_ERROR_DRIVER;
+    goto error;
+  }
+
+  /* Determine how to proceed memory reset */
+  if (0x0u == JEDEC_Basic.Params.Param_DWORD.D16.SoftResetRescueSequence_Support)
+  {
+    /* 00_0000b: no software reset instruction is supported */
+    reset_method = RESET_NONE;
+  }
+  else if (0x1u == (0x1u & JEDEC_Basic.Params.Param_DWORD.D16.SoftResetRescueSequence_Support))
+  {
+    /* xx_xxx1b: drive Fh on all 4 data wires for 8 clocks */
+    reset_method = RESET_FH_4DATA_8CLOCK;
+  }
+  else if (0x2u == (0x2u & JEDEC_Basic.Params.Param_DWORD.D16.SoftResetRescueSequence_Support))
+  {
+    /* xx_xx1xb: drive Fh on all 4 data wires for 10 clocks if device is operating in 4-byte address mode */
+    reset_method = RESET_FH_4DATA_10CLOCK;
+  }
+  else if (0x4u == (0x4u & JEDEC_Basic.Params.Param_DWORD.D16.SoftResetRescueSequence_Support))
+  {
+    /* xx_x1xxb: drive Fh on all 4 data wires for 16 clocks */
+    reset_method = RESET_FH_4DATA_16CLOCK;
+  }
+  else if (0x8u == (0x8u & JEDEC_Basic.Params.Param_DWORD.D16.SoftResetRescueSequence_Support))
+  {
+    /* xx_1xxxb: issue instruction F0h */
+    reset_method = RESET_INSTRUCTION_F0;
+  }
+  else if (0x10u == (0x10u & JEDEC_Basic.Params.Param_DWORD.D16.SoftResetRescueSequence_Support))
+  {
+    /* x1_xxxxb: issue reset enable instruction 66h, then issue reset instruction 99h. The reset enable,
+    reset sequence may be issued on 1, 2, or 4 wires depending on the device operating mode.
+    */
+    reset_method = RESET_INSTRUCTION_66_99;
+  }
+  else if (0x20u == (0x20u & JEDEC_Basic.Params.Param_DWORD.D16.SoftResetRescueSequence_Support))
+  {
+    /* 1x_xxxxb: exit 0-4-4 mode is required prior to other reset sequences above if the device may be
+      operating in this mode. See 6.4.18, 0-4-4 Mode Exit
+    */
+    /* JEDEC_Basic.Params.Param_DWORD.D16.Exit4ByteAddressing
+    Exit 4-Byte Addressing
+    xx_xxxx_xxx1b: issue instruction E9h to exit 4-Byte address mode (write enable instruction 06h is not required)
+    xx_xxxx_xx1xb: issue write enable instruction 06h, then issue instruction E9h to exit 4-Byte address mode
+    xx_xxxx_x1xxb: 8-bit volatile extended address register used to define A[31:A24] bits. Read with instruction C8h.
+                   Write instruction is C5h, data length is 1 byte. Return to lowest memory segment
+                   by setting A[31:24] to 00h and use 3-Byte addressing.
+    xx_xxxx_1xxxb: 8-bit volatile bank register used to define A[30:A24] bits. MSB (bit[7]) is used to enable/disable
+                   4-byte address mode. When MSB is cleared to 0, 3-byte address mode is active
+                   and A30:A24 are used to select the active 128 Mbit memory segment.
+                   Read with instruction 16h. Write instruction is 17h, data length is 1 byte.
+    xx_xxx1_xxxxb: A 16-bit nonvolatile configuration register controls 3-Byte/4-Byte address mode.
+                   Read instruction is B5h. Bit[0] controls address mode [0=3-Byte; 1=4-Byte].
+                   Write configuration register instruction is B1h, data length is 2 bytes.
+    xx_xx1x_xxxxb: Hardware reset
+    xx_x1xx_xxxxb: Software reset (see bits 13:8 in this DWORD)
+    xx_1xxx_xxxxb: Power cycle
+    x1_xxxx_xxxxb: Reserved
+    */
+    retr = EXTMEM_SFDP_ERROR_NOTYETHANDLED;
+    goto error;
+  }
+  else
+  {
+    /* No coherence, should be managed as error */
+    retr = EXTMEM_SFDP_ERROR_DRIVER;
+    goto error;
+  }
+
+  switch (reset_method)
+  {
+    case RESET_NONE:
+      break;
+    case RESET_INSTRUCTION_66_99:
+      /* Perform the reset in 1, 2 and 4 lines */
+      SFDP_DEBUG_STR("::reset 0x66 0x99");
+      (void)SAL_XSPI_CommandSendData(&Object->sfdp_private.SALObject, 0x66, NULL, 0);
+      (void)SAL_XSPI_CommandSendData(&Object->sfdp_private.SALObject, 0x99, NULL, 0);
+      break;
+    case RESET_INSTRUCTION_F0:
+    case RESET_FH_4DATA_8CLOCK:
+    case RESET_FH_4DATA_10CLOCK:
+    case RESET_FH_4DATA_16CLOCK:
+      retr = EXTMEM_SFDP_ERROR_NOTYETHANDLED;
+      break;
+    /* case RESET_ERROR:*/
+    default :
+      retr = EXTMEM_SFDP_ERROR_PARAM;
+      break;
+  }
+error :
+  return retr;
+}
+
+/**
+  * @brief Builds the generic driver information from SFDP tables.
+  * @param Object Pointer to the NOR SFDP memory instance object descriptor.
+  * @param FreqUpdated Pointer to a variable set to 1 if the frequency is updated, 0 otherwise.
+  * @retval SFDP_StatusTypeDef Status of the operation: EXTMEM_SFDP_OK if successful, error code otherwise.
+  */
+SFDP_StatusTypeDef SFDP_BuildGenericDriver(EXTMEM_DRIVER_NOR_SFDP_ObjectTypeDef *Object, uint8_t *FreqUpdated)
+{
+  SFDP_StatusTypeDef retr = EXTMEM_SFDP_OK;
+  static const uint16_t block_erase_unit[] = { 16u, 256u, 4000u, 64000u};
+  static const uint32_t chip_erase_unit[]  = { 16u, 256u, 4000u, 64000u};
+  SFDP_DEBUG_STR(__func__);
+  uint8_t flag4byteAddress = 0u;
+  uint32_t dummyCycles;
+  uint32_t dummyCyclesValue;
+  uint8_t FlashSize;
+
+  if ((Object->sfdp_private.Sfdp_table_mask & (uint32_t)SFDP_PARAMID_BASIC_SPIPROTOCOL) !=
+      (uint32_t)SFDP_PARAMID_BASIC_SPIPROTOCOL)
+  {
+    /* This table is mandatory to build the driver data */
+    retr = EXTMEM_SFDP_ERROR_NO_PARAMTABLE_BASIC;
+    goto error;
+  }
+
+  /* ---------------------------------------------------
+   *  Flash sizing
+   * ---------------------------------------------------
+   */
+  /* Calculation of the flash density in puissance of 2 */
+  if ((JEDEC_Basic.Params.Param_DWORD.D2.FlashSize & 0x80000000u) == 0x0u)
+  {
+#if ( __CORTEX_M == 0)
+#error "the assembly instruction is not available"
+#else
+    Object->sfdp_private.FlashSize = 31u - (uint8_t)__CLZ((JEDEC_Basic.Params.Param_DWORD.D2.FlashSize + 1u));
+#endif /* __CORTEX_M */
+  }
+  else
+  {
+    Object->sfdp_private.FlashSize = (uint8_t)(JEDEC_Basic.Params.Param_DWORD.D2.FlashSize & 0x7FFFFFFFu);
+  }
+
+  /* Conversion bit to byte */
+  Object->sfdp_private.FlashSize = Object->sfdp_private.FlashSize - 3u; /* divide by eight the value */
+
+  SFDP_DEBUG_INT("-> flash size: 2^", Object->sfdp_private.FlashSize);
+  FlashSize = Object->sfdp_private.FlashSize - 1u;
+  (void) SAL_XSPI_MemoryConfig(&Object->sfdp_private.SALObject, PARAM_FLASHSIZE, &FlashSize);
+
+  /* get the page size info */
+  Object->sfdp_private.PageSize = ((uint32_t)1u <<  JEDEC_Basic.Params.Param_DWORD.D11.PageSize);
+
+  /* ---------------------------------------------------
+   *  Set default command
+   * ---------------------------------------------------
+   */
+  Object->sfdp_private.DriverInfo.PageProgramInstruction = SFDP_DRIVER_PAGE_PROGRAM_COMMAND;
+
+
+  /* ---------------------------------------------------
+   *  Erase management
+   * ---------------------------------------------------
+   */
+  /* Manage erase data */
+  Object->sfdp_private.DriverInfo.EraseType1Size    = (uint8_t)JEDEC_Basic.Params.Param_DWORD.D8.EraseType1_Size;
+  Object->sfdp_private.DriverInfo.EraseType1Command = (uint8_t)JEDEC_Basic.Params.Param_DWORD.D8.EraseType1_Instruction;
+  Object->sfdp_private.DriverInfo.EraseType2Size    = (uint8_t)JEDEC_Basic.Params.Param_DWORD.D8.EraseType2_Size;
+  Object->sfdp_private.DriverInfo.EraseType2Command = (uint8_t)JEDEC_Basic.Params.Param_DWORD.D8.EraseType2_Instruction;
+  Object->sfdp_private.DriverInfo.EraseType3Size    = (uint8_t)JEDEC_Basic.Params.Param_DWORD.D9.EraseType3_Size;
+  Object->sfdp_private.DriverInfo.EraseType3Command = (uint8_t)JEDEC_Basic.Params.Param_DWORD.D9.EraseType3_Instruction;
+  Object->sfdp_private.DriverInfo.EraseType4Size    = (uint8_t)JEDEC_Basic.Params.Param_DWORD.D9.EraseType4_Size;
+  Object->sfdp_private.DriverInfo.EraseType4Command = (uint8_t)JEDEC_Basic.Params.Param_DWORD.D9.EraseType4_Instruction;
+
+  if (Object->sfdp_private.DriverInfo.EraseType1Size != 0x0u)
+  {
+    Object->sfdp_private.DriverInfo.EraseType1Timing =
+      (uint32_t)JEDEC_Basic.Params.Param_DWORD.D10.MutliplierEraseTime *
+      (JEDEC_Basic.Params.Param_DWORD.D10.EraseType1_TypicalTime_count + 1u) *
+      block_erase_unit[JEDEC_Basic.Params.Param_DWORD.D10.EraseType1_TypicalTime_units];
+  }
+
+  if (Object->sfdp_private.DriverInfo.EraseType2Size != 0x0u)
+  {
+    Object->sfdp_private.DriverInfo.EraseType2Timing =
+      (uint32_t)JEDEC_Basic.Params.Param_DWORD.D10.MutliplierEraseTime *
+      (JEDEC_Basic.Params.Param_DWORD.D10.EraseType2_TypicalTime_count + 1u) *
+      block_erase_unit[JEDEC_Basic.Params.Param_DWORD.D10.EraseType2_TypicalTime_units];
+  }
+
+  if (Object->sfdp_private.DriverInfo.EraseType3Size != 0x0u)
+  {
+    Object->sfdp_private.DriverInfo.EraseType3Timing =
+      (uint32_t)JEDEC_Basic.Params.Param_DWORD.D10.MutliplierEraseTime *
+      (JEDEC_Basic.Params.Param_DWORD.D10.EraseType3_TypicalTime_count + 1u) *
+      block_erase_unit[JEDEC_Basic.Params.Param_DWORD.D10.EraseType3_TypicalTime_units];
+  }
+
+  if (Object->sfdp_private.DriverInfo.EraseType4Size != 0x0u)
+  {
+    Object->sfdp_private.DriverInfo.EraseType4Timing =
+      (uint32_t)JEDEC_Basic.Params.Param_DWORD.D10.MutliplierEraseTime *
+      (JEDEC_Basic.Params.Param_DWORD.D10.EraseType4_TypicalTime_count + 1u) *
+      block_erase_unit[JEDEC_Basic.Params.Param_DWORD.D10.EraseType4_TypicalTime_units];
+  }
+
+  Object->sfdp_private.DriverInfo.EraseChipTiming =
+    JEDEC_Basic.Params.Param_DWORD.D10.MutliplierEraseTime *
+    (JEDEC_Basic.Params.Param_DWORD.D11.ChipErase_TypicalTime_count + 1u) *
+    chip_erase_unit[JEDEC_Basic.Params.Param_DWORD.D11.ChipErase_TypicalTime_units];
+
+  /* ------------------------------------------------------
+   *   WIP/WEL : write in progress/ write enable management
+   * ------------------------------------------------------
+   */
+  /* This bit definition is maintained for legacy compatibility only. New system implementations
+  should refer to 6.4.19 for a full definition of volatile and non-volatile behavior. */
+  Object->sfdp_private.DriverInfo.ReadWELCommand = SFDP_DRIVER_READ_STATUS_REGISTER_COMMAND;
+  Object->sfdp_private.DriverInfo.ReadWIPCommand = SFDP_DRIVER_READ_STATUS_REGISTER_COMMAND;
+  if (JEDEC_Basic.Params.Param_DWORD.D1.WriteEnableInstructionVolatileRegister == 0u)
+  {
+    Object->sfdp_private.DriverInfo.WriteWELCommand = SFDP_DRIVER_WRITE_ENABLE_50H_COMMAND;
+  }
+  else
+  {
+    Object->sfdp_private.DriverInfo.WriteWELCommand = SFDP_DRIVER_WRITE_ENABLE_06H_COMMAND;
+  }
+
+  /* Volatile or Non-Volatile Register and Write Enable Instruction for Status Register 1
+     The instruction 01h is typically used to write status register 1 which contains Block Protection (BP)
+     and other bits. Status register 1 is written by the first data byte following the instruction 01h.
+     The protection bits must be written to zero to enable writes/erases to the device.
+     This field describes how to modify the writable bits in status register 1
+     in either a volatile or non-volatile manner.
+     Bits 1:0 in status register 1 are de-facto standard write enable and busy status and
+     are excluded from the definitions below.
+  */
+  /* xxx_xxx1b: Non-Volatile Status Register 1, powers-up to last written value, use instruction 06h to enable write */
+  if ((JEDEC_Basic.Params.Param_DWORD.D16.VolatileNonVolatileRegister_WriteEnable & 0x1u) != 0u)
+  {
+    Object->sfdp_private.DriverInfo.WriteWELCommand = SFDP_DRIVER_WRITE_ENABLE_06H_COMMAND;
+  }
+  /* xxx_xx1xb: Volatile Status Register 1,
+                status register powers-up with bits set to "1"s, use instruction 06h to enable write */
+  else if ((JEDEC_Basic.Params.Param_DWORD.D16.VolatileNonVolatileRegister_WriteEnable & 0x02u) != 0u)
+  {
+    Object->sfdp_private.DriverInfo.WriteWELCommand = SFDP_DRIVER_WRITE_ENABLE_06H_COMMAND;
+  }
+  /* xxx_x1xxb: Volatile Status Register 1, status register powers-up with bits set to "1"s,
+                use instruction 50h to enable write */
+  else if ((JEDEC_Basic.Params.Param_DWORD.D16.VolatileNonVolatileRegister_WriteEnable & 0x04u) != 0u)
+  {
+    Object->sfdp_private.DriverInfo.WriteWELCommand = SFDP_DRIVER_WRITE_ENABLE_50H_COMMAND;
+  }
+  /* xxx_1xxxb: Non-Volatile/Volatile status register 1 powers-up to last written value in the non-volatile
+                status register, use instruction 06h to enable write to non-volatile status register.
+                Volatile status register may be activated after power-up to override the non-volatile status register,
+                use instruction 50h to enable write and activate the volatile status register.*/
+  else if ((JEDEC_Basic.Params.Param_DWORD.D16.VolatileNonVolatileRegister_WriteEnable & 0x08u) != 0u)
+  {
+    Object->sfdp_private.DriverInfo.WriteWELCommand = SFDP_DRIVER_WRITE_ENABLE_06H_COMMAND;
+  }
+  /* xx1_xxxxb: Status Register 1 contains a mix of volatile and non-volatile bits. The 06h instruction is used to
+     enable writing of the register.*/
+  else if ((JEDEC_Basic.Params.Param_DWORD.D16.VolatileNonVolatileRegister_WriteEnable & 0x10u) != 0u)
+  {
+    Object->sfdp_private.DriverInfo.WriteWELCommand = SFDP_DRIVER_WRITE_ENABLE_06H_COMMAND;
+  }
+  /* x1x_xxxxb: Reserved
+     1xx_xxxxb: Reserved
+     NOTE If the status register is read-only then this field will contain all zeros in bits 4:0.
+  */
+  else
+  {
+    retr = EXTMEM_SFDP_ERROR_JEDECBASIC_D16;
+    goto error;
+  }
+
+  if (0u != (Object->sfdp_private.Sfdp_table_mask & (uint32_t)SFDP_PARAMID_STATUS_CONTROL_CONFIG_REGISTER_MAP))
+  {
+    /* WIP */
+    if (0u != JEDEC_SCCR_Map.Param_DWORD.D5.WIPBitAvailable)
+    {
+      Object->sfdp_private.DriverInfo.ReadWIPCommand  = (uint8_t)JEDEC_SCCR_Map.Param_DWORD.D5.CommandReadAccess;
+      Object->sfdp_private.DriverInfo.WIPPosition     = JEDEC_SCCR_Map.Param_DWORD.D5.WIPBitLocationRegister;
+      Object->sfdp_private.DriverInfo.WIPBusyPolarity = (uint8_t)JEDEC_SCCR_Map.Param_DWORD.D5.WIPpolarity;
+      Object->sfdp_private.DriverInfo.WIPPosition     = JEDEC_SCCR_Map.Param_DWORD.D5.WIPBitLocationRegister;
+
+      if (0u != JEDEC_SCCR_Map.Param_DWORD.D5.BitAccessedByCommandsUsingAddress)
+      {
+        /* Address management */
+        Object->sfdp_private.DriverInfo.WIPAddress  = (uint8_t)JEDEC_SCCR_Map.Param_DWORD.D5.LocalAddressForWIP;
+      }
+      else
+      {
+        /* in that case there is no address to manage, the value EXTMEM_ADDRESS_NONE is used to detect the difference */
+        Object->sfdp_private.DriverInfo.WIPAddress = EXTMEM_ADDRESS_NONE;
+      }
+    }
+
+    /* WEL */
+    if (0u != JEDEC_SCCR_Map.Param_DWORD.D6.WELBitAvailable)
+    {
+      Object->sfdp_private.DriverInfo.ReadWELCommand  = (uint8_t)JEDEC_SCCR_Map.Param_DWORD.D6.CommandReadAccess;
+      Object->sfdp_private.DriverInfo.WELPosition     = JEDEC_SCCR_Map.Param_DWORD.D6.WELBitLocationRegister;
+      Object->sfdp_private.DriverInfo.WELBusyPolarity = (uint8_t)JEDEC_SCCR_Map.Param_DWORD.D6.WELpolarity;
+      Object->sfdp_private.DriverInfo.WELPosition     = JEDEC_SCCR_Map.Param_DWORD.D6.WELBitLocationRegister;
+
+      if (0u != JEDEC_SCCR_Map.Param_DWORD.D5.BitAccessedByCommandsUsingAddress)
+      {
+        /* Address management */
+        Object->sfdp_private.DriverInfo.WELAddress  = (uint8_t)JEDEC_SCCR_Map.Param_DWORD.D6.WELLocalAddress;
+      }
+      else
+      {
+        /* in that case there is no address to manage, the value EXTMEM_ADDRESS_NONE is used to detect the difference */
+        Object->sfdp_private.DriverInfo.WELAddress = EXTMEM_ADDRESS_NONE;
+      }
+    }
+  }
+  else
+  {
+    Object->sfdp_private.DriverInfo.WELPosition     = 1;
+    Object->sfdp_private.DriverInfo.WELBusyPolarity = 0;
+
+    /*
+     *   WIP : Status register read management
+     *         Basic D14 Status register Polling device Busy
+     */
+    if (0x01u == (JEDEC_Basic.Params.Param_DWORD.D14.StatusRegister &  0x01u))
+    {
+      /* xx_xxx1b: Use of legacy polling is supported by reading the Status Register with 05h instruction
+         and checking WIP bit[0] (0=ready; 1=busy). */
+      Object->sfdp_private.DriverInfo.ReadWIPCommand = SFDP_DRIVER_READ_STATUS_REGISTER_COMMAND;
+      Object->sfdp_private.DriverInfo.WIPPosition = 0u;
+      Object->sfdp_private.DriverInfo.WIPBusyPolarity = 0u;
+    }
+    else if (0x02u == (JEDEC_Basic.Params.Param_DWORD.D14.StatusRegister &  0x02u))
+    {
+      /* xx_xx1xb: Bit 7 of the Flag Status Register may be polled any time a Program, Erase, Suspend/Resume
+         command is issued, or after a Reset command while the device is busy. The read instruction is 70h.
+         Flag Status Register bit definitions: bit[7]: Program or erase controller status (0=busy; 1=ready)*/
+      Object->sfdp_private.DriverInfo.ReadWIPCommand = 0x70;
+      Object->sfdp_private.DriverInfo.WIPPosition = 7u;
+      Object->sfdp_private.DriverInfo.WIPBusyPolarity = 1u;
+    }
+    else
+    {
+      retr = EXTMEM_SFDP_ERROR_JEDECBASIC_D14;
+      goto error;
+    }
+  }
+
+#if defined(EXTMEM_DRIVER_NOR_SFDP_DUAL_CONFIG)
+  Object->sfdp_private.SALObject.ReadWipCommand = Object->sfdp_private.DriverInfo.ReadWIPCommand;
+  Object->sfdp_private.SALObject.ReadWelCommand = Object->sfdp_private.DriverInfo.ReadWELCommand;
+#endif /* EXTMEM_DRIVER_NOR_SFDP_DUAL_CONFIG */
+
+  /* Set default value for Read instruction */
+  Object->sfdp_private.DriverInfo.ReadInstruction     = SFDP_DRIVER_READ_COMMAND;
+  dummyCycles = 0;
+  (void)SAL_XSPI_MemoryConfig(&Object->sfdp_private.SALObject, PARAM_DUMMY_CYCLES, (void *)&dummyCycles);
+
+  /* ---------------------------------------------------
+   *  command based on SFDP_PARAMID_BASIC_SPIPROTOCOL
+   * ---------------------------------------------------
+   */
+  if (((Object->sfdp_private.Sfdp_table_mask & (uint32_t)SFDP_PARAMID_BASIC_SPIPROTOCOL)
+       == (uint32_t)SFDP_PARAMID_BASIC_SPIPROTOCOL)
+      && (Object->sfdp_private.Config < EXTMEM_LINK_CONFIG_8LINES))
+  {
+    Object->sfdp_private.DriverInfo.SpiPhyLink = PHY_LINK_1S1S1S;
+
+    if (Object->sfdp_private.Config > EXTMEM_LINK_CONFIG_1LINE)
+    {
+      /* control if read 1s1s2s is available */
+      if (JEDEC_Basic.Params.Param_DWORD.D4._1S1S2S_FastReadInstruction != 0u)
+      {
+        dummyCycles = JEDEC_Basic.Params.Param_DWORD.D4._1S1S2S_DummyClock
+                      + JEDEC_Basic.Params.Param_DWORD.D4._1S1S2S_ModeClock;
+        Object->sfdp_private.DriverInfo.ReadInstruction =
+          (uint8_t)JEDEC_Basic.Params.Param_DWORD.D4._1S1S2S_FastReadInstruction;
+        Object->sfdp_private.DriverInfo.SpiPhyLink = PHY_LINK_1S1S2S;
+      }
+
+      /* control if read 1S2S2S is available */
+      if (JEDEC_Basic.Params.Param_DWORD.D4._1S2S2S_FastReadInstruction != 0u)
+      {
+        dummyCycles = JEDEC_Basic.Params.Param_DWORD.D4._1S2S2S_DummyClock
+                      + JEDEC_Basic.Params.Param_DWORD.D4._1S2S2S_ModeClock;
+        Object->sfdp_private.DriverInfo.ReadInstruction =
+          (uint8_t)JEDEC_Basic.Params.Param_DWORD.D4._1S2S2S_FastReadInstruction;
+        Object->sfdp_private.DriverInfo.SpiPhyLink = PHY_LINK_1S2S2S;
+      }
+
+      /* The memory work only in 2S2S2S */
+      if (JEDEC_Basic.Params.Param_DWORD.D5._2S2S2S_FastReadSupport != 0u)
+      {
+        dummyCycles = JEDEC_Basic.Params.Param_DWORD.D6._2S2S2S_DummyClock
+                      + JEDEC_Basic.Params.Param_DWORD.D6._2S2S2S_ModeClock;
+        Object->sfdp_private.DriverInfo.ReadInstruction =
+          (uint8_t)JEDEC_Basic.Params.Param_DWORD.D6._2S2S2S_FastReadInstruction;
+      }
+    }
+
+    /* the command set is only based on this table */
+    /* determine the best line configuration */
+    if (Object->sfdp_private.Config > EXTMEM_LINK_CONFIG_2LINES)
+    {
+      if (JEDEC_Basic.Params.Param_DWORD.D5._4S4S4S_FastReadSupport != 0u)
+      {
+        dummyCycles = JEDEC_Basic.Params.Param_DWORD.D7._4S4S4S_DummyClock
+                      + JEDEC_Basic.Params.Param_DWORD.D7._4S4S4S_ModeClock;
+        Object->sfdp_private.DriverInfo.ReadInstruction =
+          (uint8_t)JEDEC_Basic.Params.Param_DWORD.D7._4S4S4S_FastReadInstruction;
+        Object->sfdp_private.DriverInfo.SpiPhyLink = PHY_LINK_4S4S4S;
+
+        retr = JEDEC_Basic_Manage4S4S4SEnableSequence(Object);
+        if (retr != EXTMEM_SFDP_OK)
+        {
+          goto error;
+        }
+      }
+      else if (JEDEC_Basic.Params.Param_DWORD.D1.Support_1S4S4SFastRead != 0u)
+      {
+        dummyCycles = JEDEC_Basic.Params.Param_DWORD.D3._1S4S4S_DummyClock
+                      + JEDEC_Basic.Params.Param_DWORD.D3._1S4S4S_ModeClock;
+        Object->sfdp_private.DriverInfo.ReadInstruction =
+          (uint8_t)JEDEC_Basic.Params.Param_DWORD.D3._1S4S4S_FastReadInstruction;
+        Object->sfdp_private.DriverInfo.SpiPhyLink = PHY_LINK_1S4S4S;
+
+        retr = JEDEC_Basic_ManageQuadEnableRequirement(Object);
+        if (retr != EXTMEM_SFDP_OK)
+        {
+          goto error;
+        }
+      }
+      else if (JEDEC_Basic.Params.Param_DWORD.D1.Support_1S1S4SFastRead != 0u)
+      {
+        dummyCycles = JEDEC_Basic.Params.Param_DWORD.D3._1S1S4S_DummyClock
+                      + JEDEC_Basic.Params.Param_DWORD.D3._1S1S4S_ModeClock;
+        Object->sfdp_private.DriverInfo.ReadInstruction =
+          (uint8_t)JEDEC_Basic.Params.Param_DWORD.D3._1S1S4S_FastReadInstruction;
+        Object->sfdp_private.DriverInfo.SpiPhyLink = PHY_LINK_1S1S4S;
+
+        retr = JEDEC_Basic_ManageQuadEnableRequirement(Object);
+        if (retr != EXTMEM_SFDP_OK)
+        {
+          goto error;
+        }
+      }
+      else /* other configuration with more 4 lines */
+      {
+        /* not yet handled */
+      }
+      (void)SAL_XSPI_MemoryConfig(&Object->sfdp_private.SALObject, PARAM_DUMMY_CYCLES, (void *)&dummyCycles);
+
+#if defined(IS25WP032D_ENABLE_DTR)
+      /* Check support of DTR feature (DTR Support in D1) */
+      if (JEDEC_Basic.Params.Param_DWORD.D1.Support_DTR == 1u)
+      {
+        /* Additional information regarding DTR read instruction and dummy cycles might be present in
+             D21 : Fast Read (1S-1D-1D), (1S-2D-2D), (1S-4D-4D), and (4S-4D-4D) Support
+              and
+             D23 : Fast Read (1S-4D-4D) and (4S-4D-4D) Wait States, Mode Bit Clocks, and Instruction */
+        /* Extract values for 4S4D4D */
+        if (JEDEC_Basic.Params.Param_DWORD.D21._4S4D4D_FastReadSupport == 1u)
+        {
+          dummyCycles = JEDEC_Basic.Params.Param_DWORD.D23._4S4D4D_DummyClock
+                        + JEDEC_Basic.Params.Param_DWORD.D23._4S4D4D_ModeClock;
+          Object->sfdp_private.DriverInfo.ReadInstruction =
+            (uint8_t)JEDEC_Basic.Params.Param_DWORD.D23._4S4D4D_FastReadInstruction;
+          Object->sfdp_private.DriverInfo.SpiPhyLink = PHY_LINK_4S4D4D;
+        }
+        else
+        {
+          /* Other specific cases to be managed : for example, when Basic Flash Parameter Table is not long enough
+             and D21, ... are not provided by the card. Specific cases section might have to be updated when adding
+             support for new memories whose SFDP parameter table is not complete */
+
+          /* Specific case for ISSI memories */
+          if (Object->sfdp_private.ManuID == EXTMEM_MANUFACTURER_ISSI)   /* ISSI manufacturer ID */
+          {
+            dummyCycles = 6u;
+            Object->sfdp_private.DriverInfo.ReadInstruction = 0x0D;
+            Object->sfdp_private.DriverInfo.SpiPhyLink = PHY_LINK_4S4D4D;
+            SAL_XSPI_SET_DTRREADDUMMYCYLE(Object->sfdp_private.SALObject, (uint8_t)dummyCycles);
+          }
+
+        }
+      }
+#endif /* IS25WP032D_ENABLE_DTR */
+
+    }
+
+    /* Configure the link */
+    if (HAL_OK != SAL_XSPI_MemoryConfig(&Object->sfdp_private.SALObject, PARAM_PHY_LINK,
+                                        &Object->sfdp_private.DriverInfo.SpiPhyLink))
+    {
+      retr = EXTMEM_SFDP_ERROR_DRIVER;
+      goto error;
+    }
+
+    if (HAL_OK != SAL_XSPI_MemoryConfig(&Object->sfdp_private.SALObject, PARAM_DUMMY_CYCLES, &dummyCycles))
+    {
+      retr = EXTMEM_SFDP_ERROR_DRIVER;
+      goto error;
+    }
+  }
+
+  /* -----------------------------------------------------------------------------------------------------------------
+     If an octal DDR table is present and the target is 8D8D8D,
+     when switch in octal DDR mode
+     -----------------------------------------------------------------------------------------------------------------
+  */
+  if (((uint32_t)SFDP_PARAMID_OCTAL_DDR == (Object->sfdp_private.Sfdp_table_mask & (uint32_t)SFDP_PARAMID_OCTAL_DDR))
+      && (EXTMEM_LINK_CONFIG_8LINES == Object->sfdp_private.Config))
+  {
+    /* check if we are not already in octal mode */
+    if (PHY_LINK_8D8D8D == Object->sfdp_private.DriverInfo.SpiPhyLink)
+    {
+      flag4byteAddress = 1u;
+    }
+    else
+    {
+      /* Execute the flash command sequence to switch in octal DDR */
+      if (EXTMEM_SFDP_OK == sfdp_enter_octal_mode(Object))
+      {
+        /* switch the memory interface configuration according to the Access protocol field */
+        flag4byteAddress = 1u;
+        /* Specific case of GigaDevice memory GD25LX512ME whose Instruction mode remains on 8S (8bit commands) */
+        if (Object->sfdp_private.ManuID == EXTMEM_MANUFACTURER_GIGADEVICE)
+        {
+          Object->sfdp_private.DriverInfo.SpiPhyLink = PHY_LINK_8S8D8D;
+        }
+        else
+        {
+          Object->sfdp_private.DriverInfo.SpiPhyLink = PHY_LINK_8D8D8D;
+        }
+
+        /* update the physical link */
+        if (HAL_OK != SAL_XSPI_MemoryConfig(&Object->sfdp_private.SALObject, PARAM_PHY_LINK,
+                                            &Object->sfdp_private.DriverInfo.SpiPhyLink))
+        {
+          retr = EXTMEM_SFDP_ERROR_DRIVER;
+          goto error;
+        }
+
+        if (Object->sfdp_private.Sfdp_AccessProtocol == 0xFDu)
+        {
+          /* set 20 wait state */
+          dummyCycles = 20;
+          (void)SAL_XSPI_MemoryConfig(&Object->sfdp_private.SALObject, PARAM_DUMMY_CYCLES, (void *)&dummyCycles);
+        }
+        if (Object->sfdp_private.Sfdp_AccessProtocol == 0xFEu)
+        {
+          /* set 8 wait state */
+          dummyCycles = 8;
+          (void)SAL_XSPI_MemoryConfig(&Object->sfdp_private.SALObject, PARAM_DUMMY_CYCLES, (void *)&dummyCycles);
+        }
+      }
+      else
+      {
+        /* an error occurs when trying to switch the mode                        */
+        /* when continue the process and check if another mode could be targeted */
+      }
+    }
+
+    if ((0u != (Object->sfdp_private.Sfdp_table_mask & (uint32_t)SFDP_PARAMID_BASIC_SPIPROTOCOL)) &&
+        (JEDEC_Basic.size > 16u))
+    {
+      /* check octal information to determine */
+      /* 0b00 Command Extension is the same as the Command.
+              (Command / Command Extension has the same value for the whole clock period.)*/
+      /* 0b01 Command Extension is the inverse of the Command.
+              Command Extension acts as a confirmation of the Command */
+      /* 0b11 Command and Command Extension forms a 16-bit command word */
+      if (JEDEC_Basic.Params.Param_DWORD.D18.OctalDTRCommandExtension > 1u)
+      {
+        retr = EXTMEM_SFDP_ERROR_NOTYETHANDLED;
+        goto error;
+      }
+      SAL_XSPI_SET_COMMANDEXTENSION(Object->sfdp_private.SALObject,
+                                    (uint8_t)JEDEC_Basic.Params.Param_DWORD.D18.OctalDTRCommandExtension);
+    }
+
+    /* In octal mode, check if JEDEC xSPI (Profile 1.0) Parameter Table is provided, and if yes,
+       check value of SFDP command dummy cycles in 1st DWORD */
+    if ((Object->sfdp_private.Sfdp_table_mask & (uint32_t)SFDP_PARAMID_XSPI_V1_0)
+        == (uint32_t)SFDP_PARAMID_XSPI_V1_0)
+    {
+      if (JEDEC_XSPI10.Param_DWORD.D1.SFDPCommand_8D8D8DMode_DummyCycles == 1U)
+      {
+        SAL_XSPI_SET_SFDPDUMMYCYLE(Object->sfdp_private.SALObject, EXTMEM_READ_SFDP_NB_DUMMY_CYCLES_OPI);
+      }
+    }
+  }
+
+  /* Check WIP flag with new access mode */
+  if (EXTMEM_DRIVER_NOR_SFDP_OK != driver_check_FlagBUSY(Object, 100u))
+  {
+    retr = EXTMEM_SFDP_ERROR_DRIVER;
+    goto error;
+  }
+
+  /* When provided, JEDEC 4-Byte Address instructions Table is analyzed only if present, and if
+     Flash size is > 128Mbits (16 Mbytes, i.e. limit of 24 bits addressing area).
+     This check has been added after noticing that Macronix MX25R6435F Flash (64Mbits) embeds a
+     4-byte Address Instruction Parameter Table in SFDP objects, but Enter 4-Byte Addressing and
+     Enter 4-Byte Addressing values in D16 of JEDEC Basic Flash Parameter Table only contains default values
+     (0xFF ans 0x3FF) */
+  if (((Object->sfdp_private.Sfdp_table_mask & (uint32_t)SFDP_PARAMID_4BYTE_ADDRESS_INSTRUCTION) ==
+       (uint32_t)SFDP_PARAMID_4BYTE_ADDRESS_INSTRUCTION)
+      && (Object->sfdp_private.FlashSize > SFDP_24B_ADDRESS_MAX_FLASH_SIZE)
+      && (JEDEC_Basic.Params.Param_DWORD.D16.Enter4ByteAddressing != 0xFFU))
+  {
+    if (0u == flag4byteAddress)
+    {
+      /* xxxx_xxx1b: issue instruction B7h (preceding write enable not required) */
+      if (0x01u == (JEDEC_Basic.Params.Param_DWORD.D16.Enter4ByteAddressing & 0x01u))
+      {
+        /* send command to enter 4-bytes Address mode */
+        if (HAL_OK != SAL_XSPI_CommandSendData(&Object->sfdp_private.SALObject, 0xB7, NULL, 0))
+        {
+          retr = EXTMEM_SFDP_ERROR_DRIVER;
+          goto error;
+        }
+
+        /* Set 4-Byte addressing on PHY side */
+        if (HAL_OK != SAL_XSPI_MemoryConfig(&Object->sfdp_private.SALObject, PARAM_ADDRESS_4BYTES, NULL))
+        {
+          retr = EXTMEM_SFDP_ERROR_DRIVER;
+          goto error;
+        }
+
+        /* flag4byteAddress = 1u; this setting is not needed because variable is no more used */
+      }
+      /* xxxx_xx1xb: issue write enable instruction 06h, then issue instruction B7h */
+      else if (0x2u == (JEDEC_Basic.Params.Param_DWORD.D16.Enter4ByteAddressing & 0x2u))
+      {
+        /* send command to write enable */
+        if (HAL_OK != SAL_XSPI_CommandSendData(&Object->sfdp_private.SALObject,
+                                               Object->sfdp_private.DriverInfo.WriteWELCommand, NULL, 0u))
+        {
+          retr = EXTMEM_SFDP_ERROR_DRIVER;
+          goto error;
+        }
+
+        /* control the write enable */
+        if (HAL_OK != SAL_XSPI_CheckStatusRegister(&Object->sfdp_private.SALObject,
+                                                   Object->sfdp_private.DriverInfo.ReadWELCommand,
+                                                   Object->sfdp_private.DriverInfo.WELAddress,
+                                                   (((Object->sfdp_private.DriverInfo.WELBusyPolarity == 0u) ? 1u : 0u)
+                                                    << Object->sfdp_private.DriverInfo.WELPosition),
+                                                   1u << Object->sfdp_private.DriverInfo.WELPosition,
+                                                   Object->sfdp_private.ManuID, 1000))
+        {
+          retr = EXTMEM_SFDP_ERROR_DRIVER;
+          goto error;
+        }
+
+        /* send command to enter 4-bytes Address mode */
+        if (HAL_OK != SAL_XSPI_CommandSendData(&Object->sfdp_private.SALObject, 0xB7, NULL, 0u))
+        {
+          retr = EXTMEM_SFDP_ERROR_DRIVER;
+          goto error;
+        }
+      }
+      /* x1xx_xxxxb: Always operates in 4-Byte address mode */
+      else if (0x40u == (JEDEC_Basic.Params.Param_DWORD.D16.Enter4ByteAddressing & 0x40u))
+      {
+        /* nothing to do */
+        /* flag4byteAddress = 1u; this setting is not needed because variable is no more used */
+      }
+      /* xx1x_xxxxb: Supports dedicated 4-Byte address instruction set.
+                    Consult vendor data sheet for the instruction set definition.*/
+      else if (0x20u == (JEDEC_Basic.Params.Param_DWORD.D16.Enter4ByteAddressing & 0x20u))
+      {
+        /* specific memory  */
+        /* on Macronix nothing to do the command are 4Byte specific so nothing to do */
+        /* flag4byteAddress = 1u; this setting is not needed because variable is no more used */
+      }
+      /* xxxx_x1xxb: 8-bit volatile extended address register used to define A[31:24] bits. Read with instruction C8h.
+                     Write instruction is C5h with 1 byte of data. Select the active 128 Mbit memory segment
+                     by setting the appropriate A[31:24] bits and use 3-Byte addressing.
+         xxxx_1xxxb: 8-bit volatile bank register used to define A[30:A24] bits. MSB (bit[7]) is used
+                     to enable/disable 4-byte address mode. When MSB is set to 1, 4-byte address mode is active
+                     and A[30:24] bits are do not care. Read with instruction 16h. Write instruction is 17h
+                     with 1 byte of data. When MSB is cleared to 0, select the active 128 Mbit segment
+                     by setting the appropriate A[30:24] bits and use 3-Byte addressing.
+         xxx1_xxxxb: A 16-bit nonvolatile configuration register controls 3-Byte/4-Byte address mode.
+                     Read instruction is B5h. Bit[0] controls address mode [0=3-Byte;1=4-Byte].
+                     Write configuration register instruction is B1h, data length is 2 bytes.
+      */
+      else
+      {
+        retr = EXTMEM_SFDP_ERROR_NOTYETHANDLED;
+        goto error;
+
+      }
+
+      /* Set 4 bytes addressing on PHY side */
+      if (HAL_OK != SAL_XSPI_MemoryConfig(&Object->sfdp_private.SALObject, PARAM_ADDRESS_4BYTES, NULL))
+      {
+        retr = EXTMEM_SFDP_ERROR_DRIVER;
+        goto error;
+      }
+
+      /* Set the read and program instruction for 4 bytes Address */
+      if (PHY_LINK_1S1S1S == Object->sfdp_private.DriverInfo.SpiPhyLink)
+      {
+        if (0u != JEDEC_Address4Bytes.Param_DWORD.D1.Support_1S1S1S_ReadCommand)
+        {
+          Object->sfdp_private.DriverInfo.ReadInstruction = 0x13U;
+        }
+        if (0u != JEDEC_Address4Bytes.Param_DWORD.D1.Support_1S1S1S_PageProgramCommand)
+        {
+          Object->sfdp_private.DriverInfo.PageProgramInstruction = 0x12u;
+        }
+        if (0u != JEDEC_Address4Bytes.Param_DWORD.D1.Support_1S1S1S_FastReadCommand)
+        {
+          Object->sfdp_private.DriverInfo.ReadInstruction = 0x0Cu;
+          dummyCycles = EXTMEM_FAST_READ_NB_DUMMY_CYCLES_DEFAULT;
+          (void)SAL_XSPI_MemoryConfig(&Object->sfdp_private.SALObject, PARAM_DUMMY_CYCLES, (void *)&dummyCycles);
+        }
+      }
+
+      if (PHY_LINK_1S1S2S == Object->sfdp_private.DriverInfo.SpiPhyLink)
+      {
+        if (0u != JEDEC_Address4Bytes.Param_DWORD.D1.Support_1S1S2S_FastReadCommand)
+        {
+          Object->sfdp_private.DriverInfo.ReadInstruction = 0x3CU;
+        }
+      }
+
+      if (PHY_LINK_1S2S2S == Object->sfdp_private.DriverInfo.SpiPhyLink)
+      {
+        if (0u != JEDEC_Address4Bytes.Param_DWORD.D1.Support_1S2S2S_FastReadCommand)
+        {
+          Object->sfdp_private.DriverInfo.ReadInstruction = 0xBCU;
+        }
+      }
+
+      if (PHY_LINK_1S1D1D == Object->sfdp_private.DriverInfo.SpiPhyLink)
+      {
+        if (0u != JEDEC_Address4Bytes.Param_DWORD.D1.Support_1S1D1D_DTRReadCommand)
+        {
+          Object->sfdp_private.DriverInfo.ReadInstruction = 0x0EU;
+        }
+      }
+    }
+
+    if ((EXTMEM_LINK_CONFIG_8LINES == Object->sfdp_private.Config)
+        && (PHY_LINK_1S1S1S == Object->sfdp_private.DriverInfo.SpiPhyLink))
+    {
+      /* check if we can switch to 1S8S8S */
+      if ((0u != JEDEC_Address4Bytes.Param_DWORD.D1.Support_1S8S8S_FastReadCommand)
+          && (0u != JEDEC_Address4Bytes.Param_DWORD.D1.Support_1S8S8S_PageProgramCommand))
+      {
+        /* Patch Micron write command 0x81 @0x0 0xE7 */
+        Object->sfdp_private.DriverInfo.SpiPhyLink = PHY_LINK_1S8S8S;
+        if (HAL_OK != SAL_XSPI_MemoryConfig(&Object->sfdp_private.SALObject, PARAM_PHY_LINK,
+                                            &Object->sfdp_private.DriverInfo.SpiPhyLink))
+        {
+          retr = EXTMEM_SFDP_ERROR_DRIVER;
+          goto error;
+        }
+        Object->sfdp_private.DriverInfo.ReadInstruction = 0xCC;
+        Object->sfdp_private.DriverInfo.PageProgramInstruction = 0x8E;
+      }
+    }
+
+    /*
+      need to be study more; it seems that Macronix used it to define the command maybe because only one mode is
+      supported in their case
+    */
+    if (Object->sfdp_private.DriverInfo.SpiPhyLink == PHY_LINK_8S8D8D)
+    {
+      if (0u != JEDEC_Address4Bytes.Param_DWORD.D1.Support_1S8S8S_PageProgramCommand)
+      {
+        Object->sfdp_private.DriverInfo.PageProgramInstruction  = 0x02u;
+      }
+      if (0u != JEDEC_Address4Bytes.Param_DWORD.D1.Support_1S8S8S_FastReadCommand)
+      {
+        Object->sfdp_private.DriverInfo.ReadInstruction         = 0xCCu;
+        dummyCycles = EXTMEM_FAST_READ_NB_DUMMY_CYCLES_DEFAULT;
+        (void)SAL_XSPI_MemoryConfig(&Object->sfdp_private.SALObject, PARAM_DUMMY_CYCLES, (void *)&dummyCycles);
+      }
+      if (0u != JEDEC_Address4Bytes.Param_DWORD.D1.Support_1S8D8D_DTRReadCommand)
+      {
+        Object->sfdp_private.DriverInfo.ReadInstruction         = 0xFDu;
+      }
+    }
+
+    Object->sfdp_private.DriverInfo.EraseType1Command =
+      (uint8_t)JEDEC_Address4Bytes.Param_DWORD.D2.InstructionEraseType1;
+    Object->sfdp_private.DriverInfo.EraseType2Command =
+      (uint8_t)JEDEC_Address4Bytes.Param_DWORD.D2.InstructionEraseType2;
+    Object->sfdp_private.DriverInfo.EraseType3Command =
+      (uint8_t)JEDEC_Address4Bytes.Param_DWORD.D2.InstructionEraseType3;
+    Object->sfdp_private.DriverInfo.EraseType4Command =
+      (uint8_t)JEDEC_Address4Bytes.Param_DWORD.D2.InstructionEraseType4;
+  }
+
+  if (((uint32_t)SFDP_PARAMID_XSPI_V1_0 == (Object->sfdp_private.Sfdp_table_mask & (uint32_t)SFDP_PARAMID_XSPI_V1_0))
+      &&
+      ((PHY_LINK_8D8D8D == Object->sfdp_private.DriverInfo.SpiPhyLink)
+       || (PHY_LINK_8S8D8D == Object->sfdp_private.DriverInfo.SpiPhyLink)))
+  {
+    uint32_t ClockOut = 0u;
+    uint32_t MaxFreqMhz;
+    /* Read command */
+    if (0u != JEDEC_XSPI10.Param_DWORD.D1.ReadFastCommand)
+    {
+      Object->sfdp_private.DriverInfo.ReadInstruction = (uint8_t)JEDEC_XSPI10.Param_DWORD.D1.ReadFastCommand;
+    }
+
+    if (JEDEC_XSPI10.Param_DWORD.D6._8D8D8DDefaultPOR_DummyCycle != 0u)
+    {
+      /* Set the default dummy cycle of this mode */
+      dummyCycles = JEDEC_XSPI10.Param_DWORD.D6._8D8D8DDefaultPOR_DummyCycle;
+      (void)SAL_XSPI_MemoryConfig(&Object->sfdp_private.SALObject, PARAM_DUMMY_CYCLES, (void *)&dummyCycles);
+    }
+
+    /* Adapt the memory interface frequency according to its capabilities */
+    MaxFreqMhz = sfdp_getfrequencevalue(JEDEC_Basic.Params.Param_DWORD.D20._8D8D8D_MaximumSpeedWithStrobe);
+    if (MaxFreqMhz > Object->sfdp_private.DriverInfo.ClockIn)
+    {
+      /* Adjust the frequency with the ClockIn */
+      MaxFreqMhz = Object->sfdp_private.DriverInfo.ClockIn;
+    }
+
+    /* Adapt the memory interface frequency according to max requested frequency as defined in configuration table. */
+    if (Object->sfdp_public.MaxFreq != 0)
+    {
+      if (MaxFreqMhz > Object->sfdp_public.MaxFreq)
+      {
+        /* Adjust the frequency with the max clock frequency defined in configuration table */
+        MaxFreqMhz = Object->sfdp_public.MaxFreq;
+      }
+    }
+
+    /* Update the clock to be aligned with selected configuration */
+    if (HAL_OK != SAL_XSPI_SetClock(&Object->sfdp_private.SALObject, Object->sfdp_private.DriverInfo.ClockIn,
+                                    MaxFreqMhz, &ClockOut))
+    {
+      retr = EXTMEM_SFDP_ERROR_SETCLOCK;
+      goto error;
+    }
+    *FreqUpdated = 1u; /* Used to indicate that the clock configuration has been updated */
+
+    /* get the dummy cycle value according to the real output clock */
+    if ((ClockOut >= CLOCK_200MHZ) && (JEDEC_XSPI10.Param_DWORD.D4.Operation200Mhz_DummyCycle != 0u))
+    {
+      dummyCycles = JEDEC_XSPI10.Param_DWORD.D4.Operation200Mhz_DummyCycle;
+      dummyCyclesValue = JEDEC_XSPI10.Param_DWORD.D4.Operation200Mhz_ConfigPattern;
+    }
+    else if ((ClockOut >= CLOCK_166MHZ) && (JEDEC_XSPI10.Param_DWORD.D5.Operation166Mhz_DummyCycle != 0u))
+    {
+      dummyCycles = JEDEC_XSPI10.Param_DWORD.D5.Operation166Mhz_DummyCycle;
+      dummyCyclesValue = JEDEC_XSPI10.Param_DWORD.D5.Operation166Mhz_ConfigPattern;
+    }
+    else if ((ClockOut >= CLOCK_133MHZ) && (JEDEC_XSPI10.Param_DWORD.D5.Operation133Mhz_DummyCycle != 0u))
+    {
+      dummyCycles = JEDEC_XSPI10.Param_DWORD.D5.Operation133Mhz_DummyCycle;
+      dummyCyclesValue = JEDEC_XSPI10.Param_DWORD.D5.Operation133Mhz_ConfigPattern;
+    }
+    else /* if (ClockOut =< 100Mhz) */
+    {
+      dummyCycles = JEDEC_XSPI10.Param_DWORD.D5.Operation100Mhz_DummyCycle;
+      dummyCyclesValue = JEDEC_XSPI10.Param_DWORD.D5.Operation100Mhz_ConfigPattern;
+    }
+
+    /* Specific case of GigaDevice memory with wrongly coded SFDP table in JEDEC_SCCR_Map.Param_DWORD.D9 */
+    if (Object->sfdp_private.ManuID == EXTMEM_MANUFACTURER_GIGADEVICE)
+    {
+      dummyCycles = 16;
+      (void)SAL_XSPI_MemoryConfig(&Object->sfdp_private.SALObject, PARAM_DUMMY_CYCLES, (void *)&dummyCycles);
+    }
+    else
+    {
+      /* Write the dummy cycle value in the configuration register using information coming from SCCR Map */
+      if ((0u != (Object->sfdp_private.Sfdp_table_mask & (uint32_t)SFDP_PARAMID_STATUS_CONTROL_CONFIG_REGISTER_MAP))
+          && (0u != JEDEC_SCCR_Map.Param_DWORD.D9.BitAvailable))
+      {
+        /* Update the frequency with MaxFreqMhz information */
+        if (sfdp_set_dummycycle(Object, dummyCyclesValue) == EXTMEM_SFDP_OK)
+        {
+          /* Set the dummy cycle corresponding */
+          (void)SAL_XSPI_MemoryConfig(&Object->sfdp_private.SALObject, PARAM_DUMMY_CYCLES, (void *)&dummyCycles);
+        }
+      }
+      else
+      {
+        retr = EXTMEM_SFDP_ERROR_CONFIGDUMMY;
+        goto error;
+      }
+    }
+  }
+
+error :
+  return retr;
+}
+
+/**
+  * @brief Checks the busy flag (WIP) of the NOR memory device.
+  * @param SFDPObject Pointer to the NOR SFDP memory instance object descriptor.
+  * @param Timeout Timeout value in milliseconds.
+  * @retval EXTMEM_DRIVER_NOR_SFDP_StatusTypeDef Status of the operation: EXTMEM_DRIVER_NOR_SFDP_OK if not busy,
+  *         error code otherwise.
+  */
+EXTMEM_DRIVER_NOR_SFDP_StatusTypeDef driver_check_FlagBUSY(EXTMEM_DRIVER_NOR_SFDP_ObjectTypeDef *SFDPObject,
+                                                           uint32_t Timeout)
+{
+  EXTMEM_DRIVER_NOR_SFDP_StatusTypeDef retr = EXTMEM_DRIVER_NOR_SFDP_ERROR_BUSY;
+  SFDP_DEBUG_STR((uint8_t *)__func__)
+  if (0u != SFDPObject->sfdp_private.DriverInfo.ReadWIPCommand)
+  {
+#if defined(EXTMEM_DRIVER_NOR_SFDP_DUAL_CONFIG)
+    uint8_t status_reg[2] = {0u, 0u};
+    uint32_t tickstart = HAL_GetTick();
+    uint8_t match_value = (uint8_t)(SFDPObject->sfdp_private.DriverInfo.WIPBusyPolarity
+                                    << SFDPObject->sfdp_private.DriverInfo.WIPPosition);
+    uint8_t match_mask = (uint8_t)(1u << SFDPObject->sfdp_private.DriverInfo.WIPPosition);
+
+    while ((HAL_GetTick() - tickstart) <= Timeout)
+    {
+      if (HAL_OK != SAL_XSPI_SendReadCommand(&SFDPObject->sfdp_private.SALObject,
+                                             SFDPObject->sfdp_private.DriverInfo.ReadWIPCommand,
+                                             status_reg, sizeof(status_reg)))
+      {
+        goto error;
+      }
+
+      if (((status_reg[0] & match_mask) == match_value) && ((status_reg[1] & match_mask) == match_value))
+      {
+        retr = EXTMEM_DRIVER_NOR_SFDP_OK;
+        return retr;
+      }
+    }
+#else
+    /* check that the WIP flag is not set */
+    if (HAL_OK == SAL_XSPI_CheckStatusRegister(&SFDPObject->sfdp_private.SALObject,
+                                               SFDPObject->sfdp_private.DriverInfo.ReadWIPCommand,
+                                               SFDPObject->sfdp_private.DriverInfo.WIPAddress,
+                                               SFDPObject->sfdp_private.DriverInfo.WIPBusyPolarity
+                                               << SFDPObject->sfdp_private.DriverInfo.WIPPosition,
+                                               1u << SFDPObject->sfdp_private.DriverInfo.WIPPosition,
+                                               SFDPObject->sfdp_private.ManuID, Timeout))
+    {
+      retr = EXTMEM_DRIVER_NOR_SFDP_OK;
+    }
+#endif /* EXTMEM_DRIVER_NOR_SFDP_DUAL_CONFIG */
+  }
+#if defined(EXTMEM_DRIVER_NOR_SFDP_DUAL_CONFIG)
+error:
+#endif /* EXTMEM_DRIVER_NOR_SFDP_DUAL_CONFIG */
+  return retr;
+}
+
+/**
+  * @}
+  */
+
+/** @addtogroup NOR_SFDP_DATA_Functions
+  * @{
+  */
+
+/**
+  * @brief Returns the frequency value in Hz corresponding to a bit field.
+  * @param BitField Bit field value from SFDP table.
+  * @return Frequency value in Hz, or 0 if unknown.
+  */
+uint32_t sfdp_getfrequencevalue(uint32_t BitField)
+{
+  const uint16_t freqMhz_table[] = { 0x0, 33, 50, 66, 80, 100, 133, 166, 200, 250, 266, 333, 400 };
+  SFDP_DEBUG_STR(__func__);
+
+  if (BitField < 0b1010u)
+  {
+    return (uint32_t)freqMhz_table[BitField] * 1000000u;
+  }
+  return 0; /* the max frequency is unknown */
+}
+
+/**
+  * @brief Reads and checks the SFDP parameter header at the specified address.
+  * @param Object Pointer to the NOR SFDP memory instance object descriptor.
+  * @param sfdp_address Address of the SFDP parameter table.
+  * @param Param_info Pointer to the parameter info structure to be filled.
+  * @return SFDP_StatusTypeDef: EXTMEM_SFDP_OK if successful, error code otherwise.
+  */
+SFDP_StatusTypeDef sfdp_get_paraminfo(EXTMEM_DRIVER_NOR_SFDP_ObjectTypeDef *Object, uint32_t sfdp_address,
+                                      SFDP_ParameterTable_t *Param_info)
+{
+  SFDP_StatusTypeDef retr = EXTMEM_SFDP_OK;
+  SFDP_ParameterHeader_t sfdp_param_header = {0};
+  SFDP_DEBUG_STR(__func__);
+
+  /* send the SFDP command to read the header */
+  if (HAL_OK != SAL_XSPI_GetSFDP(&Object->sfdp_private.SALObject, sfdp_address,
+                                 (uint8_t *)&sfdp_param_header, SFDP_PARAM_HEADER_SIZE))
+  {
+    retr = EXTMEM_SFDP_ERROR_SFDPREAD;
+    goto error;
+  }
+
+  Param_info->type = SFDP_PARAMID_UNKNOWN;
+  Param_info->size = sfdp_param_header.Length ;
+  Param_info->address = (((uint32_t)sfdp_param_header.TableAddressPointer[2u] << 16u)
+                         | ((uint32_t)sfdp_param_header.TableAddressPointer[1u] << 8u)
+                         | ((uint32_t)sfdp_param_header.TableAddressPointer[0u]));
+
+  if ((sfdp_param_header.ID_msb > 0x00u) && (sfdp_param_header.ID_msb < 0x80u))
+  {
+    if ((sfdp_param_header.ID_lsb & 0x01u) == 0x01u)
+    {
+      Param_info->type = SFDP_PARAMID_VENDOR;
+      SFDP_DEBUG_STR("-> type SFDP_PARAMID_VENDOR");
+    }
+    else
+    {
+      Param_info->type = SFDP_PARAMID_FUNCTION_VENDOR;
+      SFDP_DEBUG_STR("-> type SFDP_PARAMID_FUNCTION_VENDOR");
+    }
+  }
+  else if (sfdp_param_header.ID_msb >= 0x80u)
+  {
+    if ((sfdp_param_header.ID_lsb & 0x01u) == 0x00u)
+    {
+      Param_info->type = SFDP_PARAMID_FUNCTION_JEDEC;
+      SFDP_DEBUG_STR("-> type SFDP_PARAMID_FUNCTION_JEDEC");
+    }
+
+    if (sfdp_param_header.ID_msb == SFDP_BASIC_PARAMETER_TABLE_MSB)
+    {
+      switch (sfdp_param_header.ID_lsb)
+      {
+        case SFDP_BASIC_PARAMETER_TABLE_LSB :
+          Param_info->type = SFDP_PARAMID_BASIC_SPIPROTOCOL;
+          SFDP_DEBUG_STR("-> info SFDP_PARAMID_BASIC_SPIPROTOCOL");
+          Param_info->size = ((sfdp_param_header.Length) < SFDP_PARAMS_BASIC_TABLE_DEFAULTSIZE)
+                             ? sfdp_param_header.Length : SFDP_PARAMS_BASIC_TABLE_DEFAULTSIZE;
+          break;
+        case 0x81u:
+          Param_info->type = SFDP_PARAMID_SECTORMAP;
+          SFDP_DEBUG_STR("-> info SFDP_PARAMID_SECTORMAP");
+          break;
+        case 0x03u:
+          Param_info->type = SFDP_PARAMID_RPMC;
+          SFDP_DEBUG_STR("-> info SFDP_PARAMID_RPMC");
+          break;
+        case 0x84u:
+          Param_info->type = SFDP_PARAMID_4BYTE_ADDRESS_INSTRUCTION;
+          SFDP_DEBUG_STR("-> info SFDP_PARAMID_4BYTE_ADDRESS_INSTRUCTION");
+          break;
+        case 0x05u:
+          Param_info->type = SFDP_PARAMID_XSPI_V1_0;
+          SFDP_DEBUG_STR("-> info SFDP_PARAMID_XSPI_V1_0");
+          break;
+        case 0x06u:
+          Param_info->type = SFDP_PARAMID_XSPI_V2_0;
+          SFDP_DEBUG_STR("-> info SFDP_PARAMID_XSPI_V2_0");
+          break;
+        case 0x87u:
+          Param_info->type = SFDP_PARAMID_STATUS_CONTROL_CONFIG_REGISTER_MAP;
+          SFDP_DEBUG_STR("-> info SFDP_PARAMID_STATUS_CONTROL_CONFIG_REGISTER_MAP");
+          break;
+        case 0x88u:
+          Param_info->type = SFDP_PARAMID_STATUS_CONTROL_CONFIG_REGISTER_MAP_MULTICHIP;
+          SFDP_DEBUG_STR("-> info SFDP_PARAMID_STATUS_CONTROL_CONFIG_REGISTER_MAP_MULTICHIP");
+          break;
+        case 0x09u:
+          Param_info->type = SFDP_PARAMID_STATUS_CONTROL_CONFIG_XSPI_V2_0;
+          SFDP_DEBUG_STR("-> info SFDP_PARAMID_STATUS_CONTROL_CONFIG_XSPI_V2_0");
+          break;
+        case 0x0Au:
+          Param_info->type = SFDP_PARAMID_OCTAL_DDR;
+          SFDP_DEBUG_STR("-> info SFDP_PARAMID_OCTAL_DDR");
+          break;
+        case 0x8Bu:
+          Param_info->type = SFDP_PARAMID_MSPT;
+          SFDP_DEBUG_STR("-> info SFDP_PARAMID_MSPT");
+          break;
+        case 0x0Cu:
+          Param_info->type = SFDP_PARAMID_X4QUAD_DS;
+          SFDP_DEBUG_STR("-> info SFDP_PARAMID_X4QUAD_DS");
+          break;
+        case 0x8Du:
+          Param_info->type = SFDP_PARAMID_QUAD_DDR;
+          SFDP_DEBUG_STR("-> info SFDP_PARAMID_QUAD_DDR");
+          break;
+        case 0x8Eu:
+          Param_info->type = SFDP_PARAMID_SECURE_PACKET_READ_WRITE;
+          SFDP_DEBUG_STR("-> info SFDP_PARAMID_SECURE_PACKET_READ_WRITE");
+          break;
+        case 0x0Fu:
+          Param_info->type = SFDP_PARAMID_RESERVED;
+          SFDP_DEBUG_STR("-> info SFDP_PARAMID_RESERVED");
+          break;
+        default :
+          SFDP_DEBUG_STR("-> info SFDP_PARAMID_????");
+          break;
+      }
+    }
+
+    if (Param_info->type == SFDP_PARAMID_UNKNOWN)
+    {
+      SFDP_DEBUG_STR("-> the table is not compliant with to JEDEC standard");
+    }
+  }
+  else
+  {
+    /* Unexpected value for MSB field of SFDP Parameter ID */
+    SFDP_DEBUG_STR("-> Unexpected value for MSB field of SFDP Parameter ID");
+    retr = EXTMEM_SFDP_ERROR_SFDPREAD;
+    goto error;
+  }
+
+error:
+  return retr;
+}
+
+/**
+  * @brief Executes the octal DDR table to enter octal DDR mode.
+  * @param Object Pointer to the NOR SFDP memory instance object descriptor.
+  * @return SFDP_StatusTypeDef: EXTMEM_SFDP_OK if successful, error code otherwise.
+  */
+SFDP_StatusTypeDef sfdp_enter_octal_mode(EXTMEM_DRIVER_NOR_SFDP_ObjectTypeDef *Object)
+{
+  SFDP_StatusTypeDef retr = EXTMEM_SFDP_OK;
+  uint8_t data[7];
+  SFDP_DEBUG_STR(__func__);
+  /* D1-D2 command */
+  if (0u != JEDEC_OctalDdr.Param_DWORD.D1.LengthCommand)
+  {
+    data[0] = (uint8_t)JEDEC_OctalDdr.Param_DWORD.D1.Byte1CommandSequence;
+    data[1] = (uint8_t)JEDEC_OctalDdr.Param_DWORD.D1.Byte2CommandSequence;
+    data[2] = (uint8_t)JEDEC_OctalDdr.Param_DWORD.D1.Byte3CommandSequence;
+    data[3] = (uint8_t)JEDEC_OctalDdr.Param_DWORD.D2.Byte4CommandSequence;
+    data[4] = (uint8_t)JEDEC_OctalDdr.Param_DWORD.D2.Byte5CommandSequence;
+    data[5] = (uint8_t)JEDEC_OctalDdr.Param_DWORD.D2.Byte6CommandSequence;
+    data[6] = (uint8_t)JEDEC_OctalDdr.Param_DWORD.D2.Byte7CommandSequence;
+
+    if (HAL_OK != SAL_XSPI_CommandSendData(&Object->sfdp_private.SALObject, data[0], &data[1],
+                                           (uint16_t)(JEDEC_OctalDdr.Param_DWORD.D1.LengthCommand - 1u)))
+    {
+      retr = EXTMEM_SFDP_ERROR_OCTALMODE;
+      goto error;
+    }
+  }
+
+  /* D3-D4 command */
+  if (0u != JEDEC_OctalDdr.Param_DWORD.D3.LengthCommand)
+  {
+    /* wait for busy flag clear */
+    if (EXTMEM_DRIVER_NOR_SFDP_OK != driver_check_FlagBUSY(Object, 100u))
+    {
+      retr = EXTMEM_SFDP_ERROR_DRIVER;
+      goto error;
+    }
+
+    data[0] = (uint8_t)JEDEC_OctalDdr.Param_DWORD.D3.Byte1CommandSequence;
+    data[1] = (uint8_t)JEDEC_OctalDdr.Param_DWORD.D3.Byte2CommandSequence;
+    data[2] = (uint8_t)JEDEC_OctalDdr.Param_DWORD.D3.Byte3CommandSequence;
+    data[3] = (uint8_t)JEDEC_OctalDdr.Param_DWORD.D4.Byte4CommandSequence;
+    data[4] = (uint8_t)JEDEC_OctalDdr.Param_DWORD.D4.Byte5CommandSequence;
+    data[5] = (uint8_t)JEDEC_OctalDdr.Param_DWORD.D4.Byte6CommandSequence;
+    data[6] = (uint8_t)JEDEC_OctalDdr.Param_DWORD.D4.Byte7CommandSequence;
+
+    if (HAL_OK != SAL_XSPI_CommandSendData(&Object->sfdp_private.SALObject, data[0], &data[1],
+                                           (uint16_t)(JEDEC_OctalDdr.Param_DWORD.D3.LengthCommand - 1u)))
+    {
+      retr = EXTMEM_SFDP_ERROR_OCTALMODE;
+      goto error;
+    }
+  }
+
+  /* D5-D6 command */
+  if (0u != JEDEC_OctalDdr.Param_DWORD.D5.LengthCommand)
+  {
+    /* wait for busy flag clear */
+    if (EXTMEM_DRIVER_NOR_SFDP_OK != driver_check_FlagBUSY(Object, 100u))
+    {
+      retr = EXTMEM_SFDP_ERROR_DRIVER;
+      goto error;
+    }
+
+    data[0] = (uint8_t)JEDEC_OctalDdr.Param_DWORD.D5.Byte1CommandSequence;
+    data[1] = (uint8_t)JEDEC_OctalDdr.Param_DWORD.D5.Byte2CommandSequence;
+    data[2] = (uint8_t)JEDEC_OctalDdr.Param_DWORD.D5.Byte3CommandSequence;
+    data[3] = (uint8_t)JEDEC_OctalDdr.Param_DWORD.D6.Byte4CommandSequence;
+    data[4] = (uint8_t)JEDEC_OctalDdr.Param_DWORD.D6.Byte5CommandSequence;
+    data[5] = (uint8_t)JEDEC_OctalDdr.Param_DWORD.D6.Byte6CommandSequence;
+    data[6] = (uint8_t)JEDEC_OctalDdr.Param_DWORD.D6.Byte7CommandSequence;
+
+    if (HAL_OK != SAL_XSPI_CommandSendData(&Object->sfdp_private.SALObject, data[0], &data[1],
+                                           (uint16_t)(JEDEC_OctalDdr.Param_DWORD.D5.LengthCommand - 1u)))
+    {
+      retr = EXTMEM_SFDP_ERROR_OCTALMODE;
+      goto error;
+    }
+  }
+
+  /* D7-D8 command */
+  if (0u != JEDEC_OctalDdr.Param_DWORD.D7.LengthCommand)
+  {
+    /* wait for busy flag clear */
+    if (EXTMEM_DRIVER_NOR_SFDP_OK != driver_check_FlagBUSY(Object, 100u))
+    {
+      retr = EXTMEM_SFDP_ERROR_DRIVER;
+      goto error;
+    }
+
+    data[0] = (uint8_t)JEDEC_OctalDdr.Param_DWORD.D7.Byte1CommandSequence;
+    data[1] = (uint8_t)JEDEC_OctalDdr.Param_DWORD.D7.Byte2CommandSequence;
+    data[2] = (uint8_t)JEDEC_OctalDdr.Param_DWORD.D7.Byte3CommandSequence;
+    data[3] = (uint8_t)JEDEC_OctalDdr.Param_DWORD.D8.Byte4CommandSequence;
+    data[4] = (uint8_t)JEDEC_OctalDdr.Param_DWORD.D8.Byte5CommandSequence;
+    data[5] = (uint8_t)JEDEC_OctalDdr.Param_DWORD.D8.Byte6CommandSequence;
+    data[6] = (uint8_t)JEDEC_OctalDdr.Param_DWORD.D8.Byte7CommandSequence;
+
+    if (HAL_OK != SAL_XSPI_CommandSendData(&Object->sfdp_private.SALObject, data[0], &data[1],
+                                           (uint16_t)(JEDEC_OctalDdr.Param_DWORD.D7.LengthCommand - 1u)))
+    {
+      retr = EXTMEM_SFDP_ERROR_OCTALMODE;
+      goto error;
+    }
+
+    /* no more wait for busy flag clear here, as command format might have changed to Octal */
+  }
+
+  /* Abort any ongoing transfer to avoid performance issue */
+  SAL_XSPI_Abort(&Object->sfdp_private.SALObject);
+
+error:
+  return retr;
+}
+
+/**
+  * @brief Writes the configuration register to set the dummy cycle value.
+  * @param Object Pointer to the NOR SFDP memory instance object descriptor.
+  * @param DummyValue Dummy cycle value to set.
+  * @return SFDP_StatusTypeDef: EXTMEM_SFDP_OK if successful, error code otherwise.
+  */
+SFDP_StatusTypeDef sfdp_set_dummycycle(EXTMEM_DRIVER_NOR_SFDP_ObjectTypeDef *Object, uint32_t DummyValue)
+{
+  const uint8_t MaskWaitStateValue[4] = { 0x3u, 0x7u, 0xFu, 0x1Fu };
+  SFDP_StatusTypeDef retr = EXTMEM_SFDP_OK;
+  uint8_t localValue[2] = { 0 };
+  uint32_t Address;
+
+  if ((JEDEC_SCCR_Map.Param_DWORD.D9.BitAccessedByCommandsUsingAddress == 0u) &&
+      (JEDEC_SCCR_Map.Param_DWORD.D9.BitAvailable == 1u))
+  {
+    /* Not yet supported */
+    retr = EXTMEM_SFDP_ERROR_DRIVER;
+    goto error;
+  }
+
+  /* Compute the Address */
+  if (JEDEC_SCCR_Map.Param_DWORD.D9.LocalAddress == 1u)
+  {
+    /* Local Address is found in Byte 1 of 32-bit address */
+    Address = JEDEC_SCCR_Map.Param_DWORD.D9.AddressRegisterOrModesSupported << 8;
+  }
+  else
+  {
+    /* Specific case of GigaDevice GD25LX512ME where register address is wrongly coded in SFDP table */
+    if (Object->sfdp_private.ManuID == 0xC8)
+    {
+      /* Address value in datasheet : 1, address value coded in SFDP table 200 */
+      Address = 1U;
+    }
+    else
+    {
+      /* Local address for Variable Dummy Cycle Settings bits is found in last byte of the address */
+      Address = JEDEC_SCCR_Map.Param_DWORD.D9.AddressRegisterOrModesSupported;
+    }
+  }
+
+  /* Read the configuration */
+  if (HAL_OK != SAL_XSPI_CommandSendReadAddress(&Object->sfdp_private.SALObject,
+                                                (uint8_t)JEDEC_SCCR_Map.Param_DWORD.D9.CommandReadAccess,
+                                                Address,
+                                                (uint8_t *)localValue,
+                                                2u,
+                                                Object->sfdp_private.ManuID))
+  {
+    retr = EXTMEM_SFDP_ERROR_DRIVER;
+    goto error;
+  }
+
+  /* send command to write enable */
+  if (HAL_OK != SAL_XSPI_CommandSendData(&Object->sfdp_private.SALObject,
+                                         Object->sfdp_private.DriverInfo.WriteWELCommand, NULL, 0u))
+  {
+    retr = EXTMEM_SFDP_ERROR_DRIVER;
+    goto error;
+  }
+
+  /* control the write enable */
+  if (HAL_OK != SAL_XSPI_CheckStatusRegister(&Object->sfdp_private.SALObject,
+                                             Object->sfdp_private.DriverInfo.ReadWELCommand,
+                                             Object->sfdp_private.DriverInfo.WELAddress,
+                                             ((Object->sfdp_private.DriverInfo.WELBusyPolarity == 0u) ? 1u : 0u)
+                                             << Object->sfdp_private.DriverInfo.WELPosition,
+                                             1u << Object->sfdp_private.DriverInfo.WELPosition,
+                                             Object->sfdp_private.ManuID, 1000))
+  {
+    retr = EXTMEM_SFDP_ERROR_DRIVER;
+    goto error;
+  }
+
+  /* clear the value */
+  localValue[0] = localValue[0] & ~(MaskWaitStateValue[JEDEC_SCCR_Map.Param_DWORD.D9.NumberBitsUsedToSetWaitStates]
+                                    << JEDEC_SCCR_Map.Param_DWORD.D9.BitLocationLSBPhysicalBitsRegister);
+
+  /* Apply the value with the mask */
+  localValue[0] = localValue[0]
+                  | (uint8_t)(DummyValue << JEDEC_SCCR_Map.Param_DWORD.D9.BitLocationLSBPhysicalBitsRegister);
+  localValue[1] = localValue[0];
+
+  /* Write de configuration */
+  if (HAL_OK != SAL_XSPI_Write(&Object->sfdp_private.SALObject,
+                               (uint8_t)JEDEC_SCCR_Map.Param_DWORD.D9.CommandWriteAccess,
+                               Address, (uint8_t *)localValue, 2u))
+  {
+    retr = EXTMEM_SFDP_ERROR_DRIVER;
+    goto error;
+  }
+
+  /* wait for busy flag clear */
+  if (EXTMEM_DRIVER_NOR_SFDP_OK != driver_check_FlagBUSY(Object, 100u))
+  {
+    retr = EXTMEM_SFDP_ERROR_DRIVER;
+    goto error;
+  }
+
+error :
+  return retr;
+}
+
+/**
+  * @brief Manages the Quad Enable Requirement (QER) for the NOR memory device.
+  * @param Object Pointer to the NOR SFDP memory instance object descriptor.
+  * @return SFDP_StatusTypeDef: EXTMEM_SFDP_OK if successful, error code otherwise.
+  */
+SFDP_StatusTypeDef JEDEC_Basic_ManageQuadEnableRequirement(EXTMEM_DRIVER_NOR_SFDP_ObjectTypeDef *Object)
+{
+  SFDP_StatusTypeDef retr = EXTMEM_SFDP_ERROR_NOTYETHANDLED;
+  uint8_t localValue[2];
+
+  /* switch the mode in QSPI if available */
+  switch (JEDEC_Basic.Params.Param_DWORD.D15.QuadEnableRequirement & 0x7u)
+  {
+    case 0x0u: /* 000b: Device does not have a QE bit. Device detects 1-1-4 and 1-4-4 reads based on instruction.
+                        IO3/HOLD# functions as hold during instruction phase.*/
+      break;
+    case 0x1u: /* 001b: QE is bit 1 of status register 2. It is set via Write Status with two data bytes
+                  where bit 1 of the second byte is one.
+                  It is cleared via Write Status with two data bytes where bit 1 of the second byte is zero.
+                  Writing only one byte to the status register has the side-effect of clearing status register 2,
+                  including the QE bit. The 100b code is used if writing one byte to the status register
+                  does not modify status register 2.
+              */
+      break;
+    case 0x2u:
+    {
+      /* 010b: QE is bit 6 of status register 1. It is set via Write Status with one data byte where bit 6 is one.
+                     It is cleared via Write Status with one data byte where bit 6 is zero. */
+      /* 1 - set the write enable */
+      if (HAL_OK != SAL_XSPI_SendReadCommand(&Object->sfdp_private.SALObject,
+                                             Object->sfdp_private.DriverInfo.WriteWELCommand, NULL, 0u))
+      {
+        retr = EXTMEM_SFDP_ERROR_DRIVER;
+        goto error;
+      }
+
+      /* 2 - read the status register */
+      if (HAL_OK != SAL_XSPI_SendReadCommand(&Object->sfdp_private.SALObject, SFDP_DRIVER_READ_STATUS_REGISTER_COMMAND,
+                                             (uint8_t *)&localValue[0], 1u))
+      {
+        retr = EXTMEM_SFDP_ERROR_DRIVER;
+        goto error;
+      }
+
+      /* 3 - update the status register to enable QPI mode*/
+      localValue[0] = localValue[0] | 0x40u;
+
+      /* 4 - write the status register with QPI mode to 1 */
+      if (HAL_OK != SAL_XSPI_CommandSendData(&Object->sfdp_private.SALObject, 0x1u, (uint8_t *)&localValue[0], 1u))
+      {
+        retr = EXTMEM_SFDP_ERROR_DRIVER;
+        goto error;
+      }
+
+      /* wait busy flag  */
+      if (EXTMEM_DRIVER_NOR_SFDP_OK != driver_check_FlagBUSY(Object, 100))
+      {
+        retr = EXTMEM_SFDP_ERROR_DRIVER;
+        goto error;
+      }
+
+      retr = EXTMEM_SFDP_OK;
+      break;
+    }
+    case 0x3u: /* 011b: QE is bit 7 of status register 2. It is set via Write status register 2 instruction 3Eh
+                        with one data byte where bit 7 is one. It is cleared via Write status register 2
+                        instruction 3Eh with one data byte where bit 7 is zero.
+                        The status register 2 is read using instruction 3Fh.*/
+      break;
+    case 0x4u:
+    {
+      /* 100b: QE is bit 1 of status register 2. It is set via Write Status with two data bytes
+               where bit 1 of the second byte is one.
+               It is cleared via Write Status with two data bytes where bit 1 of the second byte is zero.
+               In contrast to the 001b code, writing 1 byte to the status register does not modify status register 2.*/
+
+      /* Read the status register */
+      if (HAL_OK != SAL_XSPI_SendReadCommand(&Object->sfdp_private.SALObject, 0x5, (uint8_t *)&localValue[0], 2u))
+      {
+        retr = EXTMEM_SFDP_ERROR_DRIVER;
+        goto error;
+      }
+
+      /* Update the status register */
+      localValue[1] |= 2u;
+
+      /* WEL */
+      if (HAL_OK != SAL_XSPI_SendReadCommand(&Object->sfdp_private.SALObject,
+                                             Object->sfdp_private.DriverInfo.WriteWELCommand,
+                                             NULL, 0u))
+      {
+        retr = EXTMEM_SFDP_ERROR_DRIVER;
+        goto error;
+      }
+
+      /* Write the status register */
+      if (HAL_OK != SAL_XSPI_CommandSendData(&Object->sfdp_private.SALObject, 0x1u, (uint8_t *)&localValue[0], 2u))
+      {
+        retr = EXTMEM_SFDP_ERROR_DRIVER;
+        goto error;
+      }
+
+      /* Wait busy flag  */
+      if (EXTMEM_DRIVER_NOR_SFDP_OK != driver_check_FlagBUSY(Object, 100))
+      {
+        retr = EXTMEM_SFDP_ERROR_DRIVER;
+        goto error;
+      }
+
+      /* Optional : only for control read the status register and check write operation is OK */
+      localValue[1] = 0xFF;
+      if (HAL_OK != SAL_XSPI_SendReadCommand(&Object->sfdp_private.SALObject, 0x5, (uint8_t *)&localValue[0], 2u))
+      {
+        retr = EXTMEM_SFDP_ERROR_DRIVER;
+        goto error;
+      }
+
+      retr = EXTMEM_SFDP_OK;
+      break;
+    }
+    case 0x5u: /* 101b: QE is bit 1 of the status register 2. Status register 1 is read using Read Status
+                        instruction 05h. Status register 2 is read using instruction 35h.
+                        QE is set via Write Status instruction 01h with two data bytes where bit 1 of
+                        the second byte is one. It is cleared via Write Status with two data bytes
+                        where bit 1 of the second byte is zero.*/
+      break;
+    case 0x6u: /* 110b: QE is bit 1 of the status register 2.
+                  Status register 1 is read using Read Status instruction 05h.
+                  Status register 2 is read using instruction 35h, and status register 3 is read
+                  using instruction 15h. QE is set via Write Status Register instruction 31h
+                  with one data byte where bit 1 is one.
+                  It is cleared via Write Status Register instruction 31h with one data byte where bit 1 is zero.*/
+      break;
+    case 0x7u: /*111b: Reserved */
+      break;
+    default :/* Added for Misra */
+      break;
+  }
+error :
+  return retr;
+}
+
+/**
+  * @brief Manages the 4S-4S-4S enable sequence for the NOR memory device.
+  * @param Object Pointer to the NOR SFDP memory instance object descriptor.
+  * @return SFDP_StatusTypeDef: EXTMEM_SFDP_OK if successful, error code otherwise.
+  */
+SFDP_StatusTypeDef JEDEC_Basic_Manage4S4S4SEnableSequence(EXTMEM_DRIVER_NOR_SFDP_ObjectTypeDef *Object)
+{
+  SFDP_StatusTypeDef retr = EXTMEM_SFDP_ERROR_NOTYETHANDLED;
+  uint8_t instruction = 0x00u;
+
+  /* 4-4-4 mode enable sequences; This field describes the supported methods to enter 4-4-4 mode from 1-1-1 mode */
+  /* x_xxx1b: set QE per QER description above, then issue instruction 38h */
+  if ((JEDEC_Basic.Params.Param_DWORD.D15._4S4S4S_EnableSequence & 0x1u) == 0x1u)
+  {
+    retr = JEDEC_Basic_ManageQuadEnableRequirement(Object);
+    instruction = 0x38u;
+  }
+  /* x_x1xxb: issue instruction 35h */
+  else if ((JEDEC_Basic.Params.Param_DWORD.D15._4S4S4S_EnableSequence & 0x4u) == 0x4u)
+  {
+    /* If QE bit exists, Quad Enable Requirement describes method to enable Quad operations */
+    retr = JEDEC_Basic_ManageQuadEnableRequirement(Object);
+    instruction = 0x35u;
+  }
+  else
+  {
+    /* nothing to do managed as EXTMEM_SFDP_ERROR_NOTYETHANDLED */
+  }
+
+  /*
+  x_1xxxb: device uses a read-modify-write sequence of operations: read configuration
+           using instruction 65h followed by address 800003h, set bit 6, write configuration
+           using instruction 71h followed by address 800003h. This configuration is volatile.
+  1_xxxxb:
+    4-4-4 mode enable sequences
+       Device uses a read-modify-write sequence of operations:
+       Read Volatile Enhanced Configuration Register using instruction 65h, no address is required, reset bit 7 to 0.
+       Write Volatile Enhanced Configuration Register using instruction 61h, no address is required.
+       This configuration is volatile.
+   4-4-4 mode disable sequences
+       Device uses a read-modify-write sequence of operations:
+       Read Volatile Enhanced Configuration Register using instruction 65h, no address is required, set bit 7 to 1.
+       Write Volatile Enhanced Configuration Register using instruction 61h, no address is required.
+       This configuration is volatile.
+  NOTE If device is in 0-4-4 mode, then this mode must be exited before the 4-4-4 enable sequence is issued.
+  */
+  if ((retr == EXTMEM_SFDP_OK) && (instruction != 0u))
+  {
+    (void)SAL_XSPI_SendReadCommand(&Object->sfdp_private.SALObject, instruction, NULL, 0u);
+    /* @note on memory W25Q64JV the command 38h does not exist so the control on command execution has been removed */
+    retr = EXTMEM_SFDP_OK;
+  }
+
+  return retr;
+}
+
+/**
+  * @brief Checks the validity of the SFDP signature for the NOR memory device.
+  * @param Object Pointer to the NOR SFDP memory instance object descriptor.
+  * @param Signature Value of the SFDP signature to check.
+  * @return SFDP_StatusTypeDef: EXTMEM_SFDP_OK if valid, error code otherwise.
+  */
+SFDP_StatusTypeDef CheckSFDP_Signature(EXTMEM_DRIVER_NOR_SFDP_ObjectTypeDef *Object, uint32_t Signature)
+{
+  SFDP_StatusTypeDef retr = EXTMEM_SFDP_ERROR_SIGNATURE;
+
+  /* check the magic number */
+  switch (Signature)
+  {
+    case SFDP_SIGNATURE :
+      SFDP_DEBUG_STR("signature of the header: OK");
+      retr = EXTMEM_SFDP_OK;
+      break;
+    case SFDP_SIGNATURE_INVERTED :
+      SFDP_DEBUG_STR("signature of the header: KO inverted data order");
+      /* Change the memory type settings */
+      if (HAL_OK == SAL_XSPI_UpdateMemoryType(&Object->sfdp_private.SALObject, SAL_XSPI_ORDERINVERTED))
+      {
+        retr = EXTMEM_SFDP_ERROR_SIGNATUREMTYPE;
+      }
+      break;
+    default :
+      SFDP_DEBUG_STR("signature of the header: KO");
+      break;
+  }
+  return retr;
+}
+/**
+  * @}
+  */
+
+#endif /* EXTMEM_DRIVER_NOR_SFDP == 1 */
Index: trunk/firmware/FSBL/CubeMX/Middlewares/ST/STM32_ExtMem_Manager/nor_sfdp/stm32_sfdp_data.h
===================================================================
--- trunk/firmware/FSBL/CubeMX/Middlewares/ST/STM32_ExtMem_Manager/nor_sfdp/stm32_sfdp_data.h	(revision 20)
+++ trunk/firmware/FSBL/CubeMX/Middlewares/ST/STM32_ExtMem_Manager/nor_sfdp/stm32_sfdp_data.h	(revision 20)
@@ -0,0 +1,147 @@
+/**
+  ******************************************************************************
+  * @file    stm32_sfdp_data.h
+  * @author  MCD Application Team
+  * @brief   This file contains the sfdp functions prototypes.
+  ******************************************************************************
+  * @attention
+  *
+  * Copyright (c) 2022 STMicroelectronics.
+  * All rights reserved.
+  *
+  * This software is licensed under terms that can be found in the LICENSE file
+  * in the root directory of this software component.
+  * If no LICENSE file comes with this software, it is provided AS-IS.
+  *
+  ******************************************************************************
+  */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __STM32_SFDP_DATA_H
+#define __STM32_SFDP_DATA_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Includes ------------------------------------------------------------------*/
+#if EXTMEM_SAL_XSPI == 1
+#include "../sal/stm32_sal_xspi_api.h"
+#else
+#error "the driver SFDP requires the enable of EXTMEM_SAL_XSPI"
+#endif /* EXTMEM_SAL_XSPI_ENABLED */
+
+/**
+  * @addtogroup NOR_SFDP_DATA
+  * @ingroup NOR_SFDP
+  * @{
+  */
+
+/* Exported constants --------------------------------------------------------*/
+
+/**
+  * @brief Maximum number of SFDP parameter in SFDP table
+  */
+#define SFDP_MAX_NB_OF_PARAM                                10U
+
+/* Exported types ------------------------------------------------------------*/
+
+/** @defgroup NOR_SFDP_DATA_Exported_Types Exported Types
+  * @ingroup NOR_SFDP_DATA
+  * @{
+  */
+
+/**
+  * @brief SFDP parameter table ID
+  */
+typedef enum
+{
+  SFDP_PARAMID_UNKNOWN                                      = 0x00000U,
+  SFDP_PARAMID_VENDOR                                       = 0x00001U,
+  SFDP_PARAMID_FUNCTION_VENDOR                              = 0x00002U,
+  SFDP_PARAMID_FUNCTION_JEDEC                               = 0x00004U,
+  SFDP_PARAMID_BASIC_SPIPROTOCOL                            = 0x00008U,
+  SFDP_PARAMID_SECTORMAP                                    = 0x00010U,
+  SFDP_PARAMID_RPMC                                         = 0x00020U,
+  SFDP_PARAMID_4BYTE_ADDRESS_INSTRUCTION                    = 0x00040U,
+  SFDP_PARAMID_XSPI_V1_0                                    = 0x00080U,
+  SFDP_PARAMID_XSPI_V2_0                                    = 0x00100U,
+  SFDP_PARAMID_STATUS_CONTROL_CONFIG_REGISTER_MAP           = 0x00200U,
+  SFDP_PARAMID_STATUS_CONTROL_CONFIG_REGISTER_MAP_MULTICHIP = 0x00400U,
+  SFDP_PARAMID_STATUS_CONTROL_CONFIG_XSPI_V2_0              = 0x00800U,
+  SFDP_PARAMID_OCTAL_DDR                                    = 0x01000U,
+  SFDP_PARAMID_MSPT                                         = 0x02000U,
+  SFDP_PARAMID_X4QUAD_DS                                    = 0x04000U,
+  SFDP_PARAMID_QUAD_DDR                                     = 0x08000U,
+  SFDP_PARAMID_SECURE_PACKET_READ_WRITE                     = 0x10000U,
+  SFDP_PARAMID_RESERVED                                     = 0x20000U
+} SFDP_ParamID_TypeDef;
+
+/**
+  * @brief SFDP status typedef
+  */
+typedef enum
+{
+  EXTMEM_SFDP_OK,                            /*!< Status OK */
+  EXTMEM_SFDP_ERROR_PARAM,
+  EXTMEM_SFDP_ERROR_NOREADFUNCTION,
+  EXTMEM_SFDP_ERROR_SFDPREAD,
+  EXTMEM_SFDP_ERROR_SIGNATURE,               /*!< Signature is invalid */
+  EXTMEM_SFDP_ERROR_SIGNATUREMTYPE,          /*!< Signature is invalid due to wrong memory type */
+  EXTMEM_SFDP_ERROR_PARAMTABLE_NOTFOUND,
+  EXTMEM_SFDP_ERROR_NO_PARAMTABLE_BASIC,
+  EXTMEM_SFDP_ERROR_NO_32BITADDRESSING,
+  EXTMEM_SFDP_ERROR_JEDECBASIC_D14,
+  EXTMEM_SFDP_ERROR_JEDECBASIC_D16,
+  EXTMEM_SFDP_ERROR_OCTALMODE,
+  EXTMEM_SFDP_ERROR_DRIVER,
+  EXTMEM_SFDP_ERROR_SETCLOCK,
+  EXTMEM_SFDP_ERROR_CONFIGDUMMY,
+  EXTMEM_SFDP_ERROR_NOTYETHANDLED
+} SFDP_StatusTypeDef;
+
+/**
+  * @brief SFDP header
+  */
+typedef struct
+{
+  uint32_t Signature;        /*!< Signature value */
+  uint8_t  Minor_revision;   /*!< Minor revision */
+  uint8_t  Major_revision;   /*!< Major revision */
+  uint8_t  param_number;     /*!< Number of parameters */
+  uint8_t  AccessProtocol;   /*!< Access protocol type */
+} SFDP_HeaderTypeDef;
+
+/**
+  * @}
+  */
+
+/* Exported functions --------------------------------------------------------*/
+/** @defgroup NOR_SFDP_Data_Exported_Functions Exported Functions
+  * @{
+  */
+
+SFDP_StatusTypeDef SFDP_GetHeader(EXTMEM_DRIVER_NOR_SFDP_ObjectTypeDef *Object,
+                                  SFDP_HeaderTypeDef *sfdp_header);
+SFDP_StatusTypeDef SFDP_ReadHeader(EXTMEM_DRIVER_NOR_SFDP_ObjectTypeDef *Object,
+                                   SFDP_HeaderTypeDef *sfdp_header);
+SFDP_StatusTypeDef SFDP_CollectData(EXTMEM_DRIVER_NOR_SFDP_ObjectTypeDef *Object);
+SFDP_StatusTypeDef SFDP_MemoryReset(EXTMEM_DRIVER_NOR_SFDP_ObjectTypeDef *Object);
+SFDP_StatusTypeDef SFDP_BuildGenericDriver(EXTMEM_DRIVER_NOR_SFDP_ObjectTypeDef *Object, uint8_t *FreqUpdated);
+EXTMEM_DRIVER_NOR_SFDP_StatusTypeDef driver_check_FlagBUSY(EXTMEM_DRIVER_NOR_SFDP_ObjectTypeDef *SFDPObject,
+                                                           uint32_t Timeout);
+
+
+/**
+  * @}
+  */
+
+/**
+  * @}
+  */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __STM32_SFDP_DATA_H */
Index: trunk/firmware/FSBL/CubeMX/Middlewares/ST/STM32_ExtMem_Manager/nor_sfdp/stm32_sfdp_driver.c
===================================================================
--- trunk/firmware/FSBL/CubeMX/Middlewares/ST/STM32_ExtMem_Manager/nor_sfdp/stm32_sfdp_driver.c	(revision 20)
+++ trunk/firmware/FSBL/CubeMX/Middlewares/ST/STM32_ExtMem_Manager/nor_sfdp/stm32_sfdp_driver.c	(revision 20)
@@ -0,0 +1,846 @@
+/**
+  ******************************************************************************
+  * @file    stm32_sfdp_driver.c
+  * @author  MCD Application Team
+  * @brief   This file includes a driver for SFDP support
+  ******************************************************************************
+  * @attention
+  *
+  * Copyright (c) 2022 STMicroelectronics.
+  * All rights reserved.
+  *
+  * This software is licensed under terms that can be found in the LICENSE file
+  * in the root directory of this software component.
+  * If no LICENSE file comes with this software, it is provided AS-IS.
+  *
+  ******************************************************************************
+  */
+
+/* Includes ------------------------------------------------------------------*/
+#include "stm32_extmem_conf.h"
+
+#if EXTMEM_DRIVER_NOR_SFDP == 1
+#include "stm32_sfdp_driver_type.h"
+#include "stm32_sfdp_driver_api.h"
+#include "stm32_sfdp_data.h"
+#if EXTMEM_DRIVER_NOR_SFDP_DEBUG_LEVEL != 0 && defined(EXTMEM_MACRO_DEBUG)
+#include <stdio.h>
+#endif /* EXTMEM_DRIVER_NOR_SFDP_DEBUG_LEVEL != 0 && EXTMEM_MACRO_DEBUG */
+#include <string.h>
+
+/** @defgroup NOR_SFDP NOR SFDP driver
+  * @ingroup EXTMEM_DRIVER
+  * @{
+  */
+
+
+/* Private Macros ------------------------------------------------------------*/
+/** @defgroup NOR_SFDP_Private_Macro DRIVER NOR SFDP Private Macro
+  * @{
+  */
+/**
+  * @brief MIN macro
+  */
+#define MIN(_A_,_B_)   ((_A_) > (_B_))?(_B_):(_A_);
+
+/**
+  * @brief Default timeout
+  */
+#define DRIVER_DEFAULT_TIMEOUT 300
+
+/**
+  * @brief Default clock value to read SFDP data
+  */
+#define DRIVER_SFDP_DEFAULT_CLOCK 50000000u
+
+/**
+  * @brief DEBUG macro
+  */
+#if EXTMEM_DRIVER_NOR_SFDP_DEBUG_LEVEL > 1 && defined(EXTMEM_MACRO_DEBUG)
+/**
+  * @brief Debug macro for a string
+  * @param _STR_ string
+  */
+#define SFDP_DEBUG_STR(_STR_)       \
+  {                                 \
+    EXTMEM_MACRO_DEBUG("\tSFDP::"); \
+    EXTMEM_MACRO_DEBUG(_STR_);      \
+    EXTMEM_MACRO_DEBUG("\n\r");     \
+  }
+
+/**
+  * @brief debug macro for low level
+  */
+#if EXTMEM_DRIVER_NOR_SFDP_DEBUG_LEVEL > 2
+#define DEBUG_DRIVER(_STR_)                 \
+  {                                         \
+    EXTMEM_MACRO_DEBUG("\tSFDP::DRIVER::"); \
+    EXTMEM_MACRO_DEBUG(_STR_);              \
+    EXTMEM_MACRO_DEBUG("\n");               \
+  }
+#else
+#define DEBUG_DRIVER(_STR_)
+#endif /* EXTMEM_DRIVER_NOR_SFDP_DEBUG_LEVEL > 2 */
+
+/**
+  * @brief debug macro for an integer
+  */
+#define DEBUG_ID(_ID_)                               \
+  {                                                  \
+    char StrID[40];                                  \
+    EXTMEM_MACRO_DEBUG("\tSFDP:: Flash ID(");        \
+    (void)sprintf(StrID, "0x%x:0x%x:0x%x:0x%x",      \
+                  _ID_[0],_ID_[1],_ID_[2],_ID_[3]);  \
+    EXTMEM_MACRO_DEBUG(StrID);                       \
+    EXTMEM_MACRO_DEBUG(")\n");                       \
+  }
+
+/**
+  * @brief Debug macro for error
+  */
+#define DEBUG_DRIVER_ERROR(_STR_)   SFDP_DEBUG_STR(_STR_)
+#else
+#define DEBUG_ID(_ID_)
+#define SFDP_DEBUG_STR(_STR_)
+#define DEBUG_DRIVER(_STR_)
+#define DEBUG_DRIVER_ERROR(_STR_)
+#endif /* EXTMEM_DRIVER_NOR_SFDP_DEBUG_LEVEL > 1 && EXTMEM_MACRO_DEBUG */
+
+/**
+  * @}
+  */
+
+/* Private typedefs ---------------------------------------------------------*/
+/* Private variables ---------------------------------------------------------*/
+/* Private functions ---------------------------------------------------------*/
+
+/** @defgroup DRIVER_SFDP_Private_Functions DRIVER SFDP Private Functions
+  * @{
+  */
+static EXTMEM_DRIVER_NOR_SFDP_StatusTypeDef driver_set_FlagWEL(EXTMEM_DRIVER_NOR_SFDP_ObjectTypeDef *SFDPObject,
+                                                               uint32_t Timeout);
+__weak void EXTMEM_MemCopy(uint32_t *Destination_Address, const uint8_t *ptrData, uint32_t DataSize);
+
+/**
+  * @}
+  */
+
+/** @defgroup DRIVER_SFDP_Exported_Functions DRIVER SFDP Exported Functions
+  * @{
+  */
+
+/**
+  * @brief Initializes the NOR SFDP driver.
+  * @param Peripheral Pointer to peripheral.
+  * @param Config Configuration type.
+  * @param ClockInput Clock input value.
+  * @param SFDPObject Pointer to memory object.
+  * @retval EXTMEM_DRIVER_NOR_SFDP_StatusTypeDef Status of the operation.
+  */
+EXTMEM_DRIVER_NOR_SFDP_StatusTypeDef EXTMEM_DRIVER_NOR_SFDP_Init(void *Peripheral, EXTMEM_LinkConfig_TypeDef Config,
+                                                                 uint32_t ClockInput,
+                                                                 EXTMEM_DRIVER_NOR_SFDP_ObjectTypeDef *SFDPObject)
+{
+  EXTMEM_DRIVER_NOR_SFDP_StatusTypeDef retr = EXTMEM_DRIVER_NOR_SFDP_OK;
+  SFDP_HeaderTypeDef JEDEC_SFDP_Header;
+  uint8_t FreqUpdate = 0u;
+  uint8_t DataID[6];
+  uint32_t ClockOut;
+
+  /* Reset data of SFDPObject to zero */
+  SFDP_DEBUG_STR("1 - reset data SFDPObject to zero")
+  (void)memset((void *)&SFDPObject->sfdp_private, 0x0, sizeof(SFDPObject->sfdp_private));
+
+  /* Initialize the SFDPObject */
+  SFDP_DEBUG_STR("2 - initialize the SFDPObject")
+  SFDPObject->sfdp_private.Config = Config;
+  SFDPObject->sfdp_private.DriverInfo.SpiPhyLink = PHY_LINK_1S1S1S;
+  SFDPObject->sfdp_private.DriverInfo.ClockIn = ClockInput;
+  SAL_XSPI_SET_SFDPDUMMYCYLE(SFDPObject->sfdp_private.SALObject, EXTMEM_READ_SFDP_NB_DUMMY_CYCLES_DEFAULT);
+
+  /* Set memory speed to 50Mhz maximum */
+  SFDP_DEBUG_STR("3 - set memory link and speed to 50Mhz maximum")
+  (void)SAL_XSPI_Init(&SFDPObject->sfdp_private.SALObject, Peripheral);
+  (void)SAL_XSPI_SetClock(&SFDPObject->sfdp_private.SALObject, ClockInput, DRIVER_SFDP_DEFAULT_CLOCK, &ClockOut);
+
+  /* Abort any ongoing XSPI action */
+  (void)SAL_XSPI_DisableMapMode(&SFDPObject->sfdp_private.SALObject);
+
+  /* Analyze the SFDP structure to get driver information */
+  SFDP_DEBUG_STR("4 - analyze the SFDP structure to get driver information")
+  if (EXTMEM_SFDP_OK != SFDP_GetHeader(SFDPObject, &JEDEC_SFDP_Header))
+  {
+    /* Perform SFDP Header reading (several modes are tried) */
+    SFDP_DEBUG_STR("ERROR::EXTMEM_DRIVER_NOR_SFDP_ERROR_SFDP")
+    retr = EXTMEM_DRIVER_NOR_SFDP_ERROR_SFDP;
+    goto error;
+  }
+
+  /* Reset the memory */
+  SFDP_DEBUG_STR("5 - reset the memory")
+  if (EXTMEM_SFDP_OK != SFDP_MemoryReset(SFDPObject))
+  {
+    /* Memory Reset is considered unsuccessful.
+       Try to continue Initialisation procedure anyway. */
+    SFDP_DEBUG_STR("ERROR::on the call of SFDP_MemoryReset but no error returned")
+  }
+
+  /* Wait few ms after the reset operation, this is done to avoid issue on SFDP read */
+  HAL_Delay(10);
+
+  /* Analyze the SFDP structure to get driver information after the reset */
+  SFDP_DEBUG_STR("6 - analyze the SFDP structure to get driver information")
+  if (EXTMEM_SFDP_OK != SFDP_GetHeader(SFDPObject, &JEDEC_SFDP_Header))
+  {
+    /* SFDP header reading is considered unsuccessful.
+       Abort Initialisation procedure. */
+    SFDP_DEBUG_STR("ERROR::EXTMEM_DRIVER_NOR_SFDP_ERROR_SFDP")
+    retr = EXTMEM_DRIVER_NOR_SFDP_ERROR_SFDP;
+    goto error;
+  }
+
+  /* Save information from the SFDP table
+     Nb of parameters starts at 0 (0 means 1 parameter) */
+  if (JEDEC_SFDP_Header.param_number >= SFDP_MAX_NB_OF_PARAM)
+  {
+    SFDPObject->sfdp_private.Sfdp_param_number = SFDP_MAX_NB_OF_PARAM - 1;
+  }
+  else
+  {
+    SFDPObject->sfdp_private.Sfdp_param_number = JEDEC_SFDP_Header.param_number;
+  }
+  SFDPObject->sfdp_private.Sfdp_AccessProtocol = JEDEC_SFDP_Header.AccessProtocol;
+
+  /* Read the flash ID.
+     This Flash ID could later be used to perform specific operations for some identified references. */
+  SFDP_DEBUG_STR("7 - read the flash ID")
+  (void)SAL_XSPI_GetId(&SFDPObject->sfdp_private.SALObject, DataID, EXTMEM_READ_JEDEC_ID_SIZE);
+  DEBUG_ID(DataID);
+
+  /* Keep manufacturer information, it could be used to help in
+     building of consistent driver */
+  SFDPObject->sfdp_private.ManuID = DataID[0];
+#if defined(EXTMEM_DRIVER_NOR_SFDP_DUAL_CONFIG)
+  SFDPObject->sfdp_private.SALObject.ManufacturerId = DataID[0];
+#endif /* EXTMEM_DRIVER_NOR_SFDP_DUAL_CONFIG */
+
+  /* Get the complete SFDP data */
+  SFDP_DEBUG_STR("8 - collect the SFDP data")
+  if (EXTMEM_SFDP_OK != SFDP_CollectData(SFDPObject))
+  {
+    SFDP_DEBUG_STR("ERROR::EXTMEM_DRIVER_NOR_SFDP_ERROR_SFDP")
+    retr = EXTMEM_DRIVER_NOR_SFDP_ERROR_SFDP;
+    goto error;
+  }
+
+  /* Setup the generic driver information and prepare the physical layer */
+  SFDP_DEBUG_STR("9 - build the generic driver information and prepare the physical layer")
+  if (EXTMEM_SFDP_OK != SFDP_BuildGenericDriver(SFDPObject, &FreqUpdate))
+  {
+    SFDP_DEBUG_STR("ERROR::EXTMEM_DRIVER_NOR_SFDP_ERROR_BUILD")
+    retr = EXTMEM_DRIVER_NOR_SFDP_ERROR_BUILD;
+    goto error;
+  }
+
+  /* Adjust frequency supplied to memory, if required */
+  SFDP_DEBUG_STR("10 - adjust the frequency if required")
+  if ((FreqUpdate == 0u) && (SFDPObject->sfdp_public.MaxFreq != 0u))
+  {
+    (void)SAL_XSPI_SetClock(&SFDPObject->sfdp_private.SALObject, ClockInput,
+                            SFDPObject->sfdp_public.MaxFreq, &ClockOut);
+    SFDP_DEBUG_STR("--> new freq configured");
+  }
+
+  /* Read again SFDP header to confirm memory access is properly setup */
+  SFDP_DEBUG_STR("11 - read again the SFDP header to adjust memory type if necessary")
+  if (EXTMEM_SFDP_OK != SFDP_ReadHeader(SFDPObject, &JEDEC_SFDP_Header))
+  {
+    SFDP_DEBUG_STR("ERROR::EXTMEM_DRIVER_NOR_SFDP_MEMTYPE_CHECK")
+    retr = EXTMEM_DRIVER_NOR_SFDP_ERROR_MEMTYPE_CHECK;
+    goto error;
+  }
+
+error:
+  return retr;
+}
+
+/**
+  * @brief This function un-initializes the NOR SFDP driver
+  *
+  * @param SFDPObject Memory object
+  * @return @ref EXTMEM_DRIVER_NOR_SFDP_StatusTypeDef
+  **/
+EXTMEM_DRIVER_NOR_SFDP_StatusTypeDef EXTMEM_DRIVER_NOR_SFDP_DeInit(EXTMEM_DRIVER_NOR_SFDP_ObjectTypeDef *SFDPObject)
+{
+  SFDPObject->sfdp_private.FlashSize = 0;
+  return EXTMEM_DRIVER_NOR_SFDP_OK;
+}
+
+/**
+  * @brief This function returns the flash memory information
+  *
+  * @param SFDPObject Memory object
+  * @param FlashInfo Pointer on flash info structure
+  **/
+void EXTMEM_DRIVER_NOR_SFDP_GetFlashInfo(EXTMEM_DRIVER_NOR_SFDP_ObjectTypeDef *SFDPObject,
+                                         EXTMEM_NOR_SFDP_FlashInfoTypeDef *FlashInfo)
+{
+  DEBUG_DRIVER((uint8_t *)__func__)
+  /* Format the info into structure */
+  FlashInfo->FlashSize      = SFDPObject->sfdp_private.FlashSize;
+  FlashInfo->PageSize       = SFDPObject->sfdp_private.PageSize;
+  FlashInfo->EraseType1Size = (SFDPObject->sfdp_private.DriverInfo.EraseType1Size == 0u) ? 0u :
+                              ((uint32_t)1u << SFDPObject->sfdp_private.DriverInfo.EraseType1Size);
+  FlashInfo->EraseType2Size = (SFDPObject->sfdp_private.DriverInfo.EraseType2Size == 0u) ? 0u :
+                              ((uint32_t)1u << SFDPObject->sfdp_private.DriverInfo.EraseType2Size);
+  FlashInfo->EraseType3Size = (SFDPObject->sfdp_private.DriverInfo.EraseType3Size == 0u) ? 0u :
+                              ((uint32_t)1u << SFDPObject->sfdp_private.DriverInfo.EraseType3Size);
+  FlashInfo->EraseType4Size = (SFDPObject->sfdp_private.DriverInfo.EraseType4Size == 0u) ? 0u :
+                              ((uint32_t)1u << SFDPObject->sfdp_private.DriverInfo.EraseType4Size);
+}
+
+/**
+  * @brief This function reads the memory
+  *
+  * @param SFDPObject Memory object
+  * @param Address Memory address
+  * @param Data Pointer on the data
+  * @param Size Data size to read (in bytes)
+  * @return @ref EXTMEM_DRIVER_NOR_SFDP_StatusTypeDef
+  **/
+EXTMEM_DRIVER_NOR_SFDP_StatusTypeDef EXTMEM_DRIVER_NOR_SFDP_Read(EXTMEM_DRIVER_NOR_SFDP_ObjectTypeDef *SFDPObject,
+                                                                 uint32_t Address, uint8_t *Data, uint32_t Size)
+{
+  EXTMEM_DRIVER_NOR_SFDP_StatusTypeDef retr;
+  DEBUG_DRIVER((uint8_t *)__func__)
+
+  /* Check busy flag */
+  retr = driver_check_FlagBUSY(SFDPObject, 5000);
+  if (EXTMEM_DRIVER_NOR_SFDP_OK != retr)
+  {
+    DEBUG_DRIVER_ERROR("EXTMEM_DRIVER_NOR_SFDP_Read::ERROR_CHECK_BUSY")
+    goto error;
+  }
+
+  /* Perform read access using SAL service */
+  if (HAL_OK != SAL_XSPI_Read(&SFDPObject->sfdp_private.SALObject, SFDPObject->sfdp_private.DriverInfo.ReadInstruction,
+                              Address, Data, Size))
+  {
+    DEBUG_DRIVER_ERROR("EXTMEM_DRIVER_NOR_SFDP_Read::ERROR_READ")
+    retr = EXTMEM_DRIVER_NOR_SFDP_ERROR_READ;
+  }
+error :
+  return retr;
+}
+
+/**
+  * @brief This function writes data in the memory
+  *
+  * @param SFDPObject Memory object
+  * @param Address Memory address
+  * @param Data Pointer on the data
+  * @param Size Data size to write
+  * @return @ref EXTMEM_DRIVER_NOR_SFDP_StatusTypeDef
+  **/
+EXTMEM_DRIVER_NOR_SFDP_StatusTypeDef EXTMEM_DRIVER_NOR_SFDP_Write(EXTMEM_DRIVER_NOR_SFDP_ObjectTypeDef *SFDPObject,
+                                                                  uint32_t Address, const uint8_t *Data, uint32_t Size)
+{
+  EXTMEM_DRIVER_NOR_SFDP_StatusTypeDef retr;
+  uint32_t size_write;
+  uint32_t local_size = Size;
+  uint32_t local_Address = Address;
+  uint32_t local_Data = (uint32_t)Data;
+  uint32_t misalignment = 0u;
+
+  if (0u != (local_Address % SFDPObject->sfdp_private.PageSize))
+  {
+    misalignment = 1u;
+  }
+
+  DEBUG_DRIVER((uint8_t *)__func__)
+  while (local_size != 0u)
+  {
+    if (misalignment == 1u)
+    {
+      size_write = SFDPObject->sfdp_private.PageSize - (local_Address % SFDPObject->sfdp_private.PageSize);
+      size_write = MIN(local_size, size_write);
+      misalignment = 0u;
+    }
+    else
+    {
+      size_write = MIN(local_size, SFDPObject->sfdp_private.PageSize);
+    }
+
+    /* Check WIP flag */
+    retr = driver_check_FlagBUSY(SFDPObject, 5000u);
+    if (EXTMEM_DRIVER_NOR_SFDP_OK != retr)
+    {
+      DEBUG_DRIVER_ERROR("EXTMEM_DRIVER_NOR_SFDP_Write::ERROR_CHECK_BUSY")
+      goto error;
+    }
+
+    /* Wait for WEL flag */
+    retr = driver_set_FlagWEL(SFDPObject, DRIVER_DEFAULT_TIMEOUT);
+    if (EXTMEM_DRIVER_NOR_SFDP_OK != retr)
+    {
+      DEBUG_DRIVER_ERROR("EXTMEM_DRIVER_NOR_SFDP_Write::ERROR_CHECK_WEL")
+      goto error;
+    }
+
+    /* Write the data */
+    if (HAL_OK != SAL_XSPI_Write(&SFDPObject->sfdp_private.SALObject,
+                                 SFDPObject->sfdp_private.DriverInfo.PageProgramInstruction,
+                                 local_Address, (uint8_t *)local_Data, size_write))
+    {
+      DEBUG_DRIVER_ERROR("EXTMEM_DRIVER_NOR_SFDP_Write::ERROR_WRITE")
+      retr = EXTMEM_DRIVER_NOR_SFDP_ERROR_WRITE;
+      goto error;
+    }
+
+    local_size = local_size - size_write;
+    local_Address = local_Address + size_write;
+    local_Data = local_Data + size_write;
+  }
+
+  /* Check busy flag */
+  retr = driver_check_FlagBUSY(SFDPObject, 5000);
+#if EXTMEM_MACRO_DEBUG
+  if (EXTMEM_DRIVER_NOR_SFDP_OK != retr)
+  {
+    DEBUG_DRIVER_ERROR("EXTMEM_DRIVER_NOR_SFDP_Write::ERROR_CHECK_BUSY_ON_EXIT")
+  }
+#endif /* EXTMEM_MACRO_DEBUG */
+
+error:
+  return retr;
+}
+
+/**
+  * @brief This function writes data in the memory in mapped mode
+  *
+  * @param SFDPObject Memory object
+  * @param Address Memory address in mapped mode
+  * @param Data Pointer on the data
+  * @param Size Data size to write
+  * @return @ref EXTMEM_DRIVER_NOR_SFDP_StatusTypeDef
+  **/
+EXTMEM_DRIVER_NOR_SFDP_StatusTypeDef EXTMEM_DRIVER_NOR_SFDP_WriteInMappedMode(EXTMEM_DRIVER_NOR_SFDP_ObjectTypeDef
+                                                                              *SFDPObject, uint32_t Address,
+                                                                              const uint8_t *Data, uint32_t Size)
+{
+  EXTMEM_DRIVER_NOR_SFDP_StatusTypeDef retr = EXTMEM_DRIVER_NOR_SFDP_OK;
+  uint32_t size_write;
+  uint32_t local_size = Size;
+  uint32_t local_Address = Address;
+  const uint8_t *local_Data = Data;
+  uint32_t size;
+  uint32_t misalignment = 0u;
+#if defined (__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U)
+  uint8_t dcache_status = 1;
+#endif /* __DCACHE_PRESENT */
+
+  DEBUG_DRIVER((uint8_t *)__func__)
+
+  /* Check if the input address is 32bit aligned */
+  if (0u != (local_Address % 4u))
+  {
+    retr = EXTMEM_DRIVER_NOR_SFDP_ERROR_ADDRESS_ALIGNMENT;
+    goto error;
+  }
+
+  if (0u != (local_Address % SFDPObject->sfdp_private.PageSize))
+  {
+    misalignment = 1u;
+  }
+
+#if defined (__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U)
+  /* Check if DCache is already enabled */
+  if (SCB->CCR & SCB_CCR_DC_Msk)
+  {
+    dcache_status = 1;
+  }
+  else
+  {
+    dcache_status = 0;
+    /* Enable DCache */
+    SCB_EnableDCache();
+  }
+#endif /* __DCACHE_PRESENT */
+
+  while (local_size != 0u)
+  {
+    if (misalignment == 1u)
+    {
+      size_write = SFDPObject->sfdp_private.PageSize - (local_Address % SFDPObject->sfdp_private.PageSize);
+      size_write = MIN(local_size, size_write);
+      misalignment = 0u;
+    }
+    else
+    {
+      if (local_size > SFDPObject->sfdp_private.PageSize)
+      {
+        size_write = SFDPObject->sfdp_private.PageSize;
+      }
+      else
+      {
+        size_write = local_size;
+        if (0u != (local_size % sizeof(uint32_t)))
+        {
+          size_write = size_write + sizeof(uint32_t) - (local_size % sizeof(uint32_t));
+        }
+      }
+    }
+
+    /* Wait for Write enable flag */
+    retr = driver_set_FlagWEL(SFDPObject, DRIVER_DEFAULT_TIMEOUT);
+    if (EXTMEM_DRIVER_NOR_SFDP_OK != retr)
+    {
+      DEBUG_DRIVER_ERROR("EXTMEM_DRIVER_NOR_SFDP_write::ERROR_CHECK_WEL")
+      goto error;
+    }
+
+    /* Enter the mapped mode */
+    retr = EXTMEM_DRIVER_NOR_SFDP_Enable_MemoryMappedMode(SFDPObject);
+    if (EXTMEM_DRIVER_NOR_SFDP_OK != retr)
+    {
+      goto error;
+    }
+
+    size = size_write;
+    /* Execute the copy */
+    EXTMEM_MemCopy((uint32_t *)local_Address, local_Data, size_write);
+
+#if defined (__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U)
+    /* Clean DCache starting from a 32 byte aligned address in 32 byte granularity */
+    SCB_CleanDCache_by_Addr((void *)(local_Address), size_write);
+#endif /* __DCACHE_PRESENT */
+
+    /* Enter the mapped mode */
+    retr = EXTMEM_DRIVER_NOR_SFDP_Disable_MemoryMappedMode(SFDPObject);
+    if (EXTMEM_DRIVER_NOR_SFDP_OK != retr)
+    {
+      goto error;
+    }
+
+    /* Check busy flag */
+    retr = driver_check_FlagBUSY(SFDPObject, 5000);
+    if (EXTMEM_DRIVER_NOR_SFDP_OK != retr)
+    {
+      DEBUG_DRIVER_ERROR("EXTMEM_DRIVER_NOR_SFDP_write::ERROR_CHECK_BUSY_ON_EXIT")
+      goto error;
+    }
+
+    /* Decrement the transfer size */
+    if (local_size > size)
+    {
+      local_size = local_size - size;
+      local_Data = &local_Data[size];
+      local_Address = local_Address + size;
+    }
+    else
+    {
+      local_size = 0;
+    }
+  }
+
+error:
+
+#if defined (__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U)
+  /* Disable DCache if deactivated previously */
+  if (!dcache_status)
+  {
+    SCB_DisableDCache();
+  }
+#endif /* __DCACHE_PRESENT */
+
+  return retr;
+}
+
+/**
+  * @brief This function erases all the memory
+  *
+  * @param SFDPObject Memory object
+  * @return @ref EXTMEM_DRIVER_NOR_SFDP_StatusTypeDef
+  **/
+EXTMEM_DRIVER_NOR_SFDP_StatusTypeDef EXTMEM_DRIVER_NOR_SFDP_MassErase(EXTMEM_DRIVER_NOR_SFDP_ObjectTypeDef *SFDPObject)
+{
+  EXTMEM_DRIVER_NOR_SFDP_StatusTypeDef retr;
+  DEBUG_DRIVER((uint8_t *)__func__)
+
+  /* Check busy flag */
+  retr = driver_check_FlagBUSY(SFDPObject, 1000);
+  if (EXTMEM_DRIVER_NOR_SFDP_OK != retr)
+  {
+    DEBUG_DRIVER_ERROR("EXTMEM_DRIVER_NOR_SFDP_read::ERROR_CHECK_BUSY")
+    retr = EXTMEM_DRIVER_NOR_SFDP_ERROR_FLASHBUSY;
+    goto error;
+  }
+
+  /* Wait for write enable flag */
+  retr = driver_set_FlagWEL(SFDPObject, DRIVER_DEFAULT_TIMEOUT);
+  if (EXTMEM_DRIVER_NOR_SFDP_OK != retr)
+  {
+    DEBUG_DRIVER_ERROR("EXTMEM_DRIVER_NOR_SFDP_read::ERROR_CHECK_WEL")
+    goto error;
+  }
+
+  /* Launch mass erase command */
+  (void)SAL_XSPI_CommandSendData(&SFDPObject->sfdp_private.SALObject, SFDP_DRIVER_ERASE_CHIP_COMMAND, NULL, 0);
+
+
+  /* Check busy flag : time to used should be set according the memory characteristic */
+  retr = driver_check_FlagBUSY(SFDPObject, SFDPObject->sfdp_private.DriverInfo.EraseChipTiming);
+  if (EXTMEM_DRIVER_NOR_SFDP_OK != retr)
+  {
+    DEBUG_DRIVER_ERROR("EXTMEM_DRIVER_NOR_SFDP_MassErase::ERROR_CHECK_BUSY_ON_EXIT")
+    retr = EXTMEM_DRIVER_NOR_SFDP_ERROR_ERASE_TIMEOUT;
+    goto error;
+  }
+
+error:
+  return retr;
+}
+
+/**
+  * @brief This function erases memory sector
+  *
+  * @param SFDPObject Memory object
+  * @param Address Memory address to start erase operation
+  * @param SectorType Type of sector
+  * @return @ref EXTMEM_DRIVER_NOR_SFDP_StatusTypeDef
+  **/
+EXTMEM_DRIVER_NOR_SFDP_StatusTypeDef EXTMEM_DRIVER_NOR_SFDP_SectorErase(EXTMEM_DRIVER_NOR_SFDP_ObjectTypeDef
+                                                                        *SFDPObject, uint32_t Address,
+                                                                        EXTMEM_DRIVER_NOR_SFDP_SectorTypeTypeDef
+                                                                        SectorType)
+{
+  EXTMEM_DRIVER_NOR_SFDP_StatusTypeDef retr;
+  uint8_t command;
+  uint8_t size;
+  uint32_t timeout;
+  DEBUG_DRIVER((uint8_t *)__func__)
+
+  /* Check if the selected sector type is available */
+  switch (SectorType)
+  {
+    case EXTMEM_DRIVER_NOR_SFDP_SECTOR_TYPE1:
+      command = SFDPObject->sfdp_private.DriverInfo.EraseType1Command;
+      size = SFDPObject->sfdp_private.DriverInfo.EraseType1Size;
+      timeout = SFDPObject->sfdp_private.DriverInfo.EraseType1Timing;
+      break;
+    case EXTMEM_DRIVER_NOR_SFDP_SECTOR_TYPE2:
+      command = SFDPObject->sfdp_private.DriverInfo.EraseType2Command;
+      size = SFDPObject->sfdp_private.DriverInfo.EraseType2Size;
+      timeout = SFDPObject->sfdp_private.DriverInfo.EraseType2Timing;
+      break;
+    case EXTMEM_DRIVER_NOR_SFDP_SECTOR_TYPE3:
+      command = SFDPObject->sfdp_private.DriverInfo.EraseType3Command;
+      size = SFDPObject->sfdp_private.DriverInfo.EraseType3Size;
+      timeout = SFDPObject->sfdp_private.DriverInfo.EraseType3Timing;
+      break;
+    case EXTMEM_DRIVER_NOR_SFDP_SECTOR_TYPE4:
+      command = SFDPObject->sfdp_private.DriverInfo.EraseType4Command;
+      size = SFDPObject->sfdp_private.DriverInfo.EraseType4Size;
+      timeout = SFDPObject->sfdp_private.DriverInfo.EraseType4Timing;
+      break;
+    default :
+      retr = EXTMEM_DRIVER_NOR_SFDP_ERROR_SECTORTYPE;
+      goto error;
+      break;
+  }
+
+  /* Check if the command for this sector size is available */
+  if (0x0u == command)
+  {
+    retr = EXTMEM_DRIVER_NOR_SFDP_ERROR_SECTORTYPE_UNAVAILABLE;
+    goto error;
+  }
+
+  /* Check address alignment */
+  if (0x0u != (Address % ((uint32_t)1u << size)))
+  {
+    retr = EXTMEM_DRIVER_NOR_SFDP_ERROR_ADDRESS_ALIGNMENT;
+    goto error;
+  }
+
+  /* Check busy flag */
+  retr = driver_check_FlagBUSY(SFDPObject, 5000u);
+  if (EXTMEM_DRIVER_NOR_SFDP_OK != retr)
+  {
+    goto error;
+  }
+
+  /* Wait for write enable flag */
+  retr = driver_set_FlagWEL(SFDPObject, DRIVER_DEFAULT_TIMEOUT);
+  if (EXTMEM_DRIVER_NOR_SFDP_OK != retr)
+  {
+    goto error;
+  }
+
+  /* Launch erase command */
+  (void)SAL_XSPI_CommandSendAddress(&SFDPObject->sfdp_private.SALObject, command, Address);
+
+  /* Check busy flag */
+  /* Timeout is set according the memory characteristic */
+  retr = driver_check_FlagBUSY(SFDPObject, timeout);
+  if (EXTMEM_DRIVER_NOR_SFDP_OK != retr)
+  {
+    goto error;
+  }
+
+
+error:
+  return retr;
+}
+
+/**
+  * @brief This function enables the memory mapped mode
+  *
+  * @param SFDPObject Memory object
+  * @return @ref EXTMEM_DRIVER_NOR_SFDP_StatusTypeDef
+  **/
+EXTMEM_DRIVER_NOR_SFDP_StatusTypeDef EXTMEM_DRIVER_NOR_SFDP_Enable_MemoryMappedMode(
+  EXTMEM_DRIVER_NOR_SFDP_ObjectTypeDef *SFDPObject)
+{
+  EXTMEM_DRIVER_NOR_SFDP_StatusTypeDef retr = EXTMEM_DRIVER_NOR_SFDP_OK;
+
+  /* Enter the mapped mode */
+  if (HAL_OK != SAL_XSPI_EnableMapMode(&SFDPObject->sfdp_private.SALObject,
+                                       SFDPObject->sfdp_private.DriverInfo.ReadInstruction,
+                                       (uint8_t)SFDPObject->sfdp_private.SALObject.Commandbase.DummyCycles,
+                                       SFDPObject->sfdp_private.DriverInfo.PageProgramInstruction, 0))
+  {
+    retr = EXTMEM_DRIVER_NOR_SFDP_ERROR_MAP_ENABLE;
+  }
+
+  return retr;
+}
+
+/**
+  * @brief This function disables the memory mapped mode
+  *
+  * @param SFDPObject Memory object
+  * @return @ref EXTMEM_DRIVER_NOR_SFDP_StatusTypeDef
+  **/
+EXTMEM_DRIVER_NOR_SFDP_StatusTypeDef EXTMEM_DRIVER_NOR_SFDP_Disable_MemoryMappedMode(
+  EXTMEM_DRIVER_NOR_SFDP_ObjectTypeDef *SFDPObject)
+{
+  EXTMEM_DRIVER_NOR_SFDP_StatusTypeDef retr = EXTMEM_DRIVER_NOR_SFDP_OK;
+
+  /* Exit the mapped mode */
+  if (HAL_OK != SAL_XSPI_DisableMapMode(&SFDPObject->sfdp_private.SALObject))
+  {
+    retr = EXTMEM_DRIVER_NOR_SFDP_ERROR_MAP_ENABLE;
+  }
+
+  return retr;
+}
+
+
+/**
+  * @}
+  */
+
+/** @addtogroup DRIVER_SFDP_Internal_Functions DRIVER SFDP Internal Functions
+  * @{
+  */
+
+
+/**
+  * @}
+  */
+
+/** @addtogroup DRIVER_SFDP_Private_Functions DRIVER SFDP Private Functions
+  * @{
+  */
+
+/**
+  * @brief This function enables the WEL Flag and checks its activation
+  *
+  * @param SFDPObject Memory object
+  * @param timeout Timeout value
+  * @return @ref EXTMEM_DRIVER_NOR_SFDP_StatusTypeDef
+  **/
+EXTMEM_DRIVER_NOR_SFDP_StatusTypeDef driver_set_FlagWEL(EXTMEM_DRIVER_NOR_SFDP_ObjectTypeDef *SFDPObject,
+                                                        uint32_t Timeout)
+{
+  EXTMEM_DRIVER_NOR_SFDP_StatusTypeDef retr = EXTMEM_DRIVER_NOR_SFDP_ERROR_WRITEENABLE;
+  DEBUG_DRIVER((uint8_t *)__func__)
+
+  /* Send the command write enable */
+  (void)SAL_XSPI_CommandSendData(&SFDPObject->sfdp_private.SALObject,
+                                 SFDPObject->sfdp_private.DriverInfo.WriteWELCommand, NULL, 0);
+
+  /* Wait for write enable status */
+  if (0u != SFDPObject->sfdp_private.DriverInfo.ReadWELCommand)
+  {
+#if defined(EXTMEM_DRIVER_NOR_SFDP_DUAL_CONFIG)
+    uint8_t status_reg[2] = {0u, 0u};
+    uint32_t tickstart = HAL_GetTick();
+    uint8_t match_value = (uint8_t)(((SFDPObject->sfdp_private.DriverInfo.WELBusyPolarity == 0u) ? 1u : 0u)
+                                    << SFDPObject->sfdp_private.DriverInfo.WELPosition);
+    uint8_t match_mask = (uint8_t)(1u << SFDPObject->sfdp_private.DriverInfo.WELPosition);
+
+    while ((HAL_GetTick() - tickstart) <= Timeout)
+    {
+      if (HAL_OK != SAL_XSPI_SendReadCommand(&SFDPObject->sfdp_private.SALObject,
+                                             SFDPObject->sfdp_private.DriverInfo.ReadWELCommand,
+                                             status_reg, sizeof(status_reg)))
+      {
+        goto error;
+      }
+
+      if (((status_reg[0] & match_mask) == match_value) && ((status_reg[1] & match_mask) == match_value))
+      {
+        retr = EXTMEM_DRIVER_NOR_SFDP_OK;
+        return retr;
+      }
+    }
+#else
+    /* Check if flag write enable is enabled */
+    if (HAL_OK == SAL_XSPI_CheckStatusRegister(&SFDPObject->sfdp_private.SALObject,
+                                               SFDPObject->sfdp_private.DriverInfo.ReadWELCommand,
+                                               SFDPObject->sfdp_private.DriverInfo.WELAddress,
+                                               ((SFDPObject->sfdp_private.DriverInfo.WELBusyPolarity == 0u) ? 1u : 0u)
+                                               << SFDPObject->sfdp_private.DriverInfo.WELPosition,
+                                               1u << SFDPObject->sfdp_private.DriverInfo.WELPosition,
+                                               SFDPObject->sfdp_private.ManuID, Timeout))
+    {
+      retr = EXTMEM_DRIVER_NOR_SFDP_OK;
+    }
+#endif /* EXTMEM_DRIVER_NOR_SFDP_DUAL_CONFIG */
+  }
+#if defined(EXTMEM_DRIVER_NOR_SFDP_DUAL_CONFIG)
+error:
+#endif /* EXTMEM_DRIVER_NOR_SFDP_DUAL_CONFIG */
+  return retr;
+}
+
+/**
+  * @brief This function provides a default implementation of MemCopy functionality
+  *
+  * @param Destination_Address Destination Address where data is to be copied
+  * @param ptrData Pointer on source data to be copied
+  * @param DataSize Size of data to be copied (in bytes)
+  * @return @ref EXTMEM_DRIVER_NOR_SFDP_StatusTypeDef
+  **/
+__weak void EXTMEM_MemCopy(uint32_t *Destination_Address, const uint8_t *ptrData, uint32_t DataSize)
+{
+  uint32_t *ptrDest = Destination_Address;
+  /* Write the data */
+  for (uint32_t index = 0u; index < DataSize; index = index + 4u)
+  {
+    *ptrDest = ((uint32_t)ptrData[index] | ((uint32_t)ptrData[index + 1u] << 8u) |
+                ((uint32_t)ptrData[index + 2u] << 16u) | ((uint32_t)ptrData[index + 3u] << 24u));
+    ptrDest++;
+  }
+}
+
+/**
+  * @}
+  */
+
+/**
+  * @}
+  */
+#endif /* EXTMEM_DRIVER_NOR_SFDP == 1 */
Index: trunk/firmware/FSBL/CubeMX/Middlewares/ST/STM32_ExtMem_Manager/nor_sfdp/stm32_sfdp_driver_api.h
===================================================================
--- trunk/firmware/FSBL/CubeMX/Middlewares/ST/STM32_ExtMem_Manager/nor_sfdp/stm32_sfdp_driver_api.h	(revision 20)
+++ trunk/firmware/FSBL/CubeMX/Middlewares/ST/STM32_ExtMem_Manager/nor_sfdp/stm32_sfdp_driver_api.h	(revision 20)
@@ -0,0 +1,121 @@
+/**
+  ******************************************************************************
+  * @file    stm32_sfdp_driver_api.h
+  * @author  MCD Application Team
+  * @brief   This file contains the sfdp driver definition.
+  ******************************************************************************
+  * @attention
+  *
+  * Copyright (c) 2022 STMicroelectronics.
+  * All rights reserved.
+  *
+  * This software is licensed under terms that can be found in the LICENSE file
+  * in the root directory of this software component.
+  * If no LICENSE file comes with this software, it is provided AS-IS.
+  *
+  ******************************************************************************
+  */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __STM32_NOR_SFDP_DRIVER_API_H
+#define __STM32_NOR_SFDP_DRIVER_API_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Includes ------------------------------------------------------------------*/
+
+/** @addtogroup NOR_SFDP
+  * @ingroup EXTMEM_DRIVER
+  * @{
+  */
+
+/* Exported constants --------------------------------------------------------*/
+/* Exported types ------------------------------------------------------------*/
+
+/** @defgroup DRIVER_SFDP_Exported_Types DRIVER SFDP Memory Exported Types
+  * @{
+  */
+
+
+/**
+  * @brief List of error codes for the SFDP driver.
+  */
+typedef enum
+{
+  EXTMEM_DRIVER_NOR_SFDP_OK                           =  0,
+  EXTMEM_DRIVER_NOR_SFDP_ERROR_SFDP                   = -1,
+  EXTMEM_DRIVER_NOR_SFDP_ERROR_READ                   = -2,
+  EXTMEM_DRIVER_NOR_SFDP_ERROR_BUILD                  = -3,
+  EXTMEM_DRIVER_NOR_SFDP_ERROR_UNKNOWN_COMMAND        = -4,
+  EXTMEM_DRIVER_NOR_SFDP_ERROR_BUSY                   = -5,
+  EXTMEM_DRIVER_NOR_SFDP_ERROR_WRITEENABLE            = -6,
+  EXTMEM_DRIVER_NOR_SFDP_ERROR_WRITE                  = -7,
+  EXTMEM_DRIVER_NOR_SFDP_ERROR_SECTORTYPE             = -8,
+  EXTMEM_DRIVER_NOR_SFDP_ERROR_SECTORTYPE_UNAVAILABLE = -9,
+  EXTMEM_DRIVER_NOR_SFDP_ERROR_ADDRESS_ALIGNMENT      = -10,
+  EXTMEM_DRIVER_NOR_SFDP_ERROR_ERASE_TIMEOUT          = -11,
+  EXTMEM_DRIVER_NOR_SFDP_ERROR_FLASHBUSY              = -12,
+  EXTMEM_DRIVER_NOR_SFDP_ERROR_MAP_ENABLE             = -13,
+  EXTMEM_DRIVER_NOR_SFDP_ERROR_MEMTYPE_CHECK          = -14,
+  EXTMEM_DRIVER_NOR_SFDP_ERROR                        = -128,
+} EXTMEM_DRIVER_NOR_SFDP_StatusTypeDef;
+
+/**
+  * @brief List of sector types for the SFDP driver.
+  */
+typedef enum
+{
+  EXTMEM_DRIVER_NOR_SFDP_SECTOR_TYPE1,
+  EXTMEM_DRIVER_NOR_SFDP_SECTOR_TYPE2,
+  EXTMEM_DRIVER_NOR_SFDP_SECTOR_TYPE3,
+  EXTMEM_DRIVER_NOR_SFDP_SECTOR_TYPE4
+} EXTMEM_DRIVER_NOR_SFDP_SectorTypeTypeDef;
+
+/**
+  * @}
+  */
+
+
+/* Exported functions --------------------------------------------------------*/
+/**
+  * @addtogroup DRIVER_SFDP_Exported_Functions DRIVER SFDP exported functions
+  * @{
+  */
+EXTMEM_DRIVER_NOR_SFDP_StatusTypeDef EXTMEM_DRIVER_NOR_SFDP_Init(void *Peripheral, EXTMEM_LinkConfig_TypeDef Config,
+                                                                 uint32_t ClockInput,
+                                                                 EXTMEM_DRIVER_NOR_SFDP_ObjectTypeDef *SFDPObject);
+EXTMEM_DRIVER_NOR_SFDP_StatusTypeDef EXTMEM_DRIVER_NOR_SFDP_DeInit(EXTMEM_DRIVER_NOR_SFDP_ObjectTypeDef *SFDPObject);
+void EXTMEM_DRIVER_NOR_SFDP_GetFlashInfo(EXTMEM_DRIVER_NOR_SFDP_ObjectTypeDef *SFDPObject,
+                                         EXTMEM_NOR_SFDP_FlashInfoTypeDef *FlashInfo);
+EXTMEM_DRIVER_NOR_SFDP_StatusTypeDef EXTMEM_DRIVER_NOR_SFDP_Read(EXTMEM_DRIVER_NOR_SFDP_ObjectTypeDef *SFDPObject,
+                                                                 uint32_t Address, uint8_t *Data, uint32_t Size);
+EXTMEM_DRIVER_NOR_SFDP_StatusTypeDef EXTMEM_DRIVER_NOR_SFDP_Write(EXTMEM_DRIVER_NOR_SFDP_ObjectTypeDef *SFDPObject,
+                                                                  uint32_t Address, const uint8_t *Data, uint32_t Size);
+EXTMEM_DRIVER_NOR_SFDP_StatusTypeDef EXTMEM_DRIVER_NOR_SFDP_WriteInMappedMode(EXTMEM_DRIVER_NOR_SFDP_ObjectTypeDef
+                                                                              *SFDPObject, uint32_t Address,
+                                                                              const uint8_t *Data, uint32_t Size);
+EXTMEM_DRIVER_NOR_SFDP_StatusTypeDef EXTMEM_DRIVER_NOR_SFDP_MassErase(EXTMEM_DRIVER_NOR_SFDP_ObjectTypeDef *SFDPObject);
+EXTMEM_DRIVER_NOR_SFDP_StatusTypeDef EXTMEM_DRIVER_NOR_SFDP_SectorErase(
+  EXTMEM_DRIVER_NOR_SFDP_ObjectTypeDef
+  *SFDPObject, uint32_t Address,
+  EXTMEM_DRIVER_NOR_SFDP_SectorTypeTypeDef SectorType);
+EXTMEM_DRIVER_NOR_SFDP_StatusTypeDef EXTMEM_DRIVER_NOR_SFDP_Enable_MemoryMappedMode(
+  EXTMEM_DRIVER_NOR_SFDP_ObjectTypeDef *SFDPObject);
+EXTMEM_DRIVER_NOR_SFDP_StatusTypeDef EXTMEM_DRIVER_NOR_SFDP_Disable_MemoryMappedMode(
+  EXTMEM_DRIVER_NOR_SFDP_ObjectTypeDef *SFDPObject);
+
+/**
+  * @}
+  */
+
+/**
+  * @}
+  */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __STM32_NOR_SFDP_DRIVER_API_H */
Index: trunk/firmware/FSBL/CubeMX/Middlewares/ST/STM32_ExtMem_Manager/nor_sfdp/stm32_sfdp_driver_type.h
===================================================================
--- trunk/firmware/FSBL/CubeMX/Middlewares/ST/STM32_ExtMem_Manager/nor_sfdp/stm32_sfdp_driver_type.h	(revision 20)
+++ trunk/firmware/FSBL/CubeMX/Middlewares/ST/STM32_ExtMem_Manager/nor_sfdp/stm32_sfdp_driver_type.h	(revision 20)
@@ -0,0 +1,156 @@
+/**
+  ******************************************************************************
+  * @file    stm32_sfdp_driver_type.h
+  * @author  MCD Application Team
+  * @brief   This file contains the sfdp driver definition.
+  ******************************************************************************
+  * @attention
+  *
+  * Copyright (c) 2022 STMicroelectronics.
+  * All rights reserved.
+  *
+  * This software is licensed under terms that can be found in the LICENSE file
+  * in the root directory of this software component.
+  * If no LICENSE file comes with this software, it is provided AS-IS.
+  *
+  ******************************************************************************
+  */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __STM32_SFDP_DRIVER_TYPE_H
+#define __STM32_SFDP_DRIVER_TYPE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/* Includes ------------------------------------------------------------------*/
+/** @addtogroup NOR_SFDP
+  * @ingroup EXTMEM_DRIVER
+  * @{
+  */
+
+/* Exported constants --------------------------------------------------------*/
+/**
+  * @brief Instruction ID for common JEDEC commands
+  */
+#define SFDP_DRIVER_READ_COMMAND                             0x03U
+
+#define SFDP_DRIVER_PAGE_PROGRAM_COMMAND                     0x02U
+
+#define SFDP_DRIVER_READ_STATUS_REGISTER_COMMAND             0x05U
+
+#define SFDP_DRIVER_WRITE_ENABLE_50H_COMMAND                 0x50U
+#define SFDP_DRIVER_WRITE_ENABLE_06H_COMMAND                 0x06U
+
+#define SFDP_DRIVER_ERASE_CHIP_COMMAND                       0x60U
+
+
+/* Exported types ------------------------------------------------------------*/
+
+/** @defgroup DRIVER_SFDP_Exported_Types DRIVER SFDP Memory Exported Types
+  * @{
+  */
+
+/**
+  * @brief driver data used to manage the flash
+  */
+typedef struct
+{
+
+  SAL_XSPI_PhysicalLinkTypeDef SpiPhyLink;           /*!< Physical link information */
+  uint32_t ClockIn;                                  /*!< Input Clock */
+
+  /* Table of instructions (an instruction equal to zero means not supported) */
+  /* WIP : write in progress */
+  uint8_t ReadWIPCommand;                            /*!< Read write in progress command */
+  uint8_t WIPPosition;                               /*!< Write in progress byte position */
+  uint8_t WIPBusyPolarity;                           /*!< 0: Positive (WIP=1 means write is in progress)
+                                                          1: Inverted (WIP=0 means write is in progress) */
+  uint8_t WIPAddress;                                /*!< Read write in progress address */
+
+  /* WEL: write enable */
+  uint8_t WriteWELCommand;                           /*!< Write enable command */
+
+  /* WEL : read write enable */
+  uint8_t ReadWELCommand;                            /*!< Read write enable status command */
+  uint8_t WELPosition;                               /*!< Write enable position */
+  uint8_t WELBusyPolarity;                           /*!< 0: Positive (WEL=1 means write is enabled)
+                                                          1: Inverted (WEL=0 means write is enabled) */
+  uint8_t WELAddress;                                /*!< write enable address */
+
+  /* Page Program */
+  uint8_t PageProgramInstruction;                    /*!< Page program command */
+
+  /* Read management */
+  uint8_t ReadInstruction;                           /*!< Read command */
+
+  /* Erase management */
+  uint8_t EraseType1Size;                            /*!< Erase 1 size */
+  uint8_t EraseType1Command;                         /*!< Erase 1 command */
+  uint8_t EraseType2Size;                            /*!< Erase 2 size */
+  uint8_t EraseType2Command;                         /*!< Erase 2 command */
+  uint8_t EraseType3Size;                            /*!< Erase 3 size */
+  uint8_t EraseType3Command;                         /*!< Erase 3 command */
+  uint8_t EraseType4Size;                            /*!< Erase 4 size */
+  uint8_t EraseType4Command;                         /*!< Erase 4 command */
+
+  uint32_t EraseType1Timing;                         /*!< Erase 1 timing */
+  uint32_t EraseType2Timing;                         /*!< Erase 2 timing */
+  uint32_t EraseType3Timing;                         /*!< Erase 3 timing */
+  uint32_t EraseType4Timing;                         /*!< Erase 4 timing */
+  uint32_t EraseChipTiming;                          /*!< Erase chip timing */
+} EXTMEM_DRIVER_NOR_SFDP_InfoTypeDef;
+
+
+/**
+  * @brief driver SFDP Object definition
+  */
+typedef struct
+{
+  struct
+  {
+    uint32_t                MaxFreq;              /*!< Maximum frequency supported by the memory.
+                                                       @note If the value is zero, the parameter is ignored. */
+    uint8_t                 DtrReadDummyCycle;    /*!< Number of dummy cycles for DTR read command.
+                                                       @note Used only for JEDEC basic with DTR option. */
+  } sfdp_public;
+  struct
+  {
+    SAL_XSPI_ObjectTypeDef    SALObject;             /*!< Instance of the memory */
+    EXTMEM_LinkConfig_TypeDef Config;                /*!< Memory configuration */
+    uint8_t                   ManuID;                /*!< Manufacturer ID */
+    uint8_t                   FlashSize;             /*!< Flash size as a power of two */
+    uint32_t                  PageSize;              /*!< Page size */
+    EXTMEM_DRIVER_NOR_SFDP_InfoTypeDef  DriverInfo;  /*!< Driver information */
+    uint32_t                  Sfdp_table_mask;       /*!< Sfdp table mask */
+    uint32_t                  Reset_info;            /*!< Copy of JEDEC Basic 16 Reset/Rescue info */
+    uint8_t                   Sfdp_param_number;     /*!< Number of parameters from the SFDP header table */
+    uint8_t                   Sfdp_AccessProtocol;   /*!< Access protocol type from the SFDP header table */
+  } sfdp_private;
+} EXTMEM_DRIVER_NOR_SFDP_ObjectTypeDef;
+
+/**
+  * @}
+  */
+
+
+/* Exported functions --------------------------------------------------------*/
+/**
+  * @addtogroup DRIVER_SFDP_Exported_Functions DRIVER SFDP exported functions
+  * @{
+  */
+/**
+  * @}
+  */
+
+/**
+  * @}
+  */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __STM32_SFDP_DRIVER_TYPE_H */
Index: trunk/firmware/FSBL/CubeMX/Middlewares/ST/STM32_ExtMem_Manager/sal/stm32_sal_sd.c
===================================================================
--- trunk/firmware/FSBL/CubeMX/Middlewares/ST/STM32_ExtMem_Manager/sal/stm32_sal_sd.c	(revision 20)
+++ trunk/firmware/FSBL/CubeMX/Middlewares/ST/STM32_ExtMem_Manager/sal/stm32_sal_sd.c	(revision 20)
@@ -0,0 +1,236 @@
+/**
+  ******************************************************************************
+  * @file   stm32_sal_sd.c
+  * @author  MCD Application Team
+  * @brief   This file implements the software adaptation layer for SD.
+  ******************************************************************************
+  * @attention
+  *
+  * Copyright (c) 2022 STMicroelectronics.
+  * All rights reserved.
+  *
+  * This software is licensed under terms that can be found in the LICENSE file
+  * in the root directory of this software component.
+  * If no LICENSE file comes with this software, it is provided AS-IS.
+  *
+  ******************************************************************************
+  */
+
+/* Includes ------------------------------------------------------------------*/
+#include "stm32_extmem.h"
+#include "stm32_extmem_conf.h"
+#if EXTMEM_SAL_SD_DEBUG_LEVEL != 0 && defined(EXTMEM_MACRO_DEBUG)
+#include <stdio.h>
+#endif /* EXTMEM_SAL_SD_DEBUG_LEVEL != 0 && EXTMEM_MACRO_DEBUG */
+
+#if EXTMEM_SAL_SD == 1
+#include "stm32_sal_sd_type.h"
+#include "stm32_sal_sd_api.h"
+
+/** @defgroup SAL_SD SAL_SD : Software adaptation layer for the HAL_SD
+  * @ingroup  EXTMEM_SAL
+  * @{
+  */
+
+/**
+  * @brief Ready timeout value
+  */
+#define READY_TIMEOUT 1000u
+
+/* Private Macros ------------------------------------------------------------*/
+
+/** @defgroup SAL_SD_Private_Macros SAL SD Private Macros
+  * @{
+  */
+#if EXTMEM_SAL_SD_DEBUG_LEVEL == 0 || !defined(EXTMEM_MACRO_DEBUG)
+#define DEBUG_PARAM_BEGIN()
+#define DEBUG_PARAM_DATA(_STR_)
+#define DEBUG_PARAM_INT(_INT_ )
+#define DEBUG_PARAM_END()
+#else
+/**
+  * @brief Trace header macro.
+  */
+#define DEBUG_PARAM_BEGIN()     EXTMEM_MACRO_DEBUG("\t\tSALSD::");
+
+/**
+  * @brief Trace data string macro.
+  */
+#define DEBUG_PARAM_DATA(_STR_) EXTMEM_MACRO_DEBUG(_STR_);
+
+/**
+  * @brief Trace data integer macro
+  */
+#define DEBUG_PARAM_INT(_INT_ ) {                                                 \
+                                  char str[10];                                   \
+                                  (void)snprintf(str, sizeof(str), "0x%x", _INT_);\
+                                  EXTMEM_MACRO_DEBUG(str);                        \
+                                  }
+/**
+  * @brief Trace close macro
+  */
+#define DEBUG_PARAM_END()       EXTMEM_MACRO_DEBUG("\n");
+
+#endif /* EXTMEM_SFDP_DEBUG */
+
+/**
+  * @}
+  */
+
+/* Private typedefs ---------------------------------------------------------*/
+/* Private functions ---------------------------------------------------------*/
+/** @defgroup SAL_SD_Private_Functions SAL XSP Private Functions
+  * @{
+  */
+
+/**
+  * @}
+  */
+
+/* Exported variables ---------------------------------------------------------*/
+/* Private variables ---------------------------------------------------------*/
+/** @defgroup SAL_SD_Exported_Functions SAL XSP Exported Functions
+  * @{
+  */
+
+/**
+  * @brief This function initializes the SD SAL context
+  * @param SalSD SAL SD Object
+  * @param HALHandle HAL handle
+  * @param Info  Information on the SD card
+  * @return @ref HAL_StatusTypeDef
+  **/
+HAL_StatusTypeDef SAL_SD_Init(SAL_SD_ObjectTypeDef *SalSD, void *HALHandle, EXTMEM_DRIVER_SDCARD_InfoTypeDef *Info)
+{
+  SalSD->hSD = (SD_HandleTypeDef *)HALHandle;
+
+  Info->BlockNbr  = SalSD->hSD->SdCard.BlockNbr;
+  Info->BlockSize = SalSD->hSD->SdCard.BlockSize;
+
+  /* Switch to the highest Speed mode supported by the sd-card */
+  return HAL_SD_ConfigSpeedBusOperation(SalSD->hSD, SDMMC_SPEED_MODE_AUTO);
+}
+
+/**
+  * @brief This function un-initializes the SD SAL context
+  * @param SalSD SAL SD Object
+  * @return @ref HAL_StatusTypeDef
+  **/
+HAL_StatusTypeDef SAL_SD_DeInit(SAL_SD_ObjectTypeDef *SalSD)
+{
+  SalSD->hSD->SdCard.BlockNbr = 0;
+  return HAL_OK;
+}
+
+/**
+  * @brief This function reads data from the SD
+  * @param SalSD SAL SD Object
+  * @param BlockIdx Block index
+  * @param Data Data pointer
+  * @param NumberOfBlock Number of block
+  * @return @ref HAL_StatusTypeDef
+  **/
+HAL_StatusTypeDef SAL_SD_ReadData(SAL_SD_ObjectTypeDef *SalSD, uint32_t BlockIdx, uint8_t *Data, uint32_t NumberOfBlock)
+{
+  uint32_t timeout = 100UL * NumberOfBlock;
+  HAL_StatusTypeDef retr = HAL_SD_ReadBlocks(SalSD->hSD, (uint8_t *)Data, BlockIdx, NumberOfBlock, timeout);
+  if (HAL_OK == retr)
+  {
+    timeout = HAL_GetTick();
+    /* Check the SD status */
+    while (HAL_SD_GetCardState(SalSD->hSD) != HAL_SD_CARD_TRANSFER)
+    {
+      if ((HAL_GetTick() - timeout) > READY_TIMEOUT)
+      {
+        retr = HAL_TIMEOUT;
+        break;
+      }
+    }
+  }
+  return retr;
+}
+
+/**
+  * @brief This function writes data on the SD
+  * @param SalSD SAL SD Object
+  * @param BlockIdx block index
+  * @param Data data pointer
+  * @param NumberOfBlock number of block
+  * @return @ref HAL_StatusTypeDef
+  **/
+HAL_StatusTypeDef SAL_SD_WriteData(SAL_SD_ObjectTypeDef *SalSD, uint32_t BlockIdx, const uint8_t *const Data,
+                                   uint32_t NumberOfBlock)
+{
+  uint32_t timeout = 100UL * NumberOfBlock;
+  HAL_StatusTypeDef retr;
+
+  retr = HAL_SD_WriteBlocks(SalSD->hSD, Data, BlockIdx, NumberOfBlock, timeout);
+  if (HAL_OK == retr)
+  {
+    timeout = HAL_GetTick();
+    /* Check the SD status */
+    while (HAL_SD_GetCardState(SalSD->hSD) != HAL_SD_CARD_TRANSFER)
+    {
+      if ((HAL_GetTick() - timeout) > READY_TIMEOUT)
+      {
+        retr = HAL_TIMEOUT;
+        break;
+      }
+    }
+  }
+  return retr;
+}
+
+/**
+  * @brief This function erases an amount of blocks on the SD
+  * @param SalSD SAL SD Object
+  * @param BlockIdx block index
+  * @param BlockCount number of block
+  * @return @ref HAL_StatusTypeDef
+  **/
+HAL_StatusTypeDef SAL_SD_EraseBlock(SAL_SD_ObjectTypeDef *SalSD, uint32_t BlockIdx, uint32_t BlockCount)
+{
+  uint32_t timeout;
+  HAL_StatusTypeDef retr;
+
+  retr = HAL_SD_Erase(SalSD->hSD, BlockIdx, BlockIdx + BlockCount);
+  if (HAL_OK == retr)
+  {
+    timeout = HAL_GetTick();
+    /* Check the SD status */
+    while (HAL_SD_GetCardState(SalSD->hSD) != HAL_SD_CARD_TRANSFER)
+    {
+      if ((HAL_GetTick() - timeout) > (READY_TIMEOUT * BlockCount))
+      {
+        retr = HAL_TIMEOUT;
+        break;
+      }
+    }
+  }
+  return retr;
+}
+
+/**
+  * @brief This function erases all the SD
+  * @param SalSD SAL SD Object
+  * @return @ref HAL_StatusTypeDef
+  **/
+HAL_StatusTypeDef SAL_SD_MassErase(SAL_SD_ObjectTypeDef *SalSD)
+{
+  return SAL_SD_EraseBlock(SalSD, 0, SalSD->hSD->SdCard.BlockNbr);
+}
+
+
+/**
+  * @}
+  */
+
+/**
+  * @}
+  */
+
+/**
+  * @}
+  */
+
+#endif /* EXTMEM_SAL_SD == 1 */
Index: trunk/firmware/FSBL/CubeMX/Middlewares/ST/STM32_ExtMem_Manager/sal/stm32_sal_sd_api.h
===================================================================
--- trunk/firmware/FSBL/CubeMX/Middlewares/ST/STM32_ExtMem_Manager/sal/stm32_sal_sd_api.h	(revision 20)
+++ trunk/firmware/FSBL/CubeMX/Middlewares/ST/STM32_ExtMem_Manager/sal/stm32_sal_sd_api.h	(revision 20)
@@ -0,0 +1,77 @@
+/**
+  ******************************************************************************
+  * @file    stm32_sal_sd_api.h
+  * @author  MCD Application Team
+  * @brief   This file contains SAL SD function prototypes.
+  ******************************************************************************
+  * @attention
+  *
+  * Copyright (c) 2022 STMicroelectronics.
+  * All rights reserved.
+  *
+  * This software is licensed under terms that can be found in the LICENSE file
+  * in the root directory of this software component.
+  * If no LICENSE file comes with this software, it is provided AS-IS.
+  *
+  ******************************************************************************
+  */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __STM32_SAL_SD_API_H
+#define __STM32_SAL_SD_API_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** @addtogroup SAL_SD
+  * @ingroup EXTMEM_SAL
+  * @{
+  */
+
+/** @defgroup SAL_SD
+  * @{
+  */
+
+/* Includes ------------------------------------------------------------------*/
+/* Exported constants --------------------------------------------------------*/
+/* Exported types ------------------------------------------------------------*/
+/** @defgroup SAL_SD_Exported_types SAL SD exported types
+  * @{
+  */
+
+/**
+  * @}
+  */
+
+/* Exported functions --------------------------------------------------------*/
+/** @defgroup SAL_SD_Exported_Functions SAL SD Exported Functions
+  * @{
+  */
+
+HAL_StatusTypeDef SAL_SD_Init(SAL_SD_ObjectTypeDef *SalSD, void *HALHandle, EXTMEM_DRIVER_SDCARD_InfoTypeDef *Info);
+HAL_StatusTypeDef SAL_SD_DeInit(SAL_SD_ObjectTypeDef *SalSD);
+HAL_StatusTypeDef SAL_SD_ReadData(SAL_SD_ObjectTypeDef *SalSD, uint32_t BlockIdx, uint8_t *Data,
+                                  uint32_t NumberOfBlock);
+HAL_StatusTypeDef SAL_SD_WriteData(SAL_SD_ObjectTypeDef *SalSD, uint32_t BlockIdx, const uint8_t *const Data,
+                                   uint32_t NumberOfBlock);
+HAL_StatusTypeDef SAL_SD_EraseBlock(SAL_SD_ObjectTypeDef *SalSD, uint32_t BlockIdx, uint32_t BlockCount);
+HAL_StatusTypeDef SAL_SD_MassErase(SAL_SD_ObjectTypeDef *SalSD);
+
+/**
+  * @}
+  */
+
+/**
+  * @}
+  */
+
+/**
+  * @}
+  */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __STM32_SAL_SD_API_H */
Index: trunk/firmware/FSBL/CubeMX/Middlewares/ST/STM32_ExtMem_Manager/sal/stm32_sal_sd_type.h
===================================================================
--- trunk/firmware/FSBL/CubeMX/Middlewares/ST/STM32_ExtMem_Manager/sal/stm32_sal_sd_type.h	(revision 20)
+++ trunk/firmware/FSBL/CubeMX/Middlewares/ST/STM32_ExtMem_Manager/sal/stm32_sal_sd_type.h	(revision 20)
@@ -0,0 +1,74 @@
+/**
+  ******************************************************************************
+  * @file    stm32_sal_sd_type.h
+  * @author  MCD Application Team
+  * @brief   This file contains SAL SD type definitions.
+  ******************************************************************************
+  * @attention
+  *
+  * Copyright (c) 2022 STMicroelectronics.
+  * All rights reserved.
+  *
+  * This software is licensed under terms that can be found in the LICENSE file
+  * in the root directory of this software component.
+  * If no LICENSE file comes with this software, it is provided AS-IS.
+  *
+  ******************************************************************************
+  */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __STM32_SAL_SD_TYPE_H
+#define __STM32_SAL_SD_TYPE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** @addtogroup SAL_SD
+  * @ingroup EXTMEM_SAL
+  * @{
+  */
+
+/** @defgroup SAL_SD
+  * @{
+  */
+
+/* Includes ------------------------------------------------------------------*/
+/* Exported constants --------------------------------------------------------*/
+/* Exported types ------------------------------------------------------------*/
+/** @defgroup SAL_SD_Exported_types SAL SD exported types
+  * @{
+  */
+
+typedef struct
+{
+  SD_HandleTypeDef     *hSD;            /*!< Pointer to the SD instance handle. */
+} SAL_SD_ObjectTypeDef;
+
+
+/**
+  * @}
+  */
+
+/* Exported functions --------------------------------------------------------*/
+/** @defgroup SAL_SD_Exported_Functions SAL XSP Exported Functions
+  * @{
+  */
+
+/**
+  * @}
+  */
+
+/**
+  * @}
+  */
+
+/**
+  * @}
+  */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __STM32_SAL_SD_TYPE_H */
Index: trunk/firmware/FSBL/CubeMX/Middlewares/ST/STM32_ExtMem_Manager/sal/stm32_sal_xspi.c
===================================================================
--- trunk/firmware/FSBL/CubeMX/Middlewares/ST/STM32_ExtMem_Manager/sal/stm32_sal_xspi.c	(revision 20)
+++ trunk/firmware/FSBL/CubeMX/Middlewares/ST/STM32_ExtMem_Manager/sal/stm32_sal_xspi.c	(revision 20)
@@ -0,0 +1,1293 @@
+/**
+  ******************************************************************************
+  * @file   stm32_sal_xspi.c
+  * @author  MCD Application Team
+  * @brief   This file implements the software adaptation layer for XSPI.
+  ******************************************************************************
+  * @attention
+  *
+  * Copyright (c) 2022 STMicroelectronics.
+  * All rights reserved.
+  *
+  * This software is licensed under terms that can be found in the LICENSE file
+  * in the root directory of this software component.
+  * If no LICENSE file comes with this software, it is provided AS-IS.
+  *
+  ******************************************************************************
+  */
+
+/* Includes ------------------------------------------------------------------*/
+#include "stm32_extmem.h"
+#include "stm32_extmem_conf.h"
+#if EXTMEM_SAL_XSPI_DEBUG_LEVEL != 0 && defined(EXTMEM_MACRO_DEBUG)
+#include <stdio.h>
+#endif /* EXTMEM_SAL_XSPI_DEBUG_LEVEL != 0 && EXTMEM_MACRO_DEBUG */
+
+#if EXTMEM_SAL_XSPI == 1
+
+#include "stm32_sal_xspi_type.h"
+#include "stm32_sal_xspi_api.h"
+
+/** @defgroup SAL_XSPI SAL_XSPI : Software adaptation layer for XSPI
+  * @ingroup EXTMEM_SAL
+  * @{
+  */
+
+/* Private Macros ------------------------------------------------------------*/
+/** @defgroup SAL_XSPI_Private_Macros SAL XSPI Private Macros
+  * @{
+  */
+
+#if EXTMEM_SAL_XSPI_DEBUG_LEVEL == 0 || !defined(EXTMEM_MACRO_DEBUG)
+#define DEBUG_PARAM_BEGIN()
+#define DEBUG_PARAM_DATA(_STR_)
+#define DEBUG_PARAM_INT(_INT_ )
+#define DEBUG_PARAM_INTD(_INT_ )
+#define DEBUG_PARAM_END()
+#define DEBUG_AUTOPOLLING(_DR_,_MVAL_,_MMASK_)
+#define STR_PHY_LINK(_PHY_)
+#else
+/**
+  * @brief Trace header macro.
+  */
+#define DEBUG_PARAM_BEGIN()     EXTMEM_MACRO_DEBUG("\t\tSALXSPI::");
+
+const uint8_t phylink_string[][17] = {"PHY_LINK_1S1S1S",
+                                      "PHY_LINK_1S1S2S",
+                                      "PHY_LINK_1S2S2S",
+                                      "PHY_LINK_1S1D1D",
+                                      "PHY_LINK_1S1S4S",
+                                      "PHY_LINK_1S4S4S",
+                                      "PHY_LINK_4S4S4S",
+                                      "PHY_LINK_4S4D4D",
+                                      "PHY_LINK_4D4D4D",
+                                      "PHY_LINK_1S8S8S",
+                                      "PHY_LINK_8S8D8D",
+                                      "PHY_LINK_8D8D8D",
+                                      "PHY_LINK_RAM8",
+#if defined(HAL_XSPI_DATA_16_LINES)
+                                      "PHY_LINK_RAM16",
+#endif /* HAL_XSPI_DATA_16_LINES */
+                                     };
+
+#define STR_PHY_LINK(_PHY_)  phylink_string[_PHY_]
+
+/**
+  * @brief Trace data string macro.
+  */
+#define DEBUG_PARAM_DATA(_STR_) EXTMEM_MACRO_DEBUG(_STR_);
+
+/**
+  * @brief Trace data integer macro.
+  */
+#define DEBUG_PARAM_INT(_INT_)                         \
+  {                                                    \
+    char str[10];                                      \
+    (void)snprintf(str, sizeof(str), "0x%x", _INT_);   \
+    EXTMEM_MACRO_DEBUG(str);                           \
+  }
+
+#define DEBUG_PARAM_INTD(_INT_)                        \
+  {                                                    \
+    char str[15];                                      \
+    (void)snprintf(str, sizeof(str), "%zu", _INT_);    \
+    EXTMEM_MACRO_DEBUG(str);                           \
+  }
+
+/**
+  * @brief Trace close macro
+  */
+#define DEBUG_PARAM_END()       EXTMEM_MACRO_DEBUG("\n");
+
+#if EXTMEM_SAL_XSPI_DEBUG_LEVEL == 2
+#define DEBUG_AUTOPOLLING(_DR_,_MVAL_,_MMASK_)                                                    \
+  {                                                                                               \
+    char str[50];                                                                                 \
+    (void)snprintf(str, sizeof(str),"DR:0x%x::MVal:0x%x::MMask:0x%x\n\r", _DR_, _MVAL_, _MMASK_); \
+    DEBUG_PARAM_BEGIN()                                                                           \
+    DEBUG_PARAM_DATA(str)                                                                         \
+    DEBUG_PARAM_END()                                                                             \
+  }
+#else
+#define DEBUG_AUTOPOLLING(_DR_,_MVAL_,_MMASK_)
+#endif /* EXTMEM_SAL_XSPI_DEBUG_LEVEL == 2 */
+#endif /* EXTMEM_SAL_XSPI_DEBUG_LEVEL == 0 || !EXTMEM_MACRO_DEBUG */
+
+/**
+  * @brief Default SAL timeout (100 ms)
+  */
+
+#define SAL_XSPI_TIMEOUT_DEFAULT_VALUE (100U)
+
+/**
+  * @}
+  */
+
+#if defined (USE_HAL_XSPI_REGISTER_CALLBACKS) && (USE_HAL_XSPI_REGISTER_CALLBACKS == 1U)
+/** @defgroup SAL_XSPI_Private_Transfer SAL XSPI Dma transfer management definition
+  * @{
+  */
+/**
+  * @brief State of the transfer status
+  */
+typedef enum
+{
+  SALXSPI_TRANSFER_NONE, /*!< */
+  SALXSPI_TRANSFER_OK,
+  SALXSPI_TRANSFER_ERROR
+} SAL_XSPI_TRANSFER_STATUS;
+
+/**
+  * @brief Variable of the transfer status
+  */
+volatile SAL_XSPI_TRANSFER_STATUS salXSPI_status = SALXSPI_TRANSFER_NONE;
+
+/**
+  * @}
+  */
+#endif /* USE_HAL_XSPI_REGISTER_CALLBACKS */
+
+/* Private typedefs ---------------------------------------------------------*/
+/* Private functions ---------------------------------------------------------*/
+/** @defgroup SAL_XSPI_Private_Functions SAL XSP Private Functions
+  * @{
+  */
+uint16_t XSPI_FormatCommand(uint8_t CommandExtension, uint32_t InstructionWidth, uint8_t Command);
+HAL_StatusTypeDef XSPI_Transmit(SAL_XSPI_ObjectTypeDef *SalXspi, const uint8_t *Data);
+HAL_StatusTypeDef XSPI_Receive(SAL_XSPI_ObjectTypeDef *SalXspi,  uint8_t *Data);
+#if defined (USE_HAL_XSPI_REGISTER_CALLBACKS) && (USE_HAL_XSPI_REGISTER_CALLBACKS == 1U)
+void SAL_XSPI_ErrorCallback(struct __XSPI_HandleTypeDef *hxspi);
+void SAL_XSPI_CompleteCallback(struct __XSPI_HandleTypeDef *hxspi);
+#endif /* USE_HAL_XSPI_REGISTER_CALLBACKS */
+
+/**
+  * @}
+  */
+
+/* Exported variables ---------------------------------------------------------*/
+/* Private variables ---------------------------------------------------------*/
+
+
+/** @defgroup SAL_XSPI_Exported_Functions SAL XSP Exported Functions
+  * @{
+  */
+
+/**
+  * @brief This function sets the clock according the clock in and the expected clock
+  * @param SalXspi SAL XSPI handle
+  * @param ClockIn Clock in input
+  * @param ClockRequested Clock requested
+  * @param ClockReal Pointer on the value of the real clock used
+  * @return @ref HAL_StatusTypeDef
+  **/
+HAL_StatusTypeDef SAL_XSPI_SetClock(SAL_XSPI_ObjectTypeDef *SalXspi, uint32_t ClockIn, uint32_t ClockRequested,
+                                    uint32_t *ClockReal)
+{
+  HAL_StatusTypeDef retr = HAL_OK;
+  uint32_t divider;
+
+  if (ClockRequested == 0u)
+  {
+    retr = HAL_ERROR;
+  }
+  else
+  {
+    divider = (ClockIn / ClockRequested);
+    if (divider >= 1u)
+    {
+      *ClockReal = ClockIn / divider;
+      if (*ClockReal <= ClockRequested)
+      {
+        divider--;
+      }
+    }
+
+    /* Real clock calculation */
+    *ClockReal = ClockIn / (divider + 1u);
+
+    DEBUG_PARAM_BEGIN();
+    DEBUG_PARAM_DATA("::CLOCKDIV::");
+    DEBUG_PARAM_INT(divider + 1);
+    DEBUG_PARAM_END();
+    DEBUG_PARAM_BEGIN();
+    DEBUG_PARAM_DATA("::CLKFREQ::");
+    DEBUG_PARAM_INTD(*ClockReal);
+    DEBUG_PARAM_END();
+    MODIFY_REG(SalXspi->hxspi->Instance->DCR2, XSPI_DCR2_PRESCALER, (uint32_t)divider << XSPI_DCR2_PRESCALER_Pos);
+  }
+
+  return retr;
+}
+
+/**
+  * @brief This function is used to configure the way to discuss with the memory
+  * @param SalXspi SAL XSPI handle
+  * @param HALHandle HAl XSPI handle used for memory access
+  * @return @ref HAL_StatusTypeDef
+  **/
+HAL_StatusTypeDef SAL_XSPI_Init(SAL_XSPI_ObjectTypeDef *SalXspi, void *HALHandle)
+{
+  XSPI_RegularCmdTypeDef s_commandbase =
+  {
+    .OperationType = HAL_XSPI_OPTYPE_COMMON_CFG,
+    .IOSelect = HAL_XSPI_SELECT_IO_7_0,
+    .InstructionMode = HAL_XSPI_INSTRUCTION_1_LINE,
+    .Instruction = EXTMEM_READ_SFDP_COMMAND,
+    .InstructionWidth = HAL_XSPI_INSTRUCTION_8_BITS,
+    .InstructionDTRMode = HAL_XSPI_INSTRUCTION_DTR_DISABLE,
+    .AlternateBytesMode = HAL_XSPI_ALT_BYTES_NONE,
+    .AddressMode = HAL_XSPI_ADDRESS_1_LINE,
+    .AddressWidth = HAL_XSPI_ADDRESS_24_BITS,
+    .Address = 0x0,
+    .AddressDTRMode = HAL_XSPI_ADDRESS_DTR_DISABLE,
+    .DataMode = HAL_XSPI_DATA_1_LINE,
+    .DataLength = 0x0,
+    .DataDTRMode = HAL_XSPI_DATA_DTR_DISABLE,
+    .DummyCycles = EXTMEM_READ_SFDP_NB_DUMMY_CYCLES_DEFAULT,
+    .DQSMode = HAL_XSPI_DQS_DISABLE,
+#if defined(XSPI_CCR_SIOO)
+    .SIOOMode = HAL_XSPI_SIOO_INST_EVERY_CMD,
+#endif /* XSPI_CCR_SIOO */
+  };
+
+  SalXspi->hxspi = (XSPI_HandleTypeDef *)HALHandle;
+  SalXspi->Commandbase = s_commandbase;
+  SalXspi->CommandExtension = 0;
+  SalXspi->PhyLink = PHY_LINK_1S1S1S;
+#if defined(EXTMEM_DRIVER_NOR_SFDP_DUAL_CONFIG)
+  SalXspi->ManufacturerId = 0u;
+  SalXspi->ReadWipCommand = 0u;
+  SalXspi->ReadWelCommand = 0u;
+#endif /* EXTMEM_DRIVER_NOR_SFDP_DUAL_CONFIG */
+
+#if defined (USE_HAL_XSPI_REGISTER_CALLBACKS) && (USE_HAL_XSPI_REGISTER_CALLBACKS == 1U)
+  /* Set completion call back */
+  HAL_XSPI_RegisterCallback(SalXspi->hxspi, HAL_XSPI_RX_CPLT_CB_ID, SAL_XSPI_CompleteCallback);
+  HAL_XSPI_RegisterCallback(SalXspi->hxspi, HAL_XSPI_TX_CPLT_CB_ID, SAL_XSPI_CompleteCallback);
+  /* Set the error callback */
+  HAL_XSPI_RegisterCallback(SalXspi->hxspi, HAL_XSPI_ERROR_CB_ID, SAL_XSPI_ErrorCallback);
+#endif /* USE_HAL_XSPI_REGISTER_CALLBACKS */
+
+  return HAL_OK;
+}
+
+/**
+  * @brief This function sets a configuration parameter
+  * @param SalXspi SAL XSPI handle
+  * @param ParametersType @ref SAL_XSPI_MemParamTypeTypeDef
+  * @param ParamVal Pointer on the parameter value
+  * @return @ref HAL_StatusTypeDef
+  **/
+HAL_StatusTypeDef SAL_XSPI_MemoryConfig(SAL_XSPI_ObjectTypeDef *SalXspi, SAL_XSPI_MemParamTypeTypeDef ParametersType,
+                                        void *ParamVal)
+{
+  HAL_StatusTypeDef retr = HAL_OK;
+  XSPI_RegularCmdTypeDef s_commandbase = SalXspi->Commandbase;
+
+  switch (ParametersType)
+  {
+    case PARAM_PHY_LINK:
+    {
+      SalXspi->PhyLink = *((SAL_XSPI_PhysicalLinkTypeDef *)ParamVal);
+      DEBUG_PARAM_BEGIN();
+      DEBUG_PARAM_DATA("::PARAM_PHY_LINK::");
+      DEBUG_PARAM_DATA(STR_PHY_LINK(SalXspi->PhyLink));
+      switch (SalXspi->PhyLink)
+      {
+        case PHY_LINK_1S1D1D:
+        case PHY_LINK_1S2S2S:
+        case PHY_LINK_1S1S2S:
+        case PHY_LINK_1S1S1S:
+        {
+          s_commandbase.InstructionMode = HAL_XSPI_INSTRUCTION_1_LINE;
+          s_commandbase.InstructionWidth = HAL_XSPI_INSTRUCTION_8_BITS;
+          s_commandbase.InstructionDTRMode = HAL_XSPI_INSTRUCTION_DTR_DISABLE;
+          s_commandbase.AddressMode = HAL_XSPI_ADDRESS_1_LINE;
+          s_commandbase.AddressWidth = HAL_XSPI_ADDRESS_24_BITS;
+          s_commandbase.AddressDTRMode = HAL_XSPI_ADDRESS_DTR_DISABLE;
+          s_commandbase.DataMode = HAL_XSPI_DATA_1_LINE;
+          s_commandbase.DataDTRMode = HAL_XSPI_DATA_DTR_DISABLE;
+          s_commandbase.DummyCycles = 8;
+          s_commandbase.DQSMode = HAL_XSPI_DQS_DISABLE;
+          break;
+        }
+
+        case PHY_LINK_1S1S4S:
+        {
+          s_commandbase.InstructionMode = HAL_XSPI_INSTRUCTION_1_LINE;
+          s_commandbase.InstructionWidth = HAL_XSPI_INSTRUCTION_8_BITS;
+          s_commandbase.InstructionDTRMode = HAL_XSPI_INSTRUCTION_DTR_DISABLE;
+          s_commandbase.AddressMode = HAL_XSPI_ADDRESS_1_LINE;
+          s_commandbase.AddressDTRMode = HAL_XSPI_ADDRESS_DTR_DISABLE;
+          s_commandbase.AddressWidth = HAL_XSPI_ADDRESS_24_BITS;
+          s_commandbase.DataMode = HAL_XSPI_DATA_4_LINES;
+          s_commandbase.DataDTRMode = HAL_XSPI_DATA_DTR_DISABLE;
+          s_commandbase.DummyCycles = 6;
+          s_commandbase.DQSMode = HAL_XSPI_DQS_DISABLE;
+          break;
+        }
+
+        case PHY_LINK_1S4S4S:
+        {
+          s_commandbase.InstructionMode = HAL_XSPI_INSTRUCTION_1_LINE;
+          s_commandbase.InstructionWidth = HAL_XSPI_INSTRUCTION_8_BITS;
+          s_commandbase.InstructionDTRMode = HAL_XSPI_INSTRUCTION_DTR_DISABLE;
+          s_commandbase.AddressMode = HAL_XSPI_ADDRESS_4_LINES;
+          s_commandbase.AddressDTRMode = HAL_XSPI_ADDRESS_DTR_DISABLE;
+          s_commandbase.AddressWidth = HAL_XSPI_ADDRESS_24_BITS;
+          s_commandbase.DataMode = HAL_XSPI_DATA_4_LINES;
+          s_commandbase.DataDTRMode = HAL_XSPI_DATA_DTR_DISABLE;
+          s_commandbase.DummyCycles = 6;
+          s_commandbase.DQSMode = HAL_XSPI_DQS_DISABLE;
+          break;
+        }
+
+        case PHY_LINK_4S4D4D:
+        case PHY_LINK_4S4S4S:
+        {
+          s_commandbase.InstructionMode = HAL_XSPI_INSTRUCTION_4_LINES;
+          s_commandbase.InstructionWidth = HAL_XSPI_INSTRUCTION_8_BITS;
+          s_commandbase.InstructionDTRMode = HAL_XSPI_INSTRUCTION_DTR_DISABLE;
+          s_commandbase.AddressMode = HAL_XSPI_ADDRESS_4_LINES;
+          s_commandbase.AddressDTRMode = HAL_XSPI_ADDRESS_DTR_DISABLE;
+          s_commandbase.AddressWidth = HAL_XSPI_ADDRESS_24_BITS;
+          s_commandbase.DataMode = HAL_XSPI_DATA_4_LINES;
+          s_commandbase.DataDTRMode = HAL_XSPI_DATA_DTR_DISABLE;
+          s_commandbase.DummyCycles = 6;
+          s_commandbase.DQSMode = HAL_XSPI_DQS_DISABLE;
+          break;
+        }
+        case PHY_LINK_4D4D4D:
+        {
+          s_commandbase.InstructionMode = HAL_XSPI_INSTRUCTION_4_LINES;
+          s_commandbase.InstructionWidth = HAL_XSPI_INSTRUCTION_8_BITS;
+          s_commandbase.InstructionDTRMode = HAL_XSPI_INSTRUCTION_DTR_ENABLE;
+          s_commandbase.AddressMode = HAL_XSPI_ADDRESS_4_LINES;
+          s_commandbase.AddressWidth = HAL_XSPI_ADDRESS_24_BITS;
+          s_commandbase.AddressDTRMode = HAL_XSPI_ADDRESS_DTR_ENABLE;
+          s_commandbase.DataMode = HAL_XSPI_DATA_4_LINES;
+          s_commandbase.DataDTRMode = HAL_XSPI_DATA_DTR_ENABLE;
+          s_commandbase.DummyCycles = 6;
+          s_commandbase.DQSMode = HAL_XSPI_DQS_DISABLE;
+          break;
+        }
+        case PHY_LINK_1S8S8S:
+        {
+          s_commandbase.InstructionMode = HAL_XSPI_INSTRUCTION_1_LINE;
+          s_commandbase.InstructionWidth = HAL_XSPI_INSTRUCTION_8_BITS;
+          s_commandbase.InstructionDTRMode = HAL_XSPI_INSTRUCTION_DTR_DISABLE;
+          s_commandbase.AddressMode = HAL_XSPI_ADDRESS_8_LINES;
+          s_commandbase.AddressWidth = HAL_XSPI_ADDRESS_32_BITS;
+          s_commandbase.AddressDTRMode = HAL_XSPI_ADDRESS_DTR_DISABLE;
+          s_commandbase.DataMode = HAL_XSPI_DATA_8_LINES;
+          s_commandbase.DataDTRMode = HAL_XSPI_DATA_DTR_DISABLE;
+          s_commandbase.DummyCycles = 8;
+          s_commandbase.DQSMode = HAL_XSPI_DQS_DISABLE;
+          break;
+        }
+        case PHY_LINK_8S8D8D:
+        {
+          s_commandbase.InstructionMode = HAL_XSPI_INSTRUCTION_8_LINES;
+          s_commandbase.InstructionWidth = HAL_XSPI_INSTRUCTION_8_BITS;
+          s_commandbase.InstructionDTRMode = HAL_XSPI_INSTRUCTION_DTR_DISABLE;
+          s_commandbase.AddressMode = HAL_XSPI_ADDRESS_8_LINES;
+          s_commandbase.AddressWidth = HAL_XSPI_ADDRESS_32_BITS;
+          s_commandbase.AddressDTRMode = HAL_XSPI_ADDRESS_DTR_ENABLE;
+          s_commandbase.DataMode = HAL_XSPI_DATA_8_LINES;
+          s_commandbase.DataDTRMode = HAL_XSPI_DATA_DTR_ENABLE;
+          s_commandbase.DummyCycles = 8;
+          s_commandbase.DQSMode = HAL_XSPI_DQS_ENABLE;
+          break;
+        }
+
+        case PHY_LINK_8D8D8D:
+        {
+          s_commandbase.InstructionMode = HAL_XSPI_INSTRUCTION_8_LINES;
+          s_commandbase.InstructionWidth = HAL_XSPI_INSTRUCTION_16_BITS;
+          s_commandbase.InstructionDTRMode = HAL_XSPI_INSTRUCTION_DTR_ENABLE;
+          s_commandbase.AddressMode = HAL_XSPI_ADDRESS_8_LINES;
+          s_commandbase.AddressWidth = HAL_XSPI_ADDRESS_32_BITS;
+          s_commandbase.AddressDTRMode = HAL_XSPI_ADDRESS_DTR_ENABLE;
+          s_commandbase.DataMode = HAL_XSPI_DATA_8_LINES;
+          s_commandbase.DataDTRMode = HAL_XSPI_DATA_DTR_ENABLE;
+          s_commandbase.DummyCycles = 20;
+          s_commandbase.DQSMode = HAL_XSPI_DQS_ENABLE;
+          break;
+        }
+        case PHY_LINK_RAM8:
+        {
+          s_commandbase.InstructionMode    = HAL_XSPI_INSTRUCTION_8_LINES;
+          s_commandbase.InstructionWidth   = HAL_XSPI_INSTRUCTION_8_BITS;
+          s_commandbase.InstructionDTRMode = HAL_XSPI_INSTRUCTION_DTR_DISABLE;
+          s_commandbase.AddressMode        = HAL_XSPI_ADDRESS_8_LINES;
+          s_commandbase.AddressWidth       = HAL_XSPI_ADDRESS_32_BITS;
+          s_commandbase.AddressDTRMode     = HAL_XSPI_ADDRESS_DTR_ENABLE;
+          s_commandbase.AlternateBytesMode = HAL_XSPI_ALT_BYTES_NONE;
+          s_commandbase.DataMode           = HAL_XSPI_DATA_8_LINES;
+          s_commandbase.DataDTRMode        = HAL_XSPI_DATA_DTR_ENABLE;
+          s_commandbase.DummyCycles        = 10;
+          s_commandbase.DQSMode            = HAL_XSPI_DQS_ENABLE;
+          break;
+        }
+#if defined(HAL_XSPI_DATA_16_LINES)
+        case PHY_LINK_RAM16 :
+        {
+          s_commandbase.InstructionMode    = HAL_XSPI_INSTRUCTION_8_LINES;
+          s_commandbase.InstructionWidth   = HAL_XSPI_INSTRUCTION_8_BITS;
+          s_commandbase.InstructionDTRMode = HAL_XSPI_INSTRUCTION_DTR_DISABLE;
+          s_commandbase.AddressMode        = HAL_XSPI_ADDRESS_8_LINES;
+          s_commandbase.AddressWidth       = HAL_XSPI_ADDRESS_32_BITS;
+          s_commandbase.AddressDTRMode     = HAL_XSPI_ADDRESS_DTR_ENABLE;
+          s_commandbase.AlternateBytesMode = HAL_XSPI_ALT_BYTES_NONE;
+          s_commandbase.DataMode           = HAL_XSPI_DATA_16_LINES;
+          s_commandbase.DataDTRMode        = HAL_XSPI_DATA_DTR_ENABLE;
+          s_commandbase.DummyCycles        = 10;
+          s_commandbase.DQSMode            = HAL_XSPI_DQS_ENABLE;
+          break;
+        }
+#endif /* HAL_XSPI_DATA_16_LINES */
+        default:
+          retr = HAL_ERROR;
+          break;
+      }
+      DEBUG_PARAM_END();
+      break;
+    }
+    case PARAM_ADDRESS_4BYTES:
+    {
+      DEBUG_PARAM_BEGIN();
+      DEBUG_PARAM_DATA("::PARAM_ADDRESS_4BYTES");
+      DEBUG_PARAM_END();
+      s_commandbase.AddressWidth = HAL_XSPI_ADDRESS_32_BITS;
+      break;
+    }
+    case PARAM_FLASHSIZE:
+    {
+      uint8_t valParam = *((uint8_t *)ParamVal);
+      DEBUG_PARAM_BEGIN();
+      DEBUG_PARAM_DATA("::PARAM_FLASHSIZE::");
+      DEBUG_PARAM_INT(valParam);
+      DEBUG_PARAM_END();
+      MODIFY_REG(SalXspi->hxspi->Instance->DCR1, XSPI_DCR1_DEVSIZE, ((uint32_t)valParam) << XSPI_DCR1_DEVSIZE_Pos);
+      break;
+    }
+    case PARAM_DUMMY_CYCLES:
+    {
+      uint8_t valParam = *((uint8_t *)ParamVal);
+      DEBUG_PARAM_BEGIN();
+      DEBUG_PARAM_DATA("::PARAM_DUMMY_CYCLES::");
+      DEBUG_PARAM_INT(valParam);
+      DEBUG_PARAM_END();
+      s_commandbase.DummyCycles = valParam;
+      break;
+    }
+    default:
+      DEBUG_PARAM_BEGIN();
+      DEBUG_PARAM_DATA("::SAL_XSPI_MemoryConfig::ERROR");
+      DEBUG_PARAM_END();
+      retr = HAL_ERROR;
+      break;
+  }
+  SalXspi->Commandbase = s_commandbase;
+  return retr;
+}
+
+/**
+  * @brief This function gets SFDP data
+  * @param SalXspi SAL XSPI handle
+  * @param Address Address to read the data
+  * @param Data Data pointer
+  * @param DataSize Size of the data to read
+  * @return @ref HAL_StatusTypeDef
+  **/
+HAL_StatusTypeDef SAL_XSPI_GetSFDP(SAL_XSPI_ObjectTypeDef *SalXspi, uint32_t Address, uint8_t *Data, uint32_t DataSize)
+{
+  HAL_StatusTypeDef retr;
+  XSPI_RegularCmdTypeDef s_command = SalXspi->Commandbase;
+
+  /* Initialize the read ID command */
+  s_command.Instruction = XSPI_FormatCommand(SalXspi->CommandExtension, s_command.InstructionWidth,
+                                             EXTMEM_READ_SFDP_COMMAND);
+
+  s_command.Address     = Address;
+  s_command.DataLength  = DataSize;
+  s_command.DummyCycles = SalXspi->SFDPDummyCycle;
+
+  if ((s_command.AddressMode == HAL_XSPI_ADDRESS_1_LINE) || (s_command.AddressMode == HAL_XSPI_ADDRESS_4_LINES))
+  {
+    s_command.AddressWidth = HAL_XSPI_ADDRESS_24_BITS;
+  }
+
+  if ((SalXspi->PhyLink == PHY_LINK_1S1S2S)    /*!< Physical link configured in 1S1S2S */
+      || (SalXspi->PhyLink == PHY_LINK_1S2S2S)    /*!< Physical link configured in 1S2S2S */
+      || (SalXspi->PhyLink == PHY_LINK_1S1D1D)    /*!< Physical link configured in 1S1D1D */
+      || (SalXspi->PhyLink == PHY_LINK_1S1S4S)    /*!< Physical link configured in 1S1S4S */
+      || (SalXspi->PhyLink == PHY_LINK_1S4S4S))   /*!< Physical link configured in 1S4S4S */
+  {
+    s_command.AddressMode = HAL_XSPI_ADDRESS_1_LINE;
+    s_command.DataMode    = HAL_XSPI_DATA_1_LINE;
+  }
+
+  if (s_command.DataDTRMode == HAL_XSPI_DATA_DTR_ENABLE)
+  {
+    s_command.DQSMode = HAL_XSPI_DQS_ENABLE;
+  }
+  else
+  {
+    s_command.DQSMode = HAL_XSPI_DQS_DISABLE;
+  }
+
+  /* Configure the command */
+  retr = HAL_XSPI_Command(SalXspi->hxspi, &s_command, SAL_XSPI_TIMEOUT_DEFAULT_VALUE);
+  if (retr  != HAL_OK)
+  {
+    goto error;
+  }
+
+  /* Reception of the data */
+  retr = HAL_XSPI_Receive(SalXspi->hxspi, Data, SAL_XSPI_TIMEOUT_DEFAULT_VALUE);
+
+error:
+  if (retr != HAL_OK)
+  {
+    /* Abort any ongoing transaction for the next action */
+    (void)HAL_XSPI_Abort(SalXspi->hxspi);
+  }
+  return retr;
+}
+
+/**
+  * @brief This function reads the flash ID
+  * @param SalXspi SAL XSPI handle
+  * @param Data Data pointer where read ID should be stored
+  * @param DataSize Number of data to read
+  * @return @ref HAL_StatusTypeDef
+  **/
+HAL_StatusTypeDef SAL_XSPI_GetId(SAL_XSPI_ObjectTypeDef *SalXspi, uint8_t *Data, uint32_t DataSize)
+{
+  HAL_StatusTypeDef retr;
+  XSPI_RegularCmdTypeDef s_command = SalXspi->Commandbase;
+
+  /* Initialize the Read ID command */
+  s_command.Instruction = XSPI_FormatCommand(SalXspi->CommandExtension, s_command.InstructionWidth,
+                                             EXTMEM_READ_JEDEC_ID_SPI_COMMAND);
+
+  s_command.DataLength  = DataSize;
+
+  if (s_command.InstructionMode == HAL_XSPI_INSTRUCTION_1_LINE)
+  {
+    s_command.AddressMode       = HAL_XSPI_ADDRESS_NONE;
+    s_command.DummyCycles       = 0;
+    /* This behavior is linked with micron memory to read ID in 1S8S8S */
+    s_command.DataMode = HAL_XSPI_DATA_1_LINE;
+  }
+  else if (s_command.InstructionMode == HAL_XSPI_INSTRUCTION_4_LINES)
+  {
+    s_command.AddressMode       = HAL_XSPI_ADDRESS_NONE;
+    s_command.DummyCycles       = 0;
+    /* This behavior is linked with ISSI memory to read ID in 4S4S4S */
+    s_command.DataMode          = HAL_XSPI_DATA_4_LINES;
+  }
+  else
+  {
+    /* This behavior is valid for Macromix and must be confirmed on the other memories */
+    s_command.Address = 0;
+    s_command.DummyCycles = 8;
+  }
+
+  /* Configure the command */
+  retr = HAL_XSPI_Command(SalXspi->hxspi, &s_command, SAL_XSPI_TIMEOUT_DEFAULT_VALUE);
+  if (retr  != HAL_OK)
+  {
+    goto error;
+  }
+
+  /* Reception of the data */
+  retr = HAL_XSPI_Receive(SalXspi->hxspi, Data, SAL_XSPI_TIMEOUT_DEFAULT_VALUE);
+
+error:
+  if (retr != HAL_OK)
+  {
+    /* Abort any ongoing transaction for the next action */
+    (void)HAL_XSPI_Abort(SalXspi->hxspi);
+  }
+  return retr;
+}
+
+/**
+  * @brief This function reads data from the flash
+  * @param SalXspi SAL XSPI handle
+  * @param Command Command to execute
+  * @param Address Address to read the data
+  * @param Data Data pointer
+  * @param DataSize Size of the data to read
+  * @return @ref HAL_StatusTypeDef
+  **/
+HAL_StatusTypeDef SAL_XSPI_Read(SAL_XSPI_ObjectTypeDef *SalXspi, uint8_t Command, uint32_t Address, uint8_t *Data,
+                                uint32_t DataSize)
+{
+  HAL_StatusTypeDef retr;
+  XSPI_RegularCmdTypeDef s_command = SalXspi->Commandbase;
+
+  /* Initialize the read ID command */
+  s_command.Instruction = XSPI_FormatCommand(SalXspi->CommandExtension, s_command.InstructionWidth, Command);
+
+  s_command.Address           = Address;
+  s_command.DataLength        = DataSize;
+
+  /* DTR management for single/dual/quad */
+  switch (SalXspi->PhyLink)
+  {
+    case PHY_LINK_4S4D4D :
+      s_command.AddressDTRMode = HAL_XSPI_ADDRESS_DTR_ENABLE;
+      s_command.DataDTRMode    = HAL_XSPI_DATA_DTR_ENABLE;
+      s_command.DummyCycles    = SalXspi->DTRDummyCycle;
+      break;
+
+    case PHY_LINK_1S2S2S :
+      s_command.AddressMode    = HAL_XSPI_ADDRESS_2_LINES;
+      s_command.DataMode       = HAL_XSPI_DATA_2_LINES;
+      break;
+
+    case PHY_LINK_1S1S2S :
+      s_command.DataMode       = HAL_XSPI_DATA_2_LINES;
+      break;
+
+    default :
+      /* Keep default parameters */
+      break;
+  }
+
+  /* In case of DTR read of 1 byte, set data length to 2 */
+  if ((s_command.DataDTRMode == HAL_XSPI_DATA_DTR_ENABLE) && (s_command.DataLength == 1U))
+  {
+    s_command.DataLength = 2U;
+  }
+
+  /* Configure the command */
+  retr = HAL_XSPI_Command(SalXspi->hxspi, &s_command, SAL_XSPI_TIMEOUT_DEFAULT_VALUE);
+  if (retr  != HAL_OK)
+  {
+    goto error;
+  }
+
+  /* Read data */
+  retr = XSPI_Receive(SalXspi, Data);
+
+error:
+  if (retr != HAL_OK)
+  {
+    /* Abort any ongoing transaction for the next action */
+    (void)HAL_XSPI_Abort(SalXspi->hxspi);
+  }
+  return retr;
+}
+
+/**
+  * @brief This function writes data at an Address
+  * @param SalXspi SAL XSPI handle
+  * @param Command Command to execute
+  * @param Address Address to write the data
+  * @param Data Data pointer
+  * @param DataSize Size of the data to write
+  * @return @ref HAL_StatusTypeDef
+  **/
+HAL_StatusTypeDef SAL_XSPI_Write(SAL_XSPI_ObjectTypeDef *SalXspi, uint8_t Command, uint32_t Address,
+                                 const uint8_t *Data, uint32_t DataSize)
+{
+  HAL_StatusTypeDef retr;
+  XSPI_RegularCmdTypeDef s_command = SalXspi->Commandbase;
+
+  /* Initialize the read ID command */
+  s_command.Instruction = XSPI_FormatCommand(SalXspi->CommandExtension, s_command.InstructionWidth, Command);
+
+  s_command.Address           = Address;
+  s_command.DataLength        = DataSize;
+  s_command.DummyCycles       = 0u;
+  s_command.DQSMode           = HAL_XSPI_DQS_DISABLE;
+
+  /* In case of DTR write of 1 byte, set data length to 2 */
+  if ((s_command.DataDTRMode == HAL_XSPI_DATA_DTR_ENABLE) && (s_command.DataLength == 1U))
+  {
+    s_command.DataLength = 2U;
+  }
+
+  /* Configure the command */
+  retr = HAL_XSPI_Command(SalXspi->hxspi, &s_command, SAL_XSPI_TIMEOUT_DEFAULT_VALUE);
+  if (HAL_OK != retr)
+  {
+    goto error;
+  }
+
+  /* Transmit data */
+  retr = XSPI_Transmit(SalXspi, Data);
+
+error:
+  if (retr != HAL_OK)
+  {
+    /* Abort any ongoing transaction for the next action */
+    (void)HAL_XSPI_Abort(SalXspi->hxspi);
+  }
+  return retr;
+}
+
+/**
+  * @brief This function sends a command and an address
+  * @param SalXspi SAL XSPI handle
+  * @param Command Command to execute
+  * @param Address Address to write the data
+  * @return @ref HAL_StatusTypeDef
+  **/
+HAL_StatusTypeDef SAL_XSPI_CommandSendAddress(SAL_XSPI_ObjectTypeDef *SalXspi, uint8_t Command,
+                                              uint32_t Address)
+{
+  HAL_StatusTypeDef retr;
+  XSPI_RegularCmdTypeDef s_command = SalXspi->Commandbase;
+
+  /* Initialize the writing of status register */
+  s_command.Instruction = XSPI_FormatCommand(SalXspi->CommandExtension, s_command.InstructionWidth, Command);
+
+  if (s_command.InstructionMode == HAL_XSPI_INSTRUCTION_1_LINE)
+  {
+    s_command.AddressMode = HAL_XSPI_ADDRESS_1_LINE;
+  }
+
+  s_command.Address           = Address;
+  s_command.DummyCycles       = 0U;
+  s_command.DataMode          = HAL_XSPI_DATA_NONE;
+  s_command.DQSMode           = HAL_XSPI_DQS_DISABLE;
+
+  /* Send the command */
+  retr = HAL_XSPI_Command(SalXspi->hxspi, &s_command, SAL_XSPI_TIMEOUT_DEFAULT_VALUE);
+  if (retr != HAL_OK)
+  {
+    /* Abort any ongoing transaction for the next action */
+    (void)HAL_XSPI_Abort(SalXspi->hxspi);
+  }
+  return retr;
+}
+
+/**
+  * @brief This function sends a command + data
+  * @param SalXspi SAL XSPI handle
+  * @param Command Command to execute
+  * @param Data Data pointer
+  * @param DataSize Size of the data to write
+  * @return @ref HAL_StatusTypeDef
+  **/
+HAL_StatusTypeDef SAL_XSPI_CommandSendData(SAL_XSPI_ObjectTypeDef *SalXspi, uint8_t Command,
+                                           uint8_t *Data, uint16_t DataSize)
+{
+  XSPI_RegularCmdTypeDef   s_command = SalXspi->Commandbase;
+  HAL_StatusTypeDef retr;
+
+  /* Initialize the writing of status register */
+  s_command.Instruction = XSPI_FormatCommand(SalXspi->CommandExtension, s_command.InstructionWidth, Command);
+
+  s_command.AddressMode        = HAL_XSPI_ADDRESS_NONE;
+  s_command.DummyCycles        = 0U;
+  s_command.DataLength         = DataSize;
+  s_command.DQSMode            = HAL_XSPI_DQS_DISABLE;
+
+  if (DataSize == 0u)
+  {
+    s_command.DataMode         = HAL_XSPI_DATA_NONE;
+  }
+
+  /* Send the command */
+  retr = HAL_XSPI_Command(SalXspi->hxspi, &s_command, SAL_XSPI_TIMEOUT_DEFAULT_VALUE);
+
+  if ((retr == HAL_OK) && (DataSize != 0u))
+  {
+    retr = HAL_XSPI_Transmit(SalXspi->hxspi, Data, SAL_XSPI_TIMEOUT_DEFAULT_VALUE);
+  }
+
+  if (retr != HAL_OK)
+  {
+    /* Abort any ongoing transaction for the next action */
+    (void)HAL_XSPI_Abort(SalXspi->hxspi);
+  }
+  return retr;
+}
+
+/**
+  * @brief This function sends a command to read the data
+  * @param SalXspi SAL XSPI handle
+  * @param Command Command to execute
+  * @param Data Data pointer
+  * @param DataSize Size of the data to receive
+  * @return @ref HAL_StatusTypeDef
+  **/
+HAL_StatusTypeDef SAL_XSPI_SendReadCommand(SAL_XSPI_ObjectTypeDef *SalXspi, uint8_t Command,
+                                           uint8_t *Data, uint16_t DataSize)
+{
+  XSPI_RegularCmdTypeDef   s_command = SalXspi->Commandbase;
+  HAL_StatusTypeDef retr;
+
+  /* Initialize the reading of status register */
+  s_command.Instruction = XSPI_FormatCommand(SalXspi->CommandExtension, s_command.InstructionWidth, Command);
+
+  s_command.AddressMode        = HAL_XSPI_ADDRESS_NONE;
+  s_command.DummyCycles        = 0u;
+  s_command.DataLength         = DataSize;
+  s_command.DQSMode            = HAL_XSPI_DQS_DISABLE;
+
+#if defined(EXTMEM_DRIVER_NOR_SFDP_DUAL_CONFIG)
+  if ((SalXspi->ManufacturerId == EXTMEM_MANUFACTURER_WINBOND)
+      && ((Command == SalXspi->ReadWipCommand) || (Command == SalXspi->ReadWelCommand))
+      && (s_command.InstructionMode == HAL_XSPI_INSTRUCTION_1_LINE)
+      && (s_command.DataMode == HAL_XSPI_DATA_4_LINES))
+  {
+    s_command.DataMode = HAL_XSPI_DATA_1_LINE;
+  }
+#endif /* EXTMEM_DRIVER_NOR_SFDP_DUAL_CONFIG */
+
+  if (DataSize == 0u)
+  {
+    s_command.DataMode = HAL_XSPI_DATA_NONE;
+  }
+
+  /* Send the command */
+  retr = HAL_XSPI_Command(SalXspi->hxspi, &s_command, SAL_XSPI_TIMEOUT_DEFAULT_VALUE);
+
+  if ((retr == HAL_OK) && (DataSize != 0u))
+  {
+    /* Receive data */
+    retr = HAL_XSPI_Receive(SalXspi->hxspi, Data, SAL_XSPI_TIMEOUT_DEFAULT_VALUE);
+  }
+
+  if (retr != HAL_OK)
+  {
+    /* Abort any ongoing transaction for the next action */
+    (void)HAL_XSPI_Abort(SalXspi->hxspi);
+  }
+  return retr;
+}
+
+/**
+  * @brief This function sends a command with address and read the data
+  * @param SalXspi SAL XSPI handle
+  * @param Command Command to execute
+  * @param Address Address value
+  * @param Data Data pointer
+  * @param DataSize Size of the data to read
+  * @param ManuId Manufacturer Identifier
+  * @return @ref HAL_StatusTypeDef
+  **/
+HAL_StatusTypeDef SAL_XSPI_CommandSendReadAddress(SAL_XSPI_ObjectTypeDef *SalXspi, uint8_t Command,
+                                                  uint32_t Address, uint8_t *Data, uint16_t DataSize,
+                                                  uint8_t ManuId)
+{
+  XSPI_RegularCmdTypeDef   s_command = SalXspi->Commandbase;
+  HAL_StatusTypeDef retr;
+
+  /* Initialize the reading of status register */
+  s_command.Instruction = XSPI_FormatCommand(SalXspi->CommandExtension, s_command.InstructionWidth, Command);
+
+  s_command.Address            = Address;
+  s_command.DummyCycles        = SalXspi->SFDPDummyCycle;
+  s_command.DataLength         = DataSize;
+  /* Specific case for Macronix memories : RDID and RDCR are not Data DTR  */
+  if ((ManuId == EXTMEM_MANUFACTURER_MACRONIX) && (s_command.DataDTRMode == HAL_XSPI_DATA_DTR_ENABLE))
+  {
+    s_command.DataDTRMode      = HAL_XSPI_DATA_DTR_DISABLE;
+  }
+  /* Specific case for GigaDevice memories : Read Configuration Register are not Data DTR  */
+  else if ((ManuId == 0xC8) && (s_command.DataDTRMode == HAL_XSPI_DATA_DTR_ENABLE))
+  {
+    s_command.DataDTRMode      = HAL_XSPI_DATA_DTR_DISABLE;
+    s_command.DQSMode          = HAL_XSPI_DQS_DISABLE;
+  }
+  else
+  {
+    s_command.DQSMode          = HAL_XSPI_DQS_DISABLE;
+  }
+
+  /* Send the command */
+  retr = HAL_XSPI_Command(SalXspi->hxspi, &s_command, SAL_XSPI_TIMEOUT_DEFAULT_VALUE);
+
+  if (retr == HAL_OK)
+  {
+    /* Retrieve data */
+    retr = HAL_XSPI_Receive(SalXspi->hxspi, Data, SAL_XSPI_TIMEOUT_DEFAULT_VALUE);
+  }
+
+  if (retr != HAL_OK)
+  {
+    /* Abort any ongoing transaction for the next action */
+    (void)HAL_XSPI_Abort(SalXspi->hxspi);
+  }
+  return retr;
+}
+
+/**
+  * @brief This function controls the status register
+  * @param SalXspi SAL XSPI handle
+  * @param Command Command to execute
+  * @param Address Specify the address
+  * @param MatchValue  Expected value
+  * @param MatchMask   Mask used to control the expected value
+  * @param ManuId Manufacturer Identifier
+  * @param Timeout Timeout parameter
+  * @return @ref HAL_StatusTypeDef
+  **/
+HAL_StatusTypeDef SAL_XSPI_CheckStatusRegister(SAL_XSPI_ObjectTypeDef *SalXspi, uint8_t Command, uint32_t Address,
+                                               uint8_t MatchValue, uint8_t MatchMask, uint8_t ManuId,
+                                               uint32_t Timeout)
+{
+  XSPI_RegularCmdTypeDef s_command = SalXspi->Commandbase;
+  XSPI_AutoPollingTypeDef  s_config =
+  {
+    .MatchValue    = MatchValue,
+    .MatchMask     = MatchMask,
+    .MatchMode     = HAL_XSPI_MATCH_MODE_AND,
+    .AutomaticStop = HAL_XSPI_AUTOMATIC_STOP_ENABLE,
+    .IntervalTime  = 0x10
+  };
+  HAL_StatusTypeDef retr;
+
+  /* Initialize the reading of status register */
+  s_command.Instruction = XSPI_FormatCommand(SalXspi->CommandExtension, s_command.InstructionWidth, Command);
+
+  s_command.DataLength     = 1u;
+  s_command.DQSMode        = HAL_XSPI_DQS_DISABLE;
+
+  if (s_command.InstructionMode == HAL_XSPI_INSTRUCTION_1_LINE)
+  {
+    /* Specific behavior for Cypress to force 1 line on status read */
+    s_command.DataMode    = HAL_XSPI_DATA_1_LINE;
+    s_command.AddressMode = HAL_XSPI_DATA_NONE;
+    s_command.DummyCycles = 0u;
+  }
+
+  /* Address is used only in 8 LINES format */
+  if (s_command.DataMode == HAL_XSPI_DATA_8_LINES)
+  {
+    /* Specific case for Macronix memories : RDID and RDCR are not Data DTR  */
+    if ((ManuId == EXTMEM_MANUFACTURER_MACRONIX) && (s_command.DataDTRMode == HAL_XSPI_DATA_DTR_ENABLE))
+    {
+      s_command.DQSMode        = HAL_XSPI_DQS_ENABLE;
+      s_command.DataDTRMode    = HAL_XSPI_DATA_DTR_DISABLE;
+    }
+    s_command.AddressMode    = HAL_XSPI_ADDRESS_8_LINES;
+    s_command.AddressWidth   = HAL_XSPI_ADDRESS_32_BITS;
+    s_command.Address        = Address;
+  }
+
+  /* Send the command */
+  retr = HAL_XSPI_Command(SalXspi->hxspi, &s_command, SAL_XSPI_TIMEOUT_DEFAULT_VALUE);
+  if (retr == HAL_OK)
+  {
+    retr = HAL_XSPI_AutoPolling(SalXspi->hxspi, &s_config, Timeout);
+    DEBUG_AUTOPOLLING(SalXspi->hxspi->Instance->DR, s_config.MatchValue, s_config.MatchMask)
+  }
+
+  if (retr != HAL_OK)
+  {
+    /* Abort any ongoing transaction for the next action */
+    (void)HAL_XSPI_Abort(SalXspi->hxspi);
+  }
+  return retr;
+}
+
+/**
+  * @brief This function enables the memory mapped mode
+  * @param SalXspi SAL XSPI handle
+  * @param WrapCommand Wrap command to execute in case of write operation
+  * @param WrapDummy Number of dummy cycle for the read operation
+  * @return @ref HAL_StatusTypeDef
+  **/
+HAL_StatusTypeDef SAL_XSPI_ConfigureWrappMode(SAL_XSPI_ObjectTypeDef *SalXspi, uint8_t WrapCommand, uint8_t WrapDummy)
+{
+  HAL_StatusTypeDef retr;
+  XSPI_RegularCmdTypeDef s_command = SalXspi->Commandbase;
+
+  /* Initialize the read ID command */
+  s_command.OperationType = HAL_XSPI_OPTYPE_WRAP_CFG;
+  s_command.Instruction = XSPI_FormatCommand(SalXspi->CommandExtension, s_command.InstructionWidth, WrapCommand);
+  s_command.DummyCycles = WrapDummy;
+  /* Configure the read command */
+  retr = HAL_XSPI_Command(SalXspi->hxspi, &s_command, SAL_XSPI_TIMEOUT_DEFAULT_VALUE);
+  if (retr  != HAL_OK)
+  {
+    goto error;
+  }
+
+error:
+  if (retr != HAL_OK)
+  {
+    /* Abort any ongoing transaction for the next action */
+    (void)HAL_XSPI_Abort(SalXspi->hxspi);
+  }
+  return retr;
+}
+
+/**
+  * @brief This function enables the memory mapped mode
+  * @param SalXspi SAL XSPI handle
+  * @param CommandRead command to execute in case of read operation
+  * @param DummyRead number of dummy cycle for the read operation
+  * @param CommandWrite command to execute in case of write operation
+  * @param DummyWrite number of dummy cycle for the read operation
+  * @return @ref HAL_StatusTypeDef
+  **/
+HAL_StatusTypeDef SAL_XSPI_EnableMapMode(SAL_XSPI_ObjectTypeDef *SalXspi, uint8_t CommandRead, uint8_t DummyRead,
+                                         uint8_t CommandWrite, uint8_t DummyWrite)
+{
+  HAL_StatusTypeDef retr;
+  XSPI_RegularCmdTypeDef s_command = SalXspi->Commandbase;
+  XSPI_MemoryMappedTypeDef sMemMappedCfg = {0};
+
+  /* Initialize the read ID command */
+  s_command.OperationType = HAL_XSPI_OPTYPE_READ_CFG;
+  s_command.Instruction = XSPI_FormatCommand(SalXspi->CommandExtension, s_command.InstructionWidth, CommandRead);
+  s_command.DummyCycles = DummyRead;
+  /* Configure the read command */
+  retr = HAL_XSPI_Command(SalXspi->hxspi, &s_command, SAL_XSPI_TIMEOUT_DEFAULT_VALUE);
+  if (retr  != HAL_OK)
+  {
+    goto error;
+  }
+
+  /* Initialize the read ID command */
+  s_command.OperationType     = HAL_XSPI_OPTYPE_WRITE_CFG;
+  s_command.Instruction = XSPI_FormatCommand(SalXspi->CommandExtension, s_command.InstructionWidth, CommandWrite);
+  s_command.DummyCycles = DummyWrite;
+  /* Configure the read command */
+  retr = HAL_XSPI_Command(SalXspi->hxspi, &s_command, SAL_XSPI_TIMEOUT_DEFAULT_VALUE);
+  if (retr  != HAL_OK)
+  {
+    goto error;
+  }
+
+  /* Activation of memory-mapped mode */
+  sMemMappedCfg.TimeOutActivation  = HAL_XSPI_TIMEOUT_COUNTER_DISABLE;
+  sMemMappedCfg.TimeoutPeriodClock = 0x50;
+  retr = HAL_XSPI_MemoryMapped(SalXspi->hxspi, &sMemMappedCfg);
+
+error:
+  if (retr != HAL_OK)
+  {
+    /* Abort any ongoing transaction for the next action */
+    (void)HAL_XSPI_Abort(SalXspi->hxspi);
+  }
+  return retr;
+}
+
+/**
+  * @brief This function disables the memory mapped mode
+  * @param SalXspi SAL XSPI handle
+  * @return @ref HAL_StatusTypeDef
+  **/
+HAL_StatusTypeDef SAL_XSPI_DisableMapMode(SAL_XSPI_ObjectTypeDef *SalXspi)
+{
+  __DSB();
+  return HAL_XSPI_Abort(SalXspi->hxspi);
+}
+
+/**
+  * @brief This function updates the memory according the SFDP signature value
+  * @param SalXspi SAL XSPI handle
+  * @param DataOrder Selected data order
+  * @return @ref HAL_StatusTypeDef
+  **/
+HAL_StatusTypeDef SAL_XSPI_UpdateMemoryType(SAL_XSPI_ObjectTypeDef *SalXspi, SAL_XSPI_DataOrderTypeDef DataOrder)
+{
+  HAL_StatusTypeDef retr = HAL_OK;
+
+  /* Read the memory type value */
+  uint32_t memorytype = READ_REG(SalXspi->hxspi->Instance->DCR1) & XSPI_DCR1_MTYP;
+
+  switch (DataOrder)
+  {
+    case SAL_XSPI_ORDERINVERTED :
+      if (memorytype == HAL_XSPI_MEMTYPE_MICRON)
+      {
+        memorytype = HAL_XSPI_MEMTYPE_MACRONIX;
+      }
+      else if (memorytype == HAL_XSPI_MEMTYPE_MACRONIX)
+      {
+        memorytype = HAL_XSPI_MEMTYPE_MICRON;
+      }
+      else
+      {
+        retr = HAL_ERROR;
+      }
+      MODIFY_REG(SalXspi->hxspi->Instance->DCR1, XSPI_DCR1_MTYP, memorytype);
+      break;
+    default :
+      return HAL_ERROR;
+      break;
+  }
+
+  DEBUG_PARAM_BEGIN();
+  DEBUG_PARAM_DATA("::SAL_XSPI_UpdateMemoryType::");
+  DEBUG_PARAM_INT(memorytype);
+  DEBUG_PARAM_END();
+  return retr;
+}
+
+HAL_StatusTypeDef SAL_XSPI_Abort(SAL_XSPI_ObjectTypeDef *SalXspi)
+{
+  return HAL_XSPI_Abort(SalXspi->hxspi);
+}
+
+/**
+  * @}
+  */
+
+/** @defgroup SAL_XSPI_Private_Functions SAL XSP Private Functions
+  * @{
+  */
+/**
+  * @brief This function return a formatted command
+  *
+  * @param CommandExtension Type of the command extension 0: the complement  1 : the same
+  * @param InstructionWidth Instruction width
+  * @param Command Command
+  * @return Formatted command
+  */
+uint16_t XSPI_FormatCommand(uint8_t CommandExtension, uint32_t InstructionWidth, uint8_t Command)
+{
+  uint16_t retr;
+  if (InstructionWidth == HAL_XSPI_INSTRUCTION_16_BITS)
+  {
+    /* 0b00 Command Extension is the same as the Command.
+            (Command / Command Extension has the same value for the whole clock period. */
+    /* 0b01 Command Extension is the inverse of the Command.
+            Command Extension acts as a confirmation of the Command */
+    /* 0b11 Command and Command Extension forms a 16 bit command word :: Not yet handled */
+    retr = ((uint16_t)Command << 8u);
+    if (CommandExtension == 1u)
+    {
+      retr |= (uint8_t)(~Command & 0xFFu);
+    }
+    else
+    {
+      retr |= (uint8_t)(Command & 0xFFu);
+    }
+  }
+  else
+  {
+    retr = Command;
+  }
+
+  return retr;
+}
+
+/**
+  * @brief This function transmits the data
+  *
+  * @param SalXspi SAL XSPI Handle
+  * @param Data Data pointer
+  * @return Status of the command execution
+  */
+HAL_StatusTypeDef XSPI_Transmit(SAL_XSPI_ObjectTypeDef *SalXspi, const uint8_t *Data)
+{
+  HAL_StatusTypeDef retr;
+
+#if defined (USE_HAL_XSPI_REGISTER_CALLBACKS) && (USE_HAL_XSPI_REGISTER_CALLBACKS == 1U)
+  if (SalXspi->hxspi->hdmatx == NULL)
+#endif /* USE_HAL_XSPI_REGISTER_CALLBACKS */
+  {
+    /* Transmit data */
+    retr = HAL_XSPI_Transmit(SalXspi->hxspi, Data, SAL_XSPI_TIMEOUT_DEFAULT_VALUE);
+  }
+#if defined (USE_HAL_XSPI_REGISTER_CALLBACKS) && (USE_HAL_XSPI_REGISTER_CALLBACKS == 1U)
+  else
+  {
+    /* Set completion call back */
+    salXSPI_status = SALXSPI_TRANSFER_NONE;
+
+    /* Reception of the data */
+    retr = HAL_XSPI_Transmit_DMA(SalXspi->hxspi, (uint8_t *)Data);
+
+    if (retr ==  HAL_OK)
+    {
+      /* Wait data reception completion */
+      while (salXSPI_status == SALXSPI_TRANSFER_NONE);
+      if (salXSPI_status == SALXSPI_TRANSFER_ERROR)
+      {
+        retr = HAL_ERROR;
+      }
+    }
+  }
+#endif /* USE_HAL_XSPI_REGISTER_CALLBACKS */
+
+  return retr;
+}
+
+/**
+  * @brief Start data reception in polling mode or DMA
+  *
+  * @param SalXspi SAL XSPI Handle
+  * @param Data Data pointer
+  * @return Status of the command execution
+  */
+HAL_StatusTypeDef XSPI_Receive(SAL_XSPI_ObjectTypeDef *SalXspi,  uint8_t *Data)
+{
+  HAL_StatusTypeDef retr;
+
+#if defined (USE_HAL_XSPI_REGISTER_CALLBACKS) && (USE_HAL_XSPI_REGISTER_CALLBACKS == 1U)
+  if (SalXspi->hxspi->hdmarx == NULL)
+#endif /* USE_HAL_XSPI_REGISTER_CALLBACKS */
+  {
+    /* Reception of the data */
+    retr = HAL_XSPI_Receive(SalXspi->hxspi, Data, SAL_XSPI_TIMEOUT_DEFAULT_VALUE);
+  }
+#if defined (USE_HAL_XSPI_REGISTER_CALLBACKS) && (USE_HAL_XSPI_REGISTER_CALLBACKS == 1U)
+  else
+  {
+    /* Set completion call back */
+    salXSPI_status = SALXSPI_TRANSFER_NONE;
+
+    /* Reception of the data */
+    retr = HAL_XSPI_Receive_DMA(SalXspi->hxspi, Data);
+
+    if (retr ==  HAL_OK)
+    {
+      /* Wait data completion */
+      while (salXSPI_status == SALXSPI_TRANSFER_NONE);
+      if (salXSPI_status == SALXSPI_TRANSFER_ERROR)
+      {
+        retr = HAL_ERROR;
+      }
+    }
+  }
+#endif /* USE_HAL_XSPI_REGISTER_CALLBACKS */
+  return retr;
+}
+
+#if defined (USE_HAL_XSPI_REGISTER_CALLBACKS) && (USE_HAL_XSPI_REGISTER_CALLBACKS == 1U)
+/**
+  * @brief This callback is executed when a DMA transfer error occurs
+  *
+  * @param hxspi Handle on the XSPI peripheral
+  * @return none
+  */
+void SAL_XSPI_ErrorCallback(struct __XSPI_HandleTypeDef *hxspi)
+{
+  salXSPI_status = SALXSPI_TRANSFER_ERROR;
+}
+
+/**
+  * @brief this callback is executed when a DMA transfer is complete
+  *
+  * @param hxspi Handle on the XSPI peripheral
+  * @return none
+  */
+void SAL_XSPI_CompleteCallback(struct __XSPI_HandleTypeDef *hxspi)
+{
+  salXSPI_status = SALXSPI_TRANSFER_OK;
+}
+#endif /* USE_HAL_XSPI_REGISTER_CALLBACKS */
+
+/**
+  * @}
+  */
+
+/**
+  * @}
+  */
+
+#endif /* EXTMEM_SAL_XSPI == 1 */
Index: trunk/firmware/FSBL/CubeMX/Middlewares/ST/STM32_ExtMem_Manager/sal/stm32_sal_xspi_api.h
===================================================================
--- trunk/firmware/FSBL/CubeMX/Middlewares/ST/STM32_ExtMem_Manager/sal/stm32_sal_xspi_api.h	(revision 20)
+++ trunk/firmware/FSBL/CubeMX/Middlewares/ST/STM32_ExtMem_Manager/sal/stm32_sal_xspi_api.h	(revision 20)
@@ -0,0 +1,100 @@
+/**
+  ******************************************************************************
+  * @file    stm32_sal_xspi_api.h
+  * @author  MCD Application Team
+  * @brief   This file contains SAL XSPI function prototypes.
+  ******************************************************************************
+  * @attention
+  *
+  * Copyright (c) 2022 STMicroelectronics.
+  * All rights reserved.
+  *
+  * This software is licensed under terms that can be found in the LICENSE file
+  * in the root directory of this software component.
+  * If no LICENSE file comes with this software, it is provided AS-IS.
+  *
+  ******************************************************************************
+  */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __STM32_SAL_XSPI_API_H
+#define __STM32_SAL_XSPI_API_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** @defgroup SAL_XSPI
+  * @ingroup EXTMEM_SAL
+  * @{
+  */
+
+/* Includes ------------------------------------------------------------------*/
+/* Exported constants --------------------------------------------------------*/
+/* Exported types ------------------------------------------------------------*/
+/** @defgroup SAL_XSPI_Exported_types SAL XSPI exported types
+  * @{
+  */
+
+/**
+  * @}
+  */
+
+/* Exported functions --------------------------------------------------------*/
+/** @defgroup SAL_XSPI_Exported_Functions SAL XSPI Exported Functions
+  * @{
+  */
+HAL_StatusTypeDef SAL_XSPI_SetClock(SAL_XSPI_ObjectTypeDef *SalXspi, uint32_t ClockIn, uint32_t ClockRequested,
+                                    uint32_t *ClockReal);
+HAL_StatusTypeDef SAL_XSPI_Init(SAL_XSPI_ObjectTypeDef *SalXspi, void *HALHandle);
+HAL_StatusTypeDef SAL_XSPI_MemoryConfig(SAL_XSPI_ObjectTypeDef *SalXspi, SAL_XSPI_MemParamTypeTypeDef ParametersType,
+                                        void *ParamVal);
+HAL_StatusTypeDef SAL_XSPI_GetSFDP(SAL_XSPI_ObjectTypeDef *SalXspi, uint32_t Address,
+                                   uint8_t *Data, uint32_t DataSize);
+HAL_StatusTypeDef SAL_XSPI_GetId(SAL_XSPI_ObjectTypeDef *SalXspi, uint8_t *Data, uint32_t DataSize);
+HAL_StatusTypeDef SAL_XSPI_Read(SAL_XSPI_ObjectTypeDef *SalXspi, uint8_t Command, uint32_t Address, uint8_t *Data,
+                                uint32_t DataSize);
+HAL_StatusTypeDef SAL_XSPI_Write(SAL_XSPI_ObjectTypeDef *SalXspi, uint8_t Command, uint32_t Address,
+                                 const uint8_t *Data, uint32_t DataSize);
+HAL_StatusTypeDef SAL_XSPI_CommandSendAddress(SAL_XSPI_ObjectTypeDef *SalXspi, uint8_t Command, uint32_t Address);
+HAL_StatusTypeDef SAL_XSPI_CommandSendData(SAL_XSPI_ObjectTypeDef *SalXspi, uint8_t Command,
+                                           uint8_t *Data, uint16_t DataSize);
+HAL_StatusTypeDef SAL_XSPI_SendReadCommand(SAL_XSPI_ObjectTypeDef *SalXspi, uint8_t Command,
+                                           uint8_t *Data, uint16_t DataSize);
+HAL_StatusTypeDef SAL_XSPI_CommandSendReadAddress(SAL_XSPI_ObjectTypeDef *SalXspi, uint8_t Command,
+                                                  uint32_t Address, uint8_t *Data, uint16_t DataSize,
+                                                  uint8_t ManuId);
+HAL_StatusTypeDef SAL_XSPI_CheckStatusRegister(SAL_XSPI_ObjectTypeDef *SalXspi,
+                                               uint8_t Command, uint32_t Address, uint8_t MatchValue, uint8_t MatchMask,
+                                               uint8_t ManuId, uint32_t Timeout);
+HAL_StatusTypeDef SAL_XSPI_ConfigureWrappMode(SAL_XSPI_ObjectTypeDef *SalXspi, uint8_t WrapCommand, uint8_t WrapDummy);
+HAL_StatusTypeDef SAL_XSPI_EnableMapMode(SAL_XSPI_ObjectTypeDef *SalXspi, uint8_t CommandRead, uint8_t DummyRead,
+                                         uint8_t CommandWrite, uint8_t DummyWrite);
+HAL_StatusTypeDef SAL_XSPI_DisableMapMode(SAL_XSPI_ObjectTypeDef *SalXspi);
+HAL_StatusTypeDef SAL_XSPI_UpdateMemoryType(SAL_XSPI_ObjectTypeDef *SalXspi, SAL_XSPI_DataOrderTypeDef DataOrder);
+
+/**
+  * @brief This function aborts the transaction
+  * @param SalXspi SAL XSPI handle
+  * @return @ref HAL_StatusTypeDef
+  **/
+HAL_StatusTypeDef SAL_XSPI_Abort(SAL_XSPI_ObjectTypeDef *SalXspi);
+
+/**
+  * @}
+  */
+
+/**
+  * @}
+  */
+
+/**
+  * @}
+  */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __STM32_SAL_XSPI_API_H */
+
Index: trunk/firmware/FSBL/CubeMX/Middlewares/ST/STM32_ExtMem_Manager/sal/stm32_sal_xspi_type.h
===================================================================
--- trunk/firmware/FSBL/CubeMX/Middlewares/ST/STM32_ExtMem_Manager/sal/stm32_sal_xspi_type.h	(revision 20)
+++ trunk/firmware/FSBL/CubeMX/Middlewares/ST/STM32_ExtMem_Manager/sal/stm32_sal_xspi_type.h	(revision 20)
@@ -0,0 +1,137 @@
+/**
+  ******************************************************************************
+  * @file    stm32_sal_xspi_type.h
+  * @author  MCD Application Team
+  * @brief   This file contains SAL XSPI type definitions.
+  ******************************************************************************
+  * @attention
+  *
+  * Copyright (c) 2022 STMicroelectronics.
+  * All rights reserved.
+  *
+  * This software is licensed under terms that can be found in the LICENSE file
+  * in the root directory of this software component.
+  * If no LICENSE file comes with this software, it is provided AS-IS.
+  *
+  ******************************************************************************
+  */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __STM32_SAL_XSPI_TYPE_H
+#define __STM32_SAL_XSPI_TYPE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** @addtogroup SAL_XSPI
+  * @ingroup EXTMEM_SAL
+  * @{
+  */
+
+/* Includes ------------------------------------------------------------------*/
+/* Exported constants --------------------------------------------------------*/
+/* Exported types ------------------------------------------------------------*/
+
+
+/** @defgroup SAL_XSPI_Exported_types SAL XSPI exported types
+  * @{
+  */
+
+/**
+  * @brief Data order information.
+  */
+
+typedef enum
+{
+  SAL_XSPI_ORDERINVERTED = 0,
+} SAL_XSPI_DataOrderTypeDef;
+
+/**
+  * @brief Enumeration of supported physical link configurations.
+  */
+
+typedef enum
+{
+  PHY_LINK_1S1S1S,    /*!< Physical link configure in 1S1S1S */
+  PHY_LINK_1S1S2S,    /*!< Physical link configure in 1S1S2S */
+  PHY_LINK_1S2S2S,    /*!< Physical link configure in 1S2S2S */
+  PHY_LINK_1S1D1D,    /*!< Physical link configure in 1S1D1D */
+  PHY_LINK_1S1S4S,    /*!< Physical link configure in 1S1S4S */
+  PHY_LINK_1S4S4S,    /*!< Physical link configure in 1S4S4S */
+  PHY_LINK_4S4S4S,    /*!< Physical link configure in 4S4S4S */
+  PHY_LINK_4S4D4D,    /*!< Physical link configure in 4S4D4D */
+  PHY_LINK_4D4D4D,    /*!< Physical link configure in 4D4D4D */
+  PHY_LINK_1S8S8S,    /*!< Physical link configure in 1S8S8S */
+  PHY_LINK_8S8D8D,    /*!< Physical link configure in 8S8D8D */
+  PHY_LINK_8D8D8D,    /*!< Physical link configure in 8D8D8D */
+
+  PHY_LINK_RAM8,      /*!< Physical link configure for RAM  8lines of data */
+#if defined(HAL_XSPI_DATA_16_LINES)
+  PHY_LINK_RAM16,     /*!< Physical link configure for RAM 16lines of data */
+#endif /* defined(HAL_XSPI_DATA_16_LINES) */
+} SAL_XSPI_PhysicalLinkTypeDef;
+
+typedef struct
+{
+  XSPI_HandleTypeDef           *hxspi;            /*!< Handle on the XSPI instance */
+  XSPI_RegularCmdTypeDef       Commandbase;       /*!< Command base configuration */
+  uint8_t                      CommandExtension;  /*!< Flag on the 16-bit command extension 0 inverted 1 the same */
+  uint8_t                      SFDPDummyCycle;    /*!< SDPF dummy cycle */
+  SAL_XSPI_PhysicalLinkTypeDef PhyLink;           /*!< Only used for data Read in 4S4D4d 2S2D2D 1S1D1D */
+  uint8_t                      DTRDummyCycle;     /*!< Specify that DTR read only valid for data read using DTRDummyCycle value */
+#if defined(EXTMEM_DRIVER_NOR_SFDP_DUAL_CONFIG)
+  uint8_t                      ManufacturerId;    /*!< JEDEC manufacturer ID associated with the current memory */
+  uint8_t                      ReadWipCommand;    /*!< Busy-polling read command used to apply command-specific quirks */
+  uint8_t                      ReadWelCommand;    /*!< Write-enable polling read command used to apply command-specific quirks */
+#endif /* EXTMEM_DRIVER_NOR_SFDP_DUAL_CONFIG */
+} SAL_XSPI_ObjectTypeDef;
+
+/**
+  * @brief define the list of the parameter
+  */
+typedef enum
+{
+  PARAM_PHY_LINK,                /*!< Physical link parameter */
+  PARAM_DUMMY_CYCLES,            /*!< Dummy cycle parameter */
+  PARAM_ADDRESS_4BYTES,          /*!< Address size parameter */
+  PARAM_DATA_STROBE,             /*!< Data strobe parameter */
+  PARAM_FLASHSIZE,               /*!< Flash size parameter */
+} SAL_XSPI_MemParamTypeTypeDef;
+/**
+  * @}
+  */
+
+/* Exported Macro ------------------------------------------------------------*/
+
+#define SAL_XSPI_SET_DTRREADDUMMYCYLE(_OBJ_,_VAL_) (_OBJ_).DTRDummyCycle = (_VAL_)
+#define SAL_XSPI_SET_SFDPDUMMYCYLE(_OBJ_,_VAL_)    (_OBJ_).SFDPDummyCycle = (_VAL_)
+#define SAL_XSPI_SET_COMMANDEXTENSION(_OBJ_,_VAL_) (_OBJ_).CommandExtension = (_VAL_)
+
+#define SAL_XSPI_FORMAT_COMMANDSEND(_PTR_, _CMD_)                      \
+  _PTR_.CommandType = SAL_XSPI_COMMAND_SEND;   \
+  _PTR_.Command = _CMD_;
+
+/* Exported functions --------------------------------------------------------*/
+/** @defgroup SAL_XSPI_Exported_Functions SAL XSP Exported Functions
+  * @{
+  */
+
+/**
+  * @}
+  */
+
+/**
+  * @}
+  */
+
+/**
+  * @}
+  */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __STM32_SAL_XSPI_TYPE_H */
+
Index: trunk/firmware/FSBL/CubeMX/Middlewares/ST/STM32_ExtMem_Manager/stm32_extmem.c
===================================================================
--- trunk/firmware/FSBL/CubeMX/Middlewares/ST/STM32_ExtMem_Manager/stm32_extmem.c	(revision 20)
+++ trunk/firmware/FSBL/CubeMX/Middlewares/ST/STM32_ExtMem_Manager/stm32_extmem.c	(revision 20)
@@ -0,0 +1,1196 @@
+/**
+  ******************************************************************************
+  * @file    stm32_extmem.c
+  * @author  MCD Application Team
+  * @brief   This file includes a driver for external memory support
+  ******************************************************************************
+  * @attention
+  *
+  * Copyright (c) 2022 STMicroelectronics.
+  * All rights reserved.
+  *
+  * This software is licensed under terms that can be found in the LICENSE file
+  * in the root directory of this software component.
+  * If no LICENSE file comes with this software, it is provided AS-IS.
+  *
+  ******************************************************************************
+  */
+/**
+  * @brief Macro to get memory table definition
+  */
+#define EXTMEM_C
+
+/* Includes ------------------------------------------------------------------*/
+#include "stm32_extmem.h"
+#include "stm32_extmem_conf.h"
+
+#if EXTMEM_DRIVER_NOR_SFDP == 1
+#include "nor_sfdp/stm32_sfdp_driver_api.h"
+#endif /* EXTMEM_DRIVER_NOR_SFDP */
+
+#if EXTMEM_DRIVER_PSRAM == 1
+#include "psram/stm32_psram_driver_api.h"
+#endif /* EXTMEM_DRIVER_PSRAM */
+
+#if EXTMEM_DRIVER_SDCARD == 1
+#include "sdcard/stm32_sdcard_driver_api.h"
+#endif /* EXTMEM_DRIVER_SDCARD */
+
+#if EXTMEM_DRIVER_CUSTOM == 1
+#include "custom/stm32_custom_driver_api.h"
+#endif /* EXTMEM_DRIVER_CUSTOM */
+
+#if EXTMEM_DRIVER_USER == 1
+#include "user/stm32_user_driver_api.h"
+#endif /* EXTMEM_DRIVER_USER */
+
+/**
+  * @defgroup EXTMEM_DRIVER
+  * @{
+  */
+
+/**
+  * @}
+ */
+
+/**
+  * @defgroup EXTMEM_SAL
+  * @{
+  */
+
+/**
+  * @}
+ */
+
+/**
+  * @defgroup EXTMEM
+  * @{
+  */
+
+/* Private Macros ------------------------------------------------------------*/
+/**
+  *  @defgroup EXTMEM_Private_Macros External Memory Private Macros
+  * @{
+  */
+/**
+  * @brief EXTMEM debug function
+  */
+/**
+  * @brief Macro used to trace EXTMEM function calls
+  */
+
+#if defined(EXTMEM_DEBUG_LEVEL) && defined(EXTMEM_MACRO_DEBUG)
+#if EXTMEM_DEBUG_LEVEL > 0
+#define EXTMEM_DEBUG(_MSG_)  EXTMEM_MACRO_DEBUG(_MSG_)
+#if EXTMEM_DEBUG_LEVEL > 1
+#define EXTMEM_FUNC_CALL()  \
+  do                        \
+  {                         \
+    EXTMEM_DEBUG(__func__); \
+    EXTMEM_DEBUG("\n");     \
+  } while (0);
+#else
+#define EXTMEM_FUNC_CALL()
+#endif /* EXTMEM_DEBUG_LEVEL > 1 */
+#else
+#define EXTMEM_DEBUG(_MSG_)
+#define EXTMEM_FUNC_CALL()
+#endif /* EXTMEM_DEBUG_LEVEL > 0 */
+#else
+#define EXTMEM_DEBUG(_MSG_)
+#define EXTMEM_FUNC_CALL()
+#endif /* defined(EXTMEM_DEBUG_LEVEL) && defined(EXTMEM_MACRO_DEBUG) */
+
+/**
+  * @brief Macro used to trace EXTMEM debug information
+  */
+#define EXTMEM_DEBUG_ENDL(_STRING_) \
+  do                                \
+  {                                 \
+    EXTMEM_DEBUG(_STRING_);         \
+    EXTMEM_DEBUG("\n");             \
+  } while (0);
+
+/**
+  * @}
+  */
+
+/* Private typedefs ---------------------------------------------------------*/
+/* Private functions ---------------------------------------------------------*/
+/* Exported variables ---------------------------------------------------------*/
+
+
+/** @defgroup EXTMEM_Exported_Functions External Memory Exported Functions
+  * @{
+  */
+
+/**
+  * @brief Initializes the external memory.
+  * @param MemId Memory identifier.
+  * @param ClockInput Clock input value for the memory.
+  * @retval EXTMEM_StatusTypeDef Status of the operation.
+  */
+EXTMEM_StatusTypeDef EXTMEM_Init(uint32_t MemId, uint32_t ClockInput)
+{
+  EXTMEM_StatusTypeDef retr = EXTMEM_ERROR_INVALID_ID;
+  EXTMEM_FUNC_CALL();
+
+  /* Check the memory ID */
+  if (MemId < (sizeof(extmem_list_config) / sizeof(EXTMEM_DefinitionTypeDef)))
+  {
+    retr = EXTMEM_OK;
+
+    /* Check type of EXTMEM driver used to access memory */
+    switch (extmem_list_config[MemId].MemType)
+    {
+#if EXTMEM_DRIVER_NOR_SFDP == 1
+      case EXTMEM_NOR_SFDP:
+      {
+        /* Initialize the memory using NOR SFDP driver */
+        if (EXTMEM_DRIVER_NOR_SFDP_OK != EXTMEM_DRIVER_NOR_SFDP_Init(extmem_list_config[MemId].Handle,
+                                                                     extmem_list_config[MemId].ConfigType,
+                                                                     ClockInput,
+                                                                     &extmem_list_config[MemId].NorSfdpObject))
+        {
+          retr = EXTMEM_ERROR_DRIVER;
+        }
+        break;
+      }
+#endif /* EXTMEM_DRIVER_NOR_SFDP == 1 */
+#if EXTMEM_DRIVER_SDCARD == 1
+      case EXTMEM_SDCARD:
+      {
+        /* Initialize the memory using SDCARD driver */
+        if (EXTMEM_DRIVER_SDCARD_OK != EXTMEM_DRIVER_SDCARD_Init(extmem_list_config[MemId].Handle,
+                                                                 &extmem_list_config[MemId].SdCardObject))
+        {
+          retr = EXTMEM_ERROR_DRIVER;
+        }
+        break;
+      }
+#endif /* EXTMEM_DRIVER_SDCARD == 1 */
+#if EXTMEM_DRIVER_PSRAM == 1
+      case EXTMEM_PSRAM :
+      {
+        /* Initialize the memory using PSRAM driver */
+        if (EXTMEM_DRIVER_PSRAM_OK != EXTMEM_DRIVER_PSRAM_Init(extmem_list_config[MemId].Handle,
+                                                               extmem_list_config[MemId].ConfigType,
+                                                               ClockInput,
+                                                               &extmem_list_config[MemId].PsramObject))
+        {
+          retr = EXTMEM_ERROR_DRIVER;
+        }
+        break;
+      }
+#endif /* EXTMEM_DRIVER_PSRAM == 1 */
+#if EXTMEM_DRIVER_CUSTOM == 1
+      case EXTMEM_CUSTOM :
+      {
+        /* Initialize the memory using CUSTOM driver */
+        if (EXTMEM_DRV_CUSTOM_OK != EXTMEM_DRIVER_CUSTOM_Init(extmem_list_config[MemId].Handle,
+                                                              ClockInput,
+                                                              &extmem_list_config[MemId].CustomObject))
+        {
+          retr = EXTMEM_ERROR_DRIVER;
+        }
+        break;
+      }
+#endif /* EXTMEM_DRIVER_CUSTOM == 1 */
+#if EXTMEM_DRIVER_USER == 1
+      case EXTMEM_USER :
+      {
+        /* Initialize the memory using USER driver */
+        EXTMEM_DRIVER_USER_StatusTypeDef status;
+        status = EXTMEM_DRIVER_USER_Init(MemId,
+                                         &extmem_list_config[MemId].UserObject);
+        switch (status)
+        {
+          case EXTMEM_DRIVER_USER_NOTSUPPORTED:
+          {
+            retr = EXTMEM_ERROR_NOTSUPPORTED;
+            break;
+          }
+          case EXTMEM_DRIVER_USER_OK:
+          {
+            /* Nothing to do */
+            retr = EXTMEM_OK;
+            break;
+          }
+          default:
+          {
+            retr = EXTMEM_ERROR_DRIVER;
+            break;
+          }
+        }
+        break;
+      }
+#endif /* EXTMEM_DRIVER_USER == 1 */
+      /* Unknown type of EXTMEM driver */
+      default:
+      {
+        EXTMEM_DEBUG("\terror : unknown memory type\n");
+        retr = EXTMEM_ERROR_UNKNOWNMEMORY;
+        break;
+      }
+    }
+  }
+  return retr;
+}
+
+/**
+  * @brief Deinitializes the external memory.
+  * @param MemId Memory identifier.
+  * @retval EXTMEM_StatusTypeDef Status of the operation.
+  */
+EXTMEM_StatusTypeDef EXTMEM_DeInit(uint32_t MemId)
+{
+  EXTMEM_StatusTypeDef retr = EXTMEM_ERROR_INVALID_ID;
+  EXTMEM_FUNC_CALL();
+
+  /* Check the memory ID */
+  if (MemId < (sizeof(extmem_list_config) / sizeof(EXTMEM_DefinitionTypeDef)))
+  {
+    retr = EXTMEM_OK;
+
+    /* Check type of EXTMEM driver used to access memory */
+    switch (extmem_list_config[MemId].MemType)
+    {
+#if EXTMEM_DRIVER_NOR_SFDP == 1
+      case EXTMEM_NOR_SFDP:
+      {
+        /* Uninitialize the memory using NOR SFDP driver */
+        /* Return is always OK no need to test the returned value */
+        (void)EXTMEM_DRIVER_NOR_SFDP_DeInit(&extmem_list_config[MemId].NorSfdpObject);
+        break;
+      }
+#endif /* EXTMEM_DRIVER_NOR_SFDP == 1 */
+#if EXTMEM_DRIVER_SDCARD == 1
+      case EXTMEM_SDCARD:
+      {
+        /* Uninitialize the memory using SDCARD driver */
+        if (EXTMEM_DRIVER_SDCARD_OK != EXTMEM_DRIVER_SDCARD_DeInit(&extmem_list_config[MemId].SdCardObject))
+        {
+          retr = EXTMEM_ERROR_DRIVER;
+        }
+        break;
+      }
+#endif /* EXTMEM_DRIVER_SDCARD == 1 */
+#if EXTMEM_DRIVER_PSRAM == 1
+      case EXTMEM_PSRAM :
+      {
+        /* Uninitialize the memory using PSRAM driver */
+        /* Return is always OK no need to test the returned value */
+        (void)EXTMEM_DRIVER_PSRAM_DeInit(&extmem_list_config[MemId].PsramObject);
+        break;
+      }
+#endif /* EXTMEM_DRIVER_PSRAM == 1 */
+#if EXTMEM_DRIVER_CUSTOM == 1
+      case EXTMEM_CUSTOM :
+      {
+        /* Uninitialize the memory using CUSTOM driver */
+        if (EXTMEM_DRV_CUSTOM_OK != EXTMEM_DRIVER_CUSTOM_DeInit(&extmem_list_config[MemId].CustomObject))
+        {
+          retr = EXTMEM_ERROR_DRIVER;
+        }
+        break;
+      }
+#endif /* EXTMEM_DRIVER_CUSTOM == 1 */
+#if EXTMEM_DRIVER_USER == 1
+      case EXTMEM_USER :
+      {
+        /* Uninitialize the memory using USER driver */
+        EXTMEM_DRIVER_USER_StatusTypeDef status = EXTMEM_DRIVER_USER_DeInit(&extmem_list_config[MemId].UserObject);
+        switch (status)
+        {
+          case EXTMEM_DRIVER_USER_NOTSUPPORTED:
+            retr = EXTMEM_ERROR_NOTSUPPORTED;
+            break;
+          case EXTMEM_DRIVER_USER_OK:
+            /* Nothing to do, the returned status is already set to EXTMEM_OK */
+            break;
+          default:
+            retr = EXTMEM_ERROR_DRIVER;
+            break;
+        }
+        break;
+      }
+#endif /* EXTMEM_DRIVER_USER == 1 */
+      /* Unknown type of EXTMEM driver */
+      default:
+      {
+        EXTMEM_DEBUG("\terror : unknown memory type\n");
+        retr = EXTMEM_ERROR_UNKNOWNMEMORY;
+        break;
+      }
+    }
+  }
+  return retr;
+}
+
+/**
+  * @brief Reads data from the external memory.
+  * @param MemId Memory identifier.
+  * @param Address Address in memory to read from.
+  * @param Data Pointer to buffer where read data will be stored.
+  * @param Size Number of bytes to read.
+  * @retval EXTMEM_StatusTypeDef Status of the operation.
+  */
+EXTMEM_StatusTypeDef EXTMEM_Read(uint32_t MemId, uint32_t Address, uint8_t *Data, uint32_t Size)
+{
+  EXTMEM_StatusTypeDef retr = EXTMEM_ERROR_INVALID_ID;
+  EXTMEM_FUNC_CALL()
+
+  /* Check the memory ID */
+  if (MemId < (sizeof(extmem_list_config) / sizeof(EXTMEM_DefinitionTypeDef)))
+  {
+    retr = EXTMEM_OK;
+
+    /* Check type of EXTMEM driver used to access memory */
+    switch (extmem_list_config[MemId].MemType)
+    {
+#if EXTMEM_DRIVER_NOR_SFDP == 1
+      case EXTMEM_NOR_SFDP:
+      {
+        /* Perform the Read operation using the NOR SFDP driver */
+        if (EXTMEM_DRIVER_NOR_SFDP_OK != EXTMEM_DRIVER_NOR_SFDP_Read(&extmem_list_config[MemId].NorSfdpObject,
+                                                                     Address, Data, Size))
+        {
+          retr = EXTMEM_ERROR_DRIVER;
+        }
+        break;
+      }
+#endif /* EXTMEM_DRIVER_NOR_SFDP == 1 */
+#if EXTMEM_DRIVER_SDCARD == 1
+      case EXTMEM_SDCARD:
+      {
+        /* Perform the Read operation using the SDCARD driver */
+        if (EXTMEM_DRIVER_SDCARD_OK != EXTMEM_DRIVER_SDCARD_Read(&extmem_list_config[MemId].SdCardObject,
+                                                                 Address, Data, Size))
+        {
+          retr = EXTMEM_ERROR_DRIVER;
+        }
+        break;
+      }
+#endif /* EXTMEM_DRIVER_SDCARD == 1 */
+#if EXTMEM_DRIVER_PSRAM == 1
+      case EXTMEM_PSRAM :
+      {
+        retr = EXTMEM_ERROR_NOTSUPPORTED;
+        break;
+      }
+#endif /* EXTMEM_DRIVER_PSRAM == 1 */
+#if EXTMEM_DRIVER_CUSTOM == 1
+      case EXTMEM_CUSTOM :
+      {
+        /* Perform the Read operation using the CUSTOM driver */
+        if (EXTMEM_DRV_CUSTOM_OK != EXTMEM_DRIVER_CUSTOM_Read(&extmem_list_config[MemId].CustomObject,
+                                                              Address, Data, Size))
+        {
+          retr = EXTMEM_ERROR_DRIVER;
+        }
+        break;
+      }
+#endif /* EXTMEM_DRIVER_CUSTOM == 1 */
+#if EXTMEM_DRIVER_USER == 1
+      case EXTMEM_USER :
+      {
+        /* Perform the Read operation using the USER driver */
+        EXTMEM_DRIVER_USER_StatusTypeDef status = EXTMEM_DRIVER_USER_Read(&extmem_list_config[MemId].UserObject,
+                                                                          Address, Data, Size);
+        switch (status)
+        {
+          case EXTMEM_DRIVER_USER_NOTSUPPORTED:
+            retr = EXTMEM_ERROR_NOTSUPPORTED;
+            break;
+          case EXTMEM_DRIVER_USER_OK:
+            /* Nothing to do, the returned status is already set to EXTMEM_OK */
+            break;
+          default:
+            retr = EXTMEM_ERROR_DRIVER;
+            break;
+        }
+        break;
+      }
+#endif /* EXTMEM_DRIVER_USER == 1 */
+      /* Unknown type of EXTMEM driver */
+      default:
+      {
+        EXTMEM_DEBUG("\terror : unknown memory type\n");
+        retr = EXTMEM_ERROR_UNKNOWNMEMORY;
+        break;
+      }
+    }
+  }
+  return retr;
+}
+
+/**
+  * @brief Writes data to the external memory.
+  * @param MemId Memory identifier.
+  * @param Address Address in memory to write to.
+  * @param Data Pointer to buffer containing data to be written.
+  * @param Size Number of bytes to write.
+  * @retval EXTMEM_StatusTypeDef Status of the operation.
+  */
+EXTMEM_StatusTypeDef EXTMEM_Write(uint32_t MemId, uint32_t Address, const uint8_t *Data, uint32_t Size)
+{
+  EXTMEM_StatusTypeDef retr = EXTMEM_ERROR_INVALID_ID;
+  EXTMEM_FUNC_CALL()
+
+  /* Check the memory ID */
+  if (MemId < (sizeof(extmem_list_config) / sizeof(EXTMEM_DefinitionTypeDef)))
+  {
+    retr = EXTMEM_OK;
+
+    /* Check type of EXTMEM driver used to access memory */
+    switch (extmem_list_config[MemId].MemType)
+    {
+#if EXTMEM_DRIVER_NOR_SFDP == 1
+      case EXTMEM_NOR_SFDP:
+      {
+        /* Perform the Write operation using the NOR SFDP driver */
+        if (EXTMEM_DRIVER_NOR_SFDP_OK != EXTMEM_DRIVER_NOR_SFDP_Write(&extmem_list_config[MemId].NorSfdpObject,
+                                                                      Address, Data, Size))
+        {
+          retr = EXTMEM_ERROR_DRIVER;
+        }
+        break;
+      }
+#endif /* EXTMEM_DRIVER_NOR_SFDP == 1 */
+#if EXTMEM_DRIVER_SDCARD == 1
+      case EXTMEM_SDCARD:
+      {
+        /* Perform the Write operation using the SDCARD driver */
+        if (EXTMEM_DRIVER_SDCARD_OK != EXTMEM_DRIVER_SDCARD_Write(&extmem_list_config[MemId].SdCardObject,
+                                                                  Address, Data, Size))
+        {
+          retr = EXTMEM_ERROR_DRIVER;
+        }
+        break;
+      }
+#endif /* EXTMEM_DRIVER_SDCARD == 1 */
+#if EXTMEM_DRIVER_PSRAM == 1
+      case EXTMEM_PSRAM :
+      {
+        retr = EXTMEM_ERROR_NOTSUPPORTED;
+        break;
+      }
+#endif /* EXTMEM_DRIVER_PSRAM == 1 */
+#if EXTMEM_DRIVER_CUSTOM == 1
+      case EXTMEM_CUSTOM :
+      {
+        /* Perform the Write operation using the CUSTOM driver */
+        if (EXTMEM_DRV_CUSTOM_OK != EXTMEM_DRIVER_CUSTOM_Write(&extmem_list_config[MemId].CustomObject,
+                                                               Address, Data, Size))
+        {
+          retr = EXTMEM_ERROR_DRIVER;
+        }
+        break;
+      }
+#endif /* EXTMEM_DRIVER_CUSTOM == 1 */
+#if EXTMEM_DRIVER_USER == 1
+      case EXTMEM_USER :
+      {
+        /* Perform the Write operation using the USER driver */
+        EXTMEM_DRIVER_USER_StatusTypeDef status = EXTMEM_DRIVER_USER_Write(&extmem_list_config[MemId].UserObject,
+                                                                           Address, Data, Size);
+        switch (status)
+        {
+          case EXTMEM_DRIVER_USER_NOTSUPPORTED:
+            retr = EXTMEM_ERROR_NOTSUPPORTED;
+            break;
+          case EXTMEM_DRIVER_USER_OK:
+            break;
+          default:
+            retr = EXTMEM_ERROR_DRIVER;
+            break;
+        }
+        break;
+      }
+#endif /* EXTMEM_DRIVER_USER == 1 */
+      /* Unknown type of EXTMEM driver */
+      default:
+      {
+        EXTMEM_DEBUG("\terror : unknown memory type\n");
+        retr = EXTMEM_ERROR_UNKNOWNMEMORY;
+        break;
+      }
+    }
+  }
+  return retr;
+}
+
+/**
+  * @brief Writes data to the external memory in mapped mode.
+  * @param MemId Memory identifier.
+  * @param Address Address in memory to write to.
+  * @param Data Pointer to buffer (must be 32-bit aligned) containing data to be written.
+  * @param Size Number of bytes to write.
+  * @retval EXTMEM_StatusTypeDef Status of the operation.
+  *
+  * @note This function performs write operations in mapped mode and requires specific processing due
+  *       to write enable management when the memory is mapped. The operation splits the write into packets
+  *       of page size, and for each packet, performs a write before entering mapped mode.
+  *
+  * @note To avoid issues during this process, it is mandatory that the targeted memory area has the following
+  *       characteristics: the write region must be non-bufferable, non-shareable, and non-cacheable.
+  */
+EXTMEM_StatusTypeDef EXTMEM_WriteInMappedMode(uint32_t MemId, uint32_t Address, const uint8_t *const Data,
+                                              uint32_t Size)
+{
+  EXTMEM_StatusTypeDef retr = EXTMEM_ERROR_INVALID_ID;
+  EXTMEM_FUNC_CALL()
+
+  /* Check the memory ID */
+  if (MemId < (sizeof(extmem_list_config) / sizeof(EXTMEM_DefinitionTypeDef)))
+  {
+    retr = EXTMEM_OK;
+
+    /* Check type of EXTMEM driver used to access memory */
+    switch (extmem_list_config[MemId].MemType)
+    {
+#if EXTMEM_DRIVER_NOR_SFDP == 1
+      /* Perform the Write in mapped mode operation using the NOR SFDP driver */
+      case EXTMEM_NOR_SFDP:
+      {
+        if (EXTMEM_DRIVER_NOR_SFDP_OK !=
+            EXTMEM_DRIVER_NOR_SFDP_WriteInMappedMode(&extmem_list_config[MemId].NorSfdpObject,
+                                                     Address, Data, Size))
+        {
+          retr = EXTMEM_ERROR_DRIVER;
+        }
+        break;
+      }
+#endif /* EXTMEM_DRIVER_NOR_SFDP == 1 */
+#if EXTMEM_DRIVER_SDCARD == 1
+      case EXTMEM_SDCARD :
+        /* Functionality not supported in this driver */
+        retr = EXTMEM_ERROR_NOTSUPPORTED;
+        break;
+#endif /* EXTMEM_DRIVER_SDCARD == 1 */
+#if EXTMEM_DRIVER_PSRAM == 1
+      case EXTMEM_PSRAM :
+        /* Functionality not supported in this driver */
+        retr = EXTMEM_ERROR_NOTSUPPORTED;
+        break;
+#endif /* EXTMEM_DRIVER_PSRAM == 1 */
+#if EXTMEM_DRIVER_CUSTOM == 1
+      /* Perform the Write in mapped mode operation using the CUSTOM driver */
+      case EXTMEM_CUSTOM :
+      {
+        if (EXTMEM_DRV_CUSTOM_OK !=
+            EXTMEM_DRIVER_CUSTOM_WriteInMappedMode(&extmem_list_config[MemId].CustomObject,
+                                                   Address, Data, Size))
+        {
+          retr = EXTMEM_ERROR_DRIVER;
+        }
+        break;
+      }
+#endif /* EXTMEM_DRIVER_CUSTOM == 1 */
+#if EXTMEM_DRIVER_USER == 1
+      case EXTMEM_USER :
+        /* Functionality not supported in this driver */
+        retr = EXTMEM_ERROR_NOTSUPPORTED;
+        break;
+#endif /* EXTMEM_DRIVER_USER == 1 */
+      /* Unknown type of EXTMEM driver */
+      default:
+      {
+        EXTMEM_DEBUG("\terror : unknown memory type\n");
+        retr = EXTMEM_ERROR_UNKNOWNMEMORY;
+        break;
+      }
+    }
+  }
+  return retr;
+}
+
+/**
+  * @brief Erases a number of sectors in the external memory.
+  * @param MemId Memory identifier.
+  * @param Address Address in memory to start erase operation.
+  * @param Size Number of bytes to erase.
+  * @retval EXTMEM_StatusTypeDef Status of the operation.
+  */
+EXTMEM_StatusTypeDef EXTMEM_EraseSector(uint32_t MemId, uint32_t Address, uint32_t Size)
+{
+  EXTMEM_StatusTypeDef retr = EXTMEM_ERROR_INVALID_ID;
+  EXTMEM_FUNC_CALL()
+
+  /* Check the memory ID */
+  if (MemId < (sizeof(extmem_list_config) / sizeof(EXTMEM_DefinitionTypeDef)))
+  {
+    retr = EXTMEM_OK;
+
+    /* Check type of EXTMEM driver used to access memory */
+    switch (extmem_list_config[MemId].MemType)
+    {
+#if EXTMEM_DRIVER_NOR_SFDP == 1
+      case EXTMEM_NOR_SFDP:
+      {
+        /* Perform the Sector Erase operation using the NOR SFDP driver */
+        const EXTMEM_DRIVER_NOR_SFDP_ObjectTypeDef *const object = &extmem_list_config[MemId].NorSfdpObject;
+        EXTMEM_DRIVER_NOR_SFDP_SectorTypeTypeDef sector_type = EXTMEM_DRIVER_NOR_SFDP_SECTOR_TYPE1;
+        uint32_t local_address = Address;
+        uint32_t local_size = Size;
+        uint32_t sector_size = (uint32_t)1u << object->sfdp_private.DriverInfo.EraseType4Size;
+
+        while (local_size != 0u)
+        {
+          /* if address is a modulo a sector size if sector  */
+          if ((object->sfdp_private.DriverInfo.EraseType4Size != 0u)
+              && (local_size >= sector_size)
+              && ((local_address % sector_size) == 0u))
+          {
+            sector_type = EXTMEM_DRIVER_NOR_SFDP_SECTOR_TYPE4;
+          }
+          else
+          {
+            sector_size = (uint32_t)1u << object->sfdp_private.DriverInfo.EraseType3Size;
+            if ((object->sfdp_private.DriverInfo.EraseType3Size != 0u)
+                && (local_size >= sector_size)
+                && ((local_address % sector_size) == 0u))
+            {
+              sector_type = EXTMEM_DRIVER_NOR_SFDP_SECTOR_TYPE3;
+            }
+            else
+            {
+              sector_size = (uint32_t)1u << object->sfdp_private.DriverInfo.EraseType2Size;
+              if ((object->sfdp_private.DriverInfo.EraseType2Size != 0u)
+                  && (local_size >= sector_size)
+                  && ((local_address % sector_size) == 0u))
+              {
+                sector_type = EXTMEM_DRIVER_NOR_SFDP_SECTOR_TYPE2;
+              }
+              else
+              {
+                sector_size = (uint32_t)1u << object->sfdp_private.DriverInfo.EraseType1Size;
+                if ((object->sfdp_private.DriverInfo.EraseType1Size != 0u)
+                    && ((local_address % sector_size) == 0u))
+                {
+                  sector_type = EXTMEM_DRIVER_NOR_SFDP_SECTOR_TYPE1;
+                }
+                else
+                {
+                  retr = EXTMEM_ERROR_SECTOR_SIZE;
+                }
+              }
+            }
+          }
+
+          if (retr == EXTMEM_OK)
+          {
+            if (EXTMEM_DRIVER_NOR_SFDP_OK !=
+                EXTMEM_DRIVER_NOR_SFDP_SectorErase(&extmem_list_config[MemId].NorSfdpObject,
+                                                   local_address, sector_type))
+            {
+              retr = EXTMEM_ERROR_DRIVER;
+            }
+          }
+
+          if (retr != EXTMEM_OK)
+          {
+            local_size = 0u;
+          }
+          else
+          {
+            local_address = local_address + sector_size;
+            if (sector_size > local_size)
+            {
+              local_size = 0u;
+            }
+            else
+            {
+              local_size = local_size - sector_size;
+            }
+          }
+        }
+        break;
+      }
+#endif /* EXTMEM_DRIVER_NOR_SFDP == 1 */
+#if EXTMEM_DRIVER_SDCARD == 1
+      case EXTMEM_SDCARD:
+      {
+        /* Perform the Sector Erase operation using the SDCARD driver */
+        if (EXTMEM_DRIVER_SDCARD_OK != EXTMEM_DRIVER_SDCARD_EraseBlock(&extmem_list_config[MemId].SdCardObject,
+                                                                       Address, Size))
+        {
+          retr = EXTMEM_ERROR_DRIVER;
+        }
+        break;
+      }
+#endif /* EXTMEM_DRIVER_SDCARD == 1 */
+#if EXTMEM_DRIVER_PSRAM == 1
+      case EXTMEM_PSRAM :
+      {
+        /* Functionality not supported in this driver */
+        retr = EXTMEM_ERROR_NOTSUPPORTED;
+        break;
+      }
+#endif /* EXTMEM_DRIVER_PSRAM == 1 */
+#if EXTMEM_DRIVER_CUSTOM == 1
+      case EXTMEM_CUSTOM :
+      {
+        /* Perform the Sector Erase operation using the CUSTOM driver */
+        if (EXTMEM_DRV_CUSTOM_OK != EXTMEM_DRIVER_CUSTOM_EraseSector(&extmem_list_config[MemId].CustomObject,
+                                                                     Address, Size))
+        {
+          retr = EXTMEM_ERROR_DRIVER;
+        }
+        break;
+      }
+#endif /* EXTMEM_DRIVER_CUSTOM == 1 */
+#if EXTMEM_DRIVER_USER == 1
+      case EXTMEM_USER :
+      {
+        /* Perform the Sector Erase operation using the USER driver */
+        EXTMEM_DRIVER_USER_StatusTypeDef status = EXTMEM_DRIVER_USER_EraseSector(&extmem_list_config[MemId].UserObject,
+                                                                                 Address, Size);
+        switch (status)
+        {
+          case EXTMEM_DRIVER_USER_NOTSUPPORTED:
+            retr = EXTMEM_ERROR_NOTSUPPORTED;
+            break;
+          case EXTMEM_DRIVER_USER_OK:
+            break;
+          default:
+            retr = EXTMEM_ERROR_DRIVER;
+            break;
+        }
+        break;
+      }
+#endif /* EXTMEM_DRIVER_USER == 1 */
+      /* Unknown type of EXTMEM driver */
+      default:
+      {
+        EXTMEM_DEBUG("\terror : unknown memory type\n");
+        retr = EXTMEM_ERROR_UNKNOWNMEMORY;
+        break;
+      }
+    }
+  }
+  return retr;
+}
+
+/**
+  * @brief Erases all sectors in the external memory.
+  * @param MemId Memory identifier.
+  * @retval EXTMEM_StatusTypeDef Status of the operation.
+  */
+EXTMEM_StatusTypeDef EXTMEM_EraseAll(uint32_t MemId)
+{
+  EXTMEM_StatusTypeDef retr = EXTMEM_ERROR_INVALID_ID;
+  EXTMEM_FUNC_CALL()
+
+  /* Check the memory ID */
+  if (MemId < (sizeof(extmem_list_config) / sizeof(EXTMEM_DefinitionTypeDef)))
+  {
+    retr = EXTMEM_OK;
+
+    /* Check type of EXTMEM driver used to access memory */
+    switch (extmem_list_config[MemId].MemType)
+    {
+#if EXTMEM_DRIVER_NOR_SFDP == 1
+      case EXTMEM_NOR_SFDP:
+      {
+        /* Perform the Mass Erase operation using the NOR SFDP driver */
+        if (EXTMEM_DRIVER_NOR_SFDP_OK != EXTMEM_DRIVER_NOR_SFDP_MassErase(&extmem_list_config[MemId].NorSfdpObject))
+        {
+          retr = EXTMEM_ERROR_DRIVER;
+        }
+        break;
+      }
+#endif /* EXTMEM_DRIVER_NOR_SFDP == 1 */
+#if EXTMEM_DRIVER_SDCARD == 1
+      case EXTMEM_SDCARD:
+      {
+        /* Perform the Mass Erase operation using the SD CARD driver */
+        if (EXTMEM_DRIVER_SDCARD_OK != EXTMEM_DRIVER_SDCARD_Erase(&extmem_list_config[MemId].SdCardObject))
+        {
+          retr = EXTMEM_ERROR_DRIVER;
+        }
+        break;
+      }
+#endif /* EXTMEM_DRIVER_SDCARD == 1 */
+#if EXTMEM_DRIVER_PSRAM == 1
+      case EXTMEM_PSRAM:
+      {
+        retr = EXTMEM_ERROR_NOTSUPPORTED;
+        break;
+      }
+#endif /* EXTMEM_DRIVER_PSRAM == 1 */
+#if EXTMEM_DRIVER_CUSTOM == 1
+      case EXTMEM_CUSTOM :
+      {
+        /* Perform the Mass Erase operation using the CUSTOM driver */
+        if (EXTMEM_DRV_CUSTOM_OK != EXTMEM_DRIVER_CUSTOM_MassErase(&extmem_list_config[MemId].CustomObject))
+        {
+          retr = EXTMEM_ERROR_DRIVER;
+        }
+        break;
+      }
+#endif /* EXTMEM_DRIVER_CUSTOM == 1 */
+#if EXTMEM_DRIVER_USER == 1
+      case EXTMEM_USER :
+      {
+        /* Perform the Mass Erase operation using the USER driver */
+        EXTMEM_DRIVER_USER_StatusTypeDef status = EXTMEM_DRIVER_USER_MassErase(&extmem_list_config[MemId].UserObject);
+        switch (status)
+        {
+          case EXTMEM_DRIVER_USER_NOTSUPPORTED:
+            retr = EXTMEM_ERROR_NOTSUPPORTED;
+            break;
+          case EXTMEM_DRIVER_USER_OK:
+            break;
+          default:
+            retr = EXTMEM_ERROR_DRIVER;
+            break;
+        }
+        break;
+      }
+#endif /* EXTMEM_DRIVER_USER == 1 */
+      /* Unknown type of EXTMEM driver */
+      default:
+      {
+        EXTMEM_DEBUG("\terror : unknown memory type\n");
+        retr = EXTMEM_ERROR_UNKNOWNMEMORY;
+        break;
+      }
+    }
+  }
+  return retr;
+}
+
+/**
+  * @brief Returns information about the external memory.
+  * @param MemId Memory identifier.
+  * @param Info Pointer to structure to receive memory information.
+  * @retval EXTMEM_StatusTypeDef Status of the operation.
+  */
+EXTMEM_StatusTypeDef EXTMEM_GetInfo(uint32_t MemId, void *Info)
+{
+  EXTMEM_StatusTypeDef retr = EXTMEM_ERROR_INVALID_ID;
+  EXTMEM_FUNC_CALL()
+
+  /* Check the memory ID */
+  if (MemId < (sizeof(extmem_list_config) / sizeof(EXTMEM_DefinitionTypeDef)))
+  {
+    retr = EXTMEM_OK;
+
+    /* Check type of EXTMEM driver used to access memory */
+    switch (extmem_list_config[MemId].MemType)
+    {
+#if EXTMEM_DRIVER_NOR_SFDP == 1
+      case EXTMEM_NOR_SFDP:
+      {
+        /* Perform the Get Information operation using the NOR SFDP driver */
+        EXTMEM_DRIVER_NOR_SFDP_GetFlashInfo(&extmem_list_config[MemId].NorSfdpObject,
+                                            (EXTMEM_NOR_SFDP_FlashInfoTypeDef *)Info);
+        break;
+      }
+#endif /* EXTMEM_DRIVER_NOR_SFDP == 1 */
+#if EXTMEM_DRIVER_SDCARD == 1
+      case EXTMEM_SDCARD :
+      {
+        /* Perform the Get Information operation using the SDCARD driver */
+        if (EXTMEM_DRIVER_SDCARD_OK != EXTMEM_DRIVER_SDCARD_GetInfo(&extmem_list_config[MemId].SdCardObject,
+                                                                    (EXTMEM_DRIVER_SDCARD_InfoTypeDef *)Info))
+        {
+          retr = EXTMEM_ERROR_DRIVER;
+        }
+        break;
+      }
+#endif /* EXTMEM_DRIVER_SDCARD == 1 */
+#if EXTMEM_DRIVER_CUSTOM == 1
+      case EXTMEM_CUSTOM :
+      {
+        /* Perform the Get Information operation using the CUSTOM driver */
+        if (EXTMEM_DRV_CUSTOM_OK != EXTMEM_DRIVER_CUSTOM_GetInfo(&extmem_list_config[MemId].CustomObject,
+                                                                 (EXTMEM_DRIVER_CUSTOM_MemInfoTypeDef *)Info))
+        {
+          retr = EXTMEM_ERROR_DRIVER;
+        }
+        break;
+      }
+#endif /* EXTMEM_DRIVER_CUSTOM == 1 */
+#if EXTMEM_DRIVER_USER == 1
+      case EXTMEM_USER :
+      {
+        /* Perform the Get Information operation using the USER driver */
+        if (EXTMEM_DRIVER_USER_OK != EXTMEM_DRIVER_USER_GetInfo(&extmem_list_config[MemId].UserObject,
+                                                                (EXTMEM_USER_MemInfoTypeDef *)Info))
+        {
+          retr = EXTMEM_ERROR_DRIVER;
+        }
+        break;
+      }
+#endif /* EXTMEM_DRIVER_USER == 1 */
+#if EXTMEM_DRIVER_PSRAM == 1
+      case EXTMEM_PSRAM :
+        /* Functionality not supported in this driver */
+        retr = EXTMEM_ERROR_NOTSUPPORTED;
+        break;
+#endif /* EXTMEM_DRIVER_PSRAM == 1 */
+      /* Unknown type of EXTMEM driver */
+      default:
+      {
+        EXTMEM_DEBUG("\terror : unknown memory type\n");
+        retr = EXTMEM_ERROR_UNKNOWNMEMORY;
+        break;
+      }
+    }
+  }
+  return retr;
+}
+
+/**
+  * @brief Enables or disables the memory mapped mode.
+  * @param MemId Memory identifier.
+  * @param State Enable or disable state (@ref EXTMEM_StateTypeDef).
+  * @retval EXTMEM_StatusTypeDef Status of the operation.
+  */
+EXTMEM_StatusTypeDef EXTMEM_MemoryMappedMode(uint32_t MemId, EXTMEM_StateTypeDef State)
+{
+  EXTMEM_StatusTypeDef retr = EXTMEM_ERROR_INVALID_ID;
+  EXTMEM_FUNC_CALL();
+
+  /* Check the memory ID */
+  if (MemId < (sizeof(extmem_list_config) / sizeof(EXTMEM_DefinitionTypeDef)))
+  {
+    retr = EXTMEM_OK;
+
+    /* Check type of EXTMEM driver used to access memory */
+    switch (extmem_list_config[MemId].MemType)
+    {
+#if EXTMEM_DRIVER_NOR_SFDP == 1
+      case EXTMEM_NOR_SFDP:
+      {
+        /* Perform the memory Map operation using the NOR SFDP driver */
+        if (EXTMEM_ENABLE == State)
+        {
+          /* Start the memory mapped mode */
+          if (EXTMEM_DRIVER_NOR_SFDP_OK !=
+              EXTMEM_DRIVER_NOR_SFDP_Enable_MemoryMappedMode(&extmem_list_config[MemId].NorSfdpObject))
+          {
+            return EXTMEM_ERROR_DRIVER;
+          }
+        }
+        else
+        {
+          /* Stop the memory mapped mode */
+          if (EXTMEM_DRIVER_NOR_SFDP_OK !=
+              EXTMEM_DRIVER_NOR_SFDP_Disable_MemoryMappedMode(&extmem_list_config[MemId].NorSfdpObject))
+          {
+            return EXTMEM_ERROR_DRIVER;
+          }
+        }
+        break;
+      }
+#endif /* EXTMEM_DRIVER_NOR_SFDP == 1 */
+#if EXTMEM_DRIVER_PSRAM == 1
+      case EXTMEM_PSRAM :
+      {
+        /* Perform the memory Map operation using the PSRAM driver */
+        if (EXTMEM_ENABLE == State)
+        {
+          /* Start the memory mapped mode */
+          if (EXTMEM_DRIVER_PSRAM_OK !=
+              EXTMEM_DRIVER_PSRAM_Enable_MemoryMappedMode(&extmem_list_config[MemId].PsramObject))
+          {
+            return EXTMEM_ERROR_DRIVER;
+          }
+        }
+        else
+        {
+          /* Stop the memory mapped mode */
+          if (EXTMEM_DRIVER_PSRAM_OK !=
+              EXTMEM_DRIVER_PSRAM_Disable_MemoryMappedMode(&extmem_list_config[MemId].PsramObject))
+          {
+            return EXTMEM_ERROR_DRIVER;
+          }
+        }
+        break;
+      }
+#endif /* EXTMEM_DRIVER_PSRAM == 1 */
+#if EXTMEM_DRIVER_CUSTOM == 1
+      case EXTMEM_CUSTOM :
+      {
+        /* Perform the memory Map operation using the CUSTOM driver */
+        if (EXTMEM_ENABLE == State)
+        {
+          /* Start the memory mapped mode */
+          if (EXTMEM_DRV_CUSTOM_OK !=
+              EXTMEM_DRIVER_CUSTOM_Enable_MemoryMappedMode(&extmem_list_config[MemId].CustomObject))
+          {
+            return EXTMEM_ERROR_DRIVER;
+          }
+        }
+        else
+        {
+          /* Stop the memory mapped mode */
+          if (EXTMEM_DRV_CUSTOM_OK !=
+              EXTMEM_DRIVER_CUSTOM_Disable_MemoryMappedMode(&extmem_list_config[MemId].CustomObject))
+          {
+            return EXTMEM_ERROR_DRIVER;
+          }
+        }
+        break;
+      }
+#endif /* EXTMEM_DRIVER_CUSTOM == 1 */
+#if EXTMEM_DRIVER_USER == 1
+      case EXTMEM_USER :
+      {
+        /* Perform the memory Map operation using the USER driver */
+        EXTMEM_DRIVER_USER_StatusTypeDef status;
+        if (EXTMEM_ENABLE == State)
+        {
+          /* Start the memory mapped mode */
+          status = EXTMEM_DRIVER_USER_Enable_MemoryMappedMode(&extmem_list_config[MemId].UserObject);
+        }
+        else
+        {
+          /* Stop the memory mapped mode */
+          status = EXTMEM_DRIVER_USER_Disable_MemoryMappedMode(&extmem_list_config[MemId].UserObject);
+        }
+        switch (status)
+        {
+          case EXTMEM_DRIVER_USER_NOTSUPPORTED:
+            retr = EXTMEM_ERROR_NOTSUPPORTED;
+            break;
+          case EXTMEM_DRIVER_USER_OK:
+            break;
+          default:
+            retr = EXTMEM_ERROR_DRIVER;
+            break;
+        }
+        break;
+      }
+#endif /* EXTMEM_DRIVER_USER == 1 */
+#if EXTMEM_DRIVER_SDCARD == 1
+      case EXTMEM_SDCARD :
+        /* Functionality not supported in this driver */
+        retr = EXTMEM_ERROR_NOTSUPPORTED;
+        break;
+#endif /* EXTMEM_DRIVER_SDCARD == 1 */
+      /* Unknown type of EXTMEM driver */
+      default:
+      {
+        EXTMEM_DEBUG("\terror : unknown memory type\n");
+        retr = EXTMEM_ERROR_UNKNOWNMEMORY;
+        break;
+      }
+    }
+  }
+  return retr;
+}
+
+/**
+  * @brief Gets the base address of the mapped external memory.
+  * @param MemId Memory identifier.
+  * @param BaseAddress Pointer to variable to receive the base address.
+  * @retval EXTMEM_StatusTypeDef Status of the operation.
+  */
+EXTMEM_StatusTypeDef EXTMEM_GetMapAddress(uint32_t MemId, uint32_t *BaseAddress)
+{
+  EXTMEM_StatusTypeDef retr = EXTMEM_ERROR_INVALID_ID;
+  EXTMEM_FUNC_CALL();
+
+  /* Check the memory ID */
+  if (MemId < (sizeof(extmem_list_config) / sizeof(EXTMEM_DefinitionTypeDef)))
+  {
+    retr = EXTMEM_OK;
+
+    /* Check type of EXTMEM driver used to access memory */
+    switch (extmem_list_config[MemId].MemType)
+    {
+#if EXTMEM_DRIVER_NOR_SFDP == 1 || EXTMEM_DRIVER_PSRAM == 1
+      case EXTMEM_PSRAM:
+      case EXTMEM_NOR_SFDP:
+      {
+        /* Define Map address based on Instance used for memory access */
+#if defined(XSPI1)
+        if (((XSPI_HandleTypeDef *)extmem_list_config[MemId].Handle)->Instance == XSPI1)
+        {
+          *BaseAddress = XSPI1_BASE;
+        }
+#if defined(XSPI2)
+        else if (((XSPI_HandleTypeDef *)extmem_list_config[MemId].Handle)->Instance == XSPI2)
+        {
+          *BaseAddress = XSPI2_BASE;
+        }
+#if defined(XSPI3)
+        else if (((XSPI_HandleTypeDef *)extmem_list_config[MemId].Handle)->Instance == XSPI3)
+        {
+          *BaseAddress = XSPI3_BASE;
+        }
+#endif /* XSPI3 */
+#endif /* XSPI2 */
+#else  /* XSPI1 */
+        if (((XSPI_HandleTypeDef *)extmem_list_config[MemId].Handle)->Instance == OCTOSPI1)
+        {
+          *BaseAddress = OCTOSPI1_BASE;
+        }
+#endif  /* XSPI1 */
+        else
+        {
+          retr = EXTMEM_ERROR_DRIVER;
+        }
+
+        break;
+      }
+#endif /* EXTMEM_DRIVER_NOR_SFDP == 1 || EXTMEM_DRIVER_PSRAM == 1 */
+#if EXTMEM_DRIVER_SDCARD == 1
+      case EXTMEM_SDCARD :
+      {
+        retr = EXTMEM_ERROR_NOTSUPPORTED;
+        break;
+      }
+#endif /* EXTMEM_DRIVER_SDCARD == 1 */
+#if EXTMEM_DRIVER_CUSTOM == 1
+      case EXTMEM_CUSTOM:
+      {
+        /* Perform the Get Map Address operation using the CUSTOM driver */
+        if (EXTMEM_DRV_CUSTOM_OK != EXTMEM_DRIVER_CUSTOM_GetMapAddress(&extmem_list_config[MemId].CustomObject,
+                                                                       BaseAddress))
+        {
+          retr = EXTMEM_ERROR_DRIVER;
+        }
+        break;
+      }
+#endif /* EXTMEM_DRIVER_CUSTOM == 1 */
+#if EXTMEM_DRIVER_USER == 1
+      case EXTMEM_USER:
+      {
+        /* Perform the Get Map Address operation using the USER driver */
+        switch (EXTMEM_DRIVER_USER_GetMapAddress(&extmem_list_config[MemId].UserObject, BaseAddress))
+        {
+          case EXTMEM_DRIVER_USER_OK:
+            break;
+          case EXTMEM_DRIVER_USER_NOTSUPPORTED:
+            retr = EXTMEM_ERROR_NOTSUPPORTED;
+            break;
+          default :
+            retr = EXTMEM_ERROR_DRIVER;
+            break;
+        }
+        break;
+      }
+#endif /* EXTMEM_DRIVER_USER == 1 */
+      /* Unknown type of EXTMEM driver */
+      default :
+      {
+        EXTMEM_DEBUG("\terror : unknown memory type\n");
+        retr = EXTMEM_ERROR_UNKNOWNMEMORY;
+        break;
+      }
+    }
+  }
+  return retr;
+}
+/**
+  * @}
+  */
+
+/**
+  * @}
+  */
Index: trunk/firmware/FSBL/CubeMX/Middlewares/ST/STM32_ExtMem_Manager/stm32_extmem.h
===================================================================
--- trunk/firmware/FSBL/CubeMX/Middlewares/ST/STM32_ExtMem_Manager/stm32_extmem.h	(revision 20)
+++ trunk/firmware/FSBL/CubeMX/Middlewares/ST/STM32_ExtMem_Manager/stm32_extmem.h	(revision 20)
@@ -0,0 +1,165 @@
+/**
+  ******************************************************************************
+  * @file    stm32_extmem.h
+  * @author  MCD Application Team
+  * @brief   This file contains the external memory functions prototypes.
+  ******************************************************************************
+  * @attention
+  *
+  * Copyright (c) 2022 STMicroelectronics.
+  * All rights reserved.
+  *
+  * This software is licensed under terms that can be found in the LICENSE file
+  * in the root directory of this software component.
+  * If no LICENSE file comes with this software, it is provided AS-IS.
+  *
+  ******************************************************************************
+  */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __STM32_EXTMEM_H_
+#define __STM32_EXTMEM_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** @addtogroup EXTMEM
+  * @{
+  */
+
+/* Includes ------------------------------------------------------------------*/
+#include <stdint.h>
+
+/* Exported constants --------------------------------------------------------*/
+/* Exported types ------------------------------------------------------------*/
+/** @defgroup EXTMEM_Exported_Types External Memory Exported Types
+  * @{
+  */
+
+/**
+  * @brief Middleware version number
+  */
+#define EXTMEM_VERSION 0x00010600 /* Version v1.6.0 */
+
+/**
+  * @brief Types of supported memories
+  */
+typedef enum
+{
+  EXTMEM_NOR_SFDP,
+  EXTMEM_NOR_CFI,
+  EXTMEM_PSRAM,
+  EXTMEM_SDCARD,
+  EXTMEM_CUSTOM,
+  EXTMEM_USER
+} EXTMEM_TypeTypeDef;
+
+/**
+  * @brief EXTMEM module function call return values
+  */
+typedef enum
+{
+  EXTMEM_OK,                       /*!< Action performed with a status ok */
+  EXTMEM_ERROR_NOTSUPPORTED  = -1, /*!< Action not supported by the memory type */
+  EXTMEM_ERROR_UNKNOWNMEMORY = -2, /*!< Unknown memory type */
+  EXTMEM_ERROR_DRIVER        = -3, /*!< Error return by the driver layer */
+  EXTMEM_ERROR_SECTOR_SIZE   = -4, /*!< Inconsistency between the size and the sector size of the memory */
+  EXTMEM_ERROR_INVALID_ID    = -5, /*!< Invalid memory ID */
+  EXTMEM_ERROR_PARAM         = -6, /*!< Parameter value error */
+} EXTMEM_StatusTypeDef;
+
+/**
+  * @brief Enable/disable state of the module
+  */
+typedef enum
+{
+  EXTMEM_ENABLE,              /*!< State enable */
+  EXTMEM_DISABLE              /*!< State disable */
+} EXTMEM_StateTypeDef;
+
+/**
+  * @brief NOR SFDP memory information structure
+  */
+typedef struct
+{
+  uint8_t  FlashSize;         /*!< Specifies the flash size as a power of 2 */
+  uint32_t PageSize;          /*!< Page size in bytes */
+  uint32_t EraseType1Size;    /*!< Erase Type 1 size */
+  uint32_t EraseType2Size;    /*!< Erase Type 2 size */
+  uint32_t EraseType3Size;    /*!< Erase Type 3 size */
+  uint32_t EraseType4Size;    /*!< Erase Type 4 size */
+} EXTMEM_NOR_SFDP_FlashInfoTypeDef;
+
+
+/**
+  * @brief USER memory information structure
+  */
+typedef struct
+{
+  uint8_t  MemSize;           /*!< Specifies the memory size as a power of 2 */
+  uint32_t MpuCache;          /*!< MPU Cache */
+}  EXTMEM_USER_MemInfoTypeDef;
+
+/**
+  * @brief SD card information structure
+  */
+typedef struct
+{
+  uint32_t CardType;        /*!< Specifies the card type                         */
+  uint32_t CardVersion;     /*!< Specifies the card version                      */
+  uint32_t Class;           /*!< Specifies the card class                        */
+  uint32_t RelCardAdd;      /*!< Specifies the relative card address             */
+  uint32_t BlockNbr;        /*!< Specifies the card capacity in blocks           */
+  uint32_t BlockSize;       /*!< Specifies the block size in bytes               */
+  uint32_t LogBlockNbr;     /*!< Specifies the card logical capacity in blocks   */
+  uint32_t LogBlockSize;    /*!< Specifies the logical block size in bytes       */
+  uint32_t CardSpeed;       /*!< Specifies the card speed                        */
+} EXTMEM_DRIVER_SDCARD_InfoTypeDef;
+
+/**
+  * @brief Number of physical I/O line(s) connected with the memory
+  */
+typedef enum
+{
+  EXTMEM_LINK_CONFIG_1LINE,     /*!< Configuration using  1 line  */
+  EXTMEM_LINK_CONFIG_2LINES,    /*!< Configuration using  2 lines */
+  EXTMEM_LINK_CONFIG_4LINES,    /*!< Configuration using  4 lines */
+  EXTMEM_LINK_CONFIG_8LINES,    /*!< Configuration using  8 lines */
+  EXTMEM_LINK_CONFIG_16LINES,   /*!< Configuration using 16 lines */
+} EXTMEM_LinkConfig_TypeDef;
+
+/**
+  * @}
+  */
+
+/* Exported functions --------------------------------------------------------*/
+/** @addtogroup EXTMEM_Exported_Functions External Memory Exported Functions
+  * @{
+  */
+
+EXTMEM_StatusTypeDef EXTMEM_Init(uint32_t MemId, uint32_t ClockInput);
+EXTMEM_StatusTypeDef EXTMEM_DeInit(uint32_t MemId);
+EXTMEM_StatusTypeDef EXTMEM_Read(uint32_t MemId, uint32_t Address, uint8_t *Data, uint32_t Size);
+EXTMEM_StatusTypeDef EXTMEM_Write(uint32_t MemId, uint32_t Address, const uint8_t *Data, uint32_t Size);
+EXTMEM_StatusTypeDef EXTMEM_WriteInMappedMode(uint32_t MemId, uint32_t Address, const uint8_t *const Data,
+                                              uint32_t Size);
+EXTMEM_StatusTypeDef EXTMEM_EraseSector(uint32_t MemId, uint32_t Address, uint32_t Size);
+EXTMEM_StatusTypeDef EXTMEM_EraseAll(uint32_t MemId);
+EXTMEM_StatusTypeDef EXTMEM_GetInfo(uint32_t MemId, void *Info);
+EXTMEM_StatusTypeDef EXTMEM_MemoryMappedMode(uint32_t MemId, EXTMEM_StateTypeDef State);
+EXTMEM_StatusTypeDef EXTMEM_GetMapAddress(uint32_t MemId, uint32_t *BaseAddress);
+
+/**
+  * @}
+  */
+
+/**
+  * @}
+  */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __STM32_EXTMEM_H_ */
Index: trunk/firmware/FSBL/CubeMX/Middlewares/ST/STM32_ExtMem_Manager/stm32_extmem_type.h
===================================================================
--- trunk/firmware/FSBL/CubeMX/Middlewares/ST/STM32_ExtMem_Manager/stm32_extmem_type.h	(revision 20)
+++ trunk/firmware/FSBL/CubeMX/Middlewares/ST/STM32_ExtMem_Manager/stm32_extmem_type.h	(revision 20)
@@ -0,0 +1,159 @@
+/**
+  ******************************************************************************
+  * @file    stm32_extmem_type.h
+  * @author  MCD Application Team
+  * @brief   This file contains the external memory type definition.
+  ******************************************************************************
+  * @attention
+  *
+  * Copyright (c) 2022 STMicroelectronics.
+  * All rights reserved.
+  *
+  * This software is licensed under terms that can be found in the LICENSE file
+  * in the root directory of this software component.
+  * If no LICENSE file comes with this software, it is provided AS-IS.
+  *
+  ******************************************************************************
+  */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __STM32_EXTMEM_TYPE_H_
+#define __STM32_EXTMEM_TYPE_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** @addtogroup EXTMEM
+  * @{
+  */
+
+/* Includes ------------------------------------------------------------------*/
+#if EXTMEM_SAL_XSPI == 1
+#include "sal/stm32_sal_xspi_type.h"
+#endif /* EXTMEM_SAL_XSPI */
+
+#if EXTMEM_SAL_SD == 1
+#include "sal/stm32_sal_sd_type.h"
+#endif /* EXTMEM_SAL_SD */
+
+#if EXTMEM_SAL_MMC == 1
+#include "sal/stm32_sal_mmc_type.h"
+#endif /* EXTMEM_SAL_MMC */
+
+#if EXTMEM_DRIVER_NOR_SFDP == 1
+#include "nor_sfdp/stm32_sfdp_driver_type.h"
+#endif /* DRIVER_SFDP_ENABLED */
+
+#if EXTMEM_DRIVER_SDCARD == 1
+#include "sdcard/stm32_sdcard_driver_type.h"
+#endif /* DRIVER_SDCARD_ENABLED */
+
+#if EXTMEM_DRIVER_PSRAM == 1
+#include "psram/stm32_psram_driver_type.h"
+#endif /* DRIVER_PSRAM_ENABLED */
+
+#if EXTMEM_DRIVER_CUSTOM == 1
+#include "custom/stm32_custom_driver_type.h"
+#endif /* DRIVER_USER_ENABLED */
+
+#if EXTMEM_DRIVER_USER == 1
+#include "user/stm32_user_driver_type.h"
+#endif /* DRIVER_USER_ENABLED */
+
+/* Exported macros -----------------------------------------------------------*/
+/** @defgroup EXTMEM_Exported_Macros External Memory Exported Macros
+  * @{
+  */
+/**
+  * @brief Macro to get the minimum value
+  */
+#define EXTMEM_MIN(_A_,_B_)    ((_A_)>(_B_))?(_B_):(_A_);
+/**
+  * @}
+  */
+
+/* Exported constants --------------------------------------------------------*/
+
+/** @defgroup EXTMEM_Exported_Constants External Memory Exported Constants
+  * @{
+  */
+
+/** @defgroup EXTMEM_Manufacturer_IDs EXTMEM JEDEC Manufacturer IDs
+  * @{
+  */
+#define EXTMEM_MANUFACTURER_MACRONIX    (0xC2U)   /*!< JEDEC ID for Macronix */
+#define EXTMEM_MANUFACTURER_GIGADEVICE  (0xC8U)   /*!< JEDEC ID for GigaDevice */
+#define EXTMEM_MANUFACTURER_ISSI        (0x9DU)   /*!< JEDEC ID for ISSI */
+#define EXTMEM_MANUFACTURER_WINBOND     (0xEFU)   /*!< JEDEC ID for Winbond */
+/**
+  * @}
+  */
+
+/** @defgroup EXTMEM_Common_JEDEC_Commands EXTMEM Common JEDEC commands identifiers
+  * @{
+  */
+#define EXTMEM_READ_JEDEC_ID_SPI_COMMAND                0x9FU
+#define EXTMEM_READ_JEDEC_ID_SIZE                       0x04U
+
+#define EXTMEM_READ_SFDP_COMMAND                        0x5AU
+#define EXTMEM_READ_SFDP_NB_DUMMY_CYCLES_DEFAULT        8U
+#define EXTMEM_READ_SFDP_NB_DUMMY_CYCLES_OPI            20U
+
+#define EXTMEM_FAST_READ_NB_DUMMY_CYCLES_DEFAULT        8U
+
+/**
+  * @}
+  */
+
+/**
+  * @}
+  */
+
+/* Exported types ------------------------------------------------------------*/
+/** @defgroup EXTMEM_Exported_TypeDefinitions External Memory Exported Type Definitions
+  * @{
+  */
+
+/**
+  * @brief Definition of the memory
+  */
+typedef struct
+{
+  EXTMEM_TypeTypeDef MemType;               /*!< Specifies the memory driver type */
+  void *Handle;                             /*!< Pointer to HAL handle */
+  EXTMEM_LinkConfig_TypeDef ConfigType;     /*!< Specifies the physical link configuration */
+  union
+  {
+#if EXTMEM_DRIVER_NOR_SFDP == 1
+    EXTMEM_DRIVER_NOR_SFDP_ObjectTypeDef  NorSfdpObject;  /*!< Object for NOR SFDP driver */
+#endif /* EXTMEM_DRIVER_NOR_SFDP == 1 */
+#if EXTMEM_DRIVER_SDCARD == 1
+    EXTMEM_DRIVER_SDCARD_ObjectTypeDef    SdCardObject;   /*!< Object for SD Card driver */
+#endif /* EXTMEM_DRIVER_SDCARD == 1 */
+#if EXTMEM_DRIVER_PSRAM == 1
+    EXTMEM_DRIVER_PSRAM_ObjectTypeDef     PsramObject;    /*!< Object for PSRAM driver */
+#endif /* EXTMEM_DRIVER_PSRAM == 1 */
+#if EXTMEM_DRIVER_CUSTOM == 1
+    EXTMEM_DRIVER_CUSTOM_ObjectTypeDef    CustomObject;   /*!< Object for Custom driver */
+#endif /* EXTMEM_DRIVER_CUSTOM == 1 */
+#if EXTMEM_DRIVER_USER == 1
+    EXTMEM_DRIVER_USER_ObjectTypeDef      UserObject;     /*!< Object for User driver */
+#endif /* EXTMEM_DRIVER_USER == 1 */
+  };
+} EXTMEM_DefinitionTypeDef;
+
+/**
+  * @}
+  */
+
+
+/**
+  * @}
+  */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __STM32_EXTMEM_TYPE_H_ */
